diff --git a/contracts/JBChainlinkV3PriceFeed.sol b/contracts/JBChainlinkV3PriceFeed.sol index a4529fc70..ddd85787b 100644 --- a/contracts/JBChainlinkV3PriceFeed.sol +++ b/contracts/JBChainlinkV3PriceFeed.sol @@ -1,18 +1,11 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.16; -import '@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol'; -import './interfaces/IJBPriceFeed.sol'; -import './libraries/JBFixedPointNumber.sol'; +import {AggregatorV3Interface} from '@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol'; +import {IJBPriceFeed} from './interfaces/IJBPriceFeed.sol'; +import {JBFixedPointNumber} from './libraries/JBFixedPointNumber.sol'; -/** - @notice - A generalized price feed for the Chainlink AggregatorV3Interface. - - @dev - Adheres to - - IJBPriceFeed: General interface for the methods in this contract that interact with the blockchain's state according to the protocol's rules. -*/ +/// @notice A generalized price feed for the Chainlink AggregatorV3Interface. contract JBChainlinkV3PriceFeed is IJBPriceFeed { // A library that provides utility for fixed point numbers. using JBFixedPointNumber for uint256; @@ -28,24 +21,16 @@ contract JBChainlinkV3PriceFeed is IJBPriceFeed { // ---------------- public stored immutable properties --------------- // //*********************************************************************// - /** - @notice - The feed that prices are reported from. - */ + /// @notice The feed that prices are reported from. AggregatorV3Interface public immutable feed; //*********************************************************************// // ------------------------- external views -------------------------- // //*********************************************************************// - /** - @notice - Gets the current price from the feed, normalized to the specified number of decimals. - - @param _decimals The number of decimals the returned fixed point price should include. - - @return The current price of the feed, as a fixed point number with the specified number of decimals. - */ + /// @notice Gets the current price from the feed, normalized to the specified number of decimals. + /// @param _decimals The number of decimals the returned fixed point price should include. + /// @return The current price of the feed, as a fixed point number with the specified number of decimals. function currentPrice(uint256 _decimals) external view override returns (uint256) { // Get the latest round information. (uint80 roundId, int256 _price, , uint256 updatedAt, uint80 answeredInRound) = feed @@ -71,9 +56,7 @@ contract JBChainlinkV3PriceFeed is IJBPriceFeed { // -------------------------- constructor ---------------------------- // //*********************************************************************// - /** - @param _feed The feed to report prices from. - */ + /// @param _feed The feed to report prices from. constructor(AggregatorV3Interface _feed) { feed = _feed; } diff --git a/contracts/JBController.sol b/contracts/JBController.sol index 77c07b81a..6b7c180c4 100644 --- a/contracts/JBController.sol +++ b/contracts/JBController.sol @@ -1,34 +1,37 @@ // 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. -*/ +import {ERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol'; +import {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol'; +import {SafeCast} from '@openzeppelin/contracts/utils/math/SafeCast.sol'; +import {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol'; +import {JBOperatable} from './abstract/JBOperatable.sol'; +import {JBBallotState} from './enums/JBBallotState.sol'; +import {IJBController} from './interfaces/IJBController.sol'; +import {IJBDirectory} from './interfaces/IJBDirectory.sol'; +import {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol'; +import {IJBMigratable} from './interfaces/IJBMigratable.sol'; +import {IJBOperatable} from './interfaces/IJBOperatable.sol'; +import {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol'; +import {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol'; +import {IJBProjects} from './interfaces/IJBProjects.sol'; +import {IJBSplitAllocator} from './interfaces/IJBSplitAllocator.sol'; +import {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol'; +import {IJBTokenStore} from './interfaces/IJBTokenStore.sol'; +import {JBConstants} from './libraries/JBConstants.sol'; +import {JBFundingCycleMetadataResolver} from './libraries/JBFundingCycleMetadataResolver.sol'; +import {JBOperations} from './libraries/JBOperations.sol'; +import {JBSplitsGroups} from './libraries/JBSplitsGroups.sol'; +import {JBSplitAllocationData} from './structs/JBSplitAllocationData.sol'; +import {JBFundAccessConstraints} from './structs/JBFundAccessConstraints.sol'; +import {JBFundingCycle} from './structs/JBFundingCycle.sol'; +import {JBFundingCycleData} from './structs/JBFundingCycleData.sol'; +import {JBFundingCycleMetadata} from './structs/JBFundingCycleMetadata.sol'; +import {JBGroupedSplits} from './structs/JBGroupedSplits.sol'; +import {JBProjectMetadata} from './structs/JBProjectMetadata.sol'; +import {JBSplit} from './structs/JBSplit.sol'; + +/// @notice Stitches together funding cycles and project tokens, making sure all activity is accounted for and correct. 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; @@ -50,54 +53,33 @@ contract JBController is JBOperatable, ERC165, IJBController, IJBMigratable { error MINT_NOT_ALLOWED_AND_NOT_TERMINAL_DELEGATE(); error NO_BURNABLE_TOKENS(); error NOT_CURRENT_CONTROLLER(); - error OVERFLOW_ALERT(); error ZERO_TOKENS_TO_MINT(); //*********************************************************************// // --------------------- internal stored properties ------------------ // //*********************************************************************// - /** - @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. - */ + /// @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. + /// @custom:param _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. - - @dev - bits 0-231: The amount of token that a project can distribute per funding cycle. - - @dev - 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. - _configuration The configuration during which the packed distribution limit data applies. - _terminal The terminal from which distributions are being limited. - _token The token for which distributions are being limited. - */ + /// @notice Data regarding the distribution limit of a project during a configuration. + /// @dev bits 0-231: The amount of token that a project can distribute per funding cycle. + /// @dev bits 232-255: The currency of amount that a project can distribute. + /// @custom:param _projectId The ID of the project to get the packed distribution limit data of. + /// @custom:param _configuration The configuration during which the packed distribution limit data applies. + /// @custom:param _terminal The terminal from which distributions are being limited. + /// @custom:param _token The token for which distributions are being limited. mapping(uint256 => mapping(uint256 => mapping(IJBPaymentTerminal => mapping(address => uint256)))) internal _packedDistributionLimitDataOf; - /** - @notice - Data regarding the overflow allowance of a project during a configuration. - - @dev - bits 0-231: The amount of overflow that a project is allowed to tap into on-demand throughout the configuration. - - @dev - 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. - _configuration The configuration during which the packed overflow allowance data applies. - _terminal The terminal managing the overflow. - _token The token for which overflow is being allowed. - */ + /// @notice Data regarding the overflow allowance of a project during a configuration. + /// @dev bits 0-231: The amount of overflow that a project is allowed to tap into on-demand throughout the configuration. + /// @dev bits 232-255: The currency of the amount of overflow that a project is allowed to tap. + /// @custom:param _projectId The ID of the project to get the packed overflow allowance data of. + /// @custom:param _configuration The configuration during which the packed overflow allowance data applies. + /// @custom:param _terminal The terminal managing the overflow. + /// @custom:param _token The token for which overflow is being allowed. mapping(uint256 => mapping(uint256 => mapping(IJBPaymentTerminal => mapping(address => uint256)))) internal _packedOverflowAllowanceDataOf; @@ -105,55 +87,33 @@ contract JBController is JBOperatable, ERC165, IJBController, IJBMigratable { // --------------- public immutable stored properties ---------------- // //*********************************************************************// - /** - @notice - Mints ERC-721's that represent project ownership. - */ + /// @notice Mints ERC-721's that represent project ownership. IJBProjects public immutable override projects; - /** - @notice - The contract storing all funding cycle configurations. - */ + /// @notice The contract storing all funding cycle configurations. IJBFundingCycleStore public immutable override fundingCycleStore; - /** - @notice - The contract that manages token minting and burning. - */ + /// @notice The contract that manages token minting and burning. IJBTokenStore public immutable override tokenStore; - /** - @notice - The contract that stores splits for each project. - */ + /// @notice The contract that stores splits for each project. IJBSplitsStore public immutable override splitsStore; - /** - @notice - The directory of terminals and controllers for projects. - */ + /// @notice The directory of terminals and controllers for projects. IJBDirectory public immutable override directory; //*********************************************************************// // ------------------------- external views -------------------------- // //*********************************************************************// - /** - @notice - The amount of token that a project can distribute per funding cycle, 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 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. - */ + /// @notice The amount of token that a project can distribute per funding cycle, 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 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, @@ -167,21 +127,14 @@ contract JBController is JBOperatable, ERC165, IJBController, IJBMigratable { return (uint256(uint232(_data)), _data >> 232); } - /** - @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. - */ + /// @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, @@ -195,21 +148,14 @@ contract JBController is JBOperatable, ERC165, IJBController, IJBMigratable { 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) - { + /// @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], @@ -218,21 +164,14 @@ contract JBController is JBOperatable, ERC165, IJBController, IJBMigratable { ); } - /** - @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. - */ - function totalOutstandingTokensOf(uint256 _projectId, uint256 _reservedRate) - external - view - override - returns (uint256) - { + /// @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. + function totalOutstandingTokensOf( + uint256 _projectId, + uint256 _reservedRate + ) external view override returns (uint256) { // Get the total number of tokens in circulation. uint256 _totalSupply = tokenStore.totalSupplyOf(_projectId); @@ -247,16 +186,14 @@ contract JBController is JBOperatable, ERC165, IJBController, IJBMigratable { return _totalSupply + _reservedTokenAmount; } - /** - @notice - 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. - - @return fundingCycle The funding cycle. - @return metadata The funding cycle's metadata. - */ - function getFundingCycleOf(uint256 _projectId, uint256 _configuration) + /// @notice 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. + /// @return fundingCycle The funding cycle. + /// @return metadata The funding cycle's metadata. + function getFundingCycleOf( + uint256 _projectId, + uint256 _configuration + ) external view override @@ -266,17 +203,14 @@ contract JBController is JBOperatable, ERC165, IJBController, IJBMigratable { metadata = fundingCycle.expandMetadata(); } - /** - @notice - 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. - - @return fundingCycle The latest configured funding cycle. - @return metadata The latest configured funding cycle's metadata. - @return ballotState The state of the configuration. - */ - function latestConfiguredFundingCycleOf(uint256 _projectId) + /// @notice 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. + /// @return fundingCycle The latest configured funding cycle. + /// @return metadata The latest configured funding cycle's metadata. + /// @return ballotState The state of the configuration. + function latestConfiguredFundingCycleOf( + uint256 _projectId + ) external view override @@ -290,16 +224,13 @@ contract JBController is JBOperatable, ERC165, IJBController, IJBMigratable { metadata = fundingCycle.expandMetadata(); } - /** - @notice - A project's current funding cycle along with its metadata. - - @param _projectId The ID of the project to which the funding cycle belongs. - - @return fundingCycle The current funding cycle. - @return metadata The current funding cycle's metadata. - */ - function currentFundingCycleOf(uint256 _projectId) + /// @notice A project's current funding cycle along with its metadata. + /// @param _projectId The ID of the project to which the funding cycle belongs. + /// @return fundingCycle The current funding cycle. + /// @return metadata The current funding cycle's metadata. + function currentFundingCycleOf( + uint256 _projectId + ) external view override @@ -309,16 +240,13 @@ contract JBController is JBOperatable, ERC165, IJBController, IJBMigratable { metadata = fundingCycle.expandMetadata(); } - /** - @notice - A project's queued funding cycle along with its metadata. - - @param _projectId The ID of the project to which the funding cycle belongs. - - @return fundingCycle The queued funding cycle. - @return metadata The queued funding cycle's metadata. - */ - function queuedFundingCycleOf(uint256 _projectId) + /// @notice A project's queued funding cycle along with its metadata. + /// @param _projectId The ID of the project to which the funding cycle belongs. + /// @return fundingCycle The queued funding cycle. + /// @return metadata The queued funding cycle's metadata. + function queuedFundingCycleOf( + uint256 _projectId + ) external view override @@ -332,22 +260,13 @@ contract JBController is JBOperatable, ERC165, IJBController, IJBMigratable { // -------------------------- public views --------------------------- // //*********************************************************************// - /** - @notice - Indicates if this contract adheres to the specified interface. - - @dev - See {IERC165-supportsInterface}. - - @param _interfaceId The ID of the interface to check for adherance to. - */ - function supportsInterface(bytes4 _interfaceId) - public - view - virtual - override(ERC165, IERC165) - returns (bool) - { + /// @notice Indicates if this contract adheres to the specified interface. + /// @dev See {IERC165-supportsInterface}. + /// @param _interfaceId The ID of the interface to check for adherance to. + /// @return A flag indicating if the provided interface ID is supported. + function supportsInterface( + bytes4 _interfaceId + ) public view virtual override(ERC165, IERC165) returns (bool) { return _interfaceId == type(IJBController).interfaceId || _interfaceId == type(IJBMigratable).interfaceId || @@ -359,14 +278,12 @@ contract JBController is JBOperatable, ERC165, IJBController, IJBMigratable { // ---------------------------- constructor -------------------------- // //*********************************************************************// - /** - @param _operatorStore A contract storing operator assignments. - @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 _fundingCycleStore A contract storing all funding cycle configurations. - @param _tokenStore A contract that manages token minting and burning. - @param _splitsStore A contract that stores splits for each project. - */ + /// @param _operatorStore A contract storing operator assignments. + /// @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 _fundingCycleStore A contract storing all funding cycle configurations. + /// @param _tokenStore A contract that manages token minting and burning. + /// @param _splitsStore A contract that stores splits for each project. constructor( IJBOperatorStore _operatorStore, IJBProjects _projects, @@ -386,28 +303,19 @@ contract JBController is JBOperatable, ERC165, IJBController, IJBMigratable { // --------------------- external transactions ----------------------- // //*********************************************************************// - /** - @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. - - @dev - Each operation within this transaction can be done in sequence separately. - - @dev - 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 _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 _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 _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 _terminals Payment terminals to add for the project. - @param _memo A memo to pass along to the emitted event. - - @return projectId The ID of the project. - */ + /// @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. + /// @dev Each operation within this transaction can be done in sequence separately. + /// @dev 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 _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 _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 _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 _terminals Payment terminals to add for the project. + /// @param _memo A memo to pass along to the emitted event. + /// @return projectId The ID of the project. function launchProjectFor( address _owner, JBProjectMetadata calldata _projectMetadata, @@ -444,27 +352,18 @@ contract JBController is JBOperatable, ERC165, IJBController, IJBMigratable { emit LaunchProject(_configuration, projectId, _memo, msg.sender); } - /** - @notice - Creates a funding cycle for an already existing project ERC-721. - - @dev - Each operation within this transaction can be done in sequence separately. - - @dev - Only a project owner or operator can launch its funding cycles. - - @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 _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 _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 _terminals Payment terminals to add for the project. - @param _memo A memo to pass along to the emitted event. - - @return configuration The configuration of the funding cycle that was successfully created. - */ + /// @notice Creates a funding cycle for an already existing project ERC-721. + /// @dev Each operation within this transaction can be done in sequence separately. + /// @dev Only a project owner or operator can launch its funding cycles. + /// @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 _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 _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 _terminals Payment terminals to add for the project. + /// @param _memo A memo to pass along to the emitted event. + /// @return configuration The configuration of the funding cycle that was successfully created. function launchFundingCyclesFor( uint256 _projectId, JBFundingCycleData calldata _data, @@ -504,23 +403,16 @@ contract JBController is JBOperatable, ERC165, IJBController, IJBMigratable { emit LaunchFundingCycles(configuration, _projectId, _memo, msg.sender); } - /** - @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. - - @dev - 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 _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 _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 _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. - - @return configuration The configuration of the funding cycle that was successfully reconfigured. - */ + /// @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. + /// @dev 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 _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 _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 _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. + /// @return configuration The configuration of the funding cycle that was successfully reconfigured. function reconfigureFundingCyclesOf( uint256 _projectId, JBFundingCycleData calldata _data, @@ -549,22 +441,15 @@ contract JBController is JBOperatable, ERC165, IJBController, IJBMigratable { emit ReconfigureFundingCycles(configuration, _projectId, _memo, msg.sender); } - /** - @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. - - @dev - 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 _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 _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 _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. - */ + /// @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. + /// @dev 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 _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 _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 _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. function mintTokensOf( uint256 _projectId, uint256 _tokenCount, @@ -644,19 +529,13 @@ contract JBController is JBOperatable, ERC165, IJBController, IJBMigratable { ); } - /** - @notice - Burns a token holder's supply. - - @dev - 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 _projectId The ID of the project to which the tokens being burned belong. - @param _tokenCount The number of tokens to burn. - @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. - */ + /// @notice Burns a token holder's supply. + /// @dev 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 _projectId The ID of the project to which the tokens being burned belong. + /// @param _tokenCount The number of tokens to burn. + /// @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. function burnTokensOf( address _holder, uint256 _projectId, @@ -697,34 +576,21 @@ contract JBController is JBOperatable, ERC165, IJBController, IJBMigratable { emit BurnTokens(_holder, _projectId, _tokenCount, _memo, msg.sender); } - /** - @notice - Distributes all outstanding reserved tokens for a project. - - @param _projectId The ID of the project to which the reserved tokens belong. - @param _memo A memo to pass along to the emitted event. - - @return The amount of minted reserved tokens. - */ - function distributeReservedTokensOf(uint256 _projectId, string calldata _memo) - external - virtual - override - returns (uint256) - { + /// @notice Distributes all outstanding reserved tokens for a project. + /// @param _projectId The ID of the project to which the reserved tokens belong. + /// @param _memo A memo to pass along to the emitted event. + /// @return The amount of minted reserved tokens. + function distributeReservedTokensOf( + uint256 _projectId, + string calldata _memo + ) external virtual override returns (uint256) { return _distributeReservedTokensOf(_projectId, _memo); } - /** - @notice - Allows other controllers to signal to this one that a migration is expected for the specified project. - - @dev - 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 _from The controller being migrated from. - */ + /// @notice Allows other controllers to signal to this one that a migration is expected for the specified project. + /// @dev 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 _from The controller being migrated from. function prepForMigrationOf(uint256 _projectId, address _from) external virtual override { // This controller must not be the project's current controller. if (directory.controllerOf(_projectId) == address(this)) @@ -736,17 +602,14 @@ contract JBController is JBOperatable, ERC165, IJBController, IJBMigratable { emit PrepMigration(_projectId, _from, msg.sender); } - /** - @notice - Allows a project to migrate from this controller to another. - - @dev - 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 _to The controller to which the project is migrating. - */ - function migrate(uint256 _projectId, IJBMigratable _to) + /// @notice Allows a project to migrate from this controller to another. + /// @dev 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 _to The controller to which the project is migrating. + function migrate( + uint256 _projectId, + IJBMigratable _to + ) external virtual override @@ -783,19 +646,14 @@ contract JBController is JBOperatable, ERC165, IJBController, IJBMigratable { // ------------------------ internal functions ----------------------- // //*********************************************************************// - /** - @notice - Distributes all outstanding reserved tokens for a project. - - @param _projectId The ID of the project to which the reserved tokens belong. - @param _memo A memo to pass along to the emitted event. - - @return tokenCount The amount of minted reserved tokens. - */ - function _distributeReservedTokensOf(uint256 _projectId, string memory _memo) - internal - returns (uint256 tokenCount) - { + /// @notice Distributes all outstanding reserved tokens for a project. + /// @param _projectId The ID of the project to which the reserved tokens belong. + /// @param _memo A memo to pass along to the emitted event. + /// @return tokenCount The amount of minted reserved tokens. + function _distributeReservedTokensOf( + uint256 _projectId, + string memory _memo + ) internal returns (uint256 tokenCount) { // Keep a reference to the token store. IJBTokenStore _tokenStore = tokenStore; @@ -844,17 +702,12 @@ contract JBController is JBOperatable, ERC165, IJBController, IJBMigratable { ); } - /** - @notice - 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 _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 _amount The total amount of tokens to mint. - - @return leftoverAmount If the splits percents dont add up to 100%, the leftover amount is returned. - */ + /// @notice 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 _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 _amount The total amount of tokens to mint. + /// @return leftoverAmount If the splits percents dont add up to 100%, the leftover amount is returned. function _distributeToReservedTokenSplitsOf( uint256 _projectId, uint256 _domain, @@ -932,19 +785,14 @@ contract JBController is JBOperatable, ERC165, IJBController, IJBMigratable { } } - /** - @notice - 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 _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 _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 _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. - */ + /// @notice 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 _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 _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 _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. function _configure( uint256 _projectId, JBFundingCycleData calldata _data, @@ -1025,16 +873,11 @@ contract JBController is JBOperatable, ERC165, IJBController, IJBMigratable { 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. - */ + /// @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, diff --git a/contracts/JBController3_0_1.sol b/contracts/JBController3_0_1.sol index b1d2706ea..9e939d464 100644 --- a/contracts/JBController3_0_1.sol +++ b/contracts/JBController3_0_1.sol @@ -1,40 +1,48 @@ // 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_0_1.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 - - 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 manages a project's reserved tokens explicitly instead of through a passive tracker property. - It is backwards compatible with the original IJBController, and exposes convenience view methods as part of IJBController3_1 for clearer queries. -*/ -contract JBController3_0_1 is JBOperatable, ERC165, IJBController, IJBController3_0_1, IJBMigratable { +import {ERC165, IERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol'; +import {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol'; +import {SafeCast} from '@openzeppelin/contracts/utils/math/SafeCast.sol'; +import {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol'; +import {JBOperatable} from './abstract/JBOperatable.sol'; +import {JBBallotState} from './enums/JBBallotState.sol'; +import {IJBController3_0_1} from './interfaces/IJBController3_0_1.sol'; +import {IJBController} from './interfaces/IJBController.sol'; +import {IJBDirectory} from './interfaces/IJBDirectory.sol'; +import {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol'; +import {IJBMigratable} from './interfaces/IJBMigratable.sol'; +import {IJBOperatable} from './interfaces/IJBOperatable.sol'; +import {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol'; +import {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol'; +import {IJBProjects} from './interfaces/IJBProjects.sol'; +import {IJBSplitAllocator} from './interfaces/IJBSplitAllocator.sol'; +import {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol'; +import {IJBTokenStore} from './interfaces/IJBTokenStore.sol'; +import {JBConstants} from './libraries/JBConstants.sol'; +import {JBFundingCycleMetadataResolver} from './libraries/JBFundingCycleMetadataResolver.sol'; +import {JBOperations} from './libraries/JBOperations.sol'; +import {JBSplitsGroups} from './libraries/JBSplitsGroups.sol'; +import {JBFundingCycle} from './structs/JBFundingCycle.sol'; +import {JBSplitAllocationData} from './structs/JBSplitAllocationData.sol'; +import {JBFundAccessConstraints} from './structs/JBFundAccessConstraints.sol'; +import {JBFundingCycle} from './structs/JBFundingCycle.sol'; +import {JBFundingCycleData} from './structs/JBFundingCycleData.sol'; +import {JBFundingCycleMetadata} from './structs/JBFundingCycleMetadata.sol'; +import {JBGroupedSplits} from './structs/JBGroupedSplits.sol'; +import {JBProjectMetadata} from './structs/JBProjectMetadata.sol'; +import {JBSplit} from './structs/JBSplit.sol'; + +/// @notice Stitches together funding cycles and project tokens, making sure all activity is accounted for and correct. +/// @dev This Controller manages a project's reserved tokens explicitly instead of through a passive tracker property. +/// @dev It is backwards compatible with the original IJBController, and exposes convenience view methods as part of IJBController3_1 for clearer queries. +contract JBController3_0_1 is + JBOperatable, + ERC165, + IJBController, + IJBController3_0_1, + IJBMigratable +{ // A library that parses the packed funding cycle metadata into a more friendly format. using JBFundingCycleMetadataResolver for JBFundingCycle; @@ -42,7 +50,6 @@ contract JBController3_0_1 is JBOperatable, ERC165, IJBController, IJBController // --------------------------- custom errors ------------------------- // //*********************************************************************// error BURN_PAUSED_AND_SENDER_NOT_VALID_TERMINAL_DELEGATE(); - error CANT_MIGRATE_TO_CURRENT_CONTROLLER(); error FUNDING_CYCLE_ALREADY_LAUNCHED(); error INVALID_BALLOT_REDEMPTION_RATE(); error INVALID_DISTRIBUTION_LIMIT(); @@ -55,110 +62,67 @@ contract JBController3_0_1 is JBOperatable, ERC165, IJBController, IJBController error MINT_NOT_ALLOWED_AND_NOT_TERMINAL_DELEGATE(); error NO_BURNABLE_TOKENS(); error NOT_CURRENT_CONTROLLER(); - error OVERFLOW_ALERT(); error ZERO_TOKENS_TO_MINT(); //*********************************************************************// // --------------------- internal stored properties ------------------ // //*********************************************************************// - /** - @notice - Data regarding the distribution limit of a project during a configuration. - - @dev - bits 0-231: The amount of token that a project can distribute per funding cycle. - - @dev - 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. - _configuration The configuration during which the packed distribution limit data applies. - _terminal The terminal from which distributions are being limited. - _token The token for which distributions are being limited. - */ + /// @notice Data regarding the distribution limit of a project during a configuration. + /// @dev bits 0-231: The amount of token that a project can distribute per funding cycle. + /// @dev bits 232-255: The currency of amount that a project can distribute. + /// @custom:param _projectId The ID of the project to get the packed distribution limit data of. + /// @custom:param _configuration The configuration during which the packed distribution limit data applies. + /// @custom:param _terminal The terminal from which distributions are being limited. + /// @custom:param _token The token for which distributions are being limited. mapping(uint256 => mapping(uint256 => mapping(IJBPaymentTerminal => mapping(address => uint256)))) internal _packedDistributionLimitDataOf; - /** - @notice - Data regarding the overflow allowance of a project during a configuration. - - @dev - bits 0-231: The amount of overflow that a project is allowed to tap into on-demand throughout the configuration. - - @dev - 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. - _configuration The configuration during which the packed overflow allowance data applies. - _terminal The terminal managing the overflow. - _token The token for which overflow is being allowed. - */ + /// @notice Data regarding the overflow allowance of a project during a configuration. + /// @dev bits 0-231: The amount of overflow that a project is allowed to tap into on-demand throughout the configuration. + /// @dev bits 232-255: The currency of the amount of overflow that a project is allowed to tap. + /// @custom:param _projectId The ID of the project to get the packed overflow allowance data of. + /// @custom:param _configuration The configuration during which the packed overflow allowance data applies. + /// @custom:param _terminal The terminal managing the overflow. + /// @custom:param _token The token for which overflow is being allowed. mapping(uint256 => mapping(uint256 => mapping(IJBPaymentTerminal => mapping(address => uint256)))) internal _packedOverflowAllowanceDataOf; - /** - @notice - The current undistributed reserved token balance of. - - _projectId The ID of the project to get a reserved token balance of. - */ + /// @notice The current undistributed reserved token balance of. + /// @custom:param _projectId The ID of the project to get a reserved token balance of. mapping(uint256 => uint256) internal _reservedTokenBalanceOf; //*********************************************************************// // --------------- public immutable stored properties ---------------- // //*********************************************************************// - /** - @notice - Mints ERC-721's that represent project ownership. - */ + /// @notice Mints ERC-721's that represent project ownership. IJBProjects public immutable override projects; - /** - @notice - The contract storing all funding cycle configurations. - */ + /// @notice The contract storing all funding cycle configurations. IJBFundingCycleStore public immutable override fundingCycleStore; - /** - @notice - The contract that manages token minting and burning. - */ + /// @notice The contract that manages token minting and burning. IJBTokenStore public immutable override tokenStore; - /** - @notice - The contract that stores splits for each project. - */ + /// @notice The contract that stores splits for each project. IJBSplitsStore public immutable override splitsStore; - /** - @notice - The directory of terminals and controllers for projects. - */ + /// @notice The directory of terminals and controllers for projects. IJBDirectory public immutable override directory; //*********************************************************************// // ------------------------- external views -------------------------- // //*********************************************************************// - /** - @notice - The amount of token that a project can distribute per funding cycle, 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 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. - */ + /// @notice The amount of token that a project can distribute per funding cycle, 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 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, @@ -172,21 +136,14 @@ contract JBController3_0_1 is JBOperatable, ERC165, IJBController, IJBController return (uint256(uint232(_data)), _data >> 232); } - /** - @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. - */ + /// @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, @@ -200,16 +157,14 @@ contract JBController3_0_1 is JBOperatable, ERC165, IJBController, IJBController return (uint256(uint232(_data)), _data >> 232); } - /** - @notice - 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. - - @return fundingCycle The funding cycle. - @return metadata The funding cycle's metadata. - */ - function getFundingCycleOf(uint256 _projectId, uint256 _configuration) + /// @notice 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. + /// @return fundingCycle The funding cycle. + /// @return metadata The funding cycle's metadata. + function getFundingCycleOf( + uint256 _projectId, + uint256 _configuration + ) external view override @@ -219,17 +174,14 @@ contract JBController3_0_1 is JBOperatable, ERC165, IJBController, IJBController metadata = fundingCycle.expandMetadata(); } - /** - @notice - 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. - - @return fundingCycle The latest configured funding cycle. - @return metadata The latest configured funding cycle's metadata. - @return ballotState The state of the configuration. - */ - function latestConfiguredFundingCycleOf(uint256 _projectId) + /// @notice 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. + /// @return fundingCycle The latest configured funding cycle. + /// @return metadata The latest configured funding cycle's metadata. + /// @return ballotState The state of the configuration. + function latestConfiguredFundingCycleOf( + uint256 _projectId + ) external view override @@ -243,16 +195,13 @@ contract JBController3_0_1 is JBOperatable, ERC165, IJBController, IJBController metadata = fundingCycle.expandMetadata(); } - /** - @notice - A project's current funding cycle along with its metadata. - - @param _projectId The ID of the project to which the funding cycle belongs. - - @return fundingCycle The current funding cycle. - @return metadata The current funding cycle's metadata. - */ - function currentFundingCycleOf(uint256 _projectId) + /// @notice A project's current funding cycle along with its metadata. + /// @param _projectId The ID of the project to which the funding cycle belongs. + /// @return fundingCycle The current funding cycle. + /// @return metadata The current funding cycle's metadata. + function currentFundingCycleOf( + uint256 _projectId + ) external view override @@ -262,16 +211,13 @@ contract JBController3_0_1 is JBOperatable, ERC165, IJBController, IJBController metadata = fundingCycle.expandMetadata(); } - /** - @notice - A project's queued funding cycle along with its metadata. - - @param _projectId The ID of the project to which the funding cycle belongs. - - @return fundingCycle The queued funding cycle. - @return metadata The queued funding cycle's metadata. - */ - function queuedFundingCycleOf(uint256 _projectId) + /// @notice A project's queued funding cycle along with its metadata. + /// @param _projectId The ID of the project to which the funding cycle belongs. + /// @return fundingCycle The queued funding cycle. + /// @return metadata The queued funding cycle's metadata. + function queuedFundingCycleOf( + uint256 _projectId + ) external view override @@ -281,58 +227,35 @@ contract JBController3_0_1 is JBOperatable, ERC165, IJBController, IJBController metadata = fundingCycle.expandMetadata(); } - /** - @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. - - @return The current amount of reserved tokens. - */ + /// @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. + /// @return The current amount of reserved tokens. function reservedTokenBalanceOf(uint256 _projectId) external view override returns (uint256) { return _reservedTokenBalanceOf[_projectId]; } - /** - @notice - Gets the amount of reserved tokens that a project has available to distribute. - - @dev - This is just for IJBController backwards compatibility. - - @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) - { + /// @notice Gets the amount of reserved tokens that a project has available to distribute. + /// @dev This is just for IJBController backwards compatibility. + /// @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) { _reservedRate; return _reservedTokenBalanceOf[_projectId]; } - /** - @notice - Gets the current total amount of outstanding tokens for a project, given a reserved rate. - - @dev - This is just for IJBController backwards compatibility. - - @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. - */ - function totalOutstandingTokensOf(uint256 _projectId, uint256 _reservedRate) - external - view - override - returns (uint256) - { + /// @notice Gets the current total amount of outstanding tokens for a project, given a reserved rate. + /// @dev This is just for IJBController backwards compatibility. + /// @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. + function totalOutstandingTokensOf( + uint256 _projectId, + uint256 _reservedRate + ) external view override returns (uint256) { _reservedRate; // Add the reserved tokens to the total supply. return totalOutstandingTokensOf(_projectId); @@ -342,35 +265,21 @@ contract JBController3_0_1 is JBOperatable, ERC165, IJBController, IJBController // -------------------------- public views --------------------------- // //*********************************************************************// - /** - @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. - */ + /// @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]; } - /** - @notice - Indicates if this contract adheres to the specified interface. - - @dev - See {IERC165-supportsInterface}. - - @param _interfaceId The ID of the interface to check for adherance to. - */ - function supportsInterface(bytes4 _interfaceId) - public - view - virtual - override(ERC165, IERC165) - returns (bool) - { + /// @notice Indicates if this contract adheres to the specified interface. + /// @dev See {IERC165-supportsInterface}. + /// @param _interfaceId The ID of the interface to check for adherance to. + /// @return A flag indicating if the provided interface ID is supported. + function supportsInterface( + bytes4 _interfaceId + ) public view virtual override(ERC165, IERC165) returns (bool) { return _interfaceId == type(IJBController3_0_1).interfaceId || _interfaceId == type(IJBMigratable).interfaceId || @@ -382,14 +291,12 @@ contract JBController3_0_1 is JBOperatable, ERC165, IJBController, IJBController // ---------------------------- constructor -------------------------- // //*********************************************************************// - /** - @param _operatorStore A contract storing operator assignments. - @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 _fundingCycleStore A contract storing all funding cycle configurations. - @param _tokenStore A contract that manages token minting and burning. - @param _splitsStore A contract that stores splits for each project. - */ + /// @param _operatorStore A contract storing operator assignments. + /// @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 _fundingCycleStore A contract storing all funding cycle configurations. + /// @param _tokenStore A contract that manages token minting and burning. + /// @param _splitsStore A contract that stores splits for each project. constructor( IJBOperatorStore _operatorStore, IJBProjects _projects, @@ -409,28 +316,19 @@ contract JBController3_0_1 is JBOperatable, ERC165, IJBController, IJBController // --------------------- external transactions ----------------------- // //*********************************************************************// - /** - @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. - - @dev - Each operation within this transaction can be done in sequence separately. - - @dev - 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 _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 _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 _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 _terminals Payment terminals to add for the project. - @param _memo A memo to pass along to the emitted event. - - @return projectId The ID of the project. - */ + /// @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. + /// @dev Each operation within this transaction can be done in sequence separately. + /// @dev 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 _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 _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 _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 _terminals Payment terminals to add for the project. + /// @param _memo A memo to pass along to the emitted event. + /// @return projectId The ID of the project. function launchProjectFor( address _owner, JBProjectMetadata calldata _projectMetadata, @@ -467,27 +365,18 @@ contract JBController3_0_1 is JBOperatable, ERC165, IJBController, IJBController emit LaunchProject(_configuration, projectId, _memo, msg.sender); } - /** - @notice - Creates a funding cycle for an already existing project ERC-721. - - @dev - Each operation within this transaction can be done in sequence separately. - - @dev - Only a project owner or operator can launch its funding cycles. - - @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 _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 _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 _terminals Payment terminals to add for the project. - @param _memo A memo to pass along to the emitted event. - - @return configuration The configuration of the funding cycle that was successfully created. - */ + /// @notice Creates a funding cycle for an already existing project ERC-721. + /// @dev Each operation within this transaction can be done in sequence separately. + /// @dev Only a project owner or operator can launch its funding cycles. + /// @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 _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 _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 _terminals Payment terminals to add for the project. + /// @param _memo A memo to pass along to the emitted event. + /// @return configuration The configuration of the funding cycle that was successfully created. function launchFundingCyclesFor( uint256 _projectId, JBFundingCycleData calldata _data, @@ -527,23 +416,16 @@ contract JBController3_0_1 is JBOperatable, ERC165, IJBController, IJBController emit LaunchFundingCycles(configuration, _projectId, _memo, msg.sender); } - /** - @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. - - @dev - 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 _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 _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 _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. - - @return configuration The configuration of the funding cycle that was successfully reconfigured. - */ + /// @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. + /// @dev 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 _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 _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 _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. + /// @return configuration The configuration of the funding cycle that was successfully reconfigured. function reconfigureFundingCyclesOf( uint256 _projectId, JBFundingCycleData calldata _data, @@ -572,22 +454,15 @@ contract JBController3_0_1 is JBOperatable, ERC165, IJBController, IJBController emit ReconfigureFundingCycles(configuration, _projectId, _memo, msg.sender); } - /** - @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. - - @dev - 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 _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 _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 _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. - */ + /// @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. + /// @dev 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 _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 _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 _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. function mintTokensOf( uint256 _projectId, uint256 _tokenCount, @@ -595,12 +470,7 @@ contract JBController3_0_1 is JBOperatable, ERC165, IJBController, IJBController string calldata _memo, bool _preferClaimedTokens, bool _useReservedRate - ) - external - virtual - override - returns (uint256 beneficiaryTokenCount) - { + ) external virtual override returns (uint256 beneficiaryTokenCount) { // There should be tokens to mint. if (_tokenCount == 0) revert ZERO_TOKENS_TO_MINT(); @@ -665,19 +535,13 @@ contract JBController3_0_1 is JBOperatable, ERC165, IJBController, IJBController ); } - /** - @notice - Burns a token holder's supply. - - @dev - 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 _projectId The ID of the project to which the tokens being burned belong. - @param _tokenCount The number of tokens to burn. - @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. - */ + /// @notice Burns a token holder's supply. + /// @dev 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 _projectId The ID of the project to which the tokens being burned belong. + /// @param _tokenCount The number of tokens to burn. + /// @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. function burnTokensOf( address _holder, uint256 _projectId, @@ -713,50 +577,34 @@ contract JBController3_0_1 is JBOperatable, ERC165, IJBController, IJBController emit BurnTokens(_holder, _projectId, _tokenCount, _memo, msg.sender); } - /** - @notice - Distributes all outstanding reserved tokens for a project. - - @param _projectId The ID of the project to which the reserved tokens belong. - @param _memo A memo to pass along to the emitted event. - - @return The amount of minted reserved tokens. - */ - function distributeReservedTokensOf(uint256 _projectId, string calldata _memo) - external - virtual - override - returns (uint256) - { + /// @notice Distributes all outstanding reserved tokens for a project. + /// @param _projectId The ID of the project to which the reserved tokens belong. + /// @param _memo A memo to pass along to the emitted event. + /// @return The amount of minted reserved tokens. + function distributeReservedTokensOf( + uint256 _projectId, + string calldata _memo + ) external virtual override returns (uint256) { return _distributeReservedTokensOf(_projectId, _memo); } - /** - @notice - Allows other controllers to signal to this one that a migration is expected for the specified project. - - @dev - 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 _from The controller being migrated from. - */ + /// @notice Allows other controllers to signal to this one that a migration is expected for the specified project. + /// @dev 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 _from The controller being migrated from. function prepForMigrationOf(uint256 _projectId, address _from) external virtual override { _projectId; // Prevents unused var compiler and natspec complaints. _from; // Prevents unused var compiler and natspec complaints. } - /** - @notice - Allows a project to migrate from this controller to another. - - @dev - 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 _to The controller to which the project is migrating. - */ - function migrate(uint256 _projectId, IJBMigratable _to) + /// @notice Allows a project to migrate from this controller to another. + /// @dev 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 _to The controller to which the project is migrating. + function migrate( + uint256 _projectId, + IJBMigratable _to + ) external virtual override @@ -790,19 +638,14 @@ contract JBController3_0_1 is JBOperatable, ERC165, IJBController, IJBController // ------------------------ internal functions ----------------------- // //*********************************************************************// - /** - @notice - Distributes all outstanding reserved tokens for a project. - - @param _projectId The ID of the project to which the reserved tokens belong. - @param _memo A memo to pass along to the emitted event. - - @return tokenCount The amount of minted reserved tokens. - */ - function _distributeReservedTokensOf(uint256 _projectId, string memory _memo) - internal - returns (uint256 tokenCount) - { + /// @notice Distributes all outstanding reserved tokens for a project. + /// @param _projectId The ID of the project to which the reserved tokens belong. + /// @param _memo A memo to pass along to the emitted event. + /// @return tokenCount The amount of minted reserved tokens. + function _distributeReservedTokensOf( + uint256 _projectId, + string memory _memo + ) internal returns (uint256 tokenCount) { // Keep a reference to the token store. IJBTokenStore _tokenStore = tokenStore; @@ -844,17 +687,12 @@ contract JBController3_0_1 is JBOperatable, ERC165, IJBController, IJBController ); } - /** - @notice - 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 _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 _amount The total amount of tokens to mint. - - @return leftoverAmount If the splits percents dont add up to 100%, the leftover amount is returned. - */ + /// @notice 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 _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 _amount The total amount of tokens to mint. + /// @return leftoverAmount If the splits percents dont add up to 100%, the leftover amount is returned. function _distributeToReservedTokenSplitsOf( uint256 _projectId, uint256 _domain, @@ -932,19 +770,14 @@ contract JBController3_0_1 is JBOperatable, ERC165, IJBController, IJBController } } - /** - @notice - 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 _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 _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 _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. - */ + /// @notice 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 _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 _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 _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. function _configure( uint256 _projectId, JBFundingCycleData calldata _data, diff --git a/contracts/JBController3_1.sol b/contracts/JBController3_1.sol index 24bb015f8..c8b471ec0 100644 --- a/contracts/JBController3_1.sol +++ b/contracts/JBController3_1.sol @@ -1,37 +1,41 @@ // 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. -*/ +import {ERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol'; +import {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol'; +import {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol'; +import {JBOperatable} from './abstract/JBOperatable.sol'; +import {JBBallotState} from './enums/JBBallotState.sol'; +import {IJBController3_0_1} from './interfaces/IJBController3_0_1.sol'; +import {IJBController3_1} from './interfaces/IJBController3_1.sol'; +import {IJBController} from './interfaces/IJBController.sol'; +import {IJBDirectory} from './interfaces/IJBDirectory.sol'; +import {IJBFundAccessConstraintsStore} from './interfaces/IJBFundAccessConstraintsStore.sol'; +import {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol'; +import {IJBMigratable} from './interfaces/IJBMigratable.sol'; +import {IJBOperatable} from './interfaces/IJBOperatable.sol'; +import {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol'; +import {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol'; +import {IJBProjects} from './interfaces/IJBProjects.sol'; +import {IJBSplitAllocator} from './interfaces/IJBSplitAllocator.sol'; +import {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol'; +import {IJBTokenStore} from './interfaces/IJBTokenStore.sol'; +import {JBConstants} from './libraries/JBConstants.sol'; +import {JBFundingCycleMetadataResolver} from './libraries/JBFundingCycleMetadataResolver.sol'; +import {JBOperations} from './libraries/JBOperations.sol'; +import {JBSplitsGroups} from './libraries/JBSplitsGroups.sol'; +import {JBFundingCycle} from './structs/JBFundingCycle.sol'; +import {JBSplitAllocationData} from './structs/JBSplitAllocationData.sol'; +import {JBFundAccessConstraints} from './structs/JBFundAccessConstraints.sol'; +import {JBFundingCycle} from './structs/JBFundingCycle.sol'; +import {JBFundingCycleData} from './structs/JBFundingCycleData.sol'; +import {JBFundingCycleMetadata} from './structs/JBFundingCycleMetadata.sol'; +import {JBGroupedSplits} from './structs/JBGroupedSplits.sol'; +import {JBProjectMetadata} from './structs/JBProjectMetadata.sol'; +import {JBSplit} from './structs/JBSplit.sol'; + +/// @notice Stitches together funding cycles and project tokens, making sure all activity is accounted for and correct. +/// @dev This Controller has the same functionality as JBController3_0_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. using JBFundingCycleMetadataResolver for JBFundingCycle; @@ -41,7 +45,6 @@ contract JBController3_1 is JBOperatable, ERC165, IJBController3_1, IJBMigratabl //*********************************************************************// error BURN_PAUSED_AND_SENDER_NOT_VALID_TERMINAL_DELEGATE(); - error CANT_MIGRATE_TO_CURRENT_CONTROLLER(); error FUNDING_CYCLE_ALREADY_LAUNCHED(); error INVALID_BALLOT_REDEMPTION_RATE(); error INVALID_REDEMPTION_RATE(); @@ -50,46 +53,29 @@ contract JBController3_1 is JBOperatable, ERC165, IJBController3_1, IJBMigratabl error MINT_NOT_ALLOWED_AND_NOT_TERMINAL_DELEGATE(); error NO_BURNABLE_TOKENS(); error NOT_CURRENT_CONTROLLER(); - error OVERFLOW_ALERT(); error ZERO_TOKENS_TO_MINT(); //*********************************************************************// // --------------------- internal stored properties ------------------ // //*********************************************************************// - /** - @notice - Data regarding the distribution limit of a project during a configuration. - - @dev - bits 0-231: The amount of token that a project can distribute per funding cycle. - - @dev - 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. - _configuration The configuration during which the packed distribution limit data applies. - _terminal The terminal from which distributions are being limited. - _token The token for which distributions are being limited. - */ + /// @notice Data regarding the distribution limit of a project during a configuration. + /// @dev bits 0-231: The amount of token that a project can distribute per funding cycle. + /// @dev bits 232-255: The currency of amount that a project can distribute. + /// @custom:param _projectId The ID of the project to get the packed distribution limit data of. + /// @custom:param _configuration The configuration during which the packed distribution limit data applies. + /// @custom:param _terminal The terminal from which distributions are being limited. + /// @custom:param _token The token for which distributions are being limited. mapping(uint256 => mapping(uint256 => mapping(IJBPaymentTerminal => mapping(address => uint256)))) internal _packedDistributionLimitDataOf; - /** - @notice - Data regarding the overflow allowance of a project during a configuration. - - @dev - bits 0-231: The amount of overflow that a project is allowed to tap into on-demand throughout the configuration. - - @dev - 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. - _configuration The configuration during which the packed overflow allowance data applies. - _terminal The terminal managing the overflow. - _token The token for which overflow is being allowed. - */ + /// @notice Data regarding the overflow allowance of a project during a configuration. + /// @dev bits 0-231: The amount of overflow that a project is allowed to tap into on-demand throughout the configuration. + /// @dev bits 232-255: The currency of the amount of overflow that a project is allowed to tap. + /// @custom:param _projectId The ID of the project to get the packed overflow allowance data of. + /// @custom:param _configuration The configuration during which the packed overflow allowance data applies. + /// @custom:param _terminal The terminal managing the overflow. + /// @custom:param _token The token for which overflow is being allowed. mapping(uint256 => mapping(uint256 => mapping(IJBPaymentTerminal => mapping(address => uint256)))) internal _packedOverflowAllowanceDataOf; @@ -97,68 +83,43 @@ contract JBController3_1 is JBOperatable, ERC165, IJBController3_1, IJBMigratabl // --------------- public immutable stored properties ---------------- // //*********************************************************************// - /** - @notice - Mints ERC-721's that represent project ownership. - */ + /// @notice Mints ERC-721's that represent project ownership. IJBProjects public immutable override projects; - /** - @notice - The contract storing all funding cycle configurations. - */ + /// @notice The contract storing all funding cycle configurations. IJBFundingCycleStore public immutable override fundingCycleStore; - /** - @notice - The contract that manages token minting and burning. - */ + /// @notice The contract that manages token minting and burning. IJBTokenStore public immutable override tokenStore; - /** - @notice - The contract that stores splits for each project. - */ + /// @notice The contract that stores splits for each project. IJBSplitsStore public immutable override splitsStore; - /** - @notice - A contract that stores fund access constraints for each project. - */ + /// @notice A contract that stores fund access constraints for each project. IJBFundAccessConstraintsStore public immutable override fundAccessConstraintsStore; - /** - @notice - The directory of terminals and controllers for projects. - */ + /// @notice The directory of terminals and controllers for projects. IJBDirectory public immutable override directory; //*********************************************************************// // --------------------- public stored properties -------------------- // //*********************************************************************// - /** - @notice - The current undistributed reserved token balance of. - - _projectId The ID of the project to get a reserved token balance of. - */ + /// @notice The current undistributed reserved token balance of. mapping(uint256 => uint256) public override reservedTokenBalanceOf; //*********************************************************************// // ------------------------- external views -------------------------- // //*********************************************************************// - /** - @notice - 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. - - @return fundingCycle The funding cycle. - @return metadata The funding cycle's metadata. - */ - function getFundingCycleOf(uint256 _projectId, uint256 _configuration) + /// @notice 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. + /// @return fundingCycle The funding cycle. + /// @return metadata The funding cycle's metadata. + function getFundingCycleOf( + uint256 _projectId, + uint256 _configuration + ) external view override @@ -168,17 +129,14 @@ contract JBController3_1 is JBOperatable, ERC165, IJBController3_1, IJBMigratabl metadata = fundingCycle.expandMetadata(); } - /** - @notice - 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. - - @return fundingCycle The latest configured funding cycle. - @return metadata The latest configured funding cycle's metadata. - @return ballotState The state of the configuration. - */ - function latestConfiguredFundingCycleOf(uint256 _projectId) + /// @notice 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. + /// @return fundingCycle The latest configured funding cycle. + /// @return metadata The latest configured funding cycle's metadata. + /// @return ballotState The state of the configuration. + function latestConfiguredFundingCycleOf( + uint256 _projectId + ) external view override @@ -192,16 +150,13 @@ contract JBController3_1 is JBOperatable, ERC165, IJBController3_1, IJBMigratabl metadata = fundingCycle.expandMetadata(); } - /** - @notice - A project's current funding cycle along with its metadata. - - @param _projectId The ID of the project to which the funding cycle belongs. - - @return fundingCycle The current funding cycle. - @return metadata The current funding cycle's metadata. - */ - function currentFundingCycleOf(uint256 _projectId) + /// @notice A project's current funding cycle along with its metadata. + /// @param _projectId The ID of the project to which the funding cycle belongs. + /// @return fundingCycle The current funding cycle. + /// @return metadata The current funding cycle's metadata. + function currentFundingCycleOf( + uint256 _projectId + ) external view override @@ -211,16 +166,13 @@ contract JBController3_1 is JBOperatable, ERC165, IJBController3_1, IJBMigratabl metadata = fundingCycle.expandMetadata(); } - /** - @notice - A project's queued funding cycle along with its metadata. - - @param _projectId The ID of the project to which the funding cycle belongs. - - @return fundingCycle The queued funding cycle. - @return metadata The queued funding cycle's metadata. - */ - function queuedFundingCycleOf(uint256 _projectId) + /// @notice A project's queued funding cycle along with its metadata. + /// @param _projectId The ID of the project to which the funding cycle belongs. + /// @return fundingCycle The queued funding cycle. + /// @return metadata The queued funding cycle's metadata. + function queuedFundingCycleOf( + uint256 _projectId + ) external view override @@ -234,35 +186,21 @@ contract JBController3_1 is JBOperatable, ERC165, IJBController3_1, IJBMigratabl // -------------------------- public views --------------------------- // //*********************************************************************// - /** - @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. - */ + /// @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]; } - /** - @notice - Indicates if this contract adheres to the specified interface. - - @dev - See {IERC165-supportsInterface}. - - @param _interfaceId The ID of the interface to check for adherance to. - */ - function supportsInterface(bytes4 _interfaceId) - public - view - virtual - override(ERC165, IERC165) - returns (bool) - { + /// @notice Indicates if this contract adheres to the specified interface. + /// @dev See {IERC165-supportsInterface}. + /// @param _interfaceId The ID of the interface to check for adherance to. + /// @return A flag indicating if the provided interface ID is supported. + function supportsInterface( + bytes4 _interfaceId + ) public view virtual override(ERC165, IERC165) returns (bool) { return _interfaceId == type(IJBController3_1).interfaceId || _interfaceId == type(IJBController3_0_1).interfaceId || @@ -275,15 +213,13 @@ contract JBController3_1 is JBOperatable, ERC165, IJBController3_1, IJBMigratabl // ---------------------------- constructor -------------------------- // //*********************************************************************// - /** - @param _operatorStore A contract storing operator assignments. - @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 _fundingCycleStore A contract storing all funding cycle configurations. - @param _tokenStore A contract that manages token minting and burning. - @param _splitsStore A contract that stores splits for each project. - @param _fundAccessConstraintsStore A contract that stores fund access constraints for each project. - */ + /// @param _operatorStore A contract storing operator assignments. + /// @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 _fundingCycleStore A contract storing all funding cycle configurations. + /// @param _tokenStore A contract that manages token minting and burning. + /// @param _splitsStore A contract that stores splits for each project. + /// @param _fundAccessConstraintsStore A contract that stores fund access constraints for each project. constructor( IJBOperatorStore _operatorStore, IJBProjects _projects, @@ -305,28 +241,19 @@ contract JBController3_1 is JBOperatable, ERC165, IJBController3_1, IJBMigratabl // --------------------- external transactions ----------------------- // //*********************************************************************// - /** - @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. - - @dev - Each operation within this transaction can be done in sequence separately. - - @dev - 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 _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 _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 _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 _terminals Payment terminals to add for the project. - @param _memo A memo to pass along to the emitted event. - - @return projectId The ID of the project. - */ + /// @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. + /// @dev Each operation within this transaction can be done in sequence separately. + /// @dev 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 _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 _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 _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 _terminals Payment terminals to add for the project. + /// @param _memo A memo to pass along to the emitted event. + /// @return projectId The ID of the project. function launchProjectFor( address _owner, JBProjectMetadata calldata _projectMetadata, @@ -363,27 +290,18 @@ contract JBController3_1 is JBOperatable, ERC165, IJBController3_1, IJBMigratabl emit LaunchProject(_configuration, projectId, _memo, msg.sender); } - /** - @notice - Creates a funding cycle for an already existing project ERC-721. - - @dev - Each operation within this transaction can be done in sequence separately. - - @dev - Only a project owner or operator can launch its funding cycles. - - @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 _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 _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 _terminals Payment terminals to add for the project. - @param _memo A memo to pass along to the emitted event. - - @return configuration The configuration of the funding cycle that was successfully created. - */ + /// @notice Creates a funding cycle for an already existing project ERC-721. + /// @dev Each operation within this transaction can be done in sequence separately. + /// @dev Only a project owner or operator can launch its funding cycles. + /// @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 _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 _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 _terminals Payment terminals to add for the project. + /// @param _memo A memo to pass along to the emitted event. + /// @return configuration The configuration of the funding cycle that was successfully created. function launchFundingCyclesFor( uint256 _projectId, JBFundingCycleData calldata _data, @@ -423,23 +341,16 @@ contract JBController3_1 is JBOperatable, ERC165, IJBController3_1, IJBMigratabl emit LaunchFundingCycles(configuration, _projectId, _memo, msg.sender); } - /** - @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. - - @dev - 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 _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 _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 _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. - - @return configuration The configuration of the funding cycle that was successfully reconfigured. - */ + /// @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. + /// @dev 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 _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 _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 _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. + /// @return configuration The configuration of the funding cycle that was successfully reconfigured. function reconfigureFundingCyclesOf( uint256 _projectId, JBFundingCycleData calldata _data, @@ -468,22 +379,15 @@ contract JBController3_1 is JBOperatable, ERC165, IJBController3_1, IJBMigratabl emit ReconfigureFundingCycles(configuration, _projectId, _memo, msg.sender); } - /** - @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. - - @dev - 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 _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 _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 _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. - */ + /// @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. + /// @dev 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 _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 _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 _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. function mintTokensOf( uint256 _projectId, uint256 _tokenCount, @@ -556,19 +460,13 @@ contract JBController3_1 is JBOperatable, ERC165, IJBController3_1, IJBMigratabl ); } - /** - @notice - Burns a token holder's supply. - - @dev - 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 _projectId The ID of the project to which the tokens being burned belong. - @param _tokenCount The number of tokens to burn. - @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. - */ + /// @notice Burns a token holder's supply. + /// @dev 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 _projectId The ID of the project to which the tokens being burned belong. + /// @param _tokenCount The number of tokens to burn. + /// @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. function burnTokensOf( address _holder, uint256 _projectId, @@ -604,50 +502,34 @@ contract JBController3_1 is JBOperatable, ERC165, IJBController3_1, IJBMigratabl emit BurnTokens(_holder, _projectId, _tokenCount, _memo, msg.sender); } - /** - @notice - Distributes all outstanding reserved tokens for a project. - - @param _projectId The ID of the project to which the reserved tokens belong. - @param _memo A memo to pass along to the emitted event. - - @return The amount of minted reserved tokens. - */ - function distributeReservedTokensOf(uint256 _projectId, string calldata _memo) - external - virtual - override - returns (uint256) - { + /// @notice Distributes all outstanding reserved tokens for a project. + /// @param _projectId The ID of the project to which the reserved tokens belong. + /// @param _memo A memo to pass along to the emitted event. + /// @return The amount of minted reserved tokens. + function distributeReservedTokensOf( + uint256 _projectId, + string calldata _memo + ) external virtual override returns (uint256) { return _distributeReservedTokensOf(_projectId, _memo); } - /** - @notice - Allows other controllers to signal to this one that a migration is expected for the specified project. - - @dev - 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 _from The controller being migrated from. - */ + /// @notice Allows other controllers to signal to this one that a migration is expected for the specified project. + /// @dev 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 _from The controller being migrated from. function prepForMigrationOf(uint256 _projectId, address _from) external virtual override { _projectId; // Prevents unused var compiler and natspec complaints. _from; // Prevents unused var compiler and natspec complaints. } - /** - @notice - Allows a project to migrate from this controller to another. - - @dev - 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 _to The controller to which the project is migrating. - */ - function migrate(uint256 _projectId, IJBMigratable _to) + /// @notice Allows a project to migrate from this controller to another. + /// @dev 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 _to The controller to which the project is migrating. + function migrate( + uint256 _projectId, + IJBMigratable _to + ) external virtual override @@ -681,19 +563,14 @@ contract JBController3_1 is JBOperatable, ERC165, IJBController3_1, IJBMigratabl // ------------------------ internal functions ----------------------- // //*********************************************************************// - /** - @notice - Distributes all outstanding reserved tokens for a project. - - @param _projectId The ID of the project to which the reserved tokens belong. - @param _memo A memo to pass along to the emitted event. - - @return tokenCount The amount of minted reserved tokens. - */ - function _distributeReservedTokensOf(uint256 _projectId, string memory _memo) - internal - returns (uint256 tokenCount) - { + /// @notice Distributes all outstanding reserved tokens for a project. + /// @param _projectId The ID of the project to which the reserved tokens belong. + /// @param _memo A memo to pass along to the emitted event. + /// @return tokenCount The amount of minted reserved tokens. + function _distributeReservedTokensOf( + uint256 _projectId, + string memory _memo + ) internal returns (uint256 tokenCount) { // Keep a reference to the token store. IJBTokenStore _tokenStore = tokenStore; @@ -735,17 +612,12 @@ contract JBController3_1 is JBOperatable, ERC165, IJBController3_1, IJBMigratabl ); } - /** - @notice - 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 _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 _amount The total amount of tokens to mint. - - @return leftoverAmount If the splits percents dont add up to 100%, the leftover amount is returned. - */ + /// @notice 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 _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 _amount The total amount of tokens to mint. + /// @return leftoverAmount If the splits percents dont add up to 100%, the leftover amount is returned. function _distributeToReservedTokenSplitsOf( uint256 _projectId, uint256 _domain, @@ -823,19 +695,14 @@ contract JBController3_1 is JBOperatable, ERC165, IJBController3_1, IJBMigratabl } } - /** - @notice - 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 _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 _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 _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. - */ + /// @notice 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 _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 _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 _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. function _configure( uint256 _projectId, JBFundingCycleData calldata _data, diff --git a/contracts/JBDirectory.sol b/contracts/JBDirectory.sol index a8cdfcb0d..eee32371d 100644 --- a/contracts/JBDirectory.sol +++ b/contracts/JBDirectory.sol @@ -1,25 +1,18 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.16; -import '@openzeppelin/contracts/access/Ownable.sol'; -import './abstract/JBOperatable.sol'; -import './interfaces/IJBDirectory.sol'; -import './libraries/JBFundingCycleMetadataResolver.sol'; -import './libraries/JBOperations.sol'; - -/** - @notice - Keeps a reference of which terminal contracts each project is currently accepting funds through, and which controller contract is managing each project's tokens and funding cycles. - - @dev - Adheres to - - IJBDirectory: General interface for the methods in this contract that interact with the blockchain's state according to the protocol's rules. - - @dev - Inherits from - - JBOperatable: Includes convenience functionality for checking a message sender's permissions before executing certain transactions. - Ownable: Includes convenience functionality for checking a message sender's permissions before executing certain transactions. -*/ +import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol'; +import {JBOperatable} from './abstract/JBOperatable.sol'; +import {IJBDirectory} from './interfaces/IJBDirectory.sol'; +import {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol'; +import {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol'; +import {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol'; +import {IJBProjects} from './interfaces/IJBProjects.sol'; +import {JBFundingCycleMetadataResolver} from './libraries/JBFundingCycleMetadataResolver.sol'; +import {JBOperations} from './libraries/JBOperations.sol'; +import {JBFundingCycle} from './structs/JBFundingCycle.sol'; + +/// @notice Keeps a reference of which terminal contracts each project is currently accepting funds through, and which controller contract is managing each project's tokens and funding cycles. contract JBDirectory is JBOperatable, Ownable, IJBDirectory { // A library that parses the packed funding cycle metadata into a friendlier format. using JBFundingCycleMetadataResolver for JBFundingCycle; @@ -37,71 +30,44 @@ contract JBDirectory is JBOperatable, Ownable, IJBDirectory { // --------------------- private stored properties ------------------- // //*********************************************************************// - /** - @notice - For each project ID, the terminals that are currently managing its funds. - - _projectId The ID of the project to get terminals of. - */ + /// @notice For each project ID, the terminals that are currently managing its funds. + /// @custom:member _projectId The ID of the project to get terminals of. mapping(uint256 => IJBPaymentTerminal[]) private _terminalsOf; - /** - @notice - The project's primary terminal for a token. - - _projectId The ID of the project to get the primary terminal of. - _token The token to get the project's primary terminal of. - */ + /// @notice The project's primary terminal for a token. + /// @custom:member _projectId The ID of the project to get the primary terminal of. + /// @custom:member _token The token to get the project's primary terminal of. mapping(uint256 => mapping(address => IJBPaymentTerminal)) private _primaryTerminalOf; //*********************************************************************// // ---------------- public immutable stored properties --------------- // //*********************************************************************// - /** - @notice - Mints ERC-721's that represent project ownership and transfers. - */ + /// @notice Mints ERC-721's that represent project ownership and transfers. IJBProjects public immutable override projects; - /** - @notice - The contract storing all funding cycle configurations. - */ + /// @notice The contract storing all funding cycle configurations. IJBFundingCycleStore public immutable override fundingCycleStore; //*********************************************************************// // --------------------- public stored properties -------------------- // //*********************************************************************// - /** - @notice - For each project ID, the controller that manages how terminals interact with tokens and funding cycles. - - _projectId The ID of the project to get the controller of. - */ + /// @notice For each project ID, the controller that manages how terminals interact with tokens and funding cycles. + /// @custom:member _projectId The ID of the project to get the controller of. mapping(uint256 => address) public override controllerOf; - /** - @notice - Addresses that can set a project's first controller on their behalf. These addresses/contracts have been vetted and verified by this contract's owner. - - _address The address that is either allowed or not. - */ + /// @notice Addresses that can set a project's first controller on their behalf. These addresses/contracts have been vetted and verified by this contract's owner. + /// @custom:param _address The address that is either allowed or not. mapping(address => bool) public override isAllowedToSetFirstController; //*********************************************************************// // ------------------------- external views -------------------------- // //*********************************************************************// - /** - @notice - For each project ID, the terminals that are currently managing its funds. - - @param _projectId The ID of the project to get terminals of. - - @return An array of terminal addresses. - */ + /// @notice For each project ID, the terminals that are currently managing its funds. + /// @param _projectId The ID of the project to get terminals of. + /// @return An array of terminal addresses. function terminalsOf(uint256 _projectId) external view @@ -111,18 +77,11 @@ contract JBDirectory is JBOperatable, Ownable, IJBDirectory { return _terminalsOf[_projectId]; } - /** - @notice - The primary terminal that is managing funds for a project for a specified token. - - @dev - The zero address is returned if a terminal isn't found for the specified token. - - @param _projectId The ID of the project to get a terminal for. - @param _token The token the terminal accepts. - - @return The primary terminal for the project for the specified token. - */ + /// @notice The primary terminal that is managing funds for a project for a specified token. + /// @dev The zero address is returned if a terminal isn't found for the specified token. + /// @param _projectId The ID of the project to get a terminal for. + /// @param _token The token the terminal accepts. + /// @return The primary terminal for the project for the specified token. function primaryTerminalOf(uint256 _projectId, address _token) external view @@ -162,15 +121,10 @@ contract JBDirectory is JBOperatable, Ownable, IJBDirectory { // -------------------------- public views --------------------------- // //*********************************************************************// - /** - @notice - Whether or not a specified terminal is a terminal of the specified project. - - @param _projectId The ID of the project to check within. - @param _terminal The address of the terminal to check for. - - @return A flag indicating whether or not the specified terminal is a terminal of the specified project. - */ + /// @notice Whether or not a specified terminal is a terminal of the specified project. + /// @param _projectId The ID of the project to check within. + /// @param _terminal The address of the terminal to check for. + /// @return A flag indicating whether or not the specified terminal is a terminal of the specified project. function isTerminalOf(uint256 _projectId, IJBPaymentTerminal _terminal) public view @@ -198,12 +152,10 @@ contract JBDirectory is JBOperatable, Ownable, IJBDirectory { // -------------------------- constructor ---------------------------- // //*********************************************************************// - /** - @param _operatorStore A contract storing operator assignments. - @param _projects A contract which mints ERC-721's that represent project ownership and transfers. - @param _fundingCycleStore A contract storing all funding cycle configurations. - @param _owner The address that will own the contract. - */ + /// @param _operatorStore A contract storing operator assignments. + /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers. + /// @param _fundingCycleStore A contract storing all funding cycle configurations. + /// @param _owner The address that will own the contract. constructor( IJBOperatorStore _operatorStore, IJBProjects _projects, @@ -220,19 +172,13 @@ contract JBDirectory is JBOperatable, Ownable, IJBDirectory { // ---------------------- external transactions ---------------------- // //*********************************************************************// - /** - @notice - Update the controller that manages how terminals interact with the ecosystem. - - @dev - A controller can be set if: - - the message sender is the project owner or an operator having the correct authorization. - - the message sender is the project's current controller. - - or, an allowedlisted address is setting a controller for a project that doesn't already have a controller. - - @param _projectId The ID of the project to set a new controller for. - @param _controller The new controller to set. - */ + /// @notice Update the controller that manages how terminals interact with the ecosystem. + /// @dev A controller can be set if: + /// @dev - the message sender is the project owner or an operator having the correct authorization. + /// @dev - the message sender is the project's current controller. + /// @dev - or, an allowedlisted address is setting a controller for a project that doesn't already have a controller. + /// @param _projectId The ID of the project to set a new controller for. + /// @param _controller The new controller to set. function setControllerOf(uint256 _projectId, address _controller) external override @@ -263,16 +209,10 @@ contract JBDirectory is JBOperatable, Ownable, IJBDirectory { emit SetController(_projectId, _controller, msg.sender); } - /** - @notice - Set a project's terminals. - - @dev - Only a project owner, an operator, or its controller can set its terminals. - - @param _projectId The ID of the project having terminals set. - @param _terminals The terminal to set. - */ + /// @notice Set a project's terminals. + /// @dev Only a project owner, an operator, or its controller can set its terminals. + /// @param _projectId The ID of the project having terminals set. + /// @param _terminals The terminal to set. function setTerminalsOf(uint256 _projectId, IJBPaymentTerminal[] calldata _terminals) external override @@ -313,21 +253,13 @@ contract JBDirectory is JBOperatable, Ownable, IJBDirectory { emit SetTerminals(_projectId, _terminals, msg.sender); } - /** - @notice - Project's can set which terminal should be their primary for a particular token. - This is useful in case a project has several terminals connected for a particular token. - - @dev - The terminal will be set as the primary terminal where ecosystem contracts should route tokens. - - @dev - If setting a newly added terminal and the funding cycle doesn't allow new terminals, the caller must be the current controller. - - @param _projectId The ID of the project for which a primary token is being set. - @param _token The token to set the primary terminal of. - @param _terminal The terminal to make primary. - */ + /// @notice Project's can set which terminal should be their primary for a particular token. + /// @dev This is useful in case a project has several terminals connected for a particular token. + /// @dev The terminal will be set as the primary terminal where ecosystem contracts should route tokens. + /// @dev If setting a newly added terminal and the funding cycle doesn't allow new terminals, the caller must be the current controller. + /// @param _projectId The ID of the project for which a primary token is being set. + /// @param _token The token to set the primary terminal of. + /// @param _terminal The terminal to make primary. function setPrimaryTerminalOf( uint256 _projectId, address _token, @@ -349,21 +281,13 @@ contract JBDirectory is JBOperatable, Ownable, IJBDirectory { emit SetPrimaryTerminal(_projectId, _token, _terminal, msg.sender); } - /** - @notice - Set a contract to the list of trusted addresses that can set a first controller for any project. - - @dev - The owner can add addresses which are allowed to change projects' first controllers. - These addresses are known and vetted controllers as well as contracts designed to launch new projects. - A project can set its own controller without it being on the allow list. - - @dev - If you would like an address/contract allowlisted, please reach out to the contract owner. - - @param _address The address to allow or revoke allowance from. - @param _flag Whether allowance is being added or revoked. - */ + /// @notice Set a contract to the list of trusted addresses that can set a first controller for any project. + /// @dev The owner can add addresses which are allowed to change projects' first controllers. + /// @dev These addresses are known and vetted controllers as well as contracts designed to launch new projects. + /// @dev A project can set its own controller without it being on the allow list. + /// @dev If you would like an address/contract allowlisted, please reach out to the contract owner. + /// @param _address The address to allow or revoke allowance from. + /// @param _flag Whether allowance is being added or revoked. function setIsAllowedToSetFirstController(address _address, bool _flag) external override @@ -379,13 +303,9 @@ contract JBDirectory is JBOperatable, Ownable, IJBDirectory { // --------------------- private helper functions -------------------- // //*********************************************************************// - /** - @notice - Add a terminal to a project's list of terminals if it hasn't been already. - - @param _projectId The ID of the project having a terminal added. - @param _terminal The terminal to add. - */ + /// @notice Add a terminal to a project's list of terminals if it hasn't been already. + /// @param _projectId The ID of the project having a terminal added. + /// @param _terminal The terminal to add. function _addTerminalIfNeeded(uint256 _projectId, IJBPaymentTerminal _terminal) private { // Check that the terminal has not already been added. if (isTerminalOf(_projectId, _terminal)) return; diff --git a/contracts/JBERC20PaymentTerminal.sol b/contracts/JBERC20PaymentTerminal.sol index 4b6e2e7f2..aad9ba945 100644 --- a/contracts/JBERC20PaymentTerminal.sol +++ b/contracts/JBERC20PaymentTerminal.sol @@ -1,18 +1,17 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.16; -import '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol'; -import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; -import './abstract/JBPayoutRedemptionPaymentTerminal.sol'; +import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; +import {IERC20Metadata} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol'; +import {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; +import {JBPayoutRedemptionPaymentTerminal} from './abstract/JBPayoutRedemptionPaymentTerminal.sol'; +import {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol'; +import {IJBDirectory} from './interfaces/IJBDirectory.sol'; +import {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol'; +import {IJBPrices} from './interfaces/IJBPrices.sol'; +import {IJBProjects} from './interfaces/IJBProjects.sol'; -/** - @notice - Manages the inflows and outflows of an ERC-20 token. - - @dev - Inherits from - - JBPayoutRedemptionPaymentTerminal: Includes convenience functionality for checking a message sender's permissions before executing certain transactions. -*/ +/// @notice Manages the inflows and outflows of an ERC-20 token. contract JBERC20PaymentTerminal is JBPayoutRedemptionPaymentTerminal { using SafeERC20 for IERC20; @@ -20,12 +19,8 @@ contract JBERC20PaymentTerminal is JBPayoutRedemptionPaymentTerminal { // -------------------------- internal views ------------------------- // //*********************************************************************// - /** - @notice - Checks the balance of tokens in this contract. - - @return The contract's balance, as a fixed point number with the same amount of decimals as this terminal. - */ + /// @notice Checks the balance of tokens in this contract. + /// @return The contract's balance, as a fixed point number with the same amount of decimals as this terminal. function _balance() internal view override returns (uint256) { return IERC20(token).balanceOf(address(this)); } @@ -34,19 +29,17 @@ contract JBERC20PaymentTerminal is JBPayoutRedemptionPaymentTerminal { // -------------------------- constructor ---------------------------- // //*********************************************************************// - /** - @param _token The token that this terminal manages. - @param _currency The currency that this terminal's token adheres to for price feeds. - @param _baseWeightCurrency The currency to base token issuance on. - @param _payoutSplitsGroup The group that denotes payout splits from this terminal in the splits store. - @param _operatorStore A contract storing operator assignments. - @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 _splitsStore A contract that stores splits for each project. - @param _prices A contract that exposes price feeds. - @param _store A contract that stores the terminal's data. - @param _owner The address that will own this contract. - */ + /// @param _token The token that this terminal manages. + /// @param _currency The currency that this terminal's token adheres to for price feeds. + /// @param _baseWeightCurrency The currency to base token issuance on. + /// @param _payoutSplitsGroup The group that denotes payout splits from this terminal in the splits store. + /// @param _operatorStore A contract storing operator assignments. + /// @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 _splitsStore A contract that stores splits for each project. + /// @param _prices A contract that exposes price feeds. + /// @param _store A contract that stores the terminal's data. + /// @param _owner The address that will own this contract. constructor( IERC20Metadata _token, uint256 _currency, @@ -57,7 +50,7 @@ contract JBERC20PaymentTerminal is JBPayoutRedemptionPaymentTerminal { IJBDirectory _directory, IJBSplitsStore _splitsStore, IJBPrices _prices, - IJBSingleTokenPaymentTerminalStore _store, + address _store, address _owner ) JBPayoutRedemptionPaymentTerminal( @@ -83,31 +76,19 @@ contract JBERC20PaymentTerminal is JBPayoutRedemptionPaymentTerminal { // ---------------------- internal transactions ---------------------- // //*********************************************************************// - /** - @notice - Transfers tokens. - - @param _from The address from which the transfer should originate. - @param _to The address to which the transfer should go. - @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal. - */ - function _transferFrom( - address _from, - address payable _to, - uint256 _amount - ) internal override { + /// @notice Transfers tokens. + /// @param _from The address from which the transfer should originate. + /// @param _to The address to which the transfer should go. + /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal. + function _transferFrom(address _from, address payable _to, uint256 _amount) internal override { _from == address(this) ? IERC20(token).safeTransfer(_to, _amount) : IERC20(token).safeTransferFrom(_from, _to, _amount); } - /** - @notice - Logic to be triggered before transferring tokens from this terminal. - - @param _to The address to which the transfer is going. - @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal. - */ + /// @notice Logic to be triggered before transferring tokens from this terminal. + /// @param _to The address to which the transfer is going. + /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal. function _beforeTransferTo(address _to, uint256 _amount) internal override { IERC20(token).safeApprove(_to, _amount); } diff --git a/contracts/JBERC20PaymentTerminal3_1.sol b/contracts/JBERC20PaymentTerminal3_1.sol index feeb6573e..44955b677 100644 --- a/contracts/JBERC20PaymentTerminal3_1.sol +++ b/contracts/JBERC20PaymentTerminal3_1.sol @@ -1,18 +1,17 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.16; -import '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol'; -import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; -import './abstract/JBPayoutRedemptionPaymentTerminal3_1.sol'; - -/** - @notice - Manages the inflows and outflows of an ERC-20 token. - - @dev - Inherits from - - JBPayoutRedemptionPaymentTerminal: Includes convenience functionality for checking a message sender's permissions before executing certain transactions. -*/ +import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; +import {IERC20Metadata} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol'; +import {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; +import {JBPayoutRedemptionPaymentTerminal3_1} from './abstract/JBPayoutRedemptionPaymentTerminal3_1.sol'; +import {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol'; +import {IJBDirectory} from './interfaces/IJBDirectory.sol'; +import {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol'; +import {IJBPrices} from './interfaces/IJBPrices.sol'; +import {IJBProjects} from './interfaces/IJBProjects.sol'; + +/// @notice Manages the inflows and outflows of an ERC-20 token. contract JBERC20PaymentTerminal3_1 is JBPayoutRedemptionPaymentTerminal3_1 { using SafeERC20 for IERC20; @@ -20,12 +19,8 @@ contract JBERC20PaymentTerminal3_1 is JBPayoutRedemptionPaymentTerminal3_1 { // -------------------------- internal views ------------------------- // //*********************************************************************// - /** - @notice - Checks the balance of tokens in this contract. - - @return The contract's balance, as a fixed point number with the same amount of decimals as this terminal. - */ + /// @notice Checks the balance of tokens in this contract. + /// @return The contract's balance, as a fixed point number with the same amount of decimals as this terminal. function _balance() internal view override returns (uint256) { return IERC20(token).balanceOf(address(this)); } @@ -34,19 +29,17 @@ contract JBERC20PaymentTerminal3_1 is JBPayoutRedemptionPaymentTerminal3_1 { // -------------------------- constructor ---------------------------- // //*********************************************************************// - /** - @param _token The token that this terminal manages. - @param _currency The currency that this terminal's token adheres to for price feeds. - @param _baseWeightCurrency The currency to base token issuance on. - @param _payoutSplitsGroup The group that denotes payout splits from this terminal in the splits store. - @param _operatorStore A contract storing operator assignments. - @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 _splitsStore A contract that stores splits for each project. - @param _prices A contract that exposes price feeds. - @param _store A contract that stores the terminal's data. - @param _owner The address that will own this contract. - */ + /// @param _token The token that this terminal manages. + /// @param _currency The currency that this terminal's token adheres to for price feeds. + /// @param _baseWeightCurrency The currency to base token issuance on. + /// @param _payoutSplitsGroup The group that denotes payout splits from this terminal in the splits store. + /// @param _operatorStore A contract storing operator assignments. + /// @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 _splitsStore A contract that stores splits for each project. + /// @param _prices A contract that exposes price feeds. + /// @param _store A contract that stores the terminal's data. + /// @param _owner The address that will own this contract. constructor( IERC20Metadata _token, uint256 _currency, @@ -57,7 +50,7 @@ contract JBERC20PaymentTerminal3_1 is JBPayoutRedemptionPaymentTerminal3_1 { IJBDirectory _directory, IJBSplitsStore _splitsStore, IJBPrices _prices, - IJBSingleTokenPaymentTerminalStore _store, + address _store, address _owner ) JBPayoutRedemptionPaymentTerminal3_1( @@ -83,42 +76,26 @@ contract JBERC20PaymentTerminal3_1 is JBPayoutRedemptionPaymentTerminal3_1 { // ---------------------- internal transactions ---------------------- // //*********************************************************************// - /** - @notice - Transfers tokens. - - @param _from The address from which the transfer should originate. - @param _to The address to which the transfer should go. - @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal. - */ - function _transferFrom( - address _from, - address payable _to, - uint256 _amount - ) internal override { + /// @notice Transfers tokens. + /// @param _from The address from which the transfer should originate. + /// @param _to The address to which the transfer should go. + /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal. + function _transferFrom(address _from, address payable _to, uint256 _amount) internal override { _from == address(this) ? IERC20(token).safeTransfer(_to, _amount) : IERC20(token).safeTransferFrom(_from, _to, _amount); } - /** - @notice - Logic to be triggered before transferring tokens from this terminal. - - @param _to The address to which the transfer is going. - @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal. - */ + /// @notice Logic to be triggered before transferring tokens from this terminal. + /// @param _to The address to which the transfer is going. + /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal. function _beforeTransferTo(address _to, uint256 _amount) internal override { IERC20(token).safeIncreaseAllowance(_to, _amount); } - /** - @notice - Logic to be triggered if a transfer should be undone - - @param _to The address to which the transfer went. - @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal. - */ + /// @notice Logic to be triggered if a transfer should be undone + /// @param _to The address to which the transfer went. + /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal. function _cancelTransferTo(address _to, uint256 _amount) internal override { IERC20(token).safeDecreaseAllowance(_to, _amount); } diff --git a/contracts/JBERC20PaymentTerminal3_1_1.sol b/contracts/JBERC20PaymentTerminal3_1_1.sol new file mode 100644 index 000000000..8c47a8922 --- /dev/null +++ b/contracts/JBERC20PaymentTerminal3_1_1.sol @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.16; + +import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; +import {IERC20Metadata} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol'; +import {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; +import {JBPayoutRedemptionPaymentTerminal3_1_1} from './abstract/JBPayoutRedemptionPaymentTerminal3_1_1.sol'; +import {IJBDirectory} from './interfaces/IJBDirectory.sol'; +import {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol'; +import {IJBProjects} from './interfaces/IJBProjects.sol'; +import {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol'; +import {IJBPrices} from './interfaces/IJBPrices.sol'; + +/// @notice Manages the inflows and outflows of an ERC-20 token. +contract JBERC20PaymentTerminal3_1_1 is JBPayoutRedemptionPaymentTerminal3_1_1 { + using SafeERC20 for IERC20; + + //*********************************************************************// + // -------------------------- internal views ------------------------- // + //*********************************************************************// + + /// @notice Checks the balance of tokens in this contract. + /// @return The contract's balance, as a fixed point number with the same amount of decimals as this terminal. + function _balance() internal view override returns (uint256) { + return IERC20(token).balanceOf(address(this)); + } + + //*********************************************************************// + // -------------------------- constructor ---------------------------- // + //*********************************************************************// + + /// @param _token The token that this terminal manages. + /// @param _currency The currency that this terminal's token adheres to for price feeds. + /// @param _baseWeightCurrency The currency to base token issuance on. + /// @param _payoutSplitsGroup The group that denotes payout splits from this terminal in the splits store. + /// @param _operatorStore A contract storing operator assignments. + /// @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 _splitsStore A contract that stores splits for each project. + /// @param _prices A contract that exposes price feeds. + /// @param _store A contract that stores the terminal's data. + /// @param _owner The address that will own this contract. + constructor( + IERC20Metadata _token, + uint256 _currency, + uint256 _baseWeightCurrency, + uint256 _payoutSplitsGroup, + IJBOperatorStore _operatorStore, + IJBProjects _projects, + IJBDirectory _directory, + IJBSplitsStore _splitsStore, + IJBPrices _prices, + address _store, + address _owner + ) + JBPayoutRedemptionPaymentTerminal3_1_1( + address(_token), + _token.decimals(), + _currency, + _baseWeightCurrency, + _payoutSplitsGroup, + _operatorStore, + _projects, + _directory, + _splitsStore, + _prices, + _store, + _owner + ) + // solhint-disable-next-line no-empty-blocks + { + + } + + //*********************************************************************// + // ---------------------- internal transactions ---------------------- // + //*********************************************************************// + + /// @notice Transfers tokens. + /// @param _from The address from which the transfer should originate. + /// @param _to The address to which the transfer should go. + /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal. + function _transferFrom(address _from, address payable _to, uint256 _amount) internal override { + _from == address(this) + ? IERC20(token).safeTransfer(_to, _amount) + : IERC20(token).safeTransferFrom(_from, _to, _amount); + } + + /// @notice Logic to be triggered before transferring tokens from this terminal. + /// @param _to The address to which the transfer is going. + /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal. + function _beforeTransferTo(address _to, uint256 _amount) internal override { + IERC20(token).safeIncreaseAllowance(_to, _amount); + } + + /// @notice Logic to be triggered if a transfer should be undone + /// @param _to The address to which the transfer went. + /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal. + function _cancelTransferTo(address _to, uint256 _amount) internal override { + IERC20(token).safeDecreaseAllowance(_to, _amount); + } +} diff --git a/contracts/JBETHERC20ProjectPayer.sol b/contracts/JBETHERC20ProjectPayer.sol index f807d8a4d..c33b9b307 100644 --- a/contracts/JBETHERC20ProjectPayer.sol +++ b/contracts/JBETHERC20ProjectPayer.sol @@ -1,29 +1,18 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.16; -import '@openzeppelin/contracts/access/Ownable.sol'; -import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; -import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; -import '@openzeppelin/contracts/utils/introspection/ERC165.sol'; -import './interfaces/IJBProjectPayer.sol'; -import './libraries/JBTokens.sol'; - -/** - @notice - Sends ETH or ERC20's to a project treasury as it receives direct payments or has it's functions called. - - @dev - Inherit from this contract or borrow from its logic to forward ETH or ERC20's to project treasuries from within other contracts. - - @dev - Adheres to - - IJBProjectPayer: General interface for the methods in this contract that interact with the blockchain's state according to the protocol's rules. - - @dev - Inherits from - - Ownable: Includes convenience functionality for checking a message sender's permissions before executing certain transactions. - ERC165: Introspection on interface adherance. -*/ +import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol'; +import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; +import {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; +import {ERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol'; +import {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol'; +import {IJBDirectory} from './interfaces/IJBDirectory.sol'; +import {IJBProjectPayer} from './interfaces/IJBProjectPayer.sol'; +import {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol'; +import {JBTokens} from './libraries/JBTokens.sol'; + +/// @notice Sends ETH or ERC20's to a project treasury as it receives direct payments or has it's functions called. +/// @dev Inherit from this contract or borrow from its logic to forward ETH or ERC20's to project treasuries from within other contracts. contract JBETHERC20ProjectPayer is Ownable, ERC165, IJBProjectPayer { using SafeERC20 for IERC20; @@ -39,78 +28,45 @@ contract JBETHERC20ProjectPayer is Ownable, ERC165, IJBProjectPayer { // ------------------- public immutable properties ------------------- // //*********************************************************************// - /** - @notice - A contract storing directories of terminals and controllers for each project. - */ + /// @notice A contract storing directories of terminals and controllers for each project. IJBDirectory public immutable override directory; - /** - @notice - The deployer associated with this implementation. Used to rule out double initialization. - */ + /// @notice The deployer associated with this implementation. Used to rule out double initialization. address public immutable override projectPayerDeployer; //*********************************************************************// // --------------------- public stored properties -------------------- // //*********************************************************************// - /** - @notice - The ID of the project that should be used to forward this contract's received payments. - */ + /// @notice The ID of the project that should be used to forward this contract's received payments. uint256 public override defaultProjectId; - /** - @notice - The beneficiary that should be used in the payment made when this contract receives payments. - */ + /// @notice The beneficiary that should be used in the payment made when this contract receives payments. address payable public override defaultBeneficiary; - /** - @notice - A flag indicating whether issued tokens should be automatically claimed into the beneficiary's wallet. Leaving tokens unclaimed saves gas. - */ + /// @notice A flag indicating whether issued tokens should be automatically claimed into the beneficiary's wallet. Leaving tokens unclaimed saves gas. bool public override defaultPreferClaimedTokens; - /** - @notice - The memo that should be used in the payment made when this contract receives payments. - */ + /// @notice The memo that should be used in the payment made when this contract receives payments. string public override defaultMemo; - /** - @notice - The metadata that should be used in the payment made when this contract receives payments. - */ + /// @notice The metadata that should be used in the payment made when this contract receives payments. bytes public override defaultMetadata; - /** - @notice - A flag indicating if received payments should call the `pay` function or the `addToBalance` function of a project. - */ + /// @notice A flag indicating if received payments should call the `pay` function or the `addToBalance` function of a project. bool public override defaultPreferAddToBalance; //*********************************************************************// // ------------------------- public views ---------------------------- // //*********************************************************************// - /** - @notice - Indicates if this contract adheres to the specified interface. - - @dev - See {IERC165-supportsInterface}. - - @param _interfaceId The ID of the interface to check for adherance to. - */ - function supportsInterface(bytes4 _interfaceId) - public - view - virtual - override(ERC165, IERC165) - returns (bool) - { + /// @notice Indicates if this contract adheres to the specified interface. + /// @dev See {IERC165-supportsInterface}. + /// @param _interfaceId The ID of the interface to check for adherance to. + /// @return A flag indicating if the provided interface ID is supported. + function supportsInterface( + bytes4 _interfaceId + ) public view virtual override(ERC165, IERC165) returns (bool) { return _interfaceId == type(IJBProjectPayer).interfaceId || super.supportsInterface(_interfaceId); } @@ -119,25 +75,20 @@ contract JBETHERC20ProjectPayer is Ownable, ERC165, IJBProjectPayer { // -------------------------- constructors --------------------------- // //*********************************************************************// - /** - @dev This is the constructor of the implementation. The directory is shared between project payers and is - immutable. If a new JBDirectory is needed, a new JBProjectPayerDeployer should be deployed. - @param _directory A contract storing directories of terminals and controllers for each project. - */ + /// @dev This is the constructor of the implementation. The directory is shared between project payers and is immutable. If a new JBDirectory is needed, a new JBProjectPayerDeployer should be deployed. + /// @param _directory A contract storing directories of terminals and controllers for each project. constructor(IJBDirectory _directory) { directory = _directory; projectPayerDeployer = msg.sender; } - /** - @param _defaultProjectId The ID of the project whose treasury should be forwarded this contract's received payments. - @param _defaultBeneficiary The address that'll receive the project's tokens. - @param _defaultPreferClaimedTokens A flag indicating whether issued tokens should be automatically claimed into the beneficiary's wallet. - @param _defaultMemo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate. - @param _defaultMetadata Bytes to send along to the project's data source and delegate, if provided. - @param _defaultPreferAddToBalance A flag indicating if received payments should call the `pay` function or the `addToBalance` function of a project. - @param _owner The address that will own the contract. - */ + /// @param _defaultProjectId The ID of the project whose treasury should be forwarded this contract's received payments. + /// @param _defaultBeneficiary The address that'll receive the project's tokens. + /// @param _defaultPreferClaimedTokens A flag indicating whether issued tokens should be automatically claimed into the beneficiary's wallet. + /// @param _defaultMemo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate. + /// @param _defaultMetadata Bytes to send along to the project's data source and delegate, if provided. + /// @param _defaultPreferAddToBalance A flag indicating if received payments should call the `pay` function or the `addToBalance` function of a project. + /// @param _owner The address that will own the contract. function initialize( uint256 _defaultProjectId, address payable _defaultBeneficiary, @@ -147,7 +98,7 @@ contract JBETHERC20ProjectPayer is Ownable, ERC165, IJBProjectPayer { bool _defaultPreferAddToBalance, address _owner ) public { - if(msg.sender != projectPayerDeployer) revert ALREADY_INITIALIZED(); + if (msg.sender != projectPayerDeployer) revert ALREADY_INITIALIZED(); defaultProjectId = _defaultProjectId; defaultBeneficiary = _defaultBeneficiary; @@ -162,16 +113,9 @@ contract JBETHERC20ProjectPayer is Ownable, ERC165, IJBProjectPayer { // ------------------------- default receive ------------------------- // //*********************************************************************// - /** - @notice - Received funds are paid to the default project ID using the stored default properties. - - @dev - Use the `addToBalance` function if there's a preference to do so. Otherwise use `pay`. - - @dev - This function is called automatically when the contract receives an ETH payment. - */ + /// @notice Received funds are paid to the default project ID using the stored default properties. + /// @dev Use the `addToBalance` function if there's a preference to do so. Otherwise use `pay`. + /// @dev This function is called automatically when the contract receives an ETH payment. receive() external payable virtual override { if (defaultPreferAddToBalance) _addToBalanceOf( @@ -200,17 +144,13 @@ contract JBETHERC20ProjectPayer is Ownable, ERC165, IJBProjectPayer { // ---------------------- external transactions ---------------------- // //*********************************************************************// - /** - @notice - Sets the default values that determine how to interact with a protocol treasury when this contract receives ETH directly. - - @param _projectId The ID of the project whose treasury should be forwarded this contract's received payments. - @param _beneficiary The address that'll receive the project's tokens. - @param _preferClaimedTokens A flag indicating whether issued tokens should be automatically claimed into the beneficiary's wallet. - @param _memo The memo that'll be used. - @param _metadata The metadata that'll be sent. - @param _defaultPreferAddToBalance A flag indicating if received payments should call the `pay` function or the `addToBalance` function of a project. - */ + /// @notice Sets the default values that determine how to interact with a protocol treasury when this contract receives ETH directly. + /// @param _projectId The ID of the project whose treasury should be forwarded this contract's received payments. + /// @param _beneficiary The address that'll receive the project's tokens. + /// @param _preferClaimedTokens A flag indicating whether issued tokens should be automatically claimed into the beneficiary's wallet. + /// @param _memo The memo that'll be used. + /// @param _metadata The metadata that'll be sent. + /// @param _defaultPreferAddToBalance A flag indicating if received payments should call the `pay` function or the `addToBalance` function of a project. function setDefaultValues( uint256 _projectId, address payable _beneficiary, @@ -256,20 +196,16 @@ contract JBETHERC20ProjectPayer is Ownable, ERC165, IJBProjectPayer { // ----------------------- public transactions ----------------------- // //*********************************************************************// - /** - @notice - Make a payment to the specified project. - - @param _projectId The ID of the project that is being paid. - @param _token The token being paid in. - @param _amount The amount of tokens being paid, as a fixed point number. If the token is ETH, this is ignored and msg.value is used in its place. - @param _decimals The number of decimals in the `_amount` fixed point number. If the token is ETH, this is ignored and 18 is used in its place, which corresponds to the amount of decimals expected in msg.value. - @param _beneficiary The address who will receive tokens from the payment. - @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with 18 decimals. - @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas. - @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate. - @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided. - */ + /// @notice Make a payment to the specified project. + /// @param _projectId The ID of the project that is being paid. + /// @param _token The token being paid in. + /// @param _amount The amount of tokens being paid, as a fixed point number. If the token is ETH, this is ignored and msg.value is used in its place. + /// @param _decimals The number of decimals in the `_amount` fixed point number. If the token is ETH, this is ignored and 18 is used in its place, which corresponds to the amount of decimals expected in msg.value. + /// @param _beneficiary The address who will receive tokens from the payment. + /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with 18 decimals. + /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas. + /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate. + /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided. function pay( uint256 _projectId, address _token, @@ -312,17 +248,13 @@ contract JBETHERC20ProjectPayer is Ownable, ERC165, IJBProjectPayer { ); } - /** - @notice - Add to the balance of the specified project. - - @param _projectId The ID of the project that is being paid. - @param _token The token being paid in. - @param _amount The amount of tokens being paid, as a fixed point number. If the token is ETH, this is ignored and msg.value is used in its place. - @param _decimals The number of decimals in the `_amount` fixed point number. If the token is ETH, this is ignored and 18 is used in its place, which corresponds to the amount of decimals expected in msg.value. - @param _memo A memo to pass along to the emitted event. - @param _metadata Extra data to pass along to the terminal. - */ + /// @notice Add to the balance of the specified project. + /// @param _projectId The ID of the project that is being paid. + /// @param _token The token being paid in. + /// @param _amount The amount of tokens being paid, as a fixed point number. If the token is ETH, this is ignored and msg.value is used in its place. + /// @param _decimals The number of decimals in the `_amount` fixed point number. If the token is ETH, this is ignored and 18 is used in its place, which corresponds to the amount of decimals expected in msg.value. + /// @param _memo A memo to pass along to the emitted event. + /// @param _metadata Extra data to pass along to the terminal. function addToBalanceOf( uint256 _projectId, address _token, @@ -356,20 +288,16 @@ contract JBETHERC20ProjectPayer is Ownable, ERC165, IJBProjectPayer { // ---------------------- internal transactions ---------------------- // //*********************************************************************// - /** - @notice - Make a payment to the specified project. - - @param _projectId The ID of the project that is being paid. - @param _token The token being paid in. - @param _amount The amount of tokens being paid, as a fixed point number. - @param _decimals The number of decimals in the `_amount` fixed point number. - @param _beneficiary The address who will receive tokens from the payment. - @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with 18 decimals. - @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas. - @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate. - @param _metadata Bytes to send along to the data source and delegate, if provided. - */ + /// @notice Make a payment to the specified project. + /// @param _projectId The ID of the project that is being paid. + /// @param _token The token being paid in. + /// @param _amount The amount of tokens being paid, as a fixed point number. + /// @param _decimals The number of decimals in the `_amount` fixed point number. + /// @param _beneficiary The address who will receive tokens from the payment. + /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with 18 decimals. + /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas. + /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate. + /// @param _metadata Bytes to send along to the data source and delegate, if provided. function _pay( uint256 _projectId, address _token, @@ -412,17 +340,13 @@ contract JBETHERC20ProjectPayer is Ownable, ERC165, IJBProjectPayer { ); } - /** - @notice - Add to the balance of the specified project. - - @param _projectId The ID of the project that is being paid. - @param _token The token being paid in. - @param _amount The amount of tokens being paid, as a fixed point number. If the token is ETH, this is ignored and msg.value is used in its place. - @param _decimals The number of decimals in the `_amount` fixed point number. If the token is ETH, this is ignored and 18 is used in its place, which corresponds to the amount of decimals expected in msg.value. - @param _memo A memo to pass along to the emitted event. - @param _metadata Extra data to pass along to the terminal. - */ + /// @notice Add to the balance of the specified project. + /// @param _projectId The ID of the project that is being paid. + /// @param _token The token being paid in. + /// @param _amount The amount of tokens being paid, as a fixed point number. If the token is ETH, this is ignored and msg.value is used in its place. + /// @param _decimals The number of decimals in the `_amount` fixed point number. If the token is ETH, this is ignored and 18 is used in its place, which corresponds to the amount of decimals expected in msg.value. + /// @param _memo A memo to pass along to the emitted event. + /// @param _metadata Extra data to pass along to the terminal. function _addToBalanceOf( uint256 _projectId, address _token, diff --git a/contracts/JBETHERC20ProjectPayerDeployer.sol b/contracts/JBETHERC20ProjectPayerDeployer.sol index 5d49e2456..b03bce3f1 100644 --- a/contracts/JBETHERC20ProjectPayerDeployer.sol +++ b/contracts/JBETHERC20ProjectPayerDeployer.sol @@ -1,28 +1,29 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.16; -import { Clones } from '@openzeppelin/contracts/proxy/Clones.sol'; +import {Clones} from '@openzeppelin/contracts/proxy/Clones.sol'; +import {IJBDirectory} from './interfaces/IJBDirectory.sol'; +import {IJBProjectPayer} from './interfaces/IJBProjectPayer.sol'; +import {IJBETHERC20ProjectPayerDeployer} from './interfaces/IJBETHERC20ProjectPayerDeployer.sol'; +import {JBETHERC20ProjectPayer} from './JBETHERC20ProjectPayer.sol'; -import './interfaces/IJBETHERC20ProjectPayerDeployer.sol'; -import './JBETHERC20ProjectPayer.sol'; - -/** - @notice - Deploys project payer contracts. - - @dev - Adheres to - - IJBETHERC20ProjectPayerDeployer: General interface for the methods in this contract that interact with the blockchain's state according to the protocol's rules. -*/ +/// @notice Deploys project payer contracts. contract JBETHERC20ProjectPayerDeployer is IJBETHERC20ProjectPayerDeployer { + //*********************************************************************// + // --------------- public immutable stored properties ---------------- // + //*********************************************************************// + /// @notice The implementation contract on which Clones will be based. address immutable implementation; + /// @notice directory instance which keeps a track of which controller is linked to which project. IJBDirectory immutable directory; - /** - @param _directory A contract storing directories of terminals and controllers for each project. - */ + //*********************************************************************// + // ---------------------------- constructor -------------------------- // + //*********************************************************************// + + /// @param _directory A contract storing directories of terminals and controllers for each project. constructor(IJBDirectory _directory) { implementation = address(new JBETHERC20ProjectPayer(_directory)); directory = _directory; @@ -32,20 +33,15 @@ contract JBETHERC20ProjectPayerDeployer is IJBETHERC20ProjectPayerDeployer { // ---------------------- external transactions ---------------------- // //*********************************************************************// - /** - @notice - Allows anyone to deploy a new project payer contract. - - @param _defaultProjectId The ID of the project whose treasury should be forwarded the project payer contract's received payments. - @param _defaultBeneficiary The address that'll receive the project's tokens when the project payer receives payments. - @param _defaultPreferClaimedTokens A flag indicating whether issued tokens from the project payer's received payments should be automatically claimed into the beneficiary's wallet. - @param _defaultMemo The memo that'll be forwarded with the project payer's received payments. - @param _defaultMetadata The metadata that'll be forwarded with the project payer's received payments. - @param _defaultPreferAddToBalance A flag indicating if received payments should call the `pay` function or the `addToBalance` function of a project. - @param _owner The address that will own the project payer. - - @return projectPayer The project payer contract. - */ + /// @notice Allows anyone to deploy a new project payer contract. + /// @param _defaultProjectId The ID of the project whose treasury should be forwarded the project payer contract's received payments. + /// @param _defaultBeneficiary The address that'll receive the project's tokens when the project payer receives payments. + /// @param _defaultPreferClaimedTokens A flag indicating whether issued tokens from the project payer's received payments should be automatically claimed into the beneficiary's wallet. + /// @param _defaultMemo The memo that'll be forwarded with the project payer's received payments. + /// @param _defaultMetadata The metadata that'll be forwarded with the project payer's received payments. + /// @param _defaultPreferAddToBalance A flag indicating if received payments should call the `pay` function or the `addToBalance` function of a project. + /// @param _owner The address that will own the project payer. + /// @return projectPayer The project payer contract. function deployProjectPayer( uint256 _defaultProjectId, address payable _defaultBeneficiary, diff --git a/contracts/JBETHERC20SplitsPayer.sol b/contracts/JBETHERC20SplitsPayer.sol index dec2480de..967ab9d25 100644 --- a/contracts/JBETHERC20SplitsPayer.sol +++ b/contracts/JBETHERC20SplitsPayer.sol @@ -1,31 +1,24 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.16; -import '@openzeppelin/contracts/security/ReentrancyGuard.sol'; -import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; -import '@openzeppelin/contracts/utils/Address.sol'; -import '@paulrberg/contracts/math/PRBMath.sol'; -import './interfaces/IJBSplitsPayer.sol'; -import './interfaces/IJBSplitsStore.sol'; -import './libraries/JBConstants.sol'; -import './JBETHERC20ProjectPayer.sol'; - -/** - @notice - Sends ETH or ERC20's to a group of splits as it receives direct payments or has its functions called. - - @dev - Inherit from this contract or borrow from its logic to forward ETH or ERC20's to a group of splits from within other contracts. - - @dev - Adheres to - - IJBSplitsPayer: General interface for the methods in this contract that interact with the blockchain's state according to the protocol's rules. - - @dev - Inherits from - - JBETHERC20ProjectPayer: Sends ETH or ERC20's to a project treasury as it receives direct payments or has it's functions called. - ReentrancyGuard: Contract module that helps prevent reentrant calls to a function. -*/ +import {ReentrancyGuard} from '@openzeppelin/contracts/security/ReentrancyGuard.sol'; +import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; +import {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; +import {Address} from '@openzeppelin/contracts/utils/Address.sol'; +import {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol'; +import {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol'; +import {IJBSplitsPayer} from './interfaces/IJBSplitsPayer.sol'; +import {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol'; +import {JBConstants} from './libraries/JBConstants.sol'; +import {JBETHERC20ProjectPayer} from './JBETHERC20ProjectPayer.sol'; +import {IJBSplitAllocator} from './interfaces/IJBSplitAllocator.sol'; +import {JBTokens} from './libraries/JBTokens.sol'; +import {JBGroupedSplits} from './structs/JBGroupedSplits.sol'; +import {JBSplit} from './structs/JBSplit.sol'; +import {JBSplitAllocationData} from './structs/JBSplitAllocationData.sol'; + +/// @notice Sends ETH or ERC20's to a group of splits as it receives direct payments or has its functions called. +/// @dev Inherit from this contract or borrow from its logic to forward ETH or ERC20's to a group of splits from within other contracts. contract JBETHERC20SplitsPayer is JBETHERC20ProjectPayer, ReentrancyGuard, IJBSplitsPayer { using SafeERC20 for IERC20; @@ -33,56 +26,33 @@ contract JBETHERC20SplitsPayer is JBETHERC20ProjectPayer, ReentrancyGuard, IJBSp // ---------------- public immutable stored properties --------------- // //*********************************************************************// - /** - @notice - The contract that stores splits for each project. - */ + /// @notice The contract that stores splits for each project. IJBSplitsStore public immutable override splitsStore; //*********************************************************************// // --------------------- public stored properties -------------------- // //*********************************************************************// - /** - @notice - The ID of project for which the default splits are stored. - */ + /// @notice The ID of project for which the default splits are stored. uint256 public override defaultSplitsProjectId; - /** - @notice - The domain within which the default splits are stored. - */ + /// @notice The domain within which the default splits are stored. uint256 public override defaultSplitsDomain; - /** - @notice - The group within which the default splits are stored. - */ + /// @notice The group within which the default splits are stored. uint256 public override defaultSplitsGroup; //*********************************************************************// // -------------------------- public views --------------------------- // //*********************************************************************// - /** - @notice - Indicates if this contract adheres to the specified interface. - - @dev - See {IERC165-supportsInterface}. - - @param _interfaceId The ID of the interface to check for adherance to. - - @return A flag indicating if this contract adheres to the specified interface. - */ - function supportsInterface(bytes4 _interfaceId) - public - view - virtual - override(JBETHERC20ProjectPayer, IERC165) - returns (bool) - { + /// @notice Indicates if this contract adheres to the specified interface. + /// @dev See {IERC165-supportsInterface}. + /// @param _interfaceId The ID of the interface to check for adherance to. + /// @return A flag indicating if this contract adheres to the specified interface. + function supportsInterface( + bytes4 _interfaceId + ) public view virtual override(JBETHERC20ProjectPayer, IERC165) returns (bool) { return _interfaceId == type(IJBSplitsPayer).interfaceId || super.supportsInterface(_interfaceId); } @@ -90,32 +60,23 @@ contract JBETHERC20SplitsPayer is JBETHERC20ProjectPayer, ReentrancyGuard, IJBSp //*********************************************************************// // -------------------------- constructor ---------------------------- // //*********************************************************************// -/** - @param _splitsStore A contract that stores splits for each project. -*/ - constructor( - IJBSplitsStore _splitsStore - ) - JBETHERC20ProjectPayer( - _splitsStore.directory() - ) - { + + /// @param _splitsStore A contract that stores splits for each project. + constructor(IJBSplitsStore _splitsStore) JBETHERC20ProjectPayer(_splitsStore.directory()) { splitsStore = _splitsStore; } - /** - @dev The re-initialize check is done in the inherited paroject payer - - @param _defaultSplitsProjectId The ID of project for which the default splits are stored. - @param _defaultSplitsDomain The splits domain to payout when this contract receives direct payments. - @param _defaultSplitsGroup The splits group to payout when this contract receives direct payments. - @param _defaultProjectId The ID of the project whose treasury should be forwarded the splits payer contract's received payment leftovers after distributing to the default splits group. - @param _defaultBeneficiary The address that'll receive the project's tokens. - @param _defaultPreferClaimedTokens A flag indicating whether issued tokens should be automatically claimed into the beneficiary's wallet. - @param _defaultMemo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate. - @param _defaultMetadata Bytes to send along to the project's data source and delegate, if provided. - @param _preferAddToBalance A flag indicating if received payments should call the `pay` function or the `addToBalance` function of a project. - @param _owner The address that will own the contract. - */ + + /// @dev The re-initialize check is done in the inherited paroject payer + /// @param _defaultSplitsProjectId The ID of project for which the default splits are stored. + /// @param _defaultSplitsDomain The splits domain to payout when this contract receives direct payments. + /// @param _defaultSplitsGroup The splits group to payout when this contract receives direct payments. + /// @param _defaultProjectId The ID of the project whose treasury should be forwarded the splits payer contract's received payment leftovers after distributing to the default splits group. + /// @param _defaultBeneficiary The address that'll receive the project's tokens. + /// @param _defaultPreferClaimedTokens A flag indicating whether issued tokens should be automatically claimed into the beneficiary's wallet. + /// @param _defaultMemo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate. + /// @param _defaultMetadata Bytes to send along to the project's data source and delegate, if provided. + /// @param _preferAddToBalance A flag indicating if received payments should call the `pay` function or the `addToBalance` function of a project. + /// @param _owner The address that will own the contract. function initialize( uint256 _defaultSplitsProjectId, uint256 _defaultSplitsDomain, @@ -128,7 +89,6 @@ contract JBETHERC20SplitsPayer is JBETHERC20ProjectPayer, ReentrancyGuard, IJBSp bool _preferAddToBalance, address _owner ) external override { - super.initialize( _defaultProjectId, _defaultBeneficiary, @@ -144,19 +104,12 @@ contract JBETHERC20SplitsPayer is JBETHERC20ProjectPayer, ReentrancyGuard, IJBSp defaultSplitsGroup = _defaultSplitsGroup; } - - //*********************************************************************// // ------------------------- default receive ------------------------- // //*********************************************************************// - /** - @notice - Received funds are paid to the default split group using the stored default properties. - - @dev - This function is called automatically when the contract receives an ETH payment. - */ + /// @notice Received funds are paid to the default split group using the stored default properties. + /// @dev This function is called automatically when the contract receives an ETH payment. receive() external payable virtual override nonReentrant { // Pay the splits and get a reference to the amount leftover. uint256 _leftoverAmount = _payToSplits( @@ -209,15 +162,11 @@ contract JBETHERC20SplitsPayer is JBETHERC20ProjectPayer, ReentrancyGuard, IJBSp // ---------------------- external transactions ---------------------- // //*********************************************************************// - /** - @notice - Sets the splits in the splits store that payments this contract receives will be split between. - - @param _projectId The ID of project for which the default splits are stored. - @param _domain The domain within which the default splits are stored. - @param _group The group within which the default splits are stored. - @param _groupedSplits The split groups to set. - */ + /// @notice Sets the splits in the splits store that payments this contract receives will be split between. + /// @param _projectId The ID of project for which the default splits are stored. + /// @param _domain The domain within which the default splits are stored. + /// @param _group The group within which the default splits are stored. + /// @param _groupedSplits The split groups to set. function setDefaultSplits( uint256 _projectId, uint256 _domain, @@ -235,14 +184,10 @@ contract JBETHERC20SplitsPayer is JBETHERC20ProjectPayer, ReentrancyGuard, IJBSp // ----------------------- public transactions ----------------------- // //*********************************************************************// - /** - @notice - Sets the location of the splits that payments this contract receives will be split between. - - @param _projectId The ID of project for which the default splits are stored. - @param _domain The domain within which the default splits are stored. - @param _group The group within which the default splits are stored. - */ + /// @notice Sets the location of the splits that payments this contract receives will be split between. + /// @param _projectId The ID of project for which the default splits are stored. + /// @param _domain The domain within which the default splits are stored. + /// @param _group The group within which the default splits are stored. function setDefaultSplitsReference( uint256 _projectId, uint256 _domain, @@ -260,20 +205,16 @@ contract JBETHERC20SplitsPayer is JBETHERC20ProjectPayer, ReentrancyGuard, IJBSp emit SetDefaultSplitsReference(_projectId, _domain, _group, msg.sender); } - /** - @notice - Make a payment to the specified project after first splitting the amount among the stored default splits. - - @param _projectId The ID of the project that is being paid after. - @param _token The token being paid in. - @param _amount The amount of tokens being paid, as a fixed point number. If the token is ETH, this is ignored and msg.value is used in its place. - @param _decimals The number of decimals in the `_amount` fixed point number. If the token is ETH, this is ignored and 18 is used in its place, which corresponds to the amount of decimals expected in msg.value. - @param _beneficiary The address who will receive tokens from the payment made with leftover funds. - @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with 18 decimals. - @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas. - @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate. - @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided. - */ + /// @notice Make a payment to the specified project after first splitting the amount among the stored default splits. + /// @param _projectId The ID of the project that is being paid after. + /// @param _token The token being paid in. + /// @param _amount The amount of tokens being paid, as a fixed point number. If the token is ETH, this is ignored and msg.value is used in its place. + /// @param _decimals The number of decimals in the `_amount` fixed point number. If the token is ETH, this is ignored and 18 is used in its place, which corresponds to the amount of decimals expected in msg.value. + /// @param _beneficiary The address who will receive tokens from the payment made with leftover funds. + /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with 18 decimals. + /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas. + /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate. + /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided. function pay( uint256 _projectId, address _token, @@ -372,17 +313,13 @@ contract JBETHERC20SplitsPayer is JBETHERC20ProjectPayer, ReentrancyGuard, IJBSp ); } - /** - @notice - Add to the balance of the specified project after first splitting the amount among the stored default splits. - - @param _projectId The ID of the project that is being paid after. - @param _token The token being paid in. - @param _amount The amount of tokens being paid, as a fixed point number. If the token is ETH, this is ignored and msg.value is used in its place. - @param _decimals The number of decimals in the `_amount` fixed point number. If the token is ETH, this is ignored and 18 is used in its place, which corresponds to the amount of decimals expected in msg.value. - @param _memo A memo to pass along to the emitted event. - @param _metadata Extra data to pass along to the terminal. - */ + /// @notice Add to the balance of the specified project after first splitting the amount among the stored default splits. + /// @param _projectId The ID of the project that is being paid after. + /// @param _token The token being paid in. + /// @param _amount The amount of tokens being paid, as a fixed point number. If the token is ETH, this is ignored and msg.value is used in its place. + /// @param _decimals The number of decimals in the `_amount` fixed point number. If the token is ETH, this is ignored and 18 is used in its place, which corresponds to the amount of decimals expected in msg.value. + /// @param _memo A memo to pass along to the emitted event. + /// @param _metadata Extra data to pass along to the terminal. function addToBalanceOf( uint256 _projectId, address _token, @@ -463,20 +400,15 @@ contract JBETHERC20SplitsPayer is JBETHERC20ProjectPayer, ReentrancyGuard, IJBSp // ---------------------- internal transactions ---------------------- // //*********************************************************************// - /** - @notice - Split an amount between all splits. - - @param _splitsProjectId The ID of the project to which the splits belong. - @param _splitsDomain The splits domain to which the group belongs. - @param _splitsGroup The splits group to pay. - @param _token The token the amonut being split is in. - @param _amount The amount of tokens being split, as a fixed point number. If the `_token` is ETH, this is ignored and msg.value is used in its place. - @param _decimals The number of decimals in the `_amount` fixed point number. - @param _defaultBeneficiary The address that will benefit from any non-specified beneficiaries in splits. - - @return leftoverAmount The amount leftover after all splits were paid. - */ + /// @notice Split an amount between all splits. + /// @param _splitsProjectId The ID of the project to which the splits belong. + /// @param _splitsDomain The splits domain to which the group belongs. + /// @param _splitsGroup The splits group to pay. + /// @param _token The token the amonut being split is in. + /// @param _amount The amount of tokens being split, as a fixed point number. If the `_token` is ETH, this is ignored and msg.value is used in its place. + /// @param _decimals The number of decimals in the `_amount` fixed point number. + /// @param _defaultBeneficiary The address that will benefit from any non-specified beneficiaries in splits. + /// @return leftoverAmount The amount leftover after all splits were paid. function _payToSplits( uint256 _splitsProjectId, uint256 _splitsDomain, @@ -497,18 +429,13 @@ contract JBETHERC20SplitsPayer is JBETHERC20ProjectPayer, ReentrancyGuard, IJBSp emit DistributeToSplitGroup(_splitsProjectId, _splitsDomain, _splitsGroup, msg.sender); } - /** - @notice - Split an amount between all splits. - - @param _splits The splits. - @param _token The token the amonut being split is in. - @param _amount The amount of tokens being split, as a fixed point number. If the `_token` is ETH, this is ignored and msg.value is used in its place. - @param _decimals The number of decimals in the `_amount` fixed point number. - @param _defaultBeneficiary The address that will benefit from any non-specified beneficiaries in splits. - - @return leftoverAmount The amount leftover after all splits were paid. - */ + /// @notice Split an amount between all splits. + /// @param _splits The splits. + /// @param _token The token the amonut being split is in. + /// @param _amount The amount of tokens being split, as a fixed point number. If the `_token` is ETH, this is ignored and msg.value is used in its place. + /// @param _decimals The number of decimals in the `_amount` fixed point number. + /// @param _defaultBeneficiary The address that will benefit from any non-specified beneficiaries in splits. + /// @return leftoverAmount The amount leftover after all splits were paid. function _payTo( JBSplit[] memory _splits, address _token, diff --git a/contracts/JBETHERC20SplitsPayerDeployer.sol b/contracts/JBETHERC20SplitsPayerDeployer.sol index f4f56f6db..a3f8e5cfb 100644 --- a/contracts/JBETHERC20SplitsPayerDeployer.sol +++ b/contracts/JBETHERC20SplitsPayerDeployer.sol @@ -1,27 +1,31 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.16; -import { Clones } from '@openzeppelin/contracts/proxy/Clones.sol'; - -import './interfaces/IJBETHERC20SplitsPayerDeployer.sol'; -import './structs/JBSplit.sol'; -import './structs/JBGroupedSplits.sol'; -import './JBETHERC20SplitsPayer.sol'; - -/** - @notice - Deploys splits payer contracts. - - @dev - Adheres to - - IJBETHERC20SplitsPayerDeployer: General interface for the methods in this contract that interact with the blockchain's state according to the protocol's rules. -*/ +import {Clones} from '@openzeppelin/contracts/proxy/Clones.sol'; +import {IJBETHERC20SplitsPayerDeployer} from './interfaces/IJBETHERC20SplitsPayerDeployer.sol'; +import {IJBSplitsPayer} from './interfaces/IJBSplitsPayer.sol'; +import {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol'; +import {JBSplit} from './structs/JBSplit.sol'; +import {JBGroupedSplits} from './structs/JBGroupedSplits.sol'; +import {JBETHERC20SplitsPayer} from './JBETHERC20SplitsPayer.sol'; + +/// @notice Deploys splits payer contracts. contract JBETHERC20SplitsPayerDeployer is IJBETHERC20SplitsPayerDeployer { + //*********************************************************************// + // --------------- public immutable stored properties ---------------- // + //*********************************************************************// + /// @notice The implementation contract on which Clones will be based. address immutable implementation; + /// @notice The contract that stores splits for each project. IJBSplitsStore immutable splitsStore; + //*********************************************************************// + // ---------------------------- constructor -------------------------- // + //*********************************************************************// + + /// @param _splitsStore The contract that stores splits for each project. constructor(IJBSplitsStore _splitsStore) { implementation = address(new JBETHERC20SplitsPayer(_splitsStore)); splitsStore = _splitsStore; @@ -31,26 +35,19 @@ contract JBETHERC20SplitsPayerDeployer is IJBETHERC20SplitsPayerDeployer { // ---------------------- external transactions ---------------------- // //*********************************************************************// - /** - @notice - Allows anyone to deploy a new splits payer contract. - - @dev - This contract must have Operator permissions over the SET_SPLITS permission of the specified `_defaultSplitsProjectId`. - - @param _defaultSplitsProjectId The ID of project for which the default splits are stored. - @param _defaultSplits The splits to payout when this contract receives direct payments. - @param _splitsStore A contract that stores splits for each project. - @param _defaultProjectId The ID of the project whose treasury should be forwarded the splits payer contract's received payment leftovers after distributing to the default splits group. - @param _defaultBeneficiary The address that'll receive the project's tokens when the splits payer receives payments. - @param _defaultPreferClaimedTokens A flag indicating whether issued tokens from the splits payer's received payments should be automatically claimed into the beneficiary's wallet. - @param _defaultMemo The memo that'll be forwarded with the splits payer's received payments. - @param _defaultMetadata The metadata that'll be forwarded with the splits payer's received payments. - @param _defaultPreferAddToBalance A flag indicating if received payments should call the `pay` function or the `addToBalance` function of a project. - @param _owner The address that will own the splits payer. - - @return splitsPayer The splits payer contract. - */ + /// @notice Allows anyone to deploy a new splits payer contract. + /// @dev This contract must have Operator permissions over the SET_SPLITS permission of the specified `_defaultSplitsProjectId`. + /// @param _defaultSplitsProjectId The ID of project for which the default splits are stored. + /// @param _defaultSplits The splits to payout when this contract receives direct payments. + /// @param _splitsStore A contract that stores splits for each project. + /// @param _defaultProjectId The ID of the project whose treasury should be forwarded the splits payer contract's received payment leftovers after distributing to the default splits group. + /// @param _defaultBeneficiary The address that'll receive the project's tokens when the splits payer receives payments. + /// @param _defaultPreferClaimedTokens A flag indicating whether issued tokens from the splits payer's received payments should be automatically claimed into the beneficiary's wallet. + /// @param _defaultMemo The memo that'll be forwarded with the splits payer's received payments. + /// @param _defaultMetadata The metadata that'll be forwarded with the splits payer's received payments. + /// @param _defaultPreferAddToBalance A flag indicating if received payments should call the `pay` function or the `addToBalance` function of a project. + /// @param _owner The address that will own the splits payer. + /// @return splitsPayer The splits payer contract. function deploySplitsPayerWithSplits( uint256 _defaultSplitsProjectId, JBSplit[] memory _defaultSplits, @@ -94,23 +91,18 @@ contract JBETHERC20SplitsPayerDeployer is IJBETHERC20SplitsPayerDeployer { // ---------------------- public transactions ---------------------- // //*********************************************************************// - /** - @notice - Allows anyone to deploy a new splits payer contract. - - @param _defaultSplitsProjectId The ID of project for which the default splits are stored. - @param _defaultSplitsDomain The splits domain to payout when this contract receives direct payments. - @param _defaultSplitsGroup The splits group to payout when this contract receives direct payments. - @param _defaultProjectId The ID of the project whose treasury should be forwarded the splits payer contract's received payment leftovers after distributing to the default splits group. - @param _defaultBeneficiary The address that'll receive the project's tokens when the splits payer receives payments. - @param _defaultPreferClaimedTokens A flag indicating whether issued tokens from the splits payer's received payments should be automatically claimed into the beneficiary's wallet. - @param _defaultMemo The memo that'll be forwarded with the splits payer's received payments. - @param _defaultMetadata The metadata that'll be forwarded with the splits payer's received payments. - @param _defaultPreferAddToBalance A flag indicating if received payments should call the `pay` function or the `addToBalance` function of a project. - @param _owner The address that will own the splits payer. - - @return splitsPayer The splits payer contract. - */ + /// @notice Allows anyone to deploy a new splits payer contract. + /// @param _defaultSplitsProjectId The ID of project for which the default splits are stored. + /// @param _defaultSplitsDomain The splits domain to payout when this contract receives direct payments. + /// @param _defaultSplitsGroup The splits group to payout when this contract receives direct payments. + /// @param _defaultProjectId The ID of the project whose treasury should be forwarded the splits payer contract's received payment leftovers after distributing to the default splits group. + /// @param _defaultBeneficiary The address that'll receive the project's tokens when the splits payer receives payments. + /// @param _defaultPreferClaimedTokens A flag indicating whether issued tokens from the splits payer's received payments should be automatically claimed into the beneficiary's wallet. + /// @param _defaultMemo The memo that'll be forwarded with the splits payer's received payments. + /// @param _defaultMetadata The metadata that'll be forwarded with the splits payer's received payments. + /// @param _defaultPreferAddToBalance A flag indicating if received payments should call the `pay` function or the `addToBalance` function of a project. + /// @param _owner The address that will own the splits payer. + /// @return splitsPayer The splits payer contract. function deploySplitsPayer( uint256 _defaultSplitsProjectId, uint256 _defaultSplitsDomain, @@ -123,7 +115,6 @@ contract JBETHERC20SplitsPayerDeployer is IJBETHERC20SplitsPayerDeployer { bool _defaultPreferAddToBalance, address _owner ) public override returns (IJBSplitsPayer splitsPayer) { - // Deploy the splits payer. splitsPayer = IJBSplitsPayer(payable(Clones.clone(implementation))); diff --git a/contracts/JBETHPaymentTerminal.sol b/contracts/JBETHPaymentTerminal.sol index d1db7a75e..c4be1ee8a 100644 --- a/contracts/JBETHPaymentTerminal.sol +++ b/contracts/JBETHPaymentTerminal.sol @@ -1,29 +1,25 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.16; -import '@openzeppelin/contracts/utils/Address.sol'; -import './abstract/JBPayoutRedemptionPaymentTerminal.sol'; -import './libraries/JBSplitsGroups.sol'; +import {Address} from '@openzeppelin/contracts/utils/Address.sol'; +import {JBPayoutRedemptionPaymentTerminal} from './abstract/JBPayoutRedemptionPaymentTerminal.sol'; +import {JBSplitsGroups} from './libraries/JBSplitsGroups.sol'; +import {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol'; +import {IJBDirectory} from './interfaces/IJBDirectory.sol'; +import {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol'; +import {IJBPrices} from './interfaces/IJBPrices.sol'; +import {IJBProjects} from './interfaces/IJBProjects.sol'; +import {JBCurrencies} from './libraries/JBCurrencies.sol'; +import {JBTokens} from './libraries/JBTokens.sol'; -/** - @notice - Manages all inflows and outflows of ETH funds into the protocol ecosystem. - - @dev - Inherits from - - JBPayoutRedemptionPaymentTerminal: Generic terminal managing all inflows and outflows of funds into the protocol ecosystem. -*/ +/// @notice Manages all inflows and outflows of ETH funds into the protocol ecosystem. contract JBETHPaymentTerminal is JBPayoutRedemptionPaymentTerminal { //*********************************************************************// // -------------------------- internal views ------------------------- // //*********************************************************************// - /** - @notice - Checks the balance of tokens in this contract. - - @return The contract's balance, as a fixed point number with the same amount of decimals as this terminal. - */ + /// @notice Checks the balance of tokens in this contract. + /// @return The contract's balance, as a fixed point number with the same amount of decimals as this terminal. function _balance() internal view override returns (uint256) { return address(this).balance; } @@ -32,16 +28,14 @@ contract JBETHPaymentTerminal is JBPayoutRedemptionPaymentTerminal { // -------------------------- constructor ---------------------------- // //*********************************************************************// - /** - @param _baseWeightCurrency The currency to base token issuance on. - @param _operatorStore A contract storing operator assignments. - @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 _splitsStore A contract that stores splits for each project. - @param _prices A contract that exposes price feeds. - @param _store A contract that stores the terminal's data. - @param _owner The address that will own this contract. - */ + /// @param _baseWeightCurrency The currency to base token issuance on. + /// @param _operatorStore A contract storing operator assignments. + /// @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 _splitsStore A contract that stores splits for each project. + /// @param _prices A contract that exposes price feeds. + /// @param _store A contract that stores the terminal's data. + /// @param _owner The address that will own this contract. constructor( uint256 _baseWeightCurrency, IJBOperatorStore _operatorStore, @@ -49,7 +43,7 @@ contract JBETHPaymentTerminal is JBPayoutRedemptionPaymentTerminal { IJBDirectory _directory, IJBSplitsStore _splitsStore, IJBPrices _prices, - IJBSingleTokenPaymentTerminalStore _store, + address _store, address _owner ) JBPayoutRedemptionPaymentTerminal( @@ -75,19 +69,11 @@ contract JBETHPaymentTerminal is JBPayoutRedemptionPaymentTerminal { // ---------------------- internal transactions ---------------------- // //*********************************************************************// - /** - @notice - Transfers tokens. - - @param _from The address from which the transfer should originate. - @param _to The address to which the transfer should go. - @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal. - */ - function _transferFrom( - address _from, - address payable _to, - uint256 _amount - ) internal override { + /// @notice Transfers tokens. + /// @param _from The address from which the transfer should originate. + /// @param _to The address to which the transfer should go. + /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal. + function _transferFrom(address _from, address payable _to, uint256 _amount) internal override { _from; // Prevents unused var compiler and natspec complaints. Address.sendValue(_to, _amount); diff --git a/contracts/JBETHPaymentTerminal3_1.sol b/contracts/JBETHPaymentTerminal3_1.sol index 3a667bc69..8aacc398e 100644 --- a/contracts/JBETHPaymentTerminal3_1.sol +++ b/contracts/JBETHPaymentTerminal3_1.sol @@ -1,29 +1,25 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.16; -import '@openzeppelin/contracts/utils/Address.sol'; -import './abstract/JBPayoutRedemptionPaymentTerminal3_1.sol'; -import './libraries/JBSplitsGroups.sol'; +import {Address} from '@openzeppelin/contracts/utils/Address.sol'; +import {JBPayoutRedemptionPaymentTerminal3_1} from './abstract/JBPayoutRedemptionPaymentTerminal3_1.sol'; +import {JBSplitsGroups} from './libraries/JBSplitsGroups.sol'; +import {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol'; +import {IJBDirectory} from './interfaces/IJBDirectory.sol'; +import {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol'; +import {IJBPrices} from './interfaces/IJBPrices.sol'; +import {IJBProjects} from './interfaces/IJBProjects.sol'; +import {JBCurrencies} from './libraries/JBCurrencies.sol'; +import {JBTokens} from './libraries/JBTokens.sol'; -/** - @notice - Manages all inflows and outflows of ETH funds into the protocol ecosystem. - - @dev - Inherits from - - JBPayoutRedemptionPaymentTerminal3_1: Generic terminal managing all inflows and outflows of funds into the protocol ecosystem. -*/ +/// @notice Manages all inflows and outflows of ETH funds into the protocol ecosystem. contract JBETHPaymentTerminal3_1 is JBPayoutRedemptionPaymentTerminal3_1 { //*********************************************************************// // -------------------------- internal views ------------------------- // //*********************************************************************// - /** - @notice - Checks the balance of tokens in this contract. - - @return The contract's balance, as a fixed point number with the same amount of decimals as this terminal. - */ + /// @notice Checks the balance of tokens in this contract. + /// @return The contract's balance, as a fixed point number with the same amount of decimals as this terminal. function _balance() internal view override returns (uint256) { return address(this).balance; } @@ -32,16 +28,14 @@ contract JBETHPaymentTerminal3_1 is JBPayoutRedemptionPaymentTerminal3_1 { // -------------------------- constructor ---------------------------- // //*********************************************************************// - /** - @param _baseWeightCurrency The currency to base token issuance on. - @param _operatorStore A contract storing operator assignments. - @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 _splitsStore A contract that stores splits for each project. - @param _prices A contract that exposes price feeds. - @param _store A contract that stores the terminal's data. - @param _owner The address that will own this contract. - */ + /// @param _baseWeightCurrency The currency to base token issuance on. + /// @param _operatorStore A contract storing operator assignments. + /// @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 _splitsStore A contract that stores splits for each project. + /// @param _prices A contract that exposes price feeds. + /// @param _store A contract that stores the terminal's data. + /// @param _owner The address that will own this contract. constructor( uint256 _baseWeightCurrency, IJBOperatorStore _operatorStore, @@ -49,7 +43,7 @@ contract JBETHPaymentTerminal3_1 is JBPayoutRedemptionPaymentTerminal3_1 { IJBDirectory _directory, IJBSplitsStore _splitsStore, IJBPrices _prices, - IJBSingleTokenPaymentTerminalStore _store, + address _store, address _owner ) JBPayoutRedemptionPaymentTerminal3_1( @@ -75,19 +69,11 @@ contract JBETHPaymentTerminal3_1 is JBPayoutRedemptionPaymentTerminal3_1 { // ---------------------- internal transactions ---------------------- // //*********************************************************************// - /** - @notice - Transfers tokens. - - @param _from The address from which the transfer should originate. - @param _to The address to which the transfer should go. - @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal. - */ - function _transferFrom( - address _from, - address payable _to, - uint256 _amount - ) internal override { + /// @notice Transfers tokens. + /// @param _from The address from which the transfer should originate. + /// @param _to The address to which the transfer should go. + /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal. + function _transferFrom(address _from, address payable _to, uint256 _amount) internal override { _from; // Prevents unused var compiler and natspec complaints. Address.sendValue(_to, _amount); diff --git a/contracts/JBETHPaymentTerminal3_1_1.sol b/contracts/JBETHPaymentTerminal3_1_1.sol new file mode 100644 index 000000000..9db303adb --- /dev/null +++ b/contracts/JBETHPaymentTerminal3_1_1.sol @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.16; + +import {Address} from '@openzeppelin/contracts/utils/Address.sol'; +import {JBPayoutRedemptionPaymentTerminal3_1_1} from './abstract/JBPayoutRedemptionPaymentTerminal3_1_1.sol'; +import {IJBDirectory} from './interfaces/IJBDirectory.sol'; +import {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol'; +import {IJBProjects} from './interfaces/IJBProjects.sol'; +import {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol'; +import {IJBPrices} from './interfaces/IJBPrices.sol'; +import {JBCurrencies} from './libraries/JBCurrencies.sol'; +import {JBSplitsGroups} from './libraries/JBSplitsGroups.sol'; +import {JBTokens} from './libraries/JBTokens.sol'; + +/// @notice Manages all inflows and outflows of ETH funds into the protocol ecosystem. +contract JBETHPaymentTerminal3_1_1 is JBPayoutRedemptionPaymentTerminal3_1_1 { + //*********************************************************************// + // -------------------------- internal views ------------------------- // + //*********************************************************************// + + /// @notice Checks the balance of tokens in this contract. + /// @return The contract's balance, as a fixed point number with the same amount of decimals as this terminal. + function _balance() internal view override returns (uint256) { + return address(this).balance; + } + + //*********************************************************************// + // -------------------------- constructor ---------------------------- // + //*********************************************************************// + + /// @param _baseWeightCurrency The currency to base token issuance on. + /// @param _operatorStore A contract storing operator assignments. + /// @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 _splitsStore A contract that stores splits for each project. + /// @param _prices A contract that exposes price feeds. + /// @param _store A contract that stores the terminal's data. + /// @param _owner The address that will own this contract. + constructor( + uint256 _baseWeightCurrency, + IJBOperatorStore _operatorStore, + IJBProjects _projects, + IJBDirectory _directory, + IJBSplitsStore _splitsStore, + IJBPrices _prices, + address _store, + address _owner + ) + JBPayoutRedemptionPaymentTerminal3_1_1( + JBTokens.ETH, + 18, // 18 decimals. + JBCurrencies.ETH, + _baseWeightCurrency, + JBSplitsGroups.ETH_PAYOUT, + _operatorStore, + _projects, + _directory, + _splitsStore, + _prices, + _store, + _owner + ) + // solhint-disable-next-line no-empty-blocks + { + + } + + //*********************************************************************// + // ---------------------- internal transactions ---------------------- // + //*********************************************************************// + + /// @notice Transfers tokens. + /// @param _from The address from which the transfer should originate. + /// @param _to The address to which the transfer should go. + /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal. + function _transferFrom(address _from, address payable _to, uint256 _amount) internal override { + _from; // Prevents unused var compiler and natspec complaints. + + Address.sendValue(_to, _amount); + } +} diff --git a/contracts/JBFundAccessConstraintsStore.sol b/contracts/JBFundAccessConstraintsStore.sol index 3e49cdc46..eb21eb288 100644 --- a/contracts/JBFundAccessConstraintsStore.sol +++ b/contracts/JBFundAccessConstraintsStore.sol @@ -1,23 +1,14 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.16; -import '@openzeppelin/contracts/utils/introspection/ERC165.sol'; -import './abstract/JBControllerUtility.sol'; -import './interfaces/IJBFundAccessConstraintsStore.sol'; - -/** - @notice - Information pertaining to how much funds can be accessed by a project from each payment terminal. - - @dev - Adheres to - - IJBFundAccessConstraintsStore: General interface for the generic controller methods in this contract that interacts with funding cycles and tokens according to the protocol's rules. - - @dev - Inherits from - - JBControllerUtility: 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. -*/ +import {ERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol'; +import {JBControllerUtility} from './abstract/JBControllerUtility.sol'; +import {IJBFundAccessConstraintsStore} from './interfaces/IJBFundAccessConstraintsStore.sol'; +import {IJBDirectory} from './interfaces/IJBDirectory.sol'; +import {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol'; +import {JBFundAccessConstraints} from './structs/JBFundAccessConstraints.sol'; + +/// @notice Information pertaining to how much funds can be accessed by a project from each payment terminal. contract JBFundAccessConstraintsStore is JBControllerUtility, ERC165, @@ -36,39 +27,23 @@ contract JBFundAccessConstraintsStore is // --------------------- internal stored properties ------------------ // //*********************************************************************// - /** - @notice - Data regarding the distribution limit of a project during a configuration. - - @dev - bits 0-231: The amount of token that a project can distribute per funding cycle. - - @dev - 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. - _configuration The configuration during which the packed distribution limit data applies. - _terminal The terminal from which distributions are being limited. - _token The token for which distributions are being limited. - */ + /// @notice Data regarding the distribution limit of a project during a configuration. + /// @dev bits 0-231: The amount of token that a project can distribute per funding cycle. + /// @dev bits 232-255: The currency of amount that a project can distribute. + /// @custom:param _projectId The ID of the project to get the packed distribution limit data of. + /// @custom:param _configuration The configuration during which the packed distribution limit data applies. + /// @custom:param _terminal The terminal from which distributions are being limited. + /// @custom:param _token The token for which distributions are being limited. mapping(uint256 => mapping(uint256 => mapping(IJBPaymentTerminal => mapping(address => uint256)))) internal _packedDistributionLimitDataOf; - /** - @notice - Data regarding the overflow allowance of a project during a configuration. - - @dev - bits 0-231: The amount of overflow that a project is allowed to tap into on-demand throughout the configuration. - - @dev - 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. - _configuration The configuration during which the packed overflow allowance data applies. - _terminal The terminal managing the overflow. - _token The token for which overflow is being allowed. - */ + /// @notice Data regarding the overflow allowance of a project during a configuration. + /// @dev bits 0-231: The amount of overflow that a project is allowed to tap into on-demand throughout the configuration. + /// @dev bits 232-255: The currency of the amount of overflow that a project is allowed to tap. + /// @custom:param _projectId The ID of the project to get the packed overflow allowance data of. + /// @custom:param _configuration The configuration during which the packed overflow allowance data applies. + /// @custom:param _terminal The terminal managing the overflow. + /// @custom:param _token The token for which overflow is being allowed. mapping(uint256 => mapping(uint256 => mapping(IJBPaymentTerminal => mapping(address => uint256)))) internal _packedOverflowAllowanceDataOf; @@ -76,21 +51,14 @@ contract JBFundAccessConstraintsStore is // ------------------------- external views -------------------------- // //*********************************************************************// - /** - @notice - The amount of token that a project can distribute per funding cycle, 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 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. - */ + /// @notice The amount of token that a project can distribute per funding cycle, 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 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, @@ -104,21 +72,14 @@ contract JBFundAccessConstraintsStore is return (uint256(uint232(_data)), _data >> 232); } - /** - @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. - */ + /// @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, @@ -136,9 +97,7 @@ contract JBFundAccessConstraintsStore is // -------------------------- constructor ---------------------------- // //*********************************************************************// - /** - @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. // solhint-disable-next-line no-empty-blocks constructor(IJBDirectory _directory) JBControllerUtility(_directory) {} @@ -146,17 +105,11 @@ contract JBFundAccessConstraintsStore is // --------------------- external transactions ----------------------- // //*********************************************************************// - /** - @notice - Sets a project's constraints for accessing treasury funds. - - @dev - Only a project's current controller can set its fund access constraints. - - @param _projectId The ID of the project whose fund access constraints are being set. - @param _configuration The funding cycle configuration the constraints apply within. - @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`. - */ + /// @notice Sets a project's constraints for accessing treasury funds. + /// @dev Only a project's current controller can set its fund access constraints. + /// @param _projectId The ID of the project whose fund access constraints are being set. + /// @param _configuration The funding cycle configuration the constraints apply within. + /// @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`. function setFor( uint256 _projectId, uint256 _configuration, @@ -168,14 +121,16 @@ contract JBFundAccessConstraintsStore is // Set distribution limits if there are any. for (uint256 _i; _i < _numberOfFundAccessConstraints; ) { // If distribution limit value is larger than 232 bits, revert. - if (_fundAccessConstraints[_i].distributionLimit > type(uint232).max) revert INVALID_DISTRIBUTION_LIMIT(); + if (_fundAccessConstraints[_i].distributionLimit > type(uint232).max) + revert INVALID_DISTRIBUTION_LIMIT(); // If distribution limit currency value is larger than 24 bits, revert. if (_fundAccessConstraints[_i].distributionLimitCurrency > type(uint24).max) revert INVALID_DISTRIBUTION_LIMIT_CURRENCY(); // If overflow allowance value is larger than 232 bits, revert. - if (_fundAccessConstraints[_i].overflowAllowance > type(uint232).max) revert INVALID_OVERFLOW_ALLOWANCE(); + if (_fundAccessConstraints[_i].overflowAllowance > type(uint232).max) + revert INVALID_OVERFLOW_ALLOWANCE(); // If overflow allowance currency value is larger than 24 bits, revert. if (_fundAccessConstraints[_i].overflowAllowanceCurrency > type(uint24).max) @@ -183,17 +138,26 @@ contract JBFundAccessConstraintsStore is // Set the distribution limit if there is one. if (_fundAccessConstraints[_i].distributionLimit > 0) - _packedDistributionLimitDataOf[_projectId][_configuration][_fundAccessConstraints[_i].terminal][ - _fundAccessConstraints[_i].token - ] = _fundAccessConstraints[_i].distributionLimit | (_fundAccessConstraints[_i].distributionLimitCurrency << 232); + _packedDistributionLimitDataOf[_projectId][_configuration][ + _fundAccessConstraints[_i].terminal + ][_fundAccessConstraints[_i].token] = + _fundAccessConstraints[_i].distributionLimit | + (_fundAccessConstraints[_i].distributionLimitCurrency << 232); // Set the overflow allowance if there is one. if (_fundAccessConstraints[_i].overflowAllowance > 0) - _packedOverflowAllowanceDataOf[_projectId][_configuration][_fundAccessConstraints[_i].terminal][ - _fundAccessConstraints[_i].token - ] = _fundAccessConstraints[_i].overflowAllowance | (_fundAccessConstraints[_i].overflowAllowanceCurrency << 232); - - emit SetFundAccessConstraints(_configuration, _projectId, _fundAccessConstraints[_i], msg.sender); + _packedOverflowAllowanceDataOf[_projectId][_configuration][ + _fundAccessConstraints[_i].terminal + ][_fundAccessConstraints[_i].token] = + _fundAccessConstraints[_i].overflowAllowance | + (_fundAccessConstraints[_i].overflowAllowanceCurrency << 232); + + emit SetFundAccessConstraints( + _configuration, + _projectId, + _fundAccessConstraints[_i], + msg.sender + ); unchecked { ++_i; diff --git a/contracts/JBFundingCycleStore.sol b/contracts/JBFundingCycleStore.sol index 3017a9b03..625299cef 100644 --- a/contracts/JBFundingCycleStore.sol +++ b/contracts/JBFundingCycleStore.sol @@ -1,22 +1,17 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.16; -import '@paulrberg/contracts/math/PRBMath.sol'; -import './abstract/JBControllerUtility.sol'; -import './libraries/JBConstants.sol'; - -/** - @notice - Manages funding cycle configurations and scheduling. - - @dev - Adheres to - - IJBFundingCycleStore: General interface for the methods in this contract that interact with the blockchain's state according to the protocol's rules. - - @dev - Inherits from - - JBControllerUtility: Includes convenience functionality for checking if the message sender is the current controller of the project whose data is being manipulated. -*/ +import {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol'; +import {JBControllerUtility} from './abstract/JBControllerUtility.sol'; +import {JBBallotState} from './enums/JBBallotState.sol'; +import {JBConstants} from './libraries/JBConstants.sol'; +import {IJBDirectory} from './interfaces/IJBDirectory.sol'; +import {IJBFundingCycleBallot} from './interfaces/IJBFundingCycleBallot.sol'; +import {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol'; +import {JBFundingCycle} from './structs/JBFundingCycle.sol'; +import {JBFundingCycleData} from './structs/JBFundingCycleData.sol'; + +/// @notice Manages funding cycle configurations and scheduling. contract JBFundingCycleStore is JBControllerUtility, IJBFundingCycleStore { //*********************************************************************// // --------------------------- custom errors ------------------------- // @@ -32,82 +27,51 @@ contract JBFundingCycleStore is JBControllerUtility, IJBFundingCycleStore { // --------------------- private stored properties ------------------- // //*********************************************************************// - /** - @notice - Stores the user defined properties of each funding cycle, packed into one storage slot. - - _projectId The ID of the project to get properties of. - _configuration The funding cycle configuration to get properties of. - */ + /// @notice Stores the user defined properties of each funding cycle, packed into one storage slot. + /// @custom:param _projectId The ID of the project to get properties of. + /// @custom:param _configuration The funding cycle configuration to get properties of. mapping(uint256 => mapping(uint256 => uint256)) private _packedUserPropertiesOf; - /** - @notice - Stores the properties added by the mechanism to manage and schedule each funding cycle, packed into one storage slot. - - _projectId The ID of the project to get instrinsic properties of. - _configuration The funding cycle configuration to get properties of. - */ + /// @notice Stores the properties added by the mechanism to manage and schedule each funding cycle, packed into one storage slot. + /// @custom:param _projectId The ID of the project to get instrinsic properties of. + /// @custom:param _configuration The funding cycle configuration to get properties of. mapping(uint256 => mapping(uint256 => uint256)) private _packedIntrinsicPropertiesOf; - /** - @notice - Stores the metadata for each funding cycle configuration, packed into one storage slot. - - _projectId The ID of the project to get metadata of. - _configuration The funding cycle configuration to get metadata of. - */ + /// @notice Stores the metadata for each funding cycle configuration, packed into one storage slot. + /// @custom:param _projectId The ID of the project to get metadata of. + /// @custom:param _configuration The funding cycle configuration to get metadata of. mapping(uint256 => mapping(uint256 => uint256)) private _metadataOf; //*********************************************************************// // --------------------- public stored properties -------------------- // //*********************************************************************// - /** - @notice - The latest funding cycle configuration for each project. - - _projectId The ID of the project to get the latest funding cycle configuration of. - */ + /// @notice The latest funding cycle configuration for each project. + /// @custom:param _projectId The ID of the project to get the latest funding cycle configuration of. mapping(uint256 => uint256) public override latestConfigurationOf; //*********************************************************************// // ------------------------- external views -------------------------- // //*********************************************************************// - /** - @notice - Get the funding cycle with the given configuration for the specified project. - - @param _projectId The ID of the project to which the funding cycle belongs. - @param _configuration The configuration of the funding cycle to get. - - @return fundingCycle The funding cycle. - */ - function get(uint256 _projectId, uint256 _configuration) - external - view - override - returns (JBFundingCycle memory fundingCycle) - { + /// @notice Get the funding cycle with the given configuration for the specified project. + /// @param _projectId The ID of the project to which the funding cycle belongs. + /// @param _configuration The configuration of the funding cycle to get. + /// @return fundingCycle The funding cycle. + function get( + uint256 _projectId, + uint256 _configuration + ) external view override returns (JBFundingCycle memory fundingCycle) { return _getStructFor(_projectId, _configuration); } - /** - @notice - The latest funding cycle to be configured for the specified project, and its current ballot state. - - @param _projectId The ID of the project to get the latest configured funding cycle of. - - @return fundingCycle The project's queued funding cycle. - @return ballotState The state of the ballot for the reconfiguration. - */ - function latestConfiguredOf(uint256 _projectId) - external - view - override - returns (JBFundingCycle memory fundingCycle, JBBallotState ballotState) - { + /// @notice The latest funding cycle to be configured for the specified project, and its current ballot state. + /// @param _projectId The ID of the project to get the latest configured funding cycle of. + /// @return fundingCycle The project's queued funding cycle. + /// @return ballotState The state of the ballot for the reconfiguration. + function latestConfiguredOf( + uint256 _projectId + ) external view override returns (JBFundingCycle memory fundingCycle, JBBallotState ballotState) { // Get a reference to the latest funding cycle configuration. uint256 _fundingCycleConfiguration = latestConfigurationOf[_projectId]; @@ -123,23 +87,13 @@ contract JBFundingCycleStore is JBControllerUtility, IJBFundingCycleStore { ); } - /** - @notice - The funding cycle that's next up for the specified project. - - @dev - If a queued funding cycle of the project is not found, returns an empty funding cycle with all properties set to 0. - - @param _projectId The ID of the project to get the queued funding cycle of. - - @return fundingCycle The project's queued funding cycle. - */ - function queuedOf(uint256 _projectId) - external - view - override - returns (JBFundingCycle memory fundingCycle) - { + /// @notice The funding cycle that's next up for the specified project. + /// @dev If a queued funding cycle of the project is not found, returns an empty funding cycle with all properties set to 0. + /// @param _projectId The ID of the project to get the queued funding cycle of. + /// @return fundingCycle The project's queued funding cycle. + function queuedOf( + uint256 _projectId + ) external view override returns (JBFundingCycle memory fundingCycle) { // If the project does not have a funding cycle, return an empty struct. if (latestConfigurationOf[_projectId] == 0) return _getStructFor(0, 0); @@ -181,23 +135,13 @@ contract JBFundingCycleStore is JBControllerUtility, IJBFundingCycleStore { return _mockFundingCycleBasedOn(fundingCycle, false); } - /** - @notice - The funding cycle that is currently active for the specified project. - - @dev - If a current funding cycle of the project is not found, returns an empty funding cycle with all properties set to 0. - - @param _projectId The ID of the project to get the current funding cycle of. - - @return fundingCycle The project's current funding cycle. - */ - function currentOf(uint256 _projectId) - external - view - override - returns (JBFundingCycle memory fundingCycle) - { + /// @notice The funding cycle that is currently active for the specified project. + /// @dev If a current funding cycle of the project is not found, returns an empty funding cycle with all properties set to 0. + /// @param _projectId The ID of the project to get the current funding cycle of. + /// @return fundingCycle The project's current funding cycle. + function currentOf( + uint256 _projectId + ) external view override returns (JBFundingCycle memory fundingCycle) { // If the project does not have a funding cycle, return an empty struct. if (latestConfigurationOf[_projectId] == 0) return _getStructFor(0, 0); @@ -245,14 +189,9 @@ contract JBFundingCycleStore is JBControllerUtility, IJBFundingCycleStore { return _mockFundingCycleBasedOn(_fundingCycle, true); } - /** - @notice - The current ballot state of the project. - - @param _projectId The ID of the project to check the ballot state of. - - @return The project's current ballot's state. - */ + /// @notice The current ballot state of the project. + /// @param _projectId The ID of the project to check the ballot state of. + /// @return The project's current ballot's state. function currentBallotStateOf(uint256 _projectId) external view override returns (JBBallotState) { // Get a reference to the latest funding cycle configuration. uint256 _fundingCycleConfiguration = latestConfigurationOf[_projectId]; @@ -273,9 +212,7 @@ contract JBFundingCycleStore is JBControllerUtility, IJBFundingCycleStore { // -------------------------- constructor ---------------------------- // //*********************************************************************// - /** - @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. // solhint-disable-next-line no-empty-blocks constructor(IJBDirectory _directory) JBControllerUtility(_directory) {} @@ -283,20 +220,13 @@ contract JBFundingCycleStore is JBControllerUtility, IJBFundingCycleStore { // ---------------------- external transactions ---------------------- // //*********************************************************************// - /** - @notice - Configures the next eligible funding cycle for the specified project. - - @dev - Only a project's current controller can configure its funding cycles. - - @param _projectId The ID of the project being configured. - @param _data The funding cycle configuration data. - @param _metadata Arbitrary extra data to associate with this funding cycle configuration that's not used within. - @param _mustStartAtOrAfter The time before which the initialized funding cycle cannot start. - - @return The funding cycle that the configuration will take effect during. - */ + /// @notice Configures the next eligible funding cycle for the specified project. + /// @dev Only a project's current controller can configure its funding cycles. + /// @param _projectId The ID of the project being configured. + /// @param _data The funding cycle configuration data. + /// @param _metadata Arbitrary extra data to associate with this funding cycle configuration that's not used within. + /// @param _mustStartAtOrAfter The time before which the initialized funding cycle cannot start. + /// @return The funding cycle that the configuration will take effect during. function configureFor( uint256 _projectId, JBFundingCycleData calldata _data, @@ -374,15 +304,11 @@ contract JBFundingCycleStore is JBControllerUtility, IJBFundingCycleStore { // --------------------- private helper functions -------------------- // //*********************************************************************// - /** - @notice - Updates the configurable funding cycle for this project if it exists, otherwise creates one. - - @param _projectId The ID of the project to find a configurable funding cycle for. - @param _configuration The time at which the funding cycle was configured. - @param _weight The weight to store in the configured funding cycle. - @param _mustStartAtOrAfter The time before which the initialized funding cycle can't start. - */ + /// @notice Updates the configurable funding cycle for this project if it exists, otherwise creates one. + /// @param _projectId The ID of the project to find a configurable funding cycle for. + /// @param _configuration The time at which the funding cycle was configured. + /// @param _weight The weight to store in the configured funding cycle. + /// @param _mustStartAtOrAfter The time before which the initialized funding cycle can't start. function _configureIntrinsicPropertiesFor( uint256 _projectId, uint256 _configuration, @@ -430,16 +356,12 @@ contract JBFundingCycleStore is JBControllerUtility, IJBFundingCycleStore { ); } - /** - @notice - Initializes a funding cycle with the specified properties. - - @param _projectId The ID of the project to which the funding cycle being initialized belongs. - @param _baseFundingCycle The funding cycle to base the initialized one on. - @param _configuration The configuration of the funding cycle being initialized. - @param _mustStartAtOrAfter The time before which the initialized funding cycle cannot start. - @param _weight The weight to give the newly initialized funding cycle. - */ + /// @notice Initializes a funding cycle with the specified properties. + /// @param _projectId The ID of the project to which the funding cycle being initialized belongs. + /// @param _baseFundingCycle The funding cycle to base the initialized one on. + /// @param _configuration The configuration of the funding cycle being initialized. + /// @param _mustStartAtOrAfter The time before which the initialized funding cycle cannot start. + /// @param _weight The weight to give the newly initialized funding cycle. function _initFor( uint256 _projectId, JBFundingCycle memory _baseFundingCycle, @@ -491,17 +413,13 @@ contract JBFundingCycleStore is JBControllerUtility, IJBFundingCycleStore { emit Init(_configuration, _projectId, _baseFundingCycle.configuration); } - /** - @notice - Efficiently stores a funding cycle's provided intrinsic properties. - - @param _configuration The configuration of the funding cycle to pack and store. - @param _projectId The ID of the project to which the funding cycle belongs. - @param _number The number of the funding cycle. - @param _weight The weight of the funding cycle. - @param _basedOn The configuration of the base funding cycle. - @param _start The start time of this funding cycle. - */ + /// @notice Efficiently stores a funding cycle's provided intrinsic properties. + /// @param _configuration The configuration of the funding cycle to pack and store. + /// @param _projectId The ID of the project to which the funding cycle belongs. + /// @param _number The number of the funding cycle. + /// @param _weight The weight of the funding cycle. + /// @param _basedOn The configuration of the base funding cycle. + /// @param _start The start time of this funding cycle. function _packAndStoreIntrinsicPropertiesOf( uint256 _configuration, uint256 _projectId, @@ -526,20 +444,11 @@ contract JBFundingCycleStore is JBControllerUtility, IJBFundingCycleStore { _packedIntrinsicPropertiesOf[_projectId][_configuration] = packed; } - /** - @notice - The project's stored funding cycle that hasn't yet started and should be used next, if one exists. - - @dev - A value of 0 is returned if no funding cycle was found. - - @dev - Assumes the project has a latest configuration. - - @param _projectId The ID of a project to look through for a standby cycle. - - @return configuration The configuration of the standby funding cycle if one exists, or 0 if one doesn't exist. - */ + /// @notice The project's stored funding cycle that hasn't yet started and should be used next, if one exists. + /// @dev A value of 0 is returned if no funding cycle was found. + /// @dev Assumes the project has a latest configuration. + /// @param _projectId The ID of a project to look through for a standby cycle. + /// @return configuration The configuration of the standby funding cycle if one exists, or 0 if one doesn't exist. function _standbyOf(uint256 _projectId) private view returns (uint256 configuration) { // Get a reference to the project's latest funding cycle. configuration = latestConfigurationOf[_projectId]; @@ -563,20 +472,11 @@ contract JBFundingCycleStore is JBControllerUtility, IJBFundingCycleStore { ) return 0; } - /** - @notice - The project's stored funding cycle that has started and hasn't yet expired. - - @dev - A value of 0 is returned if no funding cycle was found. - - @dev - Assumes the project has a latest configuration. - - @param _projectId The ID of the project to look through. - - @return configuration The configuration of an eligible funding cycle if one exists, or 0 if one doesn't exist. - */ + /// @notice The project's stored funding cycle that has started and hasn't yet expired. + /// @dev A value of 0 is returned if no funding cycle was found. + /// @dev Assumes the project has a latest configuration. + /// @param _projectId The ID of the project to look through. + /// @return configuration The configuration of an eligible funding cycle if one exists, or 0 if one doesn't exist. function _eligibleOf(uint256 _projectId) private view returns (uint256 configuration) { // Get a reference to the project's latest funding cycle. configuration = latestConfigurationOf[_projectId]; @@ -607,26 +507,16 @@ contract JBFundingCycleStore is JBControllerUtility, IJBFundingCycleStore { configuration = _fundingCycle.basedOn; } - /** - @notice - A view of the funding cycle that would be created based on the provided one if the project doesn't make a reconfiguration. - - @dev - Returns an empty funding cycle if there can't be a mock funding cycle based on the provided one. - - @dev - Assumes a funding cycle with a duration of 0 will never be asked to be the base of a mock. - - @param _baseFundingCycle The funding cycle that the resulting funding cycle should follow. - @param _allowMidCycle A flag indicating if the mocked funding cycle is allowed to already be mid cycle. - - @return A mock of what the next funding cycle will be. - */ - function _mockFundingCycleBasedOn(JBFundingCycle memory _baseFundingCycle, bool _allowMidCycle) - private - view - returns (JBFundingCycle memory) - { + /// @notice A view of the funding cycle that would be created based on the provided one if the project doesn't make a reconfiguration. + /// @dev Returns an empty funding cycle if there can't be a mock funding cycle based on the provided one. + /// @dev Assumes a funding cycle with a duration of 0 will never be asked to be the base of a mock. + /// @param _baseFundingCycle The funding cycle that the resulting funding cycle should follow. + /// @param _allowMidCycle A flag indicating if the mocked funding cycle is allowed to already be mid cycle. + /// @return A mock of what the next funding cycle will be. + function _mockFundingCycleBasedOn( + JBFundingCycle memory _baseFundingCycle, + bool _allowMidCycle + ) private view returns (JBFundingCycle memory) { // Get the distance of the current time to the start of the next possible funding cycle. // If the returned mock cycle must not yet have started, the start time of the mock must be in the future. uint256 _mustStartAtOrAfter = !_allowMidCycle @@ -653,20 +543,14 @@ contract JBFundingCycleStore is JBControllerUtility, IJBFundingCycleStore { ); } - /** - @notice - The date that is the nearest multiple of the specified funding cycle's duration from its end. - - @param _baseFundingCycle The funding cycle to base the calculation on. - @param _mustStartAtOrAfter A date that the derived start must be on or come after. - - @return start The next start time. - */ - function _deriveStartFrom(JBFundingCycle memory _baseFundingCycle, uint256 _mustStartAtOrAfter) - private - pure - returns (uint256 start) - { + /// @notice The date that is the nearest multiple of the specified funding cycle's duration from its end. + /// @param _baseFundingCycle The funding cycle to base the calculation on. + /// @param _mustStartAtOrAfter A date that the derived start must be on or come after. + /// @return start The next start time. + function _deriveStartFrom( + JBFundingCycle memory _baseFundingCycle, + uint256 _mustStartAtOrAfter + ) private pure returns (uint256 start) { // A subsequent cycle to one with a duration of 0 should start as soon as possible. if (_baseFundingCycle.duration == 0) return _mustStartAtOrAfter; @@ -687,20 +571,14 @@ contract JBFundingCycleStore is JBControllerUtility, IJBFundingCycleStore { while (_mustStartAtOrAfter > start) start = start + _baseFundingCycle.duration; } - /** - @notice - The accumulated weight change since the specified funding cycle. - - @param _baseFundingCycle The funding cycle to base the calculation on. - @param _start The start time of the funding cycle to derive a number for. - - @return weight The derived weight, as a fixed point number with 18 decimals. - */ - function _deriveWeightFrom(JBFundingCycle memory _baseFundingCycle, uint256 _start) - private - pure - returns (uint256 weight) - { + /// @notice The accumulated weight change since the specified funding cycle. + /// @param _baseFundingCycle The funding cycle to base the calculation on. + /// @param _start The start time of the funding cycle to derive a number for. + /// @return weight The derived weight, as a fixed point number with 18 decimals. + function _deriveWeightFrom( + JBFundingCycle memory _baseFundingCycle, + uint256 _start + ) private pure returns (uint256 weight) { // A subsequent cycle to one with a duration of 0 should have the next possible weight. if (_baseFundingCycle.duration == 0) return @@ -743,20 +621,14 @@ contract JBFundingCycleStore is JBControllerUtility, IJBFundingCycleStore { } } - /** - @notice - The number of the next funding cycle given the specified funding cycle. - - @param _baseFundingCycle The funding cycle to base the calculation on. - @param _start The start time of the funding cycle to derive a number for. - - @return The funding cycle number. - */ - function _deriveNumberFrom(JBFundingCycle memory _baseFundingCycle, uint256 _start) - private - pure - returns (uint256) - { + /// @notice The number of the next funding cycle given the specified funding cycle. + /// @param _baseFundingCycle The funding cycle to base the calculation on. + /// @param _start The start time of the funding cycle to derive a number for. + /// @return The funding cycle number. + function _deriveNumberFrom( + JBFundingCycle memory _baseFundingCycle, + uint256 _start + ) private pure returns (uint256) { // A subsequent cycle to one with a duration of 0 should be the next number. if (_baseFundingCycle.duration == 0) return _baseFundingCycle.number + 1; @@ -767,20 +639,14 @@ contract JBFundingCycleStore is JBControllerUtility, IJBFundingCycleStore { return _baseFundingCycle.number + (_startDistance / _baseFundingCycle.duration); } - /** - @notice - Checks to see if the provided funding cycle is approved according to the correct ballot. - - @param _projectId The ID of the project to which the funding cycle belongs. - @param _fundingCycle The funding cycle to get an approval flag for. - - @return The approval flag. - */ - function _isApproved(uint256 _projectId, JBFundingCycle memory _fundingCycle) - private - view - returns (bool) - { + /// @notice Checks to see if the provided funding cycle is approved according to the correct ballot. + /// @param _projectId The ID of the project to which the funding cycle belongs. + /// @param _fundingCycle The funding cycle to get an approval flag for. + /// @return The approval flag. + function _isApproved( + uint256 _projectId, + JBFundingCycle memory _fundingCycle + ) private view returns (bool) { return _ballotStateOf( _projectId, @@ -790,17 +656,12 @@ contract JBFundingCycleStore is JBControllerUtility, IJBFundingCycleStore { ) == JBBallotState.Approved; } - /** - @notice - A project's latest funding cycle configuration approval status. - - @param _projectId The ID of the project to which the funding cycle belongs. - @param _configuration The funding cycle configuration to get the ballot state of. - @param _start The start time of the funding cycle configuration to get the ballot state of. - @param _ballotFundingCycleConfiguration The configuration of the funding cycle which is configured with the ballot that should be used. - - @return The ballot state of the project. - */ + /// @notice A project's latest funding cycle configuration approval status. + /// @param _projectId The ID of the project to which the funding cycle belongs. + /// @param _configuration The funding cycle configuration to get the ballot state of. + /// @param _start The start time of the funding cycle configuration to get the ballot state of. + /// @param _ballotFundingCycleConfiguration The configuration of the funding cycle which is configured with the ballot that should be used. + /// @return The ballot state of the project. function _ballotStateOf( uint256 _projectId, uint256 _configuration, @@ -824,20 +685,14 @@ contract JBFundingCycleStore is JBControllerUtility, IJBFundingCycleStore { return _ballotFundingCycle.ballot.stateOf(_projectId, _configuration, _start); } - /** - @notice - Unpack a funding cycle's packed stored values into an easy-to-work-with funding cycle struct. - - @param _projectId The ID of the project to which the funding cycle belongs. - @param _configuration The funding cycle configuration to get the full struct for. - - @return fundingCycle A funding cycle struct. - */ - function _getStructFor(uint256 _projectId, uint256 _configuration) - private - view - returns (JBFundingCycle memory fundingCycle) - { + /// @notice Unpack a funding cycle's packed stored values into an easy-to-work-with funding cycle struct. + /// @param _projectId The ID of the project to which the funding cycle belongs. + /// @param _configuration The funding cycle configuration to get the full struct for. + /// @return fundingCycle A funding cycle struct. + function _getStructFor( + uint256 _projectId, + uint256 _configuration + ) private view returns (JBFundingCycle memory fundingCycle) { // Return an empty funding cycle if the configuration specified is 0. if (_configuration == 0) return fundingCycle; diff --git a/contracts/JBMigrationOperator.sol b/contracts/JBMigrationOperator.sol index 345c11565..236790ebf 100644 --- a/contracts/JBMigrationOperator.sol +++ b/contracts/JBMigrationOperator.sol @@ -1,26 +1,15 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.16; -import './interfaces/IJBController.sol'; -import './interfaces/IJBDirectory.sol'; -import './interfaces/IJBMigratable.sol'; -import './interfaces/IJBPayoutRedemptionPaymentTerminal.sol'; -import './interfaces/IJBPaymentTerminal.sol'; -import './interfaces/IJBProjects.sol'; - - -/** - @notice - Allows projects to migrate their controller & terminal to 3.1 version - - @dev - The project owner needs to give the migration permission to this contract for carrying out the migrations for both controller & terminal. - - @dev - The current funding cycle needs to be a reconfigured one before migration, so metadata flags allowControllerMigration, allowTerminalMigration & global.allowSetTerminals need to be set true. -*/ +import {IJBController} from './interfaces/IJBController.sol'; +import {IJBDirectory} from './interfaces/IJBDirectory.sol'; +import {IJBMigratable} from './interfaces/IJBMigratable.sol'; +import {IJBPayoutRedemptionPaymentTerminal} from './interfaces/IJBPayoutRedemptionPaymentTerminal.sol'; +import {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol'; +import {IJBProjects} from './interfaces/IJBProjects.sol'; + +/// @notice Allows projects to migrate their controller & terminal to 3.1 version contract JBMigrationOperator { - //*********************************************************************// // --------------------------- custom errors ------------------------- // //*********************************************************************// @@ -30,61 +19,52 @@ contract JBMigrationOperator { // --------------- public immutable stored properties ---------------- // //*********************************************************************// - /** - @notice - directory instance which keeps a track of which controller is linked to which project. - */ - IJBDirectory immutable public directory; - - /** - @notice - The NFT granting ownership to a Juicebox project - */ - IJBProjects immutable public projects; + /// @notice directory instance which keeps a track of which controller is linked to which project. + IJBDirectory public immutable directory; + /// @notice The NFT granting ownership to a Juicebox project + IJBProjects public immutable projects; //*********************************************************************// // ---------------------------- constructor -------------------------- // //*********************************************************************// - /** - @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. constructor(IJBDirectory _directory) { - directory = _directory; - projects = IJBProjects(_directory.projects()); + directory = _directory; + projects = IJBProjects(_directory.projects()); } - //*********************************************************************// // --------------------- external transactions ----------------------- // //*********************************************************************// - /** - @notice - Allows project owners to migrate the controller & terminal linked to their project to the latest version - - @param _projectId The project id whose controller & terminal are to be migrated - @param _newController Controller 3.1 address to migrate to. - @param _newJbTerminal Terminal 3.1 address to migrate to. - @param _oldJbTerminal Old terminal address to migrate from. - */ - function migrate(uint256 _projectId, IJBMigratable _newController, IJBPaymentTerminal _newJbTerminal, IJBPayoutRedemptionPaymentTerminal _oldJbTerminal) external { - // Only allow the project owner to migrate - if (projects.ownerOf(_projectId) != msg.sender) revert UNAUTHORIZED(); - - // controller migration - address _oldController = directory.controllerOf(_projectId); - - // assuming the project owner has reconfigured the funding cycle with allowControllerMigration - IJBController(_oldController).migrate(_projectId, _newController); - - // terminal migration - IJBPaymentTerminal[] memory _newTerminals = new IJBPaymentTerminal[](1); - _newTerminals[0] = IJBPaymentTerminal(address(_newJbTerminal)); - - // assuming the project owner has reconfigured the funding cycle with allowTerminalMigration & global.allowSetTerminals - directory.setTerminalsOf(_projectId, _newTerminals); - _oldJbTerminal.migrate(_projectId, _newJbTerminal); + /// @notice Allows project owners to migrate the controller & terminal linked to their project to the latest version. + /// @param _projectId The project id whose controller & terminal are to be migrated + /// @param _newController Controller 3.1 address to migrate to. + /// @param _newJbTerminal Terminal 3.1 address to migrate to. + /// @param _oldJbTerminal Old terminal address to migrate from. + function migrate( + uint256 _projectId, + IJBMigratable _newController, + IJBPaymentTerminal _newJbTerminal, + IJBPayoutRedemptionPaymentTerminal _oldJbTerminal + ) external { + // Only allow the project owner to migrate + if (projects.ownerOf(_projectId) != msg.sender) revert UNAUTHORIZED(); + + // controller migration + address _oldController = directory.controllerOf(_projectId); + + // assuming the project owner has reconfigured the funding cycle with allowControllerMigration + IJBController(_oldController).migrate(_projectId, _newController); + + // terminal migration + IJBPaymentTerminal[] memory _newTerminals = new IJBPaymentTerminal[](1); + _newTerminals[0] = IJBPaymentTerminal(address(_newJbTerminal)); + + // assuming the project owner has reconfigured the funding cycle with allowTerminalMigration & global.allowSetTerminals + directory.setTerminalsOf(_projectId, _newTerminals); + _oldJbTerminal.migrate(_projectId, _newJbTerminal); } } diff --git a/contracts/JBOperatorStore.sol b/contracts/JBOperatorStore.sol index 14127b3f4..6a31fd98b 100644 --- a/contracts/JBOperatorStore.sol +++ b/contracts/JBOperatorStore.sol @@ -1,16 +1,10 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.16; -import './interfaces/IJBOperatorStore.sol'; +import {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol'; +import {JBOperatorData} from './structs/JBOperatorData.sol'; -/** - @notice - Stores operator permissions for all addresses. Addresses can give permissions to any other address to take specific indexed actions on their behalf. - - @dev - Adheres to - - IJBOperatorStore: General interface for the methods in this contract that interact with the blockchain's state according to the protocol's rules. -*/ +/// @notice Stores operator permissions for all addresses. Addresses can give permissions to any other address to take specific indexed actions on their behalf. contract JBOperatorStore is IJBOperatorStore { //*********************************************************************// // --------------------------- custom errors ------------------------- // @@ -21,39 +15,25 @@ contract JBOperatorStore is IJBOperatorStore { // --------------------- public stored properties -------------------- // //*********************************************************************// - /** - @notice - The permissions that an operator has been given to operate on a specific domain. - - @dev - An account can give an operator permissions that only pertain to a specific domain namespace. - There is no domain with a value of 0 – accounts can use the 0 domain to give an operator - permissions to all domains on their behalf. - - @dev - Permissions are stored in a packed `uint256`. Each 256 bits represents the on/off state of a permission. Applications can specify the significance of each index. - - _operator The address of the operator. - _account The address of the account being operated. - _domain The domain within which the permissions apply. Applications can use the domain namespace as they wish. - */ + /// @notice The permissions that an operator has been given to operate on a specific domain. + /// @dev An account can give an operator permissions that only pertain to a specific domain namespace. + /// @dev There is no domain with a value of 0 – accounts can use the 0 domain to give an operator permissions to all domains on their behalf. + /// @dev Permissions are stored in a packed `uint256`. Each 256 bits represents the on/off state of a permission. Applications can specify the significance of each index. + /// @custom:param _operator The address of the operator. + /// @custom:param _account The address of the account being operated. + /// @custom:param _domain The domain within which the permissions apply. Applications can use the domain namespace as they wish. mapping(address => mapping(address => mapping(uint256 => uint256))) public override permissionsOf; //*********************************************************************// // ------------------------- external views -------------------------- // //*********************************************************************// - /** - @notice - Whether or not an operator has the permission to take a certain action pertaining to the specified domain. - - @param _operator The operator to check. - @param _account The account that has given out permissions to the operator. - @param _domain The domain that the operator has been given permissions to operate. - @param _permissionIndex The permission index to check for. - - @return A flag indicating whether the operator has the specified permission. - */ + /// @notice Whether or not an operator has the permission to take a certain action pertaining to the specified domain. + /// @param _operator The operator to check. + /// @param _account The account that has given out permissions to the operator. + /// @param _domain The domain that the operator has been given permissions to operate. + /// @param _permissionIndex The permission index to check for. + /// @return A flag indicating whether the operator has the specified permission. function hasPermission( address _operator, address _account, @@ -65,17 +45,12 @@ contract JBOperatorStore is IJBOperatorStore { return (((permissionsOf[_operator][_account][_domain] >> _permissionIndex) & 1) == 1); } - /** - @notice - Whether or not an operator has the permission to take certain actions pertaining to the specified domain. - - @param _operator The operator to check. - @param _account The account that has given out permissions to the operator. - @param _domain The domain that the operator has been given permissions to operate. - @param _permissionIndexes An array of permission indexes to check for. - - @return A flag indicating whether the operator has all specified permissions. - */ + /// @notice Whether or not an operator has the permission to take certain actions pertaining to the specified domain. + /// @param _operator The operator to check. + /// @param _account The account that has given out permissions to the operator. + /// @param _domain The domain that the operator has been given permissions to operate. + /// @param _permissionIndexes An array of permission indexes to check for. + /// @return A flag indicating whether the operator has all specified permissions. function hasPermissions( address _operator, address _account, @@ -101,15 +76,9 @@ contract JBOperatorStore is IJBOperatorStore { // ---------------------- external transactions ---------------------- // //*********************************************************************// - /** - @notice - Sets permissions for an operators. - - @dev - Only an address can set its own operators. - - @param _operatorData The data that specifies the params for the operator being set. - */ + /// @notice Sets permissions for an operators. + /// @dev Only an address can set its own operators. + /// @param _operatorData The data that specifies the params for the operator being set. function setOperator(JBOperatorData calldata _operatorData) external override { // Pack the indexes into a uint256. uint256 _packed = _packedPermissions(_operatorData.permissionIndexes); @@ -126,15 +95,9 @@ contract JBOperatorStore is IJBOperatorStore { ); } - /** - @notice - Sets permissions for many operators. - - @dev - Only an address can set its own operators. - - @param _operatorData The data that specify the params for each operator being set. - */ + /// @notice Sets permissions for many operators. + /// @dev Only an address can set its own operators. + /// @param _operatorData The data that specify the params for each operator being set. function setOperators(JBOperatorData[] calldata _operatorData) external override { for (uint256 _i; _i < _operatorData.length; ) { // Pack the indexes into a uint256. @@ -161,14 +124,9 @@ contract JBOperatorStore is IJBOperatorStore { // --------------------- private helper functions -------------------- // //*********************************************************************// - /** - @notice - Converts an array of permission indexes to a packed `uint256`. - - @param _indexes The indexes of the permissions to pack. - - @return packed The packed value. - */ + /// @notice Converts an array of permission indexes to a packed `uint256`. + /// @param _indexes The indexes of the permissions to pack. + /// @return packed The packed value. function _packedPermissions(uint256[] calldata _indexes) private pure returns (uint256 packed) { for (uint256 _i; _i < _indexes.length; ) { uint256 _index = _indexes[_i]; diff --git a/contracts/JBPrices.sol b/contracts/JBPrices.sol index 32fcf3d84..a278a3243 100644 --- a/contracts/JBPrices.sol +++ b/contracts/JBPrices.sol @@ -1,22 +1,12 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.16; -import '@openzeppelin/contracts/access/Ownable.sol'; -import '@paulrberg/contracts/math/PRBMath.sol'; -import './interfaces/IJBPrices.sol'; - -/** - @notice - Manages and normalizes price feeds. - - @dev - Adheres to - - IJBPrices: General interface for the methods in this contract that interact with the blockchain's state according to the protocol's rules. - - @dev - Inherits from - - Ownable: Includes convenience functionality for checking a message sender's permissions before executing certain transactions. -*/ +import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol'; +import {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol'; +import {IJBPriceFeed} from './interfaces/IJBPriceFeed.sol'; +import {IJBPrices} from './interfaces/IJBPrices.sol'; + +/// @notice Manages and normalizes price feeds. contract JBPrices is Ownable, IJBPrices { //*********************************************************************// // --------------------------- custom errors ------------------------- // @@ -28,39 +18,28 @@ contract JBPrices is Ownable, IJBPrices { // --------------------- public stored properties -------------------- // //*********************************************************************// - /** - @notice - The available price feeds. - - @dev - The feed returns the number of `_currency` units that can be converted to 1 `_base` unit. - - _currency The currency units the feed's resulting price is in terms of. - _base The base currency unit being priced by the feed. - */ + /// @notice The available price feeds. + /// @dev The feed returns the number of `_currency` units that can be converted to 1 `_base` unit. + /// @custom:param _currency The currency units the feed's resulting price is in terms of. + /// @custom:param _base The base currency unit being priced by the feed. mapping(uint256 => mapping(uint256 => IJBPriceFeed)) public override feedFor; //*********************************************************************// // ------------------------- external views -------------------------- // //*********************************************************************// - /** - @notice - Gets the number of `_currency` units that can be converted to 1 `_base` unit. - - @param _currency The currency units the resulting price is in terms of. - @param _base The base currency unit being priced. - @param _decimals The number of decimals the returned fixed point price should include. - - @return The price of the currency in terms of the base, as a fixed point number with the specified number of decimals. - */ + /// @notice Gets the number of `_currency` units that can be converted to 1 `_base` unit. + /// @param _currency The currency units the resulting price is in terms of. + /// @param _base The base currency unit being priced. + /// @param _decimals The number of decimals the returned fixed point price should include. + /// @return The price of the currency in terms of the base, as a fixed point number with the specified number of decimals. function priceFor( uint256 _currency, uint256 _base, uint256 _decimals ) external view override returns (uint256) { // If the currency is the base, return 1 since they are priced the same. Include the desired number of decimals. - if (_currency == _base) return 10**_decimals; + if (_currency == _base) return 10 ** _decimals; // Get a reference to the feed. IJBPriceFeed _feed = feedFor[_currency][_base]; @@ -73,7 +52,7 @@ contract JBPrices is Ownable, IJBPrices { // If it exists, return the inverse price. if (_feed != IJBPriceFeed(address(0))) - return PRBMath.mulDiv(10**_decimals, 10**_decimals, _feed.currentPrice(_decimals)); + return PRBMath.mulDiv(10 ** _decimals, 10 ** _decimals, _feed.currentPrice(_decimals)); // No price feed available, revert. revert PRICE_FEED_NOT_FOUND(); @@ -83,9 +62,7 @@ contract JBPrices is Ownable, IJBPrices { // ---------------------------- constructor -------------------------- // //*********************************************************************// - /** - @param _owner The address that will own the contract. - */ + /// @param _owner The address that will own the contract. constructor(address _owner) { // Transfer the ownership. transferOwnership(_owner); @@ -95,17 +72,11 @@ contract JBPrices is Ownable, IJBPrices { // ---------------------- external transactions ---------------------- // //*********************************************************************// - /** - @notice - Add a price feed for a currency in terms of the provided base currency. - - @dev - Current feeds can't be modified. - - @param _currency The currency units the feed's resulting price is in terms of. - @param _base The base currency unit being priced by the feed. - @param _feed The price feed being added. - */ + /// @notice Add a price feed for a currency in terms of the provided base currency. + /// @dev Current feeds can't be modified. + /// @param _currency The currency units the feed's resulting price is in terms of. + /// @param _base The base currency unit being priced by the feed. + /// @param _feed The price feed being added. function addFeedFor( uint256 _currency, uint256 _base, diff --git a/contracts/JBProjects.sol b/contracts/JBProjects.sol index 9e07dc31d..4c760d73e 100644 --- a/contracts/JBProjects.sol +++ b/contracts/JBProjects.sol @@ -1,71 +1,44 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.16; -import '@openzeppelin/contracts/access/Ownable.sol'; -import '@openzeppelin/contracts/token/ERC721/extensions/draft-ERC721Votes.sol'; -import './abstract/JBOperatable.sol'; -import './interfaces/IJBProjects.sol'; -import './libraries/JBOperations.sol'; - -/** - @notice - Stores project ownership and metadata. - - @dev - Projects are represented as ERC-721's. - - @dev - Adheres to - - IJBProjects: General interface for the methods in this contract that interact with the blockchain's state according to the protocol's rules. - - @dev - Inherits from - - JBOperatable: Includes convenience functionality for checking a message sender's permissions before executing certain transactions. - ERC721Votes: A checkpointable standard definition for non-fungible tokens (NFTs). - Ownable: Includes convenience functionality for checking a message sender's permissions before executing certain transactions. -*/ +import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol'; +import {ERC721Votes, ERC721, EIP712} from '@openzeppelin/contracts/token/ERC721/extensions/draft-ERC721Votes.sol'; +import {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol'; +import {JBOperatable} from './abstract/JBOperatable.sol'; +import {IJBOperatable} from './interfaces/IJBOperatable.sol'; +import {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol'; +import {IJBProjects} from './interfaces/IJBProjects.sol'; +import {IJBTokenUriResolver} from './interfaces/IJBTokenUriResolver.sol'; +import {JBOperations} from './libraries/JBOperations.sol'; +import {JBProjectMetadata} from './structs/JBProjectMetadata.sol'; + +/// @notice Stores project ownership and metadata. +/// @dev Projects are represented as ERC-721's. contract JBProjects is JBOperatable, ERC721Votes, Ownable, IJBProjects { //*********************************************************************// // --------------------- public stored properties -------------------- // //*********************************************************************// - /** - @notice - The number of projects that have been created using this contract. - - @dev - The count is incremented with each new project created. - The resulting ERC-721 token ID for each project is the newly incremented count value. - */ + /// @notice The number of projects that have been created using this contract. + /// @dev The count is incremented with each new project created. + /// @dev The resulting ERC-721 token ID for each project is the newly incremented count value. uint256 public override count = 0; - /** - @notice - The metadata for each project, which can be used across several domains. - - _projectId The ID of the project to which the metadata belongs. - _domain The domain within which the metadata applies. Applications can use the domain namespace as they wish. - */ + /// @notice The metadata for each project, which can be used across several domains. + /// @custom:param _projectId The ID of the project to which the metadata belongs. + /// @custom:param _domain The domain within which the metadata applies. Applications can use the domain namespace as they wish. mapping(uint256 => mapping(uint256 => string)) public override metadataContentOf; - /** - @notice - The contract resolving each project ID to its ERC721 URI. - */ + /// @notice The contract resolving each project ID to its ERC721 URI. IJBTokenUriResolver public override tokenUriResolver; //*********************************************************************// // -------------------------- public views --------------------------- // //*********************************************************************// - /** - @notice - Returns the URI where the ERC-721 standard JSON of a project is hosted. - - @param _projectId The ID of the project to get a URI of. - - @return The token URI to use for the provided `_projectId`. - */ + /// @notice Returns the URI where the ERC-721 standard JSON of a project is hosted. + /// @param _projectId The ID of the project to get a URI of. + /// @return The token URI to use for the provided `_projectId`. function tokenURI(uint256 _projectId) public view override returns (string memory) { // Keep a reference to the resolver. IJBTokenUriResolver _tokenUriResolver = tokenUriResolver; @@ -77,22 +50,13 @@ contract JBProjects is JBOperatable, ERC721Votes, Ownable, IJBProjects { return _tokenUriResolver.getUri(_projectId); } - /** - @notice - Indicates if this contract adheres to the specified interface. - - @dev - See {IERC165-supportsInterface}. - - @param _interfaceId The ID of the interface to check for adherance to. - */ - function supportsInterface(bytes4 _interfaceId) - public - view - virtual - override(IERC165, ERC721) - returns (bool) - { + /// @notice Indicates if this contract adheres to the specified interface. + /// @dev See {IERC165-supportsInterface}. + /// @param _interfaceId The ID of the interface to check for adherance to. + /// @return A flag indicating if the provided interface ID is supported. + function supportsInterface( + bytes4 _interfaceId + ) public view virtual override(IERC165, ERC721) returns (bool) { return _interfaceId == type(IJBProjects).interfaceId || _interfaceId == type(IJBOperatable).interfaceId || @@ -103,10 +67,10 @@ contract JBProjects is JBOperatable, ERC721Votes, Ownable, IJBProjects { // -------------------------- constructor ---------------------------- // //*********************************************************************// - /** - @param _operatorStore A contract storing operator assignments. - */ - constructor(IJBOperatorStore _operatorStore) + /// @param _operatorStore A contract storing operator assignments. + constructor( + IJBOperatorStore _operatorStore + ) ERC721('Juicebox Projects', 'JUICEBOX') EIP712('Juicebox Projects', '1') JBOperatable(_operatorStore) @@ -119,23 +83,15 @@ contract JBProjects is JBOperatable, ERC721Votes, Ownable, IJBProjects { // ---------------------- external transactions ---------------------- // //*********************************************************************// - /** - @notice - Create a new project for the specified owner, which mints an NFT (ERC-721) into their wallet. - - @dev - Anyone can create a project on an owner's behalf. - - @param _owner The address that will be the owner of the project. - @param _metadata A struct containing metadata content about the project, and domain within which the metadata applies. - - @return projectId The token ID of the newly created project. - */ - function createFor(address _owner, JBProjectMetadata calldata _metadata) - external - override - returns (uint256 projectId) - { + /// @notice Create a new project for the specified owner, which mints an NFT (ERC-721) into their wallet. + /// @dev Anyone can create a project on an owner's behalf. + /// @param _owner The address that will be the owner of the project. + /// @param _metadata A struct containing metadata content about the project, and domain within which the metadata applies. + /// @return projectId The token ID of the newly created project. + function createFor( + address _owner, + JBProjectMetadata calldata _metadata + ) external override returns (uint256 projectId) { // Increment the count, which will be used as the ID. projectId = ++count; @@ -149,20 +105,15 @@ contract JBProjects is JBOperatable, ERC721Votes, Ownable, IJBProjects { emit Create(projectId, _owner, _metadata, msg.sender); } - /** - @notice - Allows a project owner to set the project's metadata content for a particular domain namespace. - - @dev - Only a project's owner or operator can set its metadata. - - @dev - Applications can use the domain namespace as they wish. - - @param _projectId The ID of the project who's metadata is being changed. - @param _metadata A struct containing metadata content, and domain within which the metadata applies. - */ - function setMetadataOf(uint256 _projectId, JBProjectMetadata calldata _metadata) + /// @notice Allows a project owner to set the project's metadata content for a particular domain namespace. + /// @dev Only a project's owner or operator can set its metadata. + /// @dev Applications can use the domain namespace as they wish. + /// @param _projectId The ID of the project who's metadata is being changed. + /// @param _metadata A struct containing metadata content, and domain within which the metadata applies. + function setMetadataOf( + uint256 _projectId, + JBProjectMetadata calldata _metadata + ) external override requirePermission(ownerOf(_projectId), _projectId, JBOperations.SET_METADATA) @@ -173,12 +124,8 @@ contract JBProjects is JBOperatable, ERC721Votes, Ownable, IJBProjects { emit SetMetadata(_projectId, _metadata, msg.sender); } - /** - @notice - Sets the address of the resolver used to retrieve the tokenURI of projects. - - @param _newResolver The address of the new resolver. - */ + /// @notice Sets the address of the resolver used to retrieve the tokenURI of projects. + /// @param _newResolver The address of the new resolver. function setTokenUriResolver(IJBTokenUriResolver _newResolver) external override onlyOwner { // Store the new resolver. tokenUriResolver = _newResolver; diff --git a/contracts/JBReconfigurationBufferBallot.sol b/contracts/JBReconfigurationBufferBallot.sol index 40c83f73d..a1bf09d9f 100644 --- a/contracts/JBReconfigurationBufferBallot.sol +++ b/contracts/JBReconfigurationBufferBallot.sol @@ -1,47 +1,30 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.16; -import '@openzeppelin/contracts/utils/introspection/ERC165.sol'; -import './interfaces/IJBFundingCycleBallot.sol'; -import './structs/JBFundingCycle.sol'; +import {ERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol'; +import {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol'; +import {JBBallotState} from './enums/JBBallotState.sol'; +import {IJBFundingCycleBallot} from './interfaces/IJBFundingCycleBallot.sol'; +import {JBFundingCycle} from './structs/JBFundingCycle.sol'; -/** - @notice - Manages approving funding cycle reconfigurations automatically after a buffer period. - - @dev - Adheres to - - IJBFundingCycleBallot: General interface for the methods in this contract that interact with the blockchain's state according to the protocol's rules. - - @dev - Inherits from - - ERC165: Introspection on interface adherance. -*/ +/// @notice Manages approving funding cycle reconfigurations automatically after a buffer period. contract JBReconfigurationBufferBallot is ERC165, IJBFundingCycleBallot { //*********************************************************************// // ---------------- public immutable stored properties --------------- // //*********************************************************************// - /** - @notice - The number of seconds that must pass for a funding cycle reconfiguration to become either `Approved` or `Failed`. - */ + /// @notice The number of seconds that must pass for a funding cycle reconfiguration to become either `Approved` or `Failed`. uint256 public immutable override duration; //*********************************************************************// // -------------------------- public views --------------------------- // //*********************************************************************// - /** - @notice - The approval state of a particular funding cycle. - - @param _projectId The ID of the project to which the funding cycle being checked belongs. - @param _configured The configuration of the funding cycle to check the state of. - @param _start The start timestamp of the funding cycle to check the state of. - - @return The state of the provided ballot. - */ + /// @notice The approval state of a particular funding cycle. + /// @param _projectId The ID of the project to which the funding cycle being checked belongs. + /// @param _configured The configuration of the funding cycle to check the state of. + /// @param _start The start timestamp of the funding cycle to check the state of. + /// @return The state of the provided ballot. function stateOf( uint256 _projectId, uint256 _configured, @@ -58,24 +41,13 @@ contract JBReconfigurationBufferBallot is ERC165, IJBFundingCycleBallot { } } - /** - @notice - Indicates if this contract adheres to the specified interface. - - @dev - See {IERC165-supportsInterface}. - - @param _interfaceId The ID of the interface to check for adherance to. - - @return A flag indicating if this contract adheres to the specified interface. - */ - function supportsInterface(bytes4 _interfaceId) - public - view - virtual - override(ERC165, IERC165) - returns (bool) - { + /// @notice Indicates if this contract adheres to the specified interface. + /// @dev See {IERC165-supportsInterface}. + /// @param _interfaceId The ID of the interface to check for adherance to. + /// @return A flag indicating if this contract adheres to the specified interface. + function supportsInterface( + bytes4 _interfaceId + ) public view virtual override(ERC165, IERC165) returns (bool) { return _interfaceId == type(IJBFundingCycleBallot).interfaceId || super.supportsInterface(_interfaceId); @@ -85,9 +57,7 @@ contract JBReconfigurationBufferBallot is ERC165, IJBFundingCycleBallot { // -------------------------- constructor ---------------------------- // //*********************************************************************// - /** - @param _duration The number of seconds to wait until a reconfiguration can be either `Approved` or `Failed`. - */ + /// @param _duration The number of seconds to wait until a reconfiguration can be either `Approved` or `Failed`. constructor(uint256 _duration) { duration = _duration; } diff --git a/contracts/JBSingleTokenPaymentTerminalStore.sol b/contracts/JBSingleTokenPaymentTerminalStore.sol index dcfaf8290..e316a1639 100644 --- a/contracts/JBSingleTokenPaymentTerminalStore.sol +++ b/contracts/JBSingleTokenPaymentTerminalStore.sol @@ -1,30 +1,29 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.16; -import '@openzeppelin/contracts/security/ReentrancyGuard.sol'; -import '@paulrberg/contracts/math/PRBMath.sol'; -import './interfaces/IJBController.sol'; -import './interfaces/IJBFundingCycleDataSource.sol'; -import './interfaces/IJBSingleTokenPaymentTerminalStore.sol'; -import './libraries/JBConstants.sol'; -import './libraries/JBCurrencies.sol'; -import './libraries/JBFixedPointNumber.sol'; -import './libraries/JBFundingCycleMetadataResolver.sol'; -import './structs/JBPayDelegateAllocation.sol'; -import './structs/JBPayParamsData.sol'; - -/** - @notice - Manages all bookkeeping for inflows and outflows of funds from any ISingleTokenPaymentTerminal. - - @dev - Adheres to: - IJBSingleTokenPaymentTerminalStore: General interface for the methods in this contract that interact with the blockchain's state according to the protocol's rules. - - @dev - Inherits from - - ReentrancyGuard: Contract module that helps prevent reentrant calls to a function. -*/ +import {ReentrancyGuard} from '@openzeppelin/contracts/security/ReentrancyGuard.sol'; +import {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol'; +import {JBBallotState} from './enums/JBBallotState.sol'; +import {IJBDirectory} from './interfaces/IJBDirectory.sol'; +import {IJBController} from './interfaces/IJBController.sol'; +import {IJBFundingCycleDataSource} from './interfaces/IJBFundingCycleDataSource.sol'; +import {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol'; +import {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol'; +import {IJBSingleTokenPaymentTerminal} from './interfaces/IJBSingleTokenPaymentTerminal.sol'; +import {IJBSingleTokenPaymentTerminalStore} from './interfaces/IJBSingleTokenPaymentTerminalStore.sol'; +import {IJBPrices} from './interfaces/IJBPrices.sol'; +import {JBConstants} from './libraries/JBConstants.sol'; +import {JBCurrencies} from './libraries/JBCurrencies.sol'; +import {JBFixedPointNumber} from './libraries/JBFixedPointNumber.sol'; +import {JBFundingCycle} from './structs/JBFundingCycle.sol'; +import {JBFundingCycleMetadataResolver} from './libraries/JBFundingCycleMetadataResolver.sol'; +import {JBPayDelegateAllocation} from './structs/JBPayDelegateAllocation.sol'; +import {JBPayParamsData} from './structs/JBPayParamsData.sol'; +import {JBRedeemParamsData} from './structs/JBRedeemParamsData.sol'; +import {JBRedemptionDelegateAllocation} from './structs/JBRedemptionDelegateAllocation.sol'; +import {JBTokenAmount} from './structs/JBTokenAmount.sol'; + +/// @notice Manages all bookkeeping for inflows and outflows of funds from any ISingleTokenPaymentTerminal. contract JBSingleTokenPaymentTerminalStore is ReentrancyGuard, IJBSingleTokenPaymentTerminalStore { // A library that parses the packed funding cycle metadata into a friendlier format. using JBFundingCycleMetadataResolver for JBFundingCycle; @@ -48,82 +47,48 @@ contract JBSingleTokenPaymentTerminalStore is ReentrancyGuard, IJBSingleTokenPay // -------------------------- private constants ---------------------- // //*********************************************************************// - /** - @notice - Ensures a maximum number of decimal points of persisted fidelity on mulDiv operations of fixed point numbers. - */ + /// @notice Ensures a maximum number of decimal points of persisted fidelity on mulDiv operations of fixed point numbers. uint256 private constant _MAX_FIXED_POINT_FIDELITY = 18; //*********************************************************************// // ---------------- public immutable stored properties --------------- // //*********************************************************************// - /** - @notice - The directory of terminals and controllers for projects. - */ + /// @notice The directory of terminals and controllers for projects. IJBDirectory public immutable override directory; - /** - @notice - The contract storing all funding cycle configurations. - */ + /// @notice The contract storing all funding cycle configurations. IJBFundingCycleStore public immutable override fundingCycleStore; - /** - @notice - The contract that exposes price feeds. - */ + /// @notice The contract that exposes price feeds. IJBPrices public immutable override prices; //*********************************************************************// // --------------------- public stored properties -------------------- // //*********************************************************************// - /** - @notice - The amount of tokens that each project has for each terminal, in terms of the terminal's token. - - @dev - The used distribution limit is represented as a fixed point number with the same amount of decimals as its relative terminal. - - _terminal The terminal to which the balance applies. - _projectId The ID of the project to get the balance of. - */ + /// @notice The amount of tokens that each project has for each terminal, in terms of the terminal's token. + /// @dev The used distribution limit is represented as a fixed point number with the same amount of decimals as its relative terminal. + /// @custom:param _terminal The terminal to which the balance applies. + /// @custom:param _projectId The ID of the project to get the balance of. mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => uint256)) public override balanceOf; - /** - @notice - The amount of funds that a project has distributed from its limit during the current funding cycle for each terminal, in terms of the distribution limit's currency. - - @dev - Increases as projects use their preconfigured distribution limits. - - @dev - The used distribution limit is represented as a fixed point number with the same amount of decimals as its relative terminal. - - _terminal The terminal to which the used distribution limit applies. - _projectId The ID of the project to get the used distribution limit of. - _fundingCycleNumber The number of the funding cycle during which the distribution limit was used. - */ + /// @notice The amount of funds that a project has distributed from its limit during the current funding cycle for each terminal, in terms of the distribution limit's currency. + /// @dev Increases as projects use their preconfigured distribution limits. + /// @dev The used distribution limit is represented as a fixed point number with the same amount of decimals as its relative terminal. + /// @custom:param _terminal The terminal to which the used distribution limit applies. + /// @custom:param _projectId The ID of the project to get the used distribution limit of. + /// @custom:param _fundingCycleNumber The number of the funding cycle during which the distribution limit was used. mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => mapping(uint256 => uint256))) public override usedDistributionLimitOf; - /** - @notice - The amount of funds that a project has used from its allowance during the current funding cycle configuration for each terminal, in terms of the overflow allowance's currency. - - @dev - Increases as projects use their allowance. - - @dev - The used allowance is represented as a fixed point number with the same amount of decimals as its relative terminal. - - _terminal The terminal to which the overflow allowance applies. - _projectId The ID of the project to get the used overflow allowance of. - _configuration The configuration of the during which the allowance was used. - */ + /// @notice The amount of funds that a project has used from its allowance during the current funding cycle configuration for each terminal, in terms of the overflow allowance's currency. + /// @dev Increases as projects use their allowance. + /// @dev The used allowance is represented as a fixed point number with the same amount of decimals as its relative terminal. + /// @custom:param _terminal The terminal to which the overflow allowance applies. + /// @custom:param _projectId The ID of the project to get the used overflow allowance of. + /// @custom:param _configuration The configuration of the during which the allowance was used. mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => mapping(uint256 => uint256))) public override usedOverflowAllowanceOf; @@ -132,24 +97,15 @@ contract JBSingleTokenPaymentTerminalStore is ReentrancyGuard, IJBSingleTokenPay // ------------------------- external views -------------------------- // //*********************************************************************// - /** - @notice - Gets the current overflowed amount in a terminal for a specified project. - - @dev - The current overflow is represented as a fixed point number with the same amount of decimals as the specified terminal. - - @param _terminal The terminal for which the overflow is being calculated. - @param _projectId The ID of the project to get overflow for. - - @return The current amount of overflow that project has in the specified terminal. - */ - function currentOverflowOf(IJBSingleTokenPaymentTerminal _terminal, uint256 _projectId) - external - view - override - returns (uint256) - { + /// @notice Gets the current overflowed amount in a terminal for a specified project. + /// @dev The current overflow is represented as a fixed point number with the same amount of decimals as the specified terminal. + /// @param _terminal The terminal for which the overflow is being calculated. + /// @param _projectId The ID of the project to get overflow for. + /// @return The current amount of overflow that project has in the specified terminal. + function currentOverflowOf( + IJBSingleTokenPaymentTerminal _terminal, + uint256 _projectId + ) external view override returns (uint256) { // Return the overflow during the project's current funding cycle. return _overflowDuring( @@ -160,16 +116,11 @@ contract JBSingleTokenPaymentTerminalStore is ReentrancyGuard, IJBSingleTokenPay ); } - /** - @notice - Gets the current overflowed amount for a specified project across all terminals. - - @param _projectId The ID of the project to get total overflow for. - @param _decimals The number of decimals that the fixed point overflow should include. - @param _currency The currency that the total overflow should be in terms of. - - @return The current total amount of overflow that project has across all terminals. - */ + /// @notice Gets the current overflowed amount for a specified project across all terminals. + /// @param _projectId The ID of the project to get total overflow for. + /// @param _decimals The number of decimals that the fixed point overflow should include. + /// @param _currency The currency that the total overflow should be in terms of. + /// @return The current total amount of overflow that project has across all terminals. function currentTotalOverflowOf( uint256 _projectId, uint256 _decimals, @@ -178,26 +129,15 @@ contract JBSingleTokenPaymentTerminalStore is ReentrancyGuard, IJBSingleTokenPay return _currentTotalOverflowOf(_projectId, _decimals, _currency); } - /** - @notice - The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the total token supply and overflow in the ecosystem. - - @dev - If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used. - - @dev - The current reclaimable overflow is returned in terms of the specified terminal's currency. - - @dev - The reclaimable overflow is represented as a fixed point number with the same amount of decimals as the specified terminal. - - @param _terminal The terminal from which the reclaimable amount would come. - @param _projectId The ID of the project to get the reclaimable overflow amount for. - @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals. - @param _useTotalOverflow A flag indicating whether the overflow used in the calculation should be summed from all of the project's terminals. If false, overflow should be limited to the amount in the specified `_terminal`. - - @return The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_terminal`. - */ + /// @notice The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the total token supply and overflow in the ecosystem. + /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used. + /// @dev The current reclaimable overflow is returned in terms of the specified terminal's currency. + /// @dev The reclaimable overflow is represented as a fixed point number with the same amount of decimals as the specified terminal. + /// @param _terminal The terminal from which the reclaimable amount would come. + /// @param _projectId The ID of the project to get the reclaimable overflow amount for. + /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals. + /// @param _useTotalOverflow A flag indicating whether the overflow used in the calculation should be summed from all of the project's terminals. If false, overflow should be limited to the amount in the specified `_terminal`. + /// @return The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_terminal`. function currentReclaimableOverflowOf( IJBSingleTokenPaymentTerminal _terminal, uint256 _projectId, @@ -234,20 +174,13 @@ contract JBSingleTokenPaymentTerminalStore is ReentrancyGuard, IJBSingleTokenPay ); } - /** - @notice - The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the specified total token supply and overflow amounts. - - @dev - If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used. - - @param _projectId The ID of the project to get the reclaimable overflow amount for. - @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals. - @param _totalSupply The total number of tokens to make the calculation with, as a fixed point number with 18 decimals. - @param _overflow The amount of overflow to make the calculation with, as a fixed point number. - - @return The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_overflow`. - */ + /// @notice The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the specified total token supply and overflow amounts. + /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used. + /// @param _projectId The ID of the project for which the reclaimable overflow applies. + /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals. + /// @param _totalSupply The total number of tokens to make the calculation with, as a fixed point number with 18 decimals. + /// @param _overflow The amount of overflow to make the calculation with, as a fixed point number. + /// @return The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_overflow`. function currentReclaimableOverflowOf( uint256 _projectId, uint256 _tokenCount, @@ -272,16 +205,10 @@ contract JBSingleTokenPaymentTerminalStore is ReentrancyGuard, IJBSingleTokenPay // -------------------------- constructor ---------------------------- // //*********************************************************************// - /** - @param _directory A contract storing directories of terminals and controllers for each project. - @param _fundingCycleStore A contract storing all funding cycle configurations. - @param _prices A contract that exposes price feeds. - */ - constructor( - IJBDirectory _directory, - IJBFundingCycleStore _fundingCycleStore, - IJBPrices _prices - ) { + /// @param _directory A contract storing directories of terminals and controllers for each project. + /// @param _fundingCycleStore A contract storing all funding cycle configurations. + /// @param _prices A contract that exposes price feeds. + constructor(IJBDirectory _directory, IJBFundingCycleStore _fundingCycleStore, IJBPrices _prices) { directory = _directory; fundingCycleStore = _fundingCycleStore; prices = _prices; @@ -291,29 +218,20 @@ contract JBSingleTokenPaymentTerminalStore is ReentrancyGuard, IJBSingleTokenPay // ---------------------- external transactions ---------------------- // //*********************************************************************// - /** - @notice - Records newly contributed tokens to a project. - - @dev - Mints the project's tokens according to values provided by a configured data source. If no data source is configured, mints tokens proportional to the amount of the contribution. - - @dev - The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.sender's tokens. - - @param _payer The original address that sent the payment to the terminal. - @param _amount The amount of tokens being paid. Includes the token being paid, the value, the number of decimals included, and the currency of the amount. - @param _projectId The ID of the project being paid. - @param _baseWeightCurrency The currency to base token issuance on. - @param _beneficiary The specified address that should be the beneficiary of anything that results from the payment. - @param _memo A memo to pass along to the emitted event, and passed along to the funding cycle's data source. - @param _metadata Bytes to send along to the data source, if one is provided. - - @return fundingCycle The project's funding cycle during which payment was made. - @return tokenCount The number of project tokens that were minted, as a fixed point number with 18 decimals. - @return delegateAllocations The amount to send to delegates instead of adding to the local balance. - @return memo A memo that should be passed along to the emitted event. - */ + /// @notice Records newly contributed tokens to a project. + /// @dev Mints the project's tokens according to values provided by a configured data source. If no data source is configured, mints tokens proportional to the amount of the contribution. + /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.sender's tokens. + /// @param _payer The original address that sent the payment to the terminal. + /// @param _amount The amount of tokens being paid. Includes the token being paid, the value, the number of decimals included, and the currency of the amount. + /// @param _projectId The ID of the project being paid. + /// @param _baseWeightCurrency The currency to base token issuance on. + /// @param _beneficiary The specified address that should be the beneficiary of anything that results from the payment. + /// @param _memo A memo to pass along to the emitted event, and passed along to the funding cycle's data source. + /// @param _metadata Bytes to send along to the data source, if one is provided. + /// @return fundingCycle The project's funding cycle during which payment was made. + /// @return tokenCount The number of project tokens that were minted, as a fixed point number with 18 decimals. + /// @return delegateAllocations The amount to send to delegates instead of adding to the local balance. + /// @return memo A memo that should be passed along to the emitted event. function recordPaymentFrom( address _payer, JBTokenAmount calldata _amount, @@ -414,34 +332,25 @@ contract JBSingleTokenPaymentTerminalStore is ReentrancyGuard, IJBSingleTokenPay // If the terminal should base its weight on a different currency from the terminal's currency, determine the factor. // The weight is always a fixed point mumber with 18 decimals. To ensure this, the ratio should use the same number of decimals as the `_amount`. uint256 _weightRatio = _amount.currency == _baseWeightCurrency - ? 10**_decimals + ? 10 ** _decimals : prices.priceFor(_amount.currency, _baseWeightCurrency, _decimals); // Find the number of tokens to mint, as a fixed point number with as many decimals as `weight` has. tokenCount = PRBMath.mulDiv(_amount.value, _weight, _weightRatio); } - /** - @notice - Records newly redeemed tokens of a project. - - @dev - Redeems the project's tokens according to values provided by a configured data source. If no data source is configured, redeems tokens along a redemption bonding curve that is a function of the number of tokens being burned. - - @dev - The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.senders tokens. - - @param _holder The account that is having its tokens redeemed. - @param _projectId The ID of the project to which the tokens being redeemed belong. - @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals. - @param _memo A memo to pass along to the emitted event. - @param _metadata Bytes to send along to the data source, if one is provided. - - @return fundingCycle The funding cycle during which the redemption was made. - @return reclaimAmount The amount of terminal tokens reclaimed, as a fixed point number with 18 decimals. - @return delegateAllocations The amount to send to delegates instead of sending to the beneficiary. - @return memo A memo that should be passed along to the emitted event. - */ + /// @notice Records newly redeemed tokens of a project. + /// @dev Redeems the project's tokens according to values provided by a configured data source. If no data source is configured, redeems tokens along a redemption bonding curve that is a function of the number of tokens being burned. + /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.senders tokens. + /// @param _holder The account that is having its tokens redeemed. + /// @param _projectId The ID of the project to which the tokens being redeemed belong. + /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals. + /// @param _memo A memo to pass along to the emitted event. + /// @param _metadata Bytes to send along to the data source, if one is provided. + /// @return fundingCycle The funding cycle during which the redemption was made. + /// @return reclaimAmount The amount of terminal tokens reclaimed, as a fixed point number with 18 decimals. + /// @return delegateAllocations The amount to send to delegates instead of sending to the beneficiary. + /// @return memo A memo that should be passed along to the emitted event. function recordRedemptionFor( address _holder, uint256 _projectId, @@ -583,20 +492,13 @@ contract JBSingleTokenPaymentTerminalStore is ReentrancyGuard, IJBSingleTokenPay } } - /** - @notice - Records newly distributed funds for a project. - - @dev - The msg.sender must be an IJBSingleTokenPaymentTerminal. - - @param _projectId The ID of the project that is having funds distributed. - @param _amount The amount to use from the distribution limit, as a fixed point number. - @param _currency The currency of the `_amount`. This must match the project's current funding cycle's currency. - - @return fundingCycle The funding cycle during which the distribution was made. - @return distributedAmount The amount of terminal tokens distributed, as a fixed point number with the same amount of decimals as its relative terminal. - */ + /// @notice Records newly distributed funds for a project. + /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. + /// @param _projectId The ID of the project that is having funds distributed. + /// @param _amount The amount to use from the distribution limit, as a fixed point number. + /// @param _currency The currency of the `_amount`. This must match the project's current funding cycle's currency. + /// @return fundingCycle The funding cycle during which the distribution was made. + /// @return distributedAmount The amount of terminal tokens distributed, as a fixed point number with the same amount of decimals as its relative terminal. function recordDistributionFor( uint256 _projectId, uint256 _amount, @@ -643,7 +545,7 @@ contract JBSingleTokenPaymentTerminalStore is ReentrancyGuard, IJBSingleTokenPay ? _amount : PRBMath.mulDiv( _amount, - 10**_MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting. + 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting. prices.priceFor(_currency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY) ); @@ -664,20 +566,13 @@ contract JBSingleTokenPaymentTerminalStore is ReentrancyGuard, IJBSingleTokenPay } } - /** - @notice - Records newly used allowance funds of a project. - - @dev - The msg.sender must be an IJBSingleTokenPaymentTerminal. - - @param _projectId The ID of the project to use the allowance of. - @param _amount The amount to use from the allowance, as a fixed point number. - @param _currency The currency of the `_amount`. Must match the currency of the overflow allowance. - - @return fundingCycle The funding cycle during which the overflow allowance is being used. - @return usedAmount The amount of terminal tokens used, as a fixed point number with the same amount of decimals as its relative terminal. - */ + /// @notice Records newly used allowance funds of a project. + /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. + /// @param _projectId The ID of the project to use the allowance of. + /// @param _amount The amount to use from the allowance, as a fixed point number. + /// @param _currency The currency of the `_amount`. Must match the currency of the overflow allowance. + /// @return fundingCycle The funding cycle during which the overflow allowance is being used. + /// @return usedAmount The amount of terminal tokens used, as a fixed point number with the same amount of decimals as its relative terminal. function recordUsedAllowanceOf( uint256 _projectId, uint256 _amount, @@ -721,7 +616,7 @@ contract JBSingleTokenPaymentTerminalStore is ReentrancyGuard, IJBSingleTokenPay ? _amount : PRBMath.mulDiv( _amount, - 10**_MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting. + 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting. prices.priceFor(_currency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY) ); @@ -747,16 +642,10 @@ contract JBSingleTokenPaymentTerminalStore is ReentrancyGuard, IJBSingleTokenPay usedAmount; } - /** - @notice - Records newly added funds for the project. - - @dev - The msg.sender must be an IJBSingleTokenPaymentTerminal. - - @param _projectId The ID of the project to which the funds being added belong. - @param _amount The amount of terminal tokens added, as a fixed point number with the same amount of decimals as its relative terminal. - */ + /// @notice Records newly added funds for the project. + /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. + /// @param _projectId The ID of the project to which the funds being added belong. + /// @param _amount The amount of terminal tokens added, as a fixed point number with the same amount of decimals as its relative terminal. function recordAddedBalanceFor(uint256 _projectId, uint256 _amount) external override { // Increment the balance. balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] = @@ -764,23 +653,13 @@ contract JBSingleTokenPaymentTerminalStore is ReentrancyGuard, IJBSingleTokenPay _amount; } - /** - @notice - Records the migration of funds from this store. - - @dev - The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount returned is in terms of the msg.senders tokens. - - @param _projectId The ID of the project being migrated. - - @return balance The project's migrated balance, as a fixed point number with the same amount of decimals as its relative terminal. - */ - function recordMigration(uint256 _projectId) - external - override - nonReentrant - returns (uint256 balance) - { + /// @notice Records the migration of funds from this store. + /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount returned is in terms of the msg.senders tokens. + /// @param _projectId The ID of the project being migrated. + /// @return balance The project's migrated balance, as a fixed point number with the same amount of decimals as its relative terminal. + function recordMigration( + uint256 _projectId + ) external override nonReentrant returns (uint256 balance) { // Get a reference to the project's current funding cycle. JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId); @@ -798,21 +677,14 @@ contract JBSingleTokenPaymentTerminalStore is ReentrancyGuard, IJBSingleTokenPay // --------------------- private helper functions -------------------- // //*********************************************************************// - /** - @notice - The amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens when measured from the specified. - - @dev - If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used. - - @param _projectId The ID of the project to get the reclaimable overflow amount for. - @param _fundingCycle The funding cycle during which reclaimable overflow is being calculated. - @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals. - @param _totalSupply The total supply of tokens to make the calculation with, as a fixed point number with 18 decimals. - @param _overflow The amount of overflow to make the calculation with. - - @return The amount of overflowed tokens that can be reclaimed. - */ + /// @notice The amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens when measured from the specified. + /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used. + /// @param _projectId The ID of the project to get the reclaimable overflow amount for. + /// @param _fundingCycle The funding cycle during which reclaimable overflow is being calculated. + /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals. + /// @param _totalSupply The total supply of tokens to make the calculation with, as a fixed point number with 18 decimals. + /// @param _overflow The amount of overflow to make the calculation with. + /// @return The amount of overflowed tokens that can be reclaimed. function _reclaimableOverflowDuring( uint256 _projectId, JBFundingCycle memory _fundingCycle, @@ -851,20 +723,13 @@ contract JBSingleTokenPaymentTerminalStore is ReentrancyGuard, IJBSingleTokenPay ); } - /** - @notice - Gets the amount that is overflowing when measured from the specified funding cycle. - - @dev - This amount changes as the value of the balance changes in relation to the currency being used to measure the distribution limit. - - @param _terminal The terminal for which the overflow is being calculated. - @param _projectId The ID of the project to get overflow for. - @param _fundingCycle The ID of the funding cycle to base the overflow on. - @param _balanceCurrency The currency that the stored balance is expected to be in terms of. - - @return overflow The overflow of funds, as a fixed point number with 18 decimals. - */ + /// @notice Gets the amount that is overflowing when measured from the specified funding cycle. + /// @dev This amount changes as the value of the balance changes in relation to the currency being used to measure the distribution limit. + /// @param _terminal The terminal for which the overflow is being calculated. + /// @param _projectId The ID of the project to get overflow for. + /// @param _fundingCycle The ID of the funding cycle to base the overflow on. + /// @param _balanceCurrency The currency that the stored balance is expected to be in terms of. + /// @return overflow The overflow of funds, as a fixed point number with 18 decimals. function _overflowDuring( IJBSingleTokenPaymentTerminal _terminal, uint256 _projectId, @@ -890,7 +755,7 @@ contract JBSingleTokenPaymentTerminalStore is ReentrancyGuard, IJBSingleTokenPay if (_distributionLimitRemaining != 0 && _distributionLimitCurrency != _balanceCurrency) _distributionLimitRemaining = PRBMath.mulDiv( _distributionLimitRemaining, - 10**_MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting. + 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting. prices.priceFor(_distributionLimitCurrency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY) ); @@ -901,19 +766,12 @@ contract JBSingleTokenPaymentTerminalStore is ReentrancyGuard, IJBSingleTokenPay } } - /** - @notice - Gets the amount that is currently overflowing across all of a project's terminals. - - @dev - This amount changes as the value of the balances changes in relation to the currency being used to measure the project's distribution limits. - - @param _projectId The ID of the project to get the total overflow for. - @param _decimals The number of decimals that the fixed point overflow should include. - @param _currency The currency that the overflow should be in terms of. - - @return overflow The total overflow of a project's funds. - */ + /// @notice Gets the amount that is currently overflowing across all of a project's terminals. + /// @dev This amount changes as the value of the balances changes in relation to the currency being used to measure the project's distribution limits. + /// @param _projectId The ID of the project to get the total overflow for. + /// @param _decimals The number of decimals that the fixed point overflow should include. + /// @param _currency The currency that the overflow should be in terms of. + /// @return overflow The total overflow of a project's funds. function _currentTotalOverflowOf( uint256 _projectId, uint256 _decimals, @@ -936,7 +794,7 @@ contract JBSingleTokenPaymentTerminalStore is ReentrancyGuard, IJBSingleTokenPay // Convert the ETH overflow to the specified currency if needed, maintaining a fixed point number with 18 decimals. uint256 _totalOverflow18Decimal = _currency == JBCurrencies.ETH ? _ethOverflow - : PRBMath.mulDiv(_ethOverflow, 10**18, prices.priceFor(JBCurrencies.ETH, _currency, 18)); + : PRBMath.mulDiv(_ethOverflow, 10 ** 18, prices.priceFor(JBCurrencies.ETH, _currency, 18)); // Adjust the decimals of the fixed point number if needed to match the target decimals. return diff --git a/contracts/JBSingleTokenPaymentTerminalStore3_1.sol b/contracts/JBSingleTokenPaymentTerminalStore3_1.sol index a783f3b8c..c9e162777 100644 --- a/contracts/JBSingleTokenPaymentTerminalStore3_1.sol +++ b/contracts/JBSingleTokenPaymentTerminalStore3_1.sol @@ -1,33 +1,30 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.16; -import '@openzeppelin/contracts/security/ReentrancyGuard.sol'; -import '@paulrberg/contracts/math/PRBMath.sol'; -import './interfaces/IJBController3_1.sol'; -import './interfaces/IJBFundingCycleDataSource.sol'; -import './interfaces/IJBSingleTokenPaymentTerminalStore.sol'; -import './libraries/JBConstants.sol'; -import './libraries/JBCurrencies.sol'; -import './libraries/JBFixedPointNumber.sol'; -import './libraries/JBFundingCycleMetadataResolver.sol'; -import './structs/JBPayDelegateAllocation.sol'; -import './structs/JBPayParamsData.sol'; - -/** - @notice - Manages all bookkeeping for inflows and outflows of funds from any ISingleTokenPaymentTerminal. - - @dev - Adheres to: - IJBSingleTokenPaymentTerminalStore: General interface for the methods in this contract that interact with the blockchain's state according to the protocol's rules. - - @dev - Inherits from - - ReentrancyGuard: Contract module that helps prevent reentrant calls to a function. - - @dev - This Store expects a project's controller to be an IJBController3_1. This is the only difference between this version and the original. -*/ +import {ReentrancyGuard} from '@openzeppelin/contracts/security/ReentrancyGuard.sol'; +import {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol'; +import {JBBallotState} from './enums/JBBallotState.sol'; +import {IJBDirectory} from './interfaces/IJBDirectory.sol'; +import {IJBController3_1} from './interfaces/IJBController3_1.sol'; +import {IJBFundingCycleDataSource} from './interfaces/IJBFundingCycleDataSource.sol'; +import {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol'; +import {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol'; +import {IJBSingleTokenPaymentTerminal} from './interfaces/IJBSingleTokenPaymentTerminal.sol'; +import {IJBSingleTokenPaymentTerminalStore} from './interfaces/IJBSingleTokenPaymentTerminalStore.sol'; +import {IJBPrices} from './interfaces/IJBPrices.sol'; +import {JBConstants} from './libraries/JBConstants.sol'; +import {JBCurrencies} from './libraries/JBCurrencies.sol'; +import {JBFixedPointNumber} from './libraries/JBFixedPointNumber.sol'; +import {JBFundingCycle} from './structs/JBFundingCycle.sol'; +import {JBFundingCycleMetadataResolver} from './libraries/JBFundingCycleMetadataResolver.sol'; +import {JBPayDelegateAllocation} from './structs/JBPayDelegateAllocation.sol'; +import {JBPayParamsData} from './structs/JBPayParamsData.sol'; +import {JBRedeemParamsData} from './structs/JBRedeemParamsData.sol'; +import {JBRedemptionDelegateAllocation} from './structs/JBRedemptionDelegateAllocation.sol'; +import {JBTokenAmount} from './structs/JBTokenAmount.sol'; + +/// @notice Manages all bookkeeping for inflows and outflows of funds from any ISingleTokenPaymentTerminal. +/// @dev This Store expects a project's controller to be an IJBController3_1. This is the only difference between this version and the original. contract JBSingleTokenPaymentTerminalStore3_1 is ReentrancyGuard, IJBSingleTokenPaymentTerminalStore @@ -54,82 +51,48 @@ contract JBSingleTokenPaymentTerminalStore3_1 is // -------------------------- private constants ---------------------- // //*********************************************************************// - /** - @notice - Ensures a maximum number of decimal points of persisted fidelity on mulDiv operations of fixed point numbers. - */ + /// @notice Ensures a maximum number of decimal points of persisted fidelity on mulDiv operations of fixed point numbers. uint256 private constant _MAX_FIXED_POINT_FIDELITY = 18; //*********************************************************************// // ---------------- public immutable stored properties --------------- // //*********************************************************************// - /** - @notice - The directory of terminals and controllers for projects. - */ + /// @notice The directory of terminals and controllers for projects. IJBDirectory public immutable override directory; - /** - @notice - The contract storing all funding cycle configurations. - */ + /// @notice The contract storing all funding cycle configurations. IJBFundingCycleStore public immutable override fundingCycleStore; - /** - @notice - The contract that exposes price feeds. - */ + /// @notice The contract that exposes price feeds. IJBPrices public immutable override prices; //*********************************************************************// // --------------------- public stored properties -------------------- // //*********************************************************************// - /** - @notice - The amount of tokens that each project has for each terminal, in terms of the terminal's token. - - @dev - The used distribution limit is represented as a fixed point number with the same amount of decimals as its relative terminal. - - _terminal The terminal to which the balance applies. - _projectId The ID of the project to get the balance of. - */ + /// @notice The amount of tokens that each project has for each terminal, in terms of the terminal's token. + /// @dev The used distribution limit is represented as a fixed point number with the same amount of decimals as its relative terminal. + /// @custom:param _terminal The terminal to which the balance applies. + /// @custom:param _projectId The ID of the project to get the balance of. mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => uint256)) public override balanceOf; - /** - @notice - The amount of funds that a project has distributed from its limit during the current funding cycle for each terminal, in terms of the distribution limit's currency. - - @dev - Increases as projects use their preconfigured distribution limits. - - @dev - The used distribution limit is represented as a fixed point number with the same amount of decimals as its relative terminal. - - _terminal The terminal to which the used distribution limit applies. - _projectId The ID of the project to get the used distribution limit of. - _fundingCycleNumber The number of the funding cycle during which the distribution limit was used. - */ + /// @notice The amount of funds that a project has distributed from its limit during the current funding cycle for each terminal, in terms of the distribution limit's currency. + /// @dev Increases as projects use their preconfigured distribution limits. + /// @dev The used distribution limit is represented as a fixed point number with the same amount of decimals as its relative terminal. + /// @custom:param _terminal The terminal to which the used distribution limit applies. + /// @custom:param _projectId The ID of the project to get the used distribution limit of. + /// @custom:param _fundingCycleNumber The number of the funding cycle during which the distribution limit was used. mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => mapping(uint256 => uint256))) public override usedDistributionLimitOf; - /** - @notice - The amount of funds that a project has used from its allowance during the current funding cycle configuration for each terminal, in terms of the overflow allowance's currency. - - @dev - Increases as projects use their allowance. - - @dev - The used allowance is represented as a fixed point number with the same amount of decimals as its relative terminal. - - _terminal The terminal to which the overflow allowance applies. - _projectId The ID of the project to get the used overflow allowance of. - _configuration The configuration of the during which the allowance was used. - */ + /// @notice The amount of funds that a project has used from its allowance during the current funding cycle configuration for each terminal, in terms of the overflow allowance's currency. + /// @dev Increases as projects use their allowance. + /// @dev The used allowance is represented as a fixed point number with the same amount of decimals as its relative terminal. + /// @custom:param _terminal The terminal to which the overflow allowance applies. + /// @custom:param _projectId The ID of the project to get the used overflow allowance of. + /// @custom:param _configuration The configuration of the during which the allowance was used. mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => mapping(uint256 => uint256))) public override usedOverflowAllowanceOf; @@ -138,24 +101,15 @@ contract JBSingleTokenPaymentTerminalStore3_1 is // ------------------------- external views -------------------------- // //*********************************************************************// - /** - @notice - Gets the current overflowed amount in a terminal for a specified project. - - @dev - The current overflow is represented as a fixed point number with the same amount of decimals as the specified terminal. - - @param _terminal The terminal for which the overflow is being calculated. - @param _projectId The ID of the project to get overflow for. - - @return The current amount of overflow that project has in the specified terminal. - */ - function currentOverflowOf(IJBSingleTokenPaymentTerminal _terminal, uint256 _projectId) - external - view - override - returns (uint256) - { + /// @notice Gets the current overflowed amount in a terminal for a specified project. + /// @dev The current overflow is represented as a fixed point number with the same amount of decimals as the specified terminal. + /// @param _terminal The terminal for which the overflow is being calculated. + /// @param _projectId The ID of the project to get overflow for. + /// @return The current amount of overflow that project has in the specified terminal. + function currentOverflowOf( + IJBSingleTokenPaymentTerminal _terminal, + uint256 _projectId + ) external view override returns (uint256) { // Return the overflow during the project's current funding cycle. return _overflowDuring( @@ -166,16 +120,11 @@ contract JBSingleTokenPaymentTerminalStore3_1 is ); } - /** - @notice - Gets the current overflowed amount for a specified project across all terminals. - - @param _projectId The ID of the project to get total overflow for. - @param _decimals The number of decimals that the fixed point overflow should include. - @param _currency The currency that the total overflow should be in terms of. - - @return The current total amount of overflow that project has across all terminals. - */ + /// @notice Gets the current overflowed amount for a specified project across all terminals. + /// @param _projectId The ID of the project to get total overflow for. + /// @param _decimals The number of decimals that the fixed point overflow should include. + /// @param _currency The currency that the total overflow should be in terms of. + /// @return The current total amount of overflow that project has across all terminals. function currentTotalOverflowOf( uint256 _projectId, uint256 _decimals, @@ -184,26 +133,15 @@ contract JBSingleTokenPaymentTerminalStore3_1 is return _currentTotalOverflowOf(_projectId, _decimals, _currency); } - /** - @notice - The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the total token supply and overflow in the ecosystem. - - @dev - If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used. - - @dev - The current reclaimable overflow is returned in terms of the specified terminal's currency. - - @dev - The reclaimable overflow is represented as a fixed point number with the same amount of decimals as the specified terminal. - - @param _terminal The terminal from which the reclaimable amount would come. - @param _projectId The ID of the project to get the reclaimable overflow amount for. - @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals. - @param _useTotalOverflow A flag indicating whether the overflow used in the calculation should be summed from all of the project's terminals. If false, overflow should be limited to the amount in the specified `_terminal`. - - @return The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_terminal`. - */ + /// @notice The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the total token supply and overflow in the ecosystem. + /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used. + /// @dev The current reclaimable overflow is returned in terms of the specified terminal's currency. + /// @dev The reclaimable overflow is represented as a fixed point number with the same amount of decimals as the specified terminal. + /// @param _terminal The terminal from which the reclaimable amount would come. + /// @param _projectId The ID of the project to get the reclaimable overflow amount for. + /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals. + /// @param _useTotalOverflow A flag indicating whether the overflow used in the calculation should be summed from all of the project's terminals. If false, overflow should be limited to the amount in the specified `_terminal`. + /// @return The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_terminal`. function currentReclaimableOverflowOf( IJBSingleTokenPaymentTerminal _terminal, uint256 _projectId, @@ -240,20 +178,13 @@ contract JBSingleTokenPaymentTerminalStore3_1 is ); } - /** - @notice - The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the specified total token supply and overflow amounts. - - @dev - If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used. - - @param _projectId The ID of the project to get the reclaimable overflow amount for. - @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals. - @param _totalSupply The total number of tokens to make the calculation with, as a fixed point number with 18 decimals. - @param _overflow The amount of overflow to make the calculation with, as a fixed point number. - - @return The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_overflow`. - */ + /// @notice The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the specified total token supply and overflow amounts. + /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used. + /// @param _projectId The ID of the project to get the reclaimable overflow amount for. + /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals. + /// @param _totalSupply The total number of tokens to make the calculation with, as a fixed point number with 18 decimals. + /// @param _overflow The amount of overflow to make the calculation with, as a fixed point number. + /// @return The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_overflow`. function currentReclaimableOverflowOf( uint256 _projectId, uint256 _tokenCount, @@ -278,16 +209,10 @@ contract JBSingleTokenPaymentTerminalStore3_1 is // -------------------------- constructor ---------------------------- // //*********************************************************************// - /** - @param _directory A contract storing directories of terminals and controllers for each project. - @param _fundingCycleStore A contract storing all funding cycle configurations. - @param _prices A contract that exposes price feeds. - */ - constructor( - IJBDirectory _directory, - IJBFundingCycleStore _fundingCycleStore, - IJBPrices _prices - ) { + /// @param _directory A contract storing directories of terminals and controllers for each project. + /// @param _fundingCycleStore A contract storing all funding cycle configurations. + /// @param _prices A contract that exposes price feeds. + constructor(IJBDirectory _directory, IJBFundingCycleStore _fundingCycleStore, IJBPrices _prices) { directory = _directory; fundingCycleStore = _fundingCycleStore; prices = _prices; @@ -297,29 +222,20 @@ contract JBSingleTokenPaymentTerminalStore3_1 is // ---------------------- external transactions ---------------------- // //*********************************************************************// - /** - @notice - Records newly contributed tokens to a project. - - @dev - Mints the project's tokens according to values provided by a configured data source. If no data source is configured, mints tokens proportional to the amount of the contribution. - - @dev - The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.sender's tokens. - - @param _payer The original address that sent the payment to the terminal. - @param _amount The amount of tokens being paid. Includes the token being paid, the value, the number of decimals included, and the currency of the amount. - @param _projectId The ID of the project being paid. - @param _baseWeightCurrency The currency to base token issuance on. - @param _beneficiary The specified address that should be the beneficiary of anything that results from the payment. - @param _memo A memo to pass along to the emitted event, and passed along to the funding cycle's data source. - @param _metadata Bytes to send along to the data source, if one is provided. - - @return fundingCycle The project's funding cycle during which payment was made. - @return tokenCount The number of project tokens that were minted, as a fixed point number with 18 decimals. - @return delegateAllocations The amount to send to delegates instead of adding to the local balance. - @return memo A memo that should be passed along to the emitted event. - */ + /// @notice Records newly contributed tokens to a project. + /// @dev Mints the project's tokens according to values provided by a configured data source. If no data source is configured, mints tokens proportional to the amount of the contribution. + /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.sender's tokens. + /// @param _payer The original address that sent the payment to the terminal. + /// @param _amount The amount of tokens being paid. Includes the token being paid, the value, the number of decimals included, and the currency of the amount. + /// @param _projectId The ID of the project being paid. + /// @param _baseWeightCurrency The currency to base token issuance on. + /// @param _beneficiary The specified address that should be the beneficiary of anything that results from the payment. + /// @param _memo A memo to pass along to the emitted event, and passed along to the funding cycle's data source. + /// @param _metadata Bytes to send along to the data source, if one is provided. + /// @return fundingCycle The project's funding cycle during which payment was made. + /// @return tokenCount The number of project tokens that were minted, as a fixed point number with 18 decimals. + /// @return delegateAllocations The amount to send to delegates instead of adding to the local balance. + /// @return memo A memo that should be passed along to the emitted event. function recordPaymentFrom( address _payer, JBTokenAmount calldata _amount, @@ -420,34 +336,23 @@ contract JBSingleTokenPaymentTerminalStore3_1 is // If the terminal should base its weight on a different currency from the terminal's currency, determine the factor. // The weight is always a fixed point mumber with 18 decimals. To ensure this, the ratio should use the same number of decimals as the `_amount`. uint256 _weightRatio = _amount.currency == _baseWeightCurrency - ? 10**_decimals + ? 10 ** _decimals : prices.priceFor(_amount.currency, _baseWeightCurrency, _decimals); // Find the number of tokens to mint, as a fixed point number with as many decimals as `weight` has. tokenCount = PRBMath.mulDiv(_amount.value, _weight, _weightRatio); } - /** - @notice - Records newly redeemed tokens of a project. - - @dev - Redeems the project's tokens according to values provided by a configured data source. If no data source is configured, redeems tokens along a redemption bonding curve that is a function of the number of tokens being burned. - - @dev - The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.senders tokens. - - @param _holder The account that is having its tokens redeemed. - @param _projectId The ID of the project to which the tokens being redeemed belong. - @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals. - @param _memo A memo to pass along to the emitted event. - @param _metadata Bytes to send along to the data source, if one is provided. - - @return fundingCycle The funding cycle during which the redemption was made. - @return reclaimAmount The amount of terminal tokens reclaimed, as a fixed point number with 18 decimals. - @return delegateAllocations The amount to send to delegates instead of sending to the beneficiary. - @return memo A memo that should be passed along to the emitted event. - */ + /// @notice Records newly redeemed tokens of a project. + /// @dev Redeems the project's tokens according to values provided by a configured data source. If no data source is configured, redeems tokens along a redemption bonding curve that is a function of the number of tokens being burned. + /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.senders tokens. + /// @param _projectId The ID of the project to which the tokens being redeemed belong. + /// @param _memo A memo to pass along to the emitted event. + /// @param _metadata Bytes to send along to the data source, if one is provided. + /// @return fundingCycle The funding cycle during which the redemption was made. + /// @return reclaimAmount The amount of terminal tokens reclaimed, as a fixed point number with 18 decimals. + /// @return delegateAllocations The amount to send to delegates instead of sending to the beneficiary. + /// @return memo A memo that should be passed along to the emitted event. function recordRedemptionFor( address _holder, uint256 _projectId, @@ -587,20 +492,13 @@ contract JBSingleTokenPaymentTerminalStore3_1 is } } - /** - @notice - Records newly distributed funds for a project. - - @dev - The msg.sender must be an IJBSingleTokenPaymentTerminal. - - @param _projectId The ID of the project that is having funds distributed. - @param _amount The amount to use from the distribution limit, as a fixed point number. - @param _currency The currency of the `_amount`. This must match the project's current funding cycle's currency. - - @return fundingCycle The funding cycle during which the distribution was made. - @return distributedAmount The amount of terminal tokens distributed, as a fixed point number with the same amount of decimals as its relative terminal. - */ + /// @notice Records newly distributed funds for a project. + /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. + /// @param _projectId The ID of the project that is having funds distributed. + /// @param _amount The amount to use from the distribution limit, as a fixed point number. + /// @param _currency The currency of the `_amount`. This must match the project's current funding cycle's currency. + /// @return fundingCycle The funding cycle during which the distribution was made. + /// @return distributedAmount The amount of terminal tokens distributed, as a fixed point number with the same amount of decimals as its relative terminal. function recordDistributionFor( uint256 _projectId, uint256 _amount, @@ -647,7 +545,7 @@ contract JBSingleTokenPaymentTerminalStore3_1 is ? _amount : PRBMath.mulDiv( _amount, - 10**_MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting. + 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting. prices.priceFor(_currency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY) ); @@ -668,20 +566,13 @@ contract JBSingleTokenPaymentTerminalStore3_1 is } } - /** - @notice - Records newly used allowance funds of a project. - - @dev - The msg.sender must be an IJBSingleTokenPaymentTerminal. - - @param _projectId The ID of the project to use the allowance of. - @param _amount The amount to use from the allowance, as a fixed point number. - @param _currency The currency of the `_amount`. Must match the currency of the overflow allowance. - - @return fundingCycle The funding cycle during which the overflow allowance is being used. - @return usedAmount The amount of terminal tokens used, as a fixed point number with the same amount of decimals as its relative terminal. - */ + /// @notice Records newly used allowance funds of a project. + /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. + /// @param _projectId The ID of the project to use the allowance of. + /// @param _amount The amount to use from the allowance, as a fixed point number. + /// @param _currency The currency of the `_amount`. Must match the currency of the overflow allowance. + /// @return fundingCycle The funding cycle during which the overflow allowance is being used. + /// @return usedAmount The amount of terminal tokens used, as a fixed point number with the same amount of decimals as its relative terminal. function recordUsedAllowanceOf( uint256 _projectId, uint256 _amount, @@ -725,7 +616,7 @@ contract JBSingleTokenPaymentTerminalStore3_1 is ? _amount : PRBMath.mulDiv( _amount, - 10**_MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting. + 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting. prices.priceFor(_currency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY) ); @@ -751,16 +642,10 @@ contract JBSingleTokenPaymentTerminalStore3_1 is usedAmount; } - /** - @notice - Records newly added funds for the project. - - @dev - The msg.sender must be an IJBSingleTokenPaymentTerminal. - - @param _projectId The ID of the project to which the funds being added belong. - @param _amount The amount of terminal tokens added, as a fixed point number with the same amount of decimals as its relative terminal. - */ + /// @notice Records newly added funds for the project. + /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. + /// @param _projectId The ID of the project to which the funds being added belong. + /// @param _amount The amount of terminal tokens added, as a fixed point number with the same amount of decimals as its relative terminal. function recordAddedBalanceFor(uint256 _projectId, uint256 _amount) external override { // Increment the balance. balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] = @@ -768,26 +653,15 @@ contract JBSingleTokenPaymentTerminalStore3_1 is _amount; } - /** - @notice - Records the migration of funds from this store. - - @dev - The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount returned is in terms of the msg.senders tokens. - - @param _projectId The ID of the project being migrated. - - @return balance The project's migrated balance, as a fixed point number with the same amount of decimals as its relative terminal. - */ - function recordMigration(uint256 _projectId) - external - override - nonReentrant - returns (uint256 balance) - { + /// @notice Records the migration of funds from this store. + /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount returned is in terms of the msg.senders tokens. + /// @param _projectId The ID of the project being migrated. + /// @return balance The project's migrated balance, as a fixed point number with the same amount of decimals as its relative terminal. + function recordMigration( + uint256 _projectId + ) external override nonReentrant returns (uint256 balance) { // Get a reference to the project's current funding cycle. JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId); - // Migration must be allowed. if (!_fundingCycle.terminalMigrationAllowed()) revert PAYMENT_TERMINAL_MIGRATION_NOT_ALLOWED(); @@ -802,21 +676,14 @@ contract JBSingleTokenPaymentTerminalStore3_1 is // --------------------- private helper functions -------------------- // //*********************************************************************// - /** - @notice - The amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens when measured from the specified. - - @dev - If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used. - - @param _projectId The ID of the project to get the reclaimable overflow amount for. - @param _fundingCycle The funding cycle during which reclaimable overflow is being calculated. - @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals. - @param _totalSupply The total supply of tokens to make the calculation with, as a fixed point number with 18 decimals. - @param _overflow The amount of overflow to make the calculation with. - - @return The amount of overflowed tokens that can be reclaimed. - */ + /// @notice The amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens when measured from the specified. + /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used. + /// @param _projectId The ID of the project to get the reclaimable overflow amount for. + /// @param _fundingCycle The funding cycle during which reclaimable overflow is being calculated. + /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals. + /// @param _totalSupply The total supply of tokens to make the calculation with, as a fixed point number with 18 decimals. + /// @param _overflow The amount of overflow to make the calculation with. + /// @return The amount of overflowed tokens that can be reclaimed. function _reclaimableOverflowDuring( uint256 _projectId, JBFundingCycle memory _fundingCycle, @@ -855,20 +722,12 @@ contract JBSingleTokenPaymentTerminalStore3_1 is ); } - /** - @notice - Gets the amount that is overflowing when measured from the specified funding cycle. - - @dev - This amount changes as the value of the balance changes in relation to the currency being used to measure the distribution limit. - - @param _terminal The terminal for which the overflow is being calculated. - @param _projectId The ID of the project to get overflow for. - @param _fundingCycle The ID of the funding cycle to base the overflow on. - @param _balanceCurrency The currency that the stored balance is expected to be in terms of. - - @return overflow The overflow of funds, as a fixed point number with 18 decimals. - */ + /// @notice Gets the amount that is overflowing when measured from the specified funding cycle. + /// @dev This amount changes as the value of the balance changes in relation to the currency being used to measure the distribution limit. + /// @param _terminal The terminal for which the overflow is being calculated. + /// @param _fundingCycle The ID of the funding cycle to base the overflow on. + /// @param _balanceCurrency The currency that the stored balance is expected to be in terms of. + /// @return overflow The overflow of funds, as a fixed point number with 18 decimals. function _overflowDuring( IJBSingleTokenPaymentTerminal _terminal, uint256 _projectId, @@ -899,7 +758,7 @@ contract JBSingleTokenPaymentTerminalStore3_1 is if (_distributionLimitRemaining != 0 && _distributionLimitCurrency != _balanceCurrency) _distributionLimitRemaining = PRBMath.mulDiv( _distributionLimitRemaining, - 10**_MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting. + 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting. prices.priceFor(_distributionLimitCurrency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY) ); @@ -910,19 +769,12 @@ contract JBSingleTokenPaymentTerminalStore3_1 is } } - /** - @notice - Gets the amount that is currently overflowing across all of a project's terminals. - - @dev - This amount changes as the value of the balances changes in relation to the currency being used to measure the project's distribution limits. - - @param _projectId The ID of the project to get the total overflow for. - @param _decimals The number of decimals that the fixed point overflow should include. - @param _currency The currency that the overflow should be in terms of. - - @return overflow The total overflow of a project's funds. - */ + /// @notice Gets the amount that is currently overflowing across all of a project's terminals. + /// @dev This amount changes as the value of the balances changes in relation to the currency being used to measure the project's distribution limits. + /// @param _projectId The ID of the project to get the total overflow for. + /// @param _decimals The number of decimals that the fixed point overflow should include. + /// @param _currency The currency that the overflow should be in terms of. + /// @return overflow The total overflow of a project's funds. function _currentTotalOverflowOf( uint256 _projectId, uint256 _decimals, @@ -945,7 +797,7 @@ contract JBSingleTokenPaymentTerminalStore3_1 is // Convert the ETH overflow to the specified currency if needed, maintaining a fixed point number with 18 decimals. uint256 _totalOverflow18Decimal = _currency == JBCurrencies.ETH ? _ethOverflow - : PRBMath.mulDiv(_ethOverflow, 10**18, prices.priceFor(JBCurrencies.ETH, _currency, 18)); + : PRBMath.mulDiv(_ethOverflow, 10 ** 18, prices.priceFor(JBCurrencies.ETH, _currency, 18)); // Adjust the decimals of the fixed point number if needed to match the target decimals. return diff --git a/contracts/JBSingleTokenPaymentTerminalStore3_1_1.sol b/contracts/JBSingleTokenPaymentTerminalStore3_1_1.sol new file mode 100644 index 000000000..e22a98f7e --- /dev/null +++ b/contracts/JBSingleTokenPaymentTerminalStore3_1_1.sol @@ -0,0 +1,813 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.16; + +import {ReentrancyGuard} from '@openzeppelin/contracts/security/ReentrancyGuard.sol'; +import {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol'; +import {JBBallotState} from './enums/JBBallotState.sol'; +import {IJBController3_1} from './interfaces/IJBController3_1.sol'; +import {IJBDirectory} from './interfaces/IJBDirectory.sol'; +import {IJBFundingCycleDataSource3_1_1} from './interfaces/IJBFundingCycleDataSource3_1_1.sol'; +import {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol'; +import {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol'; +import {IJBPrices} from './interfaces/IJBPrices.sol'; +import {IJBSingleTokenPaymentTerminal} from './interfaces/IJBSingleTokenPaymentTerminal.sol'; +import {IJBSingleTokenPaymentTerminalStore3_1_1} from './interfaces/IJBSingleTokenPaymentTerminalStore3_1_1.sol'; +import {JBConstants} from './libraries/JBConstants.sol'; +import {JBCurrencies} from './libraries/JBCurrencies.sol'; +import {JBFixedPointNumber} from './libraries/JBFixedPointNumber.sol'; +import {JBFundingCycleMetadataResolver} from './libraries/JBFundingCycleMetadataResolver.sol'; +import {JBFundingCycle} from './structs/JBFundingCycle.sol'; +import {JBPayDelegateAllocation3_1_1} from './structs/JBPayDelegateAllocation3_1_1.sol'; +import {JBPayParamsData} from './structs/JBPayParamsData.sol'; +import {JBRedeemParamsData} from './structs/JBRedeemParamsData.sol'; +import {JBRedemptionDelegateAllocation3_1_1} from './structs/JBRedemptionDelegateAllocation3_1_1.sol'; +import {JBTokenAmount} from './structs/JBTokenAmount.sol'; + +/// @notice Manages all bookkeeping for inflows and outflows of funds from any ISingleTokenPaymentTerminal. +/// @dev This Store expects a project's controller to be an IJBController3_1. +contract JBSingleTokenPaymentTerminalStore3_1_1 is + ReentrancyGuard, + IJBSingleTokenPaymentTerminalStore3_1_1 +{ + // A library that parses the packed funding cycle metadata into a friendlier format. + using JBFundingCycleMetadataResolver for JBFundingCycle; + + //*********************************************************************// + // --------------------------- custom errors ------------------------- // + //*********************************************************************// + error INVALID_AMOUNT_TO_SEND_DELEGATE(); + error CURRENCY_MISMATCH(); + error DISTRIBUTION_AMOUNT_LIMIT_REACHED(); + error FUNDING_CYCLE_PAYMENT_PAUSED(); + error FUNDING_CYCLE_DISTRIBUTION_PAUSED(); + error FUNDING_CYCLE_REDEEM_PAUSED(); + error INADEQUATE_CONTROLLER_ALLOWANCE(); + error INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE(); + error INSUFFICIENT_TOKENS(); + error INVALID_FUNDING_CYCLE(); + error PAYMENT_TERMINAL_MIGRATION_NOT_ALLOWED(); + + //*********************************************************************// + // -------------------------- private constants ---------------------- // + //*********************************************************************// + + /// @notice Ensures a maximum number of decimal points of persisted fidelity on mulDiv operations of fixed point numbers. + uint256 private constant _MAX_FIXED_POINT_FIDELITY = 18; + + //*********************************************************************// + // ---------------- public immutable stored properties --------------- // + //*********************************************************************// + + /// @notice The directory of terminals and controllers for projects. + IJBDirectory public immutable override directory; + + /// @notice The contract storing all funding cycle configurations. + IJBFundingCycleStore public immutable override fundingCycleStore; + + /// @notice The contract that exposes price feeds. + IJBPrices public immutable override prices; + + //*********************************************************************// + // --------------------- public stored properties -------------------- // + //*********************************************************************// + + /// @notice The amount of tokens that each project has for each terminal, in terms of the terminal's token. + /// @dev The balance is represented as a fixed point number with the same amount of decimals as its relative terminal. + /// @custom:param _terminal The terminal to which the balance applies. + /// @custom:param _projectId The ID of the project to get the balance of. + mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => uint256)) public override balanceOf; + + /// @notice The amount of funds that a project has distributed from its limit during the current funding cycle for each terminal, in terms of the distribution limit's currency. + /// @dev Increases as projects use their preconfigured distribution limits. + /// @dev The used distribution limit is represented as a fixed point number with the same amount of decimals as its relative terminal. + /// @custom:param _terminal The terminal to which the used distribution limit applies. + /// @custom:param _projectId The ID of the project to get the used distribution limit of. + /// @custom:param _fundingCycleNumber The number of the funding cycle during which the distribution limit was used. + mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => mapping(uint256 => uint256))) + public + override usedDistributionLimitOf; + + /// @notice The amount of funds that a project has used from its allowance during the current funding cycle configuration for each terminal, in terms of the overflow allowance's currency. + /// @dev Increases as projects use their allowance. + /// @dev The used allowance is represented as a fixed point number with the same amount of decimals as its relative terminal. + /// @custom:param _terminal The terminal to which the overflow allowance applies. + /// @custom:param _projectId The ID of the project to get the used overflow allowance of. + /// @custom:param _configuration The configuration of the during which the allowance was used. + mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => mapping(uint256 => uint256))) + public + override usedOverflowAllowanceOf; + + //*********************************************************************// + // ------------------------- external views -------------------------- // + //*********************************************************************// + + /// @notice Gets the current overflowed amount in a terminal for a specified project. + /// @dev The current overflow is represented as a fixed point number with the same amount of decimals as the specified terminal. + /// @param _terminal The terminal for which the overflow is being calculated. + /// @param _projectId The ID of the project to get overflow for. + /// @return The current amount of overflow that project has in the specified terminal. + function currentOverflowOf( + IJBSingleTokenPaymentTerminal _terminal, + uint256 _projectId + ) external view override returns (uint256) { + // Return the overflow during the project's current funding cycle. + return + _overflowDuring( + _terminal, + _projectId, + fundingCycleStore.currentOf(_projectId), + _terminal.currency() + ); + } + + /// @notice Gets the current overflowed amount for a specified project across all terminals. + /// @param _projectId The ID of the project to get total overflow for. + /// @param _decimals The number of decimals that the fixed point overflow should include. + /// @param _currency The currency that the total overflow should be in terms of. + /// @return The current total amount of overflow that project has across all terminals. + function currentTotalOverflowOf( + uint256 _projectId, + uint256 _decimals, + uint256 _currency + ) external view override returns (uint256) { + return _currentTotalOverflowOf(_projectId, _decimals, _currency); + } + + /// @notice The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the total token supply and overflow in the ecosystem. + /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used. + /// @dev The current reclaimable overflow is returned in terms of the specified terminal's currency. + /// @dev The reclaimable overflow is represented as a fixed point number with the same amount of decimals as the specified terminal. + /// @param _terminal The terminal from which the reclaimable amount would come. + /// @param _projectId The ID of the project to get the reclaimable overflow amount for. + /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals. + /// @param _useTotalOverflow A flag indicating whether the overflow used in the calculation should be summed from all of the project's terminals. If false, overflow should be limited to the amount in the specified `_terminal`. + /// @return The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_terminal`. + function currentReclaimableOverflowOf( + IJBSingleTokenPaymentTerminal _terminal, + uint256 _projectId, + uint256 _tokenCount, + bool _useTotalOverflow + ) external view override returns (uint256) { + // Get a reference to the project's current funding cycle. + JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId); + + // Get the amount of current overflow. + // Use the project's total overflow across all of its terminals if the flag species specifies so. Otherwise, use the overflow local to the specified terminal. + uint256 _currentOverflow = _useTotalOverflow + ? _currentTotalOverflowOf(_projectId, _terminal.decimals(), _terminal.currency()) + : _overflowDuring(_terminal, _projectId, _fundingCycle, _terminal.currency()); + + // If there's no overflow, there's no reclaimable overflow. + if (_currentOverflow == 0) return 0; + + // Get the number of outstanding tokens the project has. + uint256 _totalSupply = IJBController3_1(directory.controllerOf(_projectId)) + .totalOutstandingTokensOf(_projectId); + + // Can't redeem more tokens that is in the supply. + if (_tokenCount > _totalSupply) return 0; + + // Return the reclaimable overflow amount. + return + _reclaimableOverflowDuring( + _projectId, + _fundingCycle, + _tokenCount, + _totalSupply, + _currentOverflow + ); + } + + /// @notice The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the specified total token supply and overflow amounts. + /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used. + /// @param _projectId The ID of the project to get the reclaimable overflow amount for. + /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals. + /// @param _totalSupply The total number of tokens to make the calculation with, as a fixed point number with 18 decimals. + /// @param _overflow The amount of overflow to make the calculation with, as a fixed point number. + /// @return The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_overflow`. + function currentReclaimableOverflowOf( + uint256 _projectId, + uint256 _tokenCount, + uint256 _totalSupply, + uint256 _overflow + ) external view override returns (uint256) { + // If there's no overflow, there's no reclaimable overflow. + if (_overflow == 0) return 0; + + // Can't redeem more tokens that is in the supply. + if (_tokenCount > _totalSupply) return 0; + + // Get a reference to the project's current funding cycle. + JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId); + + // Return the reclaimable overflow amount. + return + _reclaimableOverflowDuring(_projectId, _fundingCycle, _tokenCount, _totalSupply, _overflow); + } + + //*********************************************************************// + // -------------------------- constructor ---------------------------- // + //*********************************************************************// + + /// @param _directory A contract storing directories of terminals and controllers for each project. + /// @param _fundingCycleStore A contract storing all funding cycle configurations. + /// @param _prices A contract that exposes price feeds. + constructor(IJBDirectory _directory, IJBFundingCycleStore _fundingCycleStore, IJBPrices _prices) { + directory = _directory; + fundingCycleStore = _fundingCycleStore; + prices = _prices; + } + + //*********************************************************************// + // ---------------------- external transactions ---------------------- // + //*********************************************************************// + + /// @notice Records newly contributed tokens to a project. + /// @dev Mints the project's tokens according to values provided by a configured data source. If no data source is configured, mints tokens proportional to the amount of the contribution. + /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.sender's tokens. + /// @param _payer The original address that sent the payment to the terminal. + /// @param _amount The amount of tokens being paid. Includes the token being paid, the value, the number of decimals included, and the currency of the amount. + /// @param _projectId The ID of the project being paid. + /// @param _baseWeightCurrency The currency to base token issuance on. + /// @param _beneficiary The specified address that should be the beneficiary of anything that results from the payment. + /// @param _memo A memo to pass along to the emitted event, and passed along to the funding cycle's data source. + /// @param _metadata Bytes to send along to the data source, if one is provided. + /// @return fundingCycle The project's funding cycle during which payment was made. + /// @return tokenCount The number of project tokens that were minted, as a fixed point number with 18 decimals. + /// @return delegateAllocations The amount to send to delegates instead of adding to the local balance. + /// @return memo A memo that should be passed along to the emitted event. + function recordPaymentFrom( + address _payer, + JBTokenAmount calldata _amount, + uint256 _projectId, + uint256 _baseWeightCurrency, + address _beneficiary, + string calldata _memo, + bytes memory _metadata + ) + external + override + nonReentrant + returns ( + JBFundingCycle memory fundingCycle, + uint256 tokenCount, + JBPayDelegateAllocation3_1_1[] memory delegateAllocations, + string memory memo + ) + { + // Get a reference to the current funding cycle for the project. + fundingCycle = fundingCycleStore.currentOf(_projectId); + + // The project must have a funding cycle configured. + if (fundingCycle.number == 0) revert INVALID_FUNDING_CYCLE(); + + // Must not be paused. + if (fundingCycle.payPaused()) revert FUNDING_CYCLE_PAYMENT_PAUSED(); + + // The weight according to which new token supply is to be minted, as a fixed point number with 18 decimals. + uint256 _weight; + + // If the funding cycle has configured a data source, use it to derive a weight and memo. + if (fundingCycle.useDataSourceForPay() && fundingCycle.dataSource() != address(0)) { + // Create the params that'll be sent to the data source. + JBPayParamsData memory _data = JBPayParamsData( + IJBSingleTokenPaymentTerminal(msg.sender), + _payer, + _amount, + _projectId, + fundingCycle.configuration, + _beneficiary, + fundingCycle.weight, + fundingCycle.reservedRate(), + _memo, + _metadata + ); + (_weight, memo, delegateAllocations) = IJBFundingCycleDataSource3_1_1( + fundingCycle.dataSource() + ).payParams(_data); + } + // Otherwise use the funding cycle's weight + else { + _weight = fundingCycle.weight; + memo = _memo; + } + + // Scoped section prevents stack too deep. `_balanceDiff` only used within scope. + { + // Keep a reference to the amount that should be added to the project's balance. + uint256 _balanceDiff = _amount.value; + + // Validate all delegated amounts. This needs to be done before returning the delegate allocations to ensure valid delegated amounts. + if (delegateAllocations.length != 0) { + for (uint256 _i; _i < delegateAllocations.length; ) { + // Get a reference to the amount to be delegated. + uint256 _delegatedAmount = delegateAllocations[_i].amount; + + // Validate if non-zero. + if (_delegatedAmount != 0) { + // Can't delegate more than was paid. + if (_delegatedAmount > _balanceDiff) revert INVALID_AMOUNT_TO_SEND_DELEGATE(); + + // Decrement the total amount being added to the balance. + _balanceDiff = _balanceDiff - _delegatedAmount; + } + + unchecked { + ++_i; + } + } + } + + // If there's no amount being recorded, there's nothing left to do. + if (_amount.value == 0) return (fundingCycle, 0, delegateAllocations, memo); + + // Add the correct balance difference to the token balance of the project. + if (_balanceDiff != 0) + balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] = + balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] + + _balanceDiff; + } + + // If there's no weight, token count must be 0 so there's nothing left to do. + if (_weight == 0) return (fundingCycle, 0, delegateAllocations, memo); + + // Get a reference to the number of decimals in the amount. (prevents stack too deep). + uint256 _decimals = _amount.decimals; + + // If the terminal should base its weight on a different currency from the terminal's currency, determine the factor. + // The weight is always a fixed point mumber with 18 decimals. To ensure this, the ratio should use the same number of decimals as the `_amount`. + uint256 _weightRatio = _amount.currency == _baseWeightCurrency + ? 10 ** _decimals + : prices.priceFor(_amount.currency, _baseWeightCurrency, _decimals); + + // Find the number of tokens to mint, as a fixed point number with as many decimals as `weight` has. + tokenCount = PRBMath.mulDiv(_amount.value, _weight, _weightRatio); + } + + /// @notice Records newly redeemed tokens of a project. + /// @dev Redeems the project's tokens according to values provided by a configured data source. If no data source is configured, redeems tokens along a redemption bonding curve that is a function of the number of tokens being burned. + /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.senders tokens. + /// @param _holder The account that is having its tokens redeemed. + /// @param _projectId The ID of the project to which the tokens being redeemed belong. + /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals. + /// @param _memo A memo to pass along to the emitted event. + /// @param _metadata Bytes to send along to the data source, if one is provided. + /// @return fundingCycle The funding cycle during which the redemption was made. + /// @return reclaimAmount The amount of terminal tokens reclaimed, as a fixed point number with 18 decimals. + /// @return delegateAllocations The amount to send to delegates instead of sending to the beneficiary. + /// @return memo A memo that should be passed along to the emitted event. + function recordRedemptionFor( + address _holder, + uint256 _projectId, + uint256 _tokenCount, + string memory _memo, + bytes memory _metadata + ) + external + override + nonReentrant + returns ( + JBFundingCycle memory fundingCycle, + uint256 reclaimAmount, + JBRedemptionDelegateAllocation3_1_1[] memory delegateAllocations, + string memory memo + ) + { + // Get a reference to the project's current funding cycle. + fundingCycle = fundingCycleStore.currentOf(_projectId); + + // The current funding cycle must not be paused. + if (fundingCycle.redeemPaused()) revert FUNDING_CYCLE_REDEEM_PAUSED(); + + // Scoped section prevents stack too deep. `_reclaimedTokenAmount`, `_currentOverflow`, and `_totalSupply` only used within scope. + { + // Get a reference to the reclaimed token amount struct, the current overflow, and the total token supply. + JBTokenAmount memory _reclaimedTokenAmount; + uint256 _currentOverflow; + uint256 _totalSupply; + + // Another scoped section prevents stack too deep. `_token`, `_decimals`, and `_currency` only used within scope. + { + // Get a reference to the terminal's tokens. + address _token = IJBSingleTokenPaymentTerminal(msg.sender).token(); + + // Get a reference to the terminal's decimals. + uint256 _decimals = IJBSingleTokenPaymentTerminal(msg.sender).decimals(); + + // Get areference to the terminal's currency. + uint256 _currency = IJBSingleTokenPaymentTerminal(msg.sender).currency(); + + // Get the amount of current overflow. + // Use the local overflow if the funding cycle specifies that it should be used. Otherwise, use the project's total overflow across all of its terminals. + _currentOverflow = fundingCycle.useTotalOverflowForRedemptions() + ? _currentTotalOverflowOf(_projectId, _decimals, _currency) + : _overflowDuring( + IJBSingleTokenPaymentTerminal(msg.sender), + _projectId, + fundingCycle, + _currency + ); + + // Get the number of outstanding tokens the project has. + _totalSupply = IJBController3_1(directory.controllerOf(_projectId)) + .totalOutstandingTokensOf(_projectId); + + // Can't redeem more tokens that is in the supply. + if (_tokenCount > _totalSupply) revert INSUFFICIENT_TOKENS(); + + if (_currentOverflow != 0) + // Calculate reclaim amount using the current overflow amount. + reclaimAmount = _reclaimableOverflowDuring( + _projectId, + fundingCycle, + _tokenCount, + _totalSupply, + _currentOverflow + ); + + _reclaimedTokenAmount = JBTokenAmount(_token, reclaimAmount, _decimals, _currency); + } + + // If the funding cycle has configured a data source, use it to derive a claim amount and memo. + if (fundingCycle.useDataSourceForRedeem() && fundingCycle.dataSource() != address(0)) { + // Yet another scoped section prevents stack too deep. `_state` only used within scope. + { + // Get a reference to the ballot state. + JBBallotState _state = fundingCycleStore.currentBallotStateOf(_projectId); + + // Create the params that'll be sent to the data source. + JBRedeemParamsData memory _data = JBRedeemParamsData( + IJBSingleTokenPaymentTerminal(msg.sender), + _holder, + _projectId, + fundingCycle.configuration, + _tokenCount, + _totalSupply, + _currentOverflow, + _reclaimedTokenAmount, + fundingCycle.useTotalOverflowForRedemptions(), + _state == JBBallotState.Active + ? fundingCycle.ballotRedemptionRate() + : fundingCycle.redemptionRate(), + _memo, + _metadata + ); + (reclaimAmount, memo, delegateAllocations) = IJBFundingCycleDataSource3_1_1( + fundingCycle.dataSource() + ).redeemParams(_data); + } + } else { + memo = _memo; + } + } + + // Keep a reference to the amount that should be subtracted from the project's balance. + uint256 _balanceDiff = reclaimAmount; + + if (delegateAllocations.length != 0) { + // Validate all delegated amounts. + for (uint256 _i; _i < delegateAllocations.length; ) { + // Get a reference to the amount to be delegated. + uint256 _delegatedAmount = delegateAllocations[_i].amount; + + // Validate if non-zero. + if (_delegatedAmount != 0) + // Increment the total amount being subtracted from the balance. + _balanceDiff = _balanceDiff + _delegatedAmount; + + unchecked { + ++_i; + } + } + } + + // The amount being reclaimed must be within the project's balance. + if (_balanceDiff > balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId]) + revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE(); + + // Remove the reclaimed funds from the project's balance. + if (_balanceDiff != 0) { + unchecked { + balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] = + balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] - + _balanceDiff; + } + } + } + + /// @notice Records newly distributed funds for a project. + /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. + /// @param _projectId The ID of the project that is having funds distributed. + /// @param _amount The amount to use from the distribution limit, as a fixed point number. + /// @param _currency The currency of the `_amount`. This must match the project's current funding cycle's currency. + /// @return fundingCycle The funding cycle during which the distribution was made. + /// @return distributedAmount The amount of terminal tokens distributed, as a fixed point number with the same amount of decimals as its relative terminal. + function recordDistributionFor( + uint256 _projectId, + uint256 _amount, + uint256 _currency + ) + external + override + nonReentrant + returns (JBFundingCycle memory fundingCycle, uint256 distributedAmount) + { + // Get a reference to the project's current funding cycle. + fundingCycle = fundingCycleStore.currentOf(_projectId); + + // The funding cycle must not be configured to have distributions paused. + if (fundingCycle.distributionsPaused()) revert FUNDING_CYCLE_DISTRIBUTION_PAUSED(); + + // The new total amount that has been distributed during this funding cycle. + uint256 _newUsedDistributionLimitOf = usedDistributionLimitOf[ + IJBSingleTokenPaymentTerminal(msg.sender) + ][_projectId][fundingCycle.number] + _amount; + + // Amount must be within what is still distributable. + (uint256 _distributionLimitOf, uint256 _distributionLimitCurrencyOf) = IJBController3_1( + directory.controllerOf(_projectId) + ).fundAccessConstraintsStore().distributionLimitOf( + _projectId, + fundingCycle.configuration, + IJBSingleTokenPaymentTerminal(msg.sender), + IJBSingleTokenPaymentTerminal(msg.sender).token() + ); + + // Make sure the new used amount is within the distribution limit. + if (_newUsedDistributionLimitOf > _distributionLimitOf || _distributionLimitOf == 0) + revert DISTRIBUTION_AMOUNT_LIMIT_REACHED(); + + // Make sure the currencies match. + if (_currency != _distributionLimitCurrencyOf) revert CURRENCY_MISMATCH(); + + // Get a reference to the terminal's currency. + uint256 _balanceCurrency = IJBSingleTokenPaymentTerminal(msg.sender).currency(); + + // Convert the amount to the balance's currency. + distributedAmount = (_currency == _balanceCurrency) + ? _amount + : PRBMath.mulDiv( + _amount, + 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting. + prices.priceFor(_currency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY) + ); + + // The amount being distributed must be available. + if (distributedAmount > balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId]) + revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE(); + + // Store the new amount. + usedDistributionLimitOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId][ + fundingCycle.number + ] = _newUsedDistributionLimitOf; + + // Removed the distributed funds from the project's token balance. + unchecked { + balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] = + balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] - + distributedAmount; + } + } + + /// @notice Records newly used allowance funds of a project. + /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. + /// @param _projectId The ID of the project to use the allowance of. + /// @param _amount The amount to use from the allowance, as a fixed point number. + /// @param _currency The currency of the `_amount`. Must match the currency of the overflow allowance. + /// @return fundingCycle The funding cycle during which the overflow allowance is being used. + /// @return usedAmount The amount of terminal tokens used, as a fixed point number with the same amount of decimals as its relative terminal. + function recordUsedAllowanceOf( + uint256 _projectId, + uint256 _amount, + uint256 _currency + ) + external + override + nonReentrant + returns (JBFundingCycle memory fundingCycle, uint256 usedAmount) + { + // Get a reference to the project's current funding cycle. + fundingCycle = fundingCycleStore.currentOf(_projectId); + + // Get a reference to the new used overflow allowance for this funding cycle configuration. + uint256 _newUsedOverflowAllowanceOf = usedOverflowAllowanceOf[ + IJBSingleTokenPaymentTerminal(msg.sender) + ][_projectId][fundingCycle.configuration] + _amount; + + // There must be sufficient allowance available. + (uint256 _overflowAllowanceOf, uint256 _overflowAllowanceCurrency) = IJBController3_1( + directory.controllerOf(_projectId) + ).fundAccessConstraintsStore().overflowAllowanceOf( + _projectId, + fundingCycle.configuration, + IJBSingleTokenPaymentTerminal(msg.sender), + IJBSingleTokenPaymentTerminal(msg.sender).token() + ); + + // Make sure the new used amount is within the allowance. + if (_newUsedOverflowAllowanceOf > _overflowAllowanceOf || _overflowAllowanceOf == 0) + revert INADEQUATE_CONTROLLER_ALLOWANCE(); + + // Make sure the currencies match. + if (_currency != _overflowAllowanceCurrency) revert CURRENCY_MISMATCH(); + + // Get a reference to the terminal's currency. + uint256 _balanceCurrency = IJBSingleTokenPaymentTerminal(msg.sender).currency(); + + // Convert the amount to this store's terminal's token. + usedAmount = (_currency == _balanceCurrency) + ? _amount + : PRBMath.mulDiv( + _amount, + 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting. + prices.priceFor(_currency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY) + ); + + // The amount being distributed must be available in the overflow. + if ( + usedAmount > + _overflowDuring( + IJBSingleTokenPaymentTerminal(msg.sender), + _projectId, + fundingCycle, + _balanceCurrency + ) + ) revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE(); + + // Store the incremented value. + usedOverflowAllowanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId][ + fundingCycle.configuration + ] = _newUsedOverflowAllowanceOf; + + // Update the project's balance. + balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] = + balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] - + usedAmount; + } + + /// @notice Records newly added funds for the project. + /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. + /// @param _projectId The ID of the project to which the funds being added belong. + /// @param _amount The amount of terminal tokens added, as a fixed point number with the same amount of decimals as its relative terminal. + function recordAddedBalanceFor(uint256 _projectId, uint256 _amount) external override { + // Increment the balance. + balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] = + balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] + + _amount; + } + + /// @notice Records the migration of funds from this store. + /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount returned is in terms of the msg.senders tokens. + /// @param _projectId The ID of the project being migrated. + /// @return balance The project's migrated balance, as a fixed point number with the same amount of decimals as its relative terminal. + function recordMigration( + uint256 _projectId + ) external override nonReentrant returns (uint256 balance) { + // Get a reference to the project's current funding cycle. + JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId); + + // Migration must be allowed. + if (!_fundingCycle.terminalMigrationAllowed()) revert PAYMENT_TERMINAL_MIGRATION_NOT_ALLOWED(); + + // Return the current balance. + balance = balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId]; + + // Set the balance to 0. + balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] = 0; + } + + //*********************************************************************// + // --------------------- private helper functions -------------------- // + //*********************************************************************// + + /// @notice The amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens when measured from the specified. + /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used. + /// @param _projectId The ID of the project to get the reclaimable overflow amount for. + /// @param _fundingCycle The funding cycle during which reclaimable overflow is being calculated. + /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals. + /// @param _totalSupply The total supply of tokens to make the calculation with, as a fixed point number with 18 decimals. + /// @param _overflow The amount of overflow to make the calculation with. + /// @return The amount of overflowed tokens that can be reclaimed. + function _reclaimableOverflowDuring( + uint256 _projectId, + JBFundingCycle memory _fundingCycle, + uint256 _tokenCount, + uint256 _totalSupply, + uint256 _overflow + ) private view returns (uint256) { + // If the amount being redeemed is the total supply, return the rest of the overflow. + if (_tokenCount == _totalSupply) return _overflow; + + // Use the ballot redemption rate if the queued cycle is pending approval according to the previous funding cycle's ballot. + uint256 _redemptionRate = fundingCycleStore.currentBallotStateOf(_projectId) == + JBBallotState.Active + ? _fundingCycle.ballotRedemptionRate() + : _fundingCycle.redemptionRate(); + + // If the redemption rate is 0, nothing is claimable. + if (_redemptionRate == 0) return 0; + + // Get a reference to the linear proportion. + uint256 _base = PRBMath.mulDiv(_overflow, _tokenCount, _totalSupply); + + // These conditions are all part of the same curve. Edge conditions are separated because fewer operation are necessary. + if (_redemptionRate == JBConstants.MAX_REDEMPTION_RATE) return _base; + + return + PRBMath.mulDiv( + _base, + _redemptionRate + + PRBMath.mulDiv( + _tokenCount, + JBConstants.MAX_REDEMPTION_RATE - _redemptionRate, + _totalSupply + ), + JBConstants.MAX_REDEMPTION_RATE + ); + } + + /// @notice Gets the amount that is overflowing when measured from the specified funding cycle. + /// @dev This amount changes as the value of the balance changes in relation to the currency being used to measure the distribution limit. + /// @param _terminal The terminal for which the overflow is being calculated. + /// @param _projectId The ID of the project to get overflow for. + /// @param _fundingCycle The ID of the funding cycle to base the overflow on. + /// @param _balanceCurrency The currency that the stored balance is expected to be in terms of. + /// @return overflow The overflow of funds, as a fixed point number with 18 decimals. + function _overflowDuring( + IJBSingleTokenPaymentTerminal _terminal, + uint256 _projectId, + JBFundingCycle memory _fundingCycle, + uint256 _balanceCurrency + ) private view returns (uint256) { + // Get the current balance of the project. + uint256 _balanceOf = balanceOf[_terminal][_projectId]; + + // If there's no balance, there's no overflow. + if (_balanceOf == 0) return 0; + + // Get a reference to the distribution limit during the funding cycle. + (uint256 _distributionLimit, uint256 _distributionLimitCurrency) = IJBController3_1( + directory.controllerOf(_projectId) + ).fundAccessConstraintsStore().distributionLimitOf( + _projectId, + _fundingCycle.configuration, + _terminal, + _terminal.token() + ); + + // Get a reference to the amount still distributable during the funding cycle. + uint256 _distributionLimitRemaining = _distributionLimit - + usedDistributionLimitOf[_terminal][_projectId][_fundingCycle.number]; + + // Convert the _distributionRemaining to be in terms of the provided currency. + if (_distributionLimitRemaining != 0 && _distributionLimitCurrency != _balanceCurrency) + _distributionLimitRemaining = PRBMath.mulDiv( + _distributionLimitRemaining, + 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting. + prices.priceFor(_distributionLimitCurrency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY) + ); + + // Overflow is the balance of this project minus the amount that can still be distributed. + unchecked { + return + _balanceOf > _distributionLimitRemaining ? _balanceOf - _distributionLimitRemaining : 0; + } + } + + /// @notice Gets the amount that is currently overflowing across all of a project's terminals. + /// @dev This amount changes as the value of the balances changes in relation to the currency being used to measure the project's distribution limits. + /// @param _projectId The ID of the project to get the total overflow for. + /// @param _decimals The number of decimals that the fixed point overflow should include. + /// @param _currency The currency that the overflow should be in terms of. + /// @return overflow The total overflow of a project's funds. + function _currentTotalOverflowOf( + uint256 _projectId, + uint256 _decimals, + uint256 _currency + ) private view returns (uint256) { + // Get a reference to the project's terminals. + IJBPaymentTerminal[] memory _terminals = directory.terminalsOf(_projectId); + + // Keep a reference to the ETH overflow across all terminals, as a fixed point number with 18 decimals. + uint256 _ethOverflow; + + // Add the current ETH overflow for each terminal. + for (uint256 _i; _i < _terminals.length; ) { + _ethOverflow = _ethOverflow + _terminals[_i].currentEthOverflowOf(_projectId); + unchecked { + ++_i; + } + } + + // Convert the ETH overflow to the specified currency if needed, maintaining a fixed point number with 18 decimals. + uint256 _totalOverflow18Decimal = _currency == JBCurrencies.ETH + ? _ethOverflow + : PRBMath.mulDiv(_ethOverflow, 10 ** 18, prices.priceFor(JBCurrencies.ETH, _currency, 18)); + + // Adjust the decimals of the fixed point number if needed to match the target decimals. + return + (_decimals == 18) + ? _totalOverflow18Decimal + : JBFixedPointNumber.adjustDecimals(_totalOverflow18Decimal, 18, _decimals); + } +} diff --git a/contracts/JBSplitsStore.sol b/contracts/JBSplitsStore.sol index c8268875c..89a508285 100644 --- a/contracts/JBSplitsStore.sol +++ b/contracts/JBSplitsStore.sol @@ -1,24 +1,18 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.16; -import './abstract/JBOperatable.sol'; -import './interfaces/IJBDirectory.sol'; -import './interfaces/IJBSplitsStore.sol'; -import './libraries/JBConstants.sol'; -import './libraries/JBOperations.sol'; - -/** - @notice - Stores splits for each project. - - @dev - Adheres to - - IJBSplitsStore: General interface for the methods in this contract that interact with the blockchain's state according to the protocol's rules. - - @dev - Inherits from - - JBOperatable: Includes convenience functionality for checking a message sender's permissions before executing certain transactions. -*/ +import {JBOperatable} from './abstract/JBOperatable.sol'; +import {IJBDirectory} from './interfaces/IJBDirectory.sol'; +import {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol'; +import {IJBProjects} from './interfaces/IJBProjects.sol'; +import {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol'; +import {IJBSplitAllocator} from './interfaces/IJBSplitAllocator.sol'; +import {JBConstants} from './libraries/JBConstants.sol'; +import {JBOperations} from './libraries/JBOperations.sol'; +import {JBGroupedSplits} from './structs/JBGroupedSplits.sol'; +import {JBSplit} from './structs/JBSplit.sol'; + +/// @notice Stores splits for each project. contract JBSplitsStore is JBOperatable, IJBSplitsStore { //*********************************************************************// // --------------------------- custom errors ------------------------- // @@ -33,40 +27,26 @@ contract JBSplitsStore is JBOperatable, IJBSplitsStore { // --------------------- private stored properties ------------------- // //*********************************************************************// - /** - @notice - The number of splits currently set for each project ID's configurations. - - _projectId The ID of the project to get the split count for. - _domain An identifier within which the returned splits should be considered active. - _group The identifying group of the splits. - */ + /// @notice The number of splits currently set for each project ID's configurations. + /// @custom:param _projectId The ID of the project to get the split count for. + /// @custom:param _domain An identifier within which the returned splits should be considered active. + /// @custom:param _group The identifying group of the splits. mapping(uint256 => mapping(uint256 => mapping(uint256 => uint256))) private _splitCountOf; - /** - @notice - Packed data of splits for each project ID's configurations. - - _projectId The ID of the project to get packed splits data for. - _domain An identifier within which the returned splits should be considered active. - _group The identifying group of the splits. - _index The indexed order that the split was set at. - */ + /// @notice Packed data of splits for each project ID's configurations. + /// @custom:param _projectId The ID of the project to get packed splits data for. + /// @custom:param _domain An identifier within which the returned splits should be considered active. + /// @custom:param _group The identifying group of the splits. + /// @custom:param _index The indexed order that the split was set at. mapping(uint256 => mapping(uint256 => mapping(uint256 => mapping(uint256 => uint256)))) private _packedSplitParts1Of; - /** - @notice - More packed data of splits for each project ID's configurations. - - @dev - This packed data is often 0. - - _projectId The ID of the project to get packed splits data for. - _domain An identifier within which the returned splits should be considered active. - _group The identifying group of the splits. - _index The indexed order that the split was set at. - */ + /// @notice More packed data of splits for each project ID's configurations. + /// @dev This packed data is often 0. + /// @custom:param _projectId The ID of the project to get packed splits data for. + /// @custom:param _domain An identifier within which the returned splits should be considered active. + /// @custom:param _group The identifying group of the splits. + /// @custom:param _index The indexed order that the split was set at. mapping(uint256 => mapping(uint256 => mapping(uint256 => mapping(uint256 => uint256)))) private _packedSplitParts2Of; @@ -74,32 +54,21 @@ contract JBSplitsStore is JBOperatable, IJBSplitsStore { // ---------------- public immutable stored properties --------------- // //*********************************************************************// - /** - @notice - Mints ERC-721's that represent project ownership and transfers. - */ + /// @notice Mints ERC-721's that represent project ownership and transfers. IJBProjects public immutable override projects; - /** - @notice - The directory of terminals and controllers for projects. - */ + /// @notice The directory of terminals and controllers for projects. IJBDirectory public immutable override directory; //*********************************************************************// // ------------------------- external views -------------------------- // //*********************************************************************// - /** - @notice - Get all splits for the specified project ID, within the specified domain, for the specified group. - - @param _projectId The ID of the project to get splits for. - @param _domain An identifier within which the returned splits should be considered active. - @param _group The identifying group of the splits. - - @return An array of all splits for the project. -*/ + /// @notice Get all splits for the specified project ID, within the specified domain, for the specified group. + /// @param _projectId The ID of the project to get splits for. + /// @param _domain An identifier within which the returned splits should be considered active. + /// @param _group The identifying group of the splits. + /// @return An array of all splits for the project. function splitsOf( uint256 _projectId, uint256 _domain, @@ -112,11 +81,9 @@ contract JBSplitsStore is JBOperatable, IJBSplitsStore { // -------------------------- constructor ---------------------------- // //*********************************************************************// - /** - @param _operatorStore A contract storing operator assignments. - @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 _operatorStore A contract storing operator assignments. + /// @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. constructor( IJBOperatorStore _operatorStore, IJBProjects _projects, @@ -130,20 +97,12 @@ contract JBSplitsStore is JBOperatable, IJBSplitsStore { // ---------------------- external transactions ---------------------- // //*********************************************************************// - /** - @notice - Sets a project's splits. - - @dev - Only the owner or operator of a project, or the current controller contract of the project, can set its splits. - - @dev - The new splits must include any currently set splits that are locked. - - @param _projectId The ID of the project for which splits are being added. - @param _domain An identifier within which the splits should be considered active. - @param _groupedSplits An array of splits to set for any number of groups. - */ + /// @notice Sets a project's splits. + /// @dev Only the owner or operator of a project, or the current controller contract of the project, can set its splits. + /// @dev The new splits must include any currently set splits that are locked. + /// @param _projectId The ID of the project for which splits are being added. + /// @param _domain An identifier within which the splits should be considered active. + /// @param _groupedSplits An array of splits to set for any number of groups. function set( uint256 _projectId, uint256 _domain, @@ -179,18 +138,12 @@ contract JBSplitsStore is JBOperatable, IJBSplitsStore { // --------------------- private helper functions -------------------- // //*********************************************************************// - /** - @notice - Sets a project's splits. - - @dev - The new splits must include any currently set splits that are locked. - - @param _projectId The ID of the project for which splits are being added. - @param _domain An identifier within which the splits should be considered active. - @param _group An identifier between of splits being set. All splits within this _group must add up to within 100%. - @param _splits The splits to set. - */ + /// @notice Sets a project's splits. + /// @dev The new splits must include any currently set splits that are locked. + /// @param _projectId The ID of the project for which splits are being added. + /// @param _domain An identifier within which the splits should be considered active. + /// @param _group An identifier between of splits being set. All splits within this _group must add up to within 100%. + /// @param _splits The splits to set. function _set( uint256 _projectId, uint256 _domain, @@ -279,20 +232,14 @@ contract JBSplitsStore is JBOperatable, IJBSplitsStore { _splitCountOf[_projectId][_domain][_group] = _splitsLength; } - /** - @notice - A flag indiciating if the provided splits array includes the locked split. - - @param _splits The array of splits to check within. - @param _lockedSplit The locked split. - - @return A flag indicating if the `_lockedSplit` is contained in the `_splits`. - */ - function _includesLocked(JBSplit[] memory _splits, JBSplit memory _lockedSplit) - private - pure - returns (bool) - { + /// @notice A flag indiciating if the provided splits array includes the locked split. + /// @param _splits The array of splits to check within. + /// @param _lockedSplit The locked split. + /// @return A flag indicating if the `_lockedSplit` is contained in the `_splits`. + function _includesLocked( + JBSplit[] memory _splits, + JBSplit memory _lockedSplit + ) private pure returns (bool) { // Keep a reference to the number of splits. uint256 _numberOfSplits = _splits.length; @@ -317,16 +264,11 @@ contract JBSplitsStore is JBOperatable, IJBSplitsStore { return false; } - /** - @notice - Unpack splits' packed stored values into easy-to-work-with split structs. - - @param _projectId The ID of the project to which the split belongs. - @param _domain The identifier within which the returned splits should be considered active. - @param _group The identifying group of the splits. - - @return splits The split structs. - */ + /// @notice Unpack splits' packed stored values into easy-to-work-with split structs. + /// @param _projectId The ID of the project to which the split belongs. + /// @param _domain The identifier within which the returned splits should be considered active. + /// @param _group The identifying group of the splits. + /// @return splits The split structs. function _getStructsFor( uint256 _projectId, uint256 _domain, diff --git a/contracts/JBToken.sol b/contracts/JBToken.sol index 594e29cd3..59320f933 100644 --- a/contracts/JBToken.sol +++ b/contracts/JBToken.sol @@ -1,23 +1,11 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.16; -import '@openzeppelin/contracts/access/Ownable.sol'; -import '@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.sol'; -import './interfaces/IJBToken.sol'; - -/** - @notice - An ERC-20 token that can be used by a project in the `JBTokenStore`. - - @dev - Adheres to - - IJBToken: Allows this contract to be used by projects in the JBTokenStore. - - @dev - Inherits from - - ERC20Votes: General token standard for fungible membership with snapshot capabilities sufficient to interact with standard governance contracts. - Ownable: Includes convenience functionality for checking a message sender's permissions before executing certain transactions. -*/ +import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol'; +import {ERC20Votes, ERC20, ERC20Permit} from '@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.sol'; +import {IJBToken} from './interfaces/IJBToken.sol'; + +/// @notice An ERC-20 token that can be used by a project in the `JBTokenStore`. contract JBToken is ERC20Votes, Ownable, IJBToken { //*********************************************************************// // --------------------------- custom errors ------------------------- // @@ -28,45 +16,30 @@ contract JBToken is ERC20Votes, Ownable, IJBToken { // --------------------- public stored properties -------------------- // //*********************************************************************// - /** - @notice - The ID of the project that this token should be exclusively used for. Send 0 to support any project. - */ + /// @notice The ID of the project that this token should be exclusively used for. Send 0 to support any project. uint256 public immutable override projectId; //*********************************************************************// // ------------------------- external views -------------------------- // //*********************************************************************// - /** - @notice - The total supply of this ERC20. - - @param _projectId the ID of the project to which the token belongs. This is ignored. - - @return The total supply of this ERC20, as a fixed point number. - */ + /// @notice The total supply of this ERC20. + /// @param _projectId the ID of the project to which the token belongs. This is ignored. + /// @return The total supply of this ERC20, as a fixed point number. function totalSupply(uint256 _projectId) external view override returns (uint256) { _projectId; // Prevents unused var compiler and natspec complaints. return super.totalSupply(); } - /** - @notice - An account's balance of this ERC20. - - @param _account The account to get a balance of. - @param _projectId is the ID of the project to which the token belongs. This is ignored. - - @return The balance of the `_account` of this ERC20, as a fixed point number with 18 decimals. - */ - function balanceOf(address _account, uint256 _projectId) - external - view - override - returns (uint256) - { + /// @notice An account's balance of this ERC20. + /// @param _account The account to get a balance of. + /// @param _projectId is the ID of the project to which the token belongs. This is ignored. + /// @return The balance of the `_account` of this ERC20, as a fixed point number with 18 decimals. + function balanceOf( + address _account, + uint256 _projectId + ) external view override returns (uint256) { _account; // Prevents unused var compiler and natspec complaints. _projectId; // Prevents unused var compiler and natspec complaints. @@ -77,12 +50,8 @@ contract JBToken is ERC20Votes, Ownable, IJBToken { // -------------------------- public views --------------------------- // //*********************************************************************// - /** - @notice - The number of decimals included in the fixed point accounting of this token. - - @return The number of decimals. - */ + /// @notice The number of decimals included in the fixed point accounting of this token. + /// @return The number of decimals. function decimals() public view override(ERC20, IJBToken) returns (uint8) { return super.decimals(); } @@ -91,11 +60,9 @@ contract JBToken is ERC20Votes, Ownable, IJBToken { // -------------------------- constructor ---------------------------- // //*********************************************************************// - /** - @param _name The name of the token. - @param _symbol The symbol that the token should be represented by. - @param _projectId The ID of the project that this token should be exclusively used for. Send 0 to support any project. - */ + /// @param _name The name of the token. + /// @param _symbol The symbol that the token should be represented by. + /// @param _projectId The ID of the project that this token should be exclusively used for. Send 0 to support any project. constructor( string memory _name, string memory _symbol, @@ -108,97 +75,57 @@ contract JBToken is ERC20Votes, Ownable, IJBToken { // ---------------------- external transactions ---------------------- // //*********************************************************************// - /** - @notice - Mints more of the token. - - @dev - Only the owner of this contract cant mint more of it. - - @param _projectId The ID of the project to which the token belongs. - @param _account The account to mint the tokens for. - @param _amount The amount of tokens to mint, as a fixed point number with 18 decimals. - */ - function mint( - uint256 _projectId, - address _account, - uint256 _amount - ) external override onlyOwner { + /// @notice Mints more of the token. + /// @dev Only the owner of this contract cant mint more of it. + /// @param _projectId The ID of the project to which the token belongs. + /// @param _account The account to mint the tokens for. + /// @param _amount The amount of tokens to mint, as a fixed point number with 18 decimals. + function mint(uint256 _projectId, address _account, uint256 _amount) external override onlyOwner { // Can't mint for a wrong project. if (projectId != 0 && _projectId != projectId) revert BAD_PROJECT(); return _mint(_account, _amount); } - /** - @notice - Burn some outstanding tokens. - - @dev - Only the owner of this contract cant burn some of its supply. - - @param _projectId The ID of the project to which the token belongs. - @param _account The account to burn tokens from. - @param _amount The amount of tokens to burn, as a fixed point number with 18 decimals. - */ - function burn( - uint256 _projectId, - address _account, - uint256 _amount - ) external override onlyOwner { + /// @notice Burn some outstanding tokens. + /// @dev Only the owner of this contract cant burn some of its supply. + /// @param _projectId The ID of the project to which the token belongs. + /// @param _account The account to burn tokens from. + /// @param _amount The amount of tokens to burn, as a fixed point number with 18 decimals. + function burn(uint256 _projectId, address _account, uint256 _amount) external override onlyOwner { // Can't burn for a wrong project. if (projectId != 0 && _projectId != projectId) revert BAD_PROJECT(); return _burn(_account, _amount); } - /** - @notice - Approves an account to spend tokens on the `msg.sender`s behalf. - - @param _projectId the ID of the project to which the token belongs. - @param _spender The address that will be spending tokens on the `msg.sender`s behalf. - @param _amount The amount the `_spender` is allowed to spend. - */ - function approve( - uint256 _projectId, - address _spender, - uint256 _amount - ) external override { + /// @notice Approves an account to spend tokens on the `msg.sender`s behalf. + /// @param _projectId the ID of the project to which the token belongs. + /// @param _spender The address that will be spending tokens on the `msg.sender`s behalf. + /// @param _amount The amount the `_spender` is allowed to spend. + function approve(uint256 _projectId, address _spender, uint256 _amount) external override { // Can't approve for a wrong project. if (projectId != 0 && _projectId != projectId) revert BAD_PROJECT(); approve(_spender, _amount); } - /** - @notice - Transfer tokens to an account. - - @param _projectId The ID of the project to which the token belongs. - @param _to The destination address. - @param _amount The amount of the transfer, as a fixed point number with 18 decimals. - */ - function transfer( - uint256 _projectId, - address _to, - uint256 _amount - ) external override { + /// @notice Transfer tokens to an account. + /// @param _projectId The ID of the project to which the token belongs. + /// @param _to The destination address. + /// @param _amount The amount of the transfer, as a fixed point number with 18 decimals. + function transfer(uint256 _projectId, address _to, uint256 _amount) external override { // Can't transfer for a wrong project. if (projectId != 0 && _projectId != projectId) revert BAD_PROJECT(); transfer(_to, _amount); } - /** - @notice - Transfer tokens between accounts. - - @param _projectId The ID of the project to which the token belongs. - @param _from The originating address. - @param _to The destination address. - @param _amount The amount of the transfer, as a fixed point number with 18 decimals. - */ + /// @notice Transfer tokens between accounts. + /// @param _projectId The ID of the project to which the token belongs. + /// @param _from The originating address. + /// @param _to The destination address. + /// @param _amount The amount of the transfer, as a fixed point number with 18 decimals. function transferFrom( uint256 _projectId, address _from, diff --git a/contracts/JBTokenStore.sol b/contracts/JBTokenStore.sol index ef52d0638..a7e010798 100644 --- a/contracts/JBTokenStore.sol +++ b/contracts/JBTokenStore.sol @@ -1,36 +1,23 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.16; -import './abstract/JBControllerUtility.sol'; -import './abstract/JBOperatable.sol'; -import './interfaces/IJBTokenStore.sol'; -import './libraries/JBFundingCycleMetadataResolver.sol'; -import './libraries/JBOperations.sol'; -import './JBToken.sol'; - -/** - @notice - Manage token minting, burning, and account balances. - - @dev - Token balances can be either represented internally or claimed as ERC-20s into wallets. - This contract manages these two representations and allows claiming. - - @dev - The total supply of a project's tokens and the balance of each account are calculated in this contract. - - @dev - Each project can bring their own token if they prefer, and swap between tokens at any time. - - @dev - Adheres to - - IJBTokenStore: General interface for the methods in this contract that interact with the blockchain's state according to the protocol's rules. - - @dev - Inherits from - - JBControllerUtility: Includes convenience functionality for checking if the message sender is the current controller of the project whose data is being manipulated. - JBOperatable: Includes convenience functionality for checking a message sender's permissions before executing certain transactions. -*/ +import {JBControllerUtility} from './abstract/JBControllerUtility.sol'; +import {JBOperatable} from './abstract/JBOperatable.sol'; +import {IJBDirectory} from './interfaces/IJBDirectory.sol'; +import {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol'; +import {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol'; +import {IJBProjects} from './interfaces/IJBProjects.sol'; +import {IJBToken} from './interfaces/IJBToken.sol'; +import {IJBTokenStore} from './interfaces/IJBTokenStore.sol'; +import {JBFundingCycleMetadataResolver} from './libraries/JBFundingCycleMetadataResolver.sol'; +import {JBOperations} from './libraries/JBOperations.sol'; +import {JBFundingCycle} from './structs/JBFundingCycle.sol'; +import {JBToken} from './JBToken.sol'; + +/// @notice Manage token minting, burning, and account balances. +/// @dev Token balances can be either represented internally or claimed as ERC-20s into wallets. This contract manages these two representations and allows claiming. +/// @dev The total supply of a project's tokens and the balance of each account are calculated in this contract. +/// @dev Each project can bring their own token if they prefer, and swap between tokens at any time. contract JBTokenStore is JBControllerUtility, JBOperatable, IJBTokenStore { // A library that parses the packed funding cycle metadata into a friendlier format. using JBFundingCycleMetadataResolver for JBFundingCycle; @@ -55,60 +42,37 @@ contract JBTokenStore is JBControllerUtility, JBOperatable, IJBTokenStore { // ---------------- public immutable stored properties --------------- // //*********************************************************************// - /** - @notice - Mints ERC-721's that represent project ownership and transfers. - */ + /// @notice Mints ERC-721's that represent project ownership and transfers. IJBProjects public immutable override projects; - /** - @notice - The contract storing all funding cycle configurations. - */ + /// @notice The contract storing all funding cycle configurations. IJBFundingCycleStore public immutable override fundingCycleStore; //*********************************************************************// // --------------------- public stored properties -------------------- // //*********************************************************************// - /** - @notice - Each project's attached token contract. - - _projectId The ID of the project to which the token belongs. - */ + /// @notice Each project's attached token contract. + /// @custom:param _projectId The ID of the project to which the token belongs. mapping(uint256 => IJBToken) public override tokenOf; - /** - @notice - The total supply of unclaimed tokens for each project. - - _projectId The ID of the project to which the token belongs. - */ + /// @notice The total supply of unclaimed tokens for each project. + /// @custom:param _projectId The ID of the project to which the token belongs. mapping(uint256 => uint256) public override unclaimedTotalSupplyOf; - /** - @notice - Each holder's balance of unclaimed tokens for each project. - - _holder The holder of balance. - _projectId The ID of the project to which the token belongs. - */ + /// @notice Each holder's balance of unclaimed tokens for each project. + /// @custom:param _holder The holder of balance. + /// @custom:param _projectId The ID of the project to which the token belongs. mapping(address => mapping(uint256 => uint256)) public override unclaimedBalanceOf; //*********************************************************************// // ------------------------- external views -------------------------- // //*********************************************************************// - /** - @notice - The total balance of tokens a holder has for a specified project, including claimed and unclaimed tokens. - - @param _holder The token holder to get a balance for. - @param _projectId The project to get the `_holder`s balance of. - - @return balance The project token balance of the `_holder - */ + /// @notice The total balance of tokens a holder has for a specified project, including claimed and unclaimed tokens. + /// @param _holder The token holder to get a balance for. + /// @param _projectId The project to get the `_holder`s balance of. + /// @return balance The project token balance of the `_holder function balanceOf(address _holder, uint256 _projectId) external view @@ -129,14 +93,9 @@ contract JBTokenStore is JBControllerUtility, JBOperatable, IJBTokenStore { // --------------------------- public views -------------------------- // //*********************************************************************// - /** - @notice - The total supply of tokens for each project, including claimed and unclaimed tokens. - - @param _projectId The ID of the project to get the total token supply of. - - @return totalSupply The total supply of the project's tokens. - */ + /// @notice The total supply of tokens for each project, including claimed and unclaimed tokens. + /// @param _projectId The ID of the project to get the total token supply of. + /// @return totalSupply The total supply of the project's tokens. function totalSupplyOf(uint256 _projectId) public view override returns (uint256 totalSupply) { // Get a reference to the total supply of the project's unclaimed tokens. totalSupply = unclaimedTotalSupplyOf[_projectId]; @@ -152,12 +111,10 @@ contract JBTokenStore is JBControllerUtility, JBOperatable, IJBTokenStore { // -------------------------- constructor ---------------------------- // //*********************************************************************// - /** - @param _operatorStore A contract storing operator assignments. - @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 _fundingCycleStore A contract storing all funding cycle configurations. - */ + /// @param _operatorStore A contract storing operator assignments. + /// @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 _fundingCycleStore A contract storing all funding cycle configurations. constructor( IJBOperatorStore _operatorStore, IJBProjects _projects, @@ -172,22 +129,13 @@ contract JBTokenStore is JBControllerUtility, JBOperatable, IJBTokenStore { // ---------------------- external transactions ---------------------- // //*********************************************************************// - /** - @notice - Issues a project's ERC-20 tokens that'll be used when claiming tokens. - - @dev - Deploys a project's ERC-20 token contract. - - @dev - Only a project's owner or operator can issue its token. - - @param _projectId The ID of the project being issued tokens. - @param _name The ERC-20's name. - @param _symbol The ERC-20's symbol. - - @return token The token that was issued. - */ + /// @notice Issues a project's ERC-20 tokens that'll be used when claiming tokens. + /// @dev Deploys a project's ERC-20 token contract. + /// @dev Only a project's owner or operator can issue its token. + /// @param _projectId The ID of the project being issued tokens. + /// @param _name The ERC-20's name. + /// @param _symbol The ERC-20's symbol. + /// @return token The token that was issued. function issueFor( uint256 _projectId, string calldata _name, @@ -203,7 +151,7 @@ contract JBTokenStore is JBControllerUtility, JBOperatable, IJBTokenStore { // There must be a symbol. if (bytes(_symbol).length == 0) revert EMPTY_SYMBOL(); - + // The project shouldn't already have a token. if (tokenOf[_projectId] != IJBToken(address(0))) revert PROJECT_ALREADY_HAS_TOKEN(); @@ -216,16 +164,10 @@ contract JBTokenStore is JBControllerUtility, JBOperatable, IJBTokenStore { emit Issue(_projectId, token, _name, _symbol, msg.sender); } - /** - @notice - Set a project's token if not already set. - - @dev - Only a project's owner or operator can set its token. - - @param _projectId The ID of the project to which the set token belongs. - @param _token The new token. - */ + /// @notice Set a project's token if not already set. + /// @dev Only a project's owner or operator can set its token. + /// @param _projectId The ID of the project to which the set token belongs. + /// @param _token The new token. function setFor(uint256 _projectId, IJBToken _token) external override @@ -246,18 +188,12 @@ contract JBTokenStore is JBControllerUtility, JBOperatable, IJBTokenStore { emit Set(_projectId, _token, msg.sender); } - /** - @notice - Mint new project tokens. - - @dev - Only a project's current controller can mint its tokens. - - @param _holder The address receiving the new tokens. - @param _projectId The ID of the project to which the tokens belong. - @param _amount The amount of tokens to mint. - @param _preferClaimedTokens A flag indicating whether there's a preference for minted tokens to be claimed automatically into the `_holder`s wallet if the project currently has a token contract attached. - */ + /// @notice Mint new project tokens. + /// @dev Only a project's current controller can mint its tokens. + /// @param _holder The address receiving the new tokens. + /// @param _projectId The ID of the project to which the tokens belong. + /// @param _amount The amount of tokens to mint. + /// @param _preferClaimedTokens A flag indicating whether there's a preference for minted tokens to be claimed automatically into the `_holder`s wallet if the project currently has a token contract attached. function mintFor( address _holder, uint256 _projectId, @@ -285,18 +221,12 @@ contract JBTokenStore is JBControllerUtility, JBOperatable, IJBTokenStore { emit Mint(_holder, _projectId, _amount, _shouldClaimTokens, _preferClaimedTokens, msg.sender); } - /** - @notice - Burns a project's tokens. - - @dev - Only a project's current controller can burn its tokens. - - @param _holder The address that owns the tokens being burned. - @param _projectId The ID of the project to which the burned tokens belong. - @param _amount The amount of tokens to burn. - @param _preferClaimedTokens A flag indicating whether there's a preference for tokens to burned from the `_holder`s wallet if the project currently has a token contract attached. - */ + /// @notice Burns a project's tokens. + /// @dev Only a project's current controller can burn its tokens. + /// @param _holder The address that owns the tokens being burned. + /// @param _projectId The ID of the project to which the burned tokens belong. + /// @param _amount The amount of tokens to burn. + /// @param _preferClaimedTokens A flag indicating whether there's a preference for tokens to burned from the `_holder`s wallet if the project currently has a token contract attached. function burnFrom( address _holder, uint256 _projectId, @@ -363,17 +293,11 @@ contract JBTokenStore is JBControllerUtility, JBOperatable, IJBTokenStore { ); } - /** - @notice - Claims internally accounted for tokens into a holder's wallet. - - @dev - Only a token holder or an operator specified by the token holder can claim its unclaimed tokens. - - @param _holder The owner of the tokens being claimed. - @param _projectId The ID of the project whose tokens are being claimed. - @param _amount The amount of tokens to claim. - */ + /// @notice Claims internally accounted for tokens into a holder's wallet. + /// @dev Only a token holder or an operator specified by the token holder can claim its unclaimed tokens. + /// @param _holder The owner of the tokens being claimed. + /// @param _projectId The ID of the project whose tokens are being claimed. + /// @param _amount The amount of tokens to claim. function claimFor( address _holder, uint256 _projectId, @@ -405,18 +329,12 @@ contract JBTokenStore is JBControllerUtility, JBOperatable, IJBTokenStore { emit Claim(_holder, _projectId, _unclaimedBalance, _amount, msg.sender); } - /** - @notice - Allows a holder to transfer unclaimed tokens to another account. - - @dev - Only a token holder or an operator can transfer its unclaimed tokens. - - @param _holder The address to transfer tokens from. - @param _projectId The ID of the project whose tokens are being transferred. - @param _recipient The recipient of the tokens. - @param _amount The amount of tokens to transfer. - */ + /// @notice Allows a holder to transfer unclaimed tokens to another account. + /// @dev Only a token holder or an operator can transfer its unclaimed tokens. + /// @param _holder The address to transfer tokens from. + /// @param _projectId The ID of the project whose tokens are being transferred. + /// @param _recipient The recipient of the tokens. + /// @param _amount The amount of tokens to transfer. function transferFrom( address _holder, uint256 _projectId, diff --git a/contracts/abstract/JBControllerUtility.sol b/contracts/abstract/JBControllerUtility.sol index f89e37c5c..2d0fe9647 100644 --- a/contracts/abstract/JBControllerUtility.sol +++ b/contracts/abstract/JBControllerUtility.sol @@ -1,16 +1,10 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.16; -import './../interfaces/IJBControllerUtility.sol'; +import {IJBControllerUtility} from './../interfaces/IJBControllerUtility.sol'; +import {IJBDirectory} from './../interfaces/IJBDirectory.sol'; -/** - @notice - Provides tools for contracts with functionality that can only be accessed by a project's controller. - - @dev - Adheres to - - IJBControllerUtility: General interface for the methods in this contract that interact with the blockchain's state according to the protocol's rules. -*/ +/// @notice Provides tools for contracts with functionality that can only be accessed by a project's controller. abstract contract JBControllerUtility is IJBControllerUtility { //*********************************************************************// // --------------------------- custom errors -------------------------- // @@ -21,12 +15,8 @@ abstract contract JBControllerUtility is IJBControllerUtility { // ---------------------------- modifiers ---------------------------- // //*********************************************************************// - /** - @notice - Only allows the controller of the specified project to proceed. - - @param _projectId The ID of the project. - */ + /// @notice Only allows the controller of the specified project to proceed. + /// @param _projectId The ID of the project. modifier onlyController(uint256 _projectId) { if (address(directory.controllerOf(_projectId)) != msg.sender) revert CONTROLLER_UNAUTHORIZED(); _; @@ -36,19 +26,14 @@ abstract contract JBControllerUtility is IJBControllerUtility { // ---------------- public immutable stored properties --------------- // //*********************************************************************// - /** - @notice - The directory of terminals and controllers for projects. - */ + /// @notice The directory of terminals and controllers for projects. IJBDirectory public immutable override directory; //*********************************************************************// // -------------------------- constructor ---------------------------- // //*********************************************************************// - /** - @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. constructor(IJBDirectory _directory) { directory = _directory; } diff --git a/contracts/abstract/JBOperatable.sol b/contracts/abstract/JBOperatable.sol index e0bc96857..fc93b21da 100644 --- a/contracts/abstract/JBOperatable.sol +++ b/contracts/abstract/JBOperatable.sol @@ -1,16 +1,10 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.16; -import './../interfaces/IJBOperatable.sol'; +import {IJBOperatable} from './../interfaces/IJBOperatable.sol'; +import {IJBOperatorStore} from './../interfaces/IJBOperatorStore.sol'; -/** - @notice - Modifiers to allow access to functions based on the message sender's operator status. - - @dev - Adheres to - - IJBOperatable: General interface for the methods in this contract that interact with the blockchain's state according to the protocol's rules. -*/ +/// @notice Modifiers to allow access to functions based on the message sender's operator status. abstract contract JBOperatable is IJBOperatable { //*********************************************************************// // --------------------------- custom errors -------------------------- // @@ -21,14 +15,10 @@ abstract contract JBOperatable is IJBOperatable { // ---------------------------- modifiers ---------------------------- // //*********************************************************************// - /** - @notice - Only allows the speficied account or an operator of the account to proceed. - - @param _account The account to check for. - @param _domain The domain namespace to look for an operator within. - @param _permissionIndex The index of the permission to check for. - */ + /// @notice Only allows the speficied account or an operator of the account to proceed. + /// @param _account The account to check for. + /// @param _domain The domain namespace to look for an operator within. + /// @param _permissionIndex The index of the permission to check for. modifier requirePermission( address _account, uint256 _domain, @@ -38,15 +28,11 @@ abstract contract JBOperatable is IJBOperatable { _; } - /** - @notice - Only allows the speficied account, an operator of the account to proceed, or a truthy override flag. - - @param _account The account to check for. - @param _domain The domain namespace to look for an operator within. - @param _permissionIndex The index of the permission to check for. - @param _override A condition to force allowance for. - */ + /// @notice Only allows the speficied account, an operator of the account to proceed, or a truthy override flag. + /// @param _account The account to check for. + /// @param _domain The domain namespace to look for an operator within. + /// @param _permissionIndex The index of the permission to check for. + /// @param _override A condition to force allowance for. modifier requirePermissionAllowingOverride( address _account, uint256 _domain, @@ -61,19 +47,14 @@ abstract contract JBOperatable is IJBOperatable { // ---------------- public immutable stored properties --------------- // //*********************************************************************// - /** - @notice - A contract storing operator assignments. - */ + /// @notice A contract storing operator assignments. IJBOperatorStore public immutable override operatorStore; //*********************************************************************// // -------------------------- constructor ---------------------------- // //*********************************************************************// - /** - @param _operatorStore A contract storing operator assignments. - */ + /// @param _operatorStore A contract storing operator assignments. constructor(IJBOperatorStore _operatorStore) { operatorStore = _operatorStore; } @@ -82,14 +63,10 @@ abstract contract JBOperatable is IJBOperatable { // -------------------------- internal views ------------------------- // //*********************************************************************// - /** - @notice - Require the message sender is either the account or has the specified permission. - - @param _account The account to allow. - @param _domain The domain namespace within which the permission index will be checked. - @param _permissionIndex The permission index that an operator must have within the specified domain to be allowed. - */ + /// @notice Require the message sender is either the account or has the specified permission. + /// @param _account The account to allow. + /// @param _domain The domain namespace within which the permission index will be checked. + /// @param _permissionIndex The permission index that an operator must have within the specified domain to be allowed. function _requirePermission( address _account, uint256 _domain, @@ -102,15 +79,11 @@ abstract contract JBOperatable is IJBOperatable { ) revert UNAUTHORIZED(); } - /** - @notice - Require the message sender is either the account, has the specified permission, or the override condition is true. - - @param _account The account to allow. - @param _domain The domain namespace within which the permission index will be checked. - @param _domain The permission index that an operator must have within the specified domain to be allowed. - @param _override The override condition to allow. - */ + /// @notice Require the message sender is either the account, has the specified permission, or the override condition is true. + /// @param _account The account to allow. + /// @param _domain The domain namespace within which the permission index will be checked. + /// @param _domain The permission index that an operator must have within the specified domain to be allowed. + /// @param _override The override condition to allow. function _requirePermissionAllowingOverride( address _account, uint256 _domain, diff --git a/contracts/abstract/JBPayoutRedemptionPaymentTerminal.sol b/contracts/abstract/JBPayoutRedemptionPaymentTerminal.sol index a7b714f95..6a97ea3d9 100644 --- a/contracts/abstract/JBPayoutRedemptionPaymentTerminal.sol +++ b/contracts/abstract/JBPayoutRedemptionPaymentTerminal.sol @@ -1,38 +1,44 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.16; -import '@openzeppelin/contracts/access/Ownable.sol'; -import '@paulrberg/contracts/math/PRBMath.sol'; -import './../interfaces/IJBController.sol'; -import './../interfaces/IJBPayoutRedemptionPaymentTerminal.sol'; -import './../libraries/JBConstants.sol'; -import './../libraries/JBCurrencies.sol'; -import './../libraries/JBFixedPointNumber.sol'; -import './../libraries/JBFundingCycleMetadataResolver.sol'; -import './../libraries/JBOperations.sol'; -import './../libraries/JBTokens.sol'; -import './../structs/JBPayDelegateAllocation.sol'; -import './../structs/JBTokenAmount.sol'; -import './JBOperatable.sol'; -import './JBSingleTokenPaymentTerminal.sol'; - -/** - @notice - Generic terminal managing all inflows and outflows of funds into the protocol ecosystem. - - @dev - A project can transfer its funds, along with the power to reconfigure and mint/burn their tokens, from this contract to another allowed terminal of the same token type contract at any time. - - @dev - Adheres to - - IJBPayoutRedemptionPaymentTerminal: General interface for the methods in this contract that interact with the blockchain's state according to the protocol's rules. - - @dev - Inherits from - - JBSingleTokenPaymentTerminal: Generic terminal managing all inflows of funds into the protocol ecosystem for one token. - JBOperatable: Includes convenience functionality for checking a message sender's permissions before executing certain transactions. - Ownable: Includes convenience functionality for checking a message sender's permissions before executing certain transactions. -*/ +import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol'; +import {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol'; +import {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol'; +import {IJBAllowanceTerminal} from './../interfaces/IJBAllowanceTerminal.sol'; +import {IJBController} from './../interfaces/IJBController.sol'; +import {IJBDirectory} from './../interfaces/IJBDirectory.sol'; +import {IJBPayoutRedemptionPaymentTerminal} from './../interfaces/IJBPayoutRedemptionPaymentTerminal.sol'; +import {IJBSplitAllocator} from './../interfaces/IJBSplitAllocator.sol'; +import {IJBFeeGauge} from './../interfaces/IJBFeeGauge.sol'; +import {IJBOperatable} from './../interfaces/IJBOperatable.sol'; +import {IJBOperatorStore} from './../interfaces/IJBOperatorStore.sol'; +import {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol'; +import {IJBPayoutTerminal} from './../interfaces/IJBPayoutTerminal.sol'; +import {IJBPrices} from './../interfaces/IJBPrices.sol'; +import {IJBProjects} from './../interfaces/IJBProjects.sol'; +import {IJBRedemptionTerminal} from './../interfaces/IJBRedemptionTerminal.sol'; +import {IJBSingleTokenPaymentTerminalStore} from './../interfaces/IJBSingleTokenPaymentTerminalStore.sol'; +import {IJBSplitsStore} from './../interfaces/IJBSplitsStore.sol'; +import {JBConstants} from './../libraries/JBConstants.sol'; +import {JBCurrencies} from './../libraries/JBCurrencies.sol'; +import {JBFixedPointNumber} from './../libraries/JBFixedPointNumber.sol'; +import {JBFundingCycleMetadataResolver} from './../libraries/JBFundingCycleMetadataResolver.sol'; +import {JBOperations} from './../libraries/JBOperations.sol'; +import {JBTokens} from './../libraries/JBTokens.sol'; +import {JBDidPayData} from './../structs/JBDidPayData.sol'; +import {JBDidRedeemData} from './../structs/JBDidRedeemData.sol'; +import {JBFee} from './../structs/JBFee.sol'; +import {JBFundingCycle} from './../structs/JBFundingCycle.sol'; +import {JBPayDelegateAllocation} from './../structs/JBPayDelegateAllocation.sol'; +import {JBTokenAmount} from './../structs/JBTokenAmount.sol'; +import {JBRedemptionDelegateAllocation} from './../structs/JBRedemptionDelegateAllocation.sol'; +import {JBSplit} from './../structs/JBSplit.sol'; +import {JBSplitAllocationData} from './../structs/JBSplitAllocationData.sol'; +import {JBOperatable} from './JBOperatable.sol'; +import {JBSingleTokenPaymentTerminal} from './JBSingleTokenPaymentTerminal.sol'; + +/// @notice Generic terminal managing all inflows and outflows of funds into the protocol ecosystem. +/// A project can transfer its funds, along with the power to reconfigure and mint/burn their tokens, from this contract to another allowed terminal of the same token type contract at any time. abstract contract JBPayoutRedemptionPaymentTerminal is JBSingleTokenPaymentTerminal, JBOperatable, @@ -60,10 +66,7 @@ abstract contract JBPayoutRedemptionPaymentTerminal is // ---------------------------- modifiers ---------------------------- // //*********************************************************************// - /** - @notice - A modifier that verifies this terminal is a terminal of provided project ID. - */ + /// @notice A modifier that verifies this terminal is a terminal of provided project ID. modifier isTerminalOf(uint256 _projectId) { if (!directory.isTerminalOf(_projectId, this)) revert PROJECT_TERMINAL_MISMATCH(); _; @@ -73,136 +76,79 @@ abstract contract JBPayoutRedemptionPaymentTerminal is // --------------------- internal stored constants ------------------- // //*********************************************************************// - /** - @notice - Maximum fee that can be set for a funding cycle configuration. - - @dev - Out of MAX_FEE (50_000_000 / 1_000_000_000). - */ + /// @notice Maximum fee that can be set for a funding cycle configuration. + /// @dev Out of MAX_FEE (50_000_000 / 1_000_000_000). uint256 internal constant _FEE_CAP = 50_000_000; - /** - @notice - The fee beneficiary project ID is 1, as it should be the first project launched during the deployment process. - */ + /// @notice The fee beneficiary project ID is 1, as it should be the first project launched during the deployment process. uint256 internal constant _FEE_BENEFICIARY_PROJECT_ID = 1; //*********************************************************************// // --------------------- internal stored properties ------------------ // //*********************************************************************// - /** - @notice - Fees that are being held to be processed later. - - _projectId The ID of the project for which fees are being held. - */ + /// @notice Fees that are being held to be processed later. + /// @custom:param _projectId The ID of the project for which fees are being held. mapping(uint256 => JBFee[]) internal _heldFeesOf; //*********************************************************************// // ---------------- public immutable stored properties --------------- // //*********************************************************************// - /** - @notice - Mints ERC-721's that represent project ownership and transfers. - */ + /// @notice Mints ERC-721's that represent project ownership and transfers. IJBProjects public immutable override projects; - /** - @notice - The directory of terminals and controllers for projects. - */ + /// @notice The directory of terminals and controllers for projects. IJBDirectory public immutable override directory; - /** - @notice - The contract that stores splits for each project. - */ + /// @notice The contract that stores splits for each project. IJBSplitsStore public immutable override splitsStore; - /** - @notice - The contract that exposes price feeds. - */ + /// @notice The contract that exposes price feeds. IJBPrices public immutable override prices; - /** - @notice - The contract that stores and manages the terminal's data. - */ - IJBSingleTokenPaymentTerminalStore public immutable override store; - - /** - @notice - The currency to base token issuance on. + /// @notice The contract that stores and manages the terminal's data. + address public immutable override store; - @dev - If this differs from `currency`, there must be a price feed available to convert `currency` to `baseWeightCurrency`. - */ + /// @notice The currency to base token issuance on. + /// @dev If this differs from `currency`, there must be a price feed available to convert `currency` to `baseWeightCurrency`. uint256 public immutable override baseWeightCurrency; - /** - @notice - The group that payout splits coming from this terminal are identified by. - */ + /// @notice The group that payout splits coming from this terminal are identified by. uint256 public immutable override payoutSplitsGroup; //*********************************************************************// // --------------------- public stored properties -------------------- // //*********************************************************************// - /** - @notice - The platform fee percent. - - @dev - Out of MAX_FEE (25_000_000 / 1_000_000_000) - */ + /// @notice The platform fee percent. + /// @dev Out of MAX_FEE (25_000_000 / 1_000_000_000) uint256 public override fee = 25_000_000; // 2.5% - /** - @notice - The data source that returns a discount to apply to a project's fee. - */ - IJBFeeGauge public override feeGauge; - - /** - @notice - Addresses that can be paid towards from this terminal without incurring a fee. - - @dev - Only addresses that are considered to be contained within the ecosystem can be feeless. Funds sent outside the ecosystem may incur fees despite being stored as feeless. + /// @notice The data source that returns a discount to apply to a project's fee. + address public override feeGauge; - _address The address that can be paid toward. - */ + /// @notice Addresses that can be paid towards from this terminal without incurring a fee. + /// @dev Only addresses that are considered to be contained within the ecosystem can be feeless. Funds sent outside the ecosystem may incur fees despite being stored as feeless. + /// @custom:param _address The address that can be paid toward. mapping(address => bool) public override isFeelessAddress; //*********************************************************************// // ------------------------- external views -------------------------- // //*********************************************************************// - /** - @notice - Gets the current overflowed amount in this terminal for a specified project, in terms of ETH. - - @dev - The current overflow is represented as a fixed point number with 18 decimals. - - @param _projectId The ID of the project to get overflow for. - - @return The current amount of ETH overflow that project has in this terminal, as a fixed point number with 18 decimals. - */ - function currentEthOverflowOf(uint256 _projectId) - external - view - virtual - override - returns (uint256) - { + /// @notice Gets the current overflowed amount in this terminal for a specified project, in terms of ETH. + /// @dev The current overflow is represented as a fixed point number with 18 decimals. + /// @param _projectId The ID of the project to get overflow for. + /// @return The current amount of ETH overflow that project has in this terminal, as a fixed point number with 18 decimals. + function currentEthOverflowOf( + uint256 _projectId + ) external view virtual override returns (uint256) { // Get this terminal's current overflow. - uint256 _overflow = store.currentOverflowOf(this, _projectId); + uint256 _overflow = IJBSingleTokenPaymentTerminalStore(store).currentOverflowOf( + this, + _projectId + ); // Adjust the decimals of the fixed point number if needed to have 18 decimals. uint256 _adjustedOverflow = (decimals == 18) @@ -215,19 +161,14 @@ abstract contract JBPayoutRedemptionPaymentTerminal is ? _adjustedOverflow : PRBMath.mulDiv( _adjustedOverflow, - 10**decimals, + 10 ** decimals, prices.priceFor(currency, JBCurrencies.ETH, decimals) ); } - /** - @notice - The fees that are currently being held to be processed later for each project. - - @param _projectId The ID of the project for which fees are being held. - - @return An array of fees that are being held. - */ + /// @notice The fees that are currently being held to be processed later for each project. + /// @param _projectId The ID of the project for which fees are being held. + /// @return An array of fees that are being held. function heldFeesOf(uint256 _projectId) external view override returns (JBFee[] memory) { return _heldFeesOf[_projectId]; } @@ -236,22 +177,13 @@ abstract contract JBPayoutRedemptionPaymentTerminal is // -------------------------- public views --------------------------- // //*********************************************************************// - /** - @notice - Indicates if this contract adheres to the specified interface. - - @dev - See {IERC165-supportsInterface}. - - @param _interfaceId The ID of the interface to check for adherance to. - */ - function supportsInterface(bytes4 _interfaceId) - public - view - virtual - override(JBSingleTokenPaymentTerminal, IERC165) - returns (bool) - { + /// @notice Indicates if this contract adheres to the specified interface. + /// @dev See {IERC165-supportsInterface}. + /// @param _interfaceId The ID of the interface to check for adherance to. + /// @return A flag indicating if the provided interface ID is supported. + function supportsInterface( + bytes4 _interfaceId + ) public view virtual override(JBSingleTokenPaymentTerminal, IERC165) returns (bool) { return _interfaceId == type(IJBPayoutRedemptionPaymentTerminal).interfaceId || _interfaceId == type(IJBPayoutTerminal).interfaceId || @@ -265,32 +197,26 @@ abstract contract JBPayoutRedemptionPaymentTerminal is // -------------------------- internal views ------------------------- // //*********************************************************************// - /** - @notice - Checks the balance of tokens in this contract. - - @return The contract's balance. - */ + /// @notice Checks the balance of tokens in this contract. + /// @return The contract's balance. function _balance() internal view virtual returns (uint256); //*********************************************************************// // -------------------------- constructor ---------------------------- // //*********************************************************************// - /** - @param _token The token that this terminal manages. - @param _decimals The number of decimals the token fixed point amounts are expected to have. - @param _currency The currency that this terminal's token adheres to for price feeds. - @param _baseWeightCurrency The currency to base token issuance on. - @param _payoutSplitsGroup The group that denotes payout splits from this terminal in the splits store. - @param _operatorStore A contract storing operator assignments. - @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 _splitsStore A contract that stores splits for each project. - @param _prices A contract that exposes price feeds. - @param _store A contract that stores the terminal's data. - @param _owner The address that will own this contract. - */ + /// @param _token The token that this terminal manages. + /// @param _decimals The number of decimals the token fixed point amounts are expected to have. + /// @param _currency The currency that this terminal's token adheres to for price feeds. + /// @param _baseWeightCurrency The currency to base token issuance on. + /// @param _payoutSplitsGroup The group that denotes payout splits from this terminal in the splits store. + /// @param _operatorStore A contract storing operator assignments. + /// @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 _splitsStore A contract that stores splits for each project. + /// @param _prices A contract that exposes price feeds. + /// @param _store A contract that stores the terminal's data. + /// @param _owner The address that will own this contract. constructor( // payable constructor save the gas used to check msg.value==0 address _token, @@ -303,7 +229,7 @@ abstract contract JBPayoutRedemptionPaymentTerminal is IJBDirectory _directory, IJBSplitsStore _splitsStore, IJBPrices _prices, - IJBSingleTokenPaymentTerminalStore _store, + address _store, address _owner ) payable @@ -325,21 +251,16 @@ abstract contract JBPayoutRedemptionPaymentTerminal is // ---------------------- external transactions ---------------------- // //*********************************************************************// - /** - @notice - Contribute tokens to a project. - - @param _projectId The ID of the project being paid. - @param _amount The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place. - @param _token The token being paid. This terminal ignores this property since it only manages one token. - @param _beneficiary The address to mint tokens for and pass along to the funding cycle's data source and delegate. - @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal. - @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas. - @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate. - @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided. - - @return The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals. - */ + /// @notice Contribute tokens to a project. + /// @param _projectId The ID of the project being paid. + /// @param _amount The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place. + /// @param _token The token being paid. This terminal ignores this property since it only manages one token. + /// @param _beneficiary The address to mint tokens for and pass along to the funding cycle's data source and delegate. + /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal. + /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas. + /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate. + /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided. + /// @return The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals. function pay( uint256 _projectId, uint256 _amount, @@ -381,24 +302,17 @@ abstract contract JBPayoutRedemptionPaymentTerminal is ); } - /** - @notice - Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source. - - @dev - Only a token holder or a designated operator can redeem its tokens. - - @param _holder The account to redeem tokens for. - @param _projectId The ID of the project to which the tokens being redeemed belong. - @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals. - @param _token The token being reclaimed. This terminal ignores this property since it only manages one token. - @param _minReturnedTokens The minimum amount of terminal tokens expected in return, as a fixed point number with the same amount of decimals as the terminal. - @param _beneficiary The address to send the terminal tokens to. - @param _memo A memo to pass along to the emitted event. - @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided. - - @return reclaimAmount The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals. - */ + /// @notice Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source. + /// @dev Only a token holder or a designated operator can redeem its tokens. + /// @param _holder The account to redeem tokens for. + /// @param _projectId The ID of the project to which the tokens being redeemed belong. + /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals. + /// @param _token The token being reclaimed. This terminal ignores this property since it only manages one token. + /// @param _minReturnedTokens The minimum amount of terminal tokens expected in return, as a fixed point number with the same amount of decimals as the terminal. + /// @param _beneficiary The address to send the terminal tokens to. + /// @param _memo A memo to pass along to the emitted event. + /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided. + /// @return reclaimAmount The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals. function redeemTokensOf( address _holder, uint256 _projectId, @@ -429,28 +343,17 @@ abstract contract JBPayoutRedemptionPaymentTerminal is ); } - /** - @notice - Distributes payouts for a project with the distribution limit of its current funding cycle. - - @dev - Payouts are sent to the preprogrammed splits. Any leftover is sent to the project's owner. - - @dev - 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. - - @dev - All funds distributed outside of this contract or any feeless terminals incure the protocol fee. - - @param _projectId The ID of the project having its payouts distributed. - @param _amount The amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal. - @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency. - @param _token The token being distributed. This terminal ignores this property since it only manages one token. - @param _minReturnedTokens 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. - @param _memo A memo to pass along to the emitted event. - - @return netLeftoverDistributionAmount The amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal. - */ + /// @notice Distributes payouts for a project with the distribution limit of its current funding cycle. + /// @dev Payouts are sent to the preprogrammed splits. Any leftover is sent to the project's owner. + /// @dev 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. + /// @dev All funds distributed outside of this contract or any feeless terminals incure the protocol fee. + /// @param _projectId The ID of the project having its payouts distributed. + /// @param _amount The amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal. + /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency. + /// @param _token The token being distributed. This terminal ignores this property since it only manages one token. + /// @param _minReturnedTokens 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. + /// @param _memo A memo to pass along to the emitted event. + /// @return netLeftoverDistributionAmount The amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal. function distributePayoutsOf( uint256 _projectId, uint256 _amount, @@ -464,26 +367,17 @@ abstract contract JBPayoutRedemptionPaymentTerminal is return _distributePayoutsOf(_projectId, _amount, _currency, _minReturnedTokens, _memo); } - /** - @notice - Allows a project to send funds from its overflow up to the preconfigured allowance. - - @dev - Only a project's owner or a designated operator can use its allowance. - - @dev - Incurs the protocol fee. - - @param _projectId The ID of the project to use the allowance of. - @param _amount The amount of terminal tokens to use from this project's current allowance, as a fixed point number with the same amount of decimals as this terminal. - @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's overflow allowance currency. - @param _token The token being distributed. This terminal ignores this property since it only manages one token. - @param _minReturnedTokens The minimum number of tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with 18 decimals. - @param _beneficiary The address to send the funds to. - @param _memo A memo to pass along to the emitted event. - - @return netDistributedAmount The amount of tokens that was distributed to the beneficiary, as a fixed point number with the same amount of decimals as the terminal. - */ + /// @notice Allows a project to send funds from its overflow up to the preconfigured allowance. + /// @dev Only a project's owner or a designated operator can use its allowance. + /// @dev Incurs the protocol fee. + /// @param _projectId The ID of the project to use the allowance of. + /// @param _amount The amount of terminal tokens to use from this project's current allowance, as a fixed point number with the same amount of decimals as this terminal. + /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's overflow allowance currency. + /// @param _token The token being distributed. This terminal ignores this property since it only manages one token. + /// @param _minReturnedTokens The minimum number of tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with 18 decimals. + /// @param _beneficiary The address to send the funds to. + /// @param _memo A memo to pass along to the emitted event. + /// @return netDistributedAmount The amount of tokens that was distributed to the beneficiary, as a fixed point number with the same amount of decimals as the terminal. function useAllowanceOf( uint256 _projectId, uint256 _amount, @@ -504,19 +398,15 @@ abstract contract JBPayoutRedemptionPaymentTerminal is return _useAllowanceOf(_projectId, _amount, _currency, _minReturnedTokens, _beneficiary, _memo); } - /** - @notice - Allows a project owner to migrate its funds and operations to a new terminal that accepts the same token type. - - @dev - Only a project's owner or a designated operator can migrate it. - - @param _projectId The ID of the project being migrated. - @param _to The terminal contract that will gain the project's funds. - - @return balance The amount of funds that were migrated, as a fixed point number with the same amount of decimals as this terminal. - */ - function migrate(uint256 _projectId, IJBPaymentTerminal _to) + /// @notice Allows a project owner to migrate its funds and operations to a new terminal that accepts the same token type. + /// @dev Only a project's owner or a designated operator can migrate it. + /// @param _projectId The ID of the project being migrated. + /// @param _to The terminal contract that will gain the project's funds. + /// @return balance The amount of funds that were migrated, as a fixed point number with the same amount of decimals as this terminal. + function migrate( + uint256 _projectId, + IJBPaymentTerminal _to + ) external virtual override @@ -527,7 +417,7 @@ abstract contract JBPayoutRedemptionPaymentTerminal is if (!_to.acceptsToken(token, _projectId)) revert TERMINAL_TOKENS_INCOMPATIBLE(); // Record the migration in the store. - balance = store.recordMigration(_projectId); + balance = IJBSingleTokenPaymentTerminalStore(store).recordMigration(_projectId); // Transfer the balance if needed. if (balance > 0) { @@ -544,16 +434,12 @@ abstract contract JBPayoutRedemptionPaymentTerminal is emit Migrate(_projectId, _to, balance, msg.sender); } - /** - @notice - Receives funds belonging to the specified project. - - @param _projectId The ID of the project to which the funds received belong. - @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead. - @param _token The token being paid. This terminal ignores this property since it only manages one currency. - @param _memo A memo to pass along to the emitted event. - @param _metadata Extra data to pass along to the emitted event. - */ + /// @notice Receives funds belonging to the specified project. + /// @param _projectId The ID of the project to which the funds received belong. + /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead. + /// @param _token The token being paid. This terminal ignores this property since it only manages one currency. + /// @param _memo A memo to pass along to the emitted event. + /// @param _metadata Extra data to pass along to the emitted event. function addToBalanceOf( uint256 _projectId, uint256 _amount, @@ -584,16 +470,12 @@ abstract contract JBPayoutRedemptionPaymentTerminal is _addToBalanceOf(_projectId, _amount, !isFeelessAddress[msg.sender], _memo, _metadata); } - /** - @notice - Process any fees that are being held for the project. - - @dev - Only a project owner, an operator, or the contract's owner can process held fees. - - @param _projectId The ID of the project whos held fees should be processed. - */ - function processFees(uint256 _projectId) + /// @notice Process any fees that are being held for the project. + /// @dev Only a project owner, an operator, or the contract's owner can process held fees. + /// @param _projectId The ID of the project whos held fees should be processed. + function processFees( + uint256 _projectId + ) external virtual override @@ -633,15 +515,9 @@ abstract contract JBPayoutRedemptionPaymentTerminal is } } - /** - @notice - Allows the fee to be updated. - - @dev - Only the owner of this contract can change the fee. - - @param _fee The new fee, out of MAX_FEE. - */ + /// @notice Allows the fee to be updated. + /// @dev Only the owner of this contract can change the fee. + /// @param _fee The new fee, out of MAX_FEE. function setFee(uint256 _fee) external virtual override onlyOwner { // The provided fee must be within the max. if (_fee > _FEE_CAP) revert FEE_TOO_HIGH(); @@ -652,32 +528,20 @@ abstract contract JBPayoutRedemptionPaymentTerminal is emit SetFee(_fee, msg.sender); } - /** - @notice - Allows the fee gauge to be updated. - - @dev - Only the owner of this contract can change the fee gauge. - - @param _feeGauge The new fee gauge. - */ - function setFeeGauge(IJBFeeGauge _feeGauge) external virtual override onlyOwner { + /// @notice Allows the fee gauge to be updated. + /// @dev Only the owner of this contract can change the fee gauge. + /// @param _feeGauge The new fee gauge. + function setFeeGauge(address _feeGauge) external virtual override onlyOwner { // Store the new fee gauge. feeGauge = _feeGauge; emit SetFeeGauge(_feeGauge, msg.sender); } - /** - @notice - Sets whether projects operating on this terminal can pay towards the specified address without incurring a fee. - - @dev - Only the owner of this contract can set addresses as feeless. - - @param _address The address that can be paid towards while still bypassing fees. - @param _flag A flag indicating whether the terminal should be feeless or not. - */ + /// @notice Sets whether projects operating on this terminal can pay towards the specified address without incurring a fee. + /// @dev Only the owner of this contract can set addresses as feeless. + /// @param _address The address that can be paid towards while still bypassing fees. + /// @param _flag A flag indicating whether the terminal should be feeless or not. function setFeelessAddress(address _address, bool _flag) external virtual override onlyOwner { // Set the flag value. isFeelessAddress[_address] = _flag; @@ -689,53 +553,34 @@ abstract contract JBPayoutRedemptionPaymentTerminal is // ---------------------- internal transactions ---------------------- // //*********************************************************************// - /** - @notice - Transfers tokens. - - @param _from The address from which the transfer should originate. - @param _to The address to which the transfer should go. - @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal. - */ - function _transferFrom( - address _from, - address payable _to, - uint256 _amount - ) internal virtual { + /// @notice Transfers tokens. + /// @param _from The address from which the transfer should originate. + /// @param _to The address to which the transfer should go. + /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal. + function _transferFrom(address _from, address payable _to, uint256 _amount) internal virtual { _from; // Prevents unused var compiler and natspec complaints. _to; // Prevents unused var compiler and natspec complaints. _amount; // Prevents unused var compiler and natspec complaints. } - /** - @notice - Logic to be triggered before transferring tokens from this terminal. - - @param _to The address to which the transfer is going. - @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal. - */ + /// @notice Logic to be triggered before transferring tokens from this terminal. + /// @param _to The address to which the transfer is going. + /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal. function _beforeTransferTo(address _to, uint256 _amount) internal virtual { _to; // Prevents unused var compiler and natspec complaints. _amount; // Prevents unused var compiler and natspec complaints. } - /** - @notice - Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source. - - @dev - Only a token holder or a designated operator can redeem its tokens. - - @param _holder The account to redeem tokens for. - @param _projectId The ID of the project to which the tokens being redeemed belong. - @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals. - @param _minReturnedTokens The minimum amount of terminal tokens expected in return, as a fixed point number with the same amount of decimals as the terminal. - @param _beneficiary The address to send the terminal tokens to. - @param _memo A memo to pass along to the emitted event. - @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided. - - @return reclaimAmount The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals. - */ + /// @notice Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source. + /// @dev Only a token holder or a designated operator can redeem its tokens. + /// @param _holder The account to redeem tokens for. + /// @param _projectId The ID of the project to which the tokens being redeemed belong. + /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals. + /// @param _minReturnedTokens The minimum amount of terminal tokens expected in return, as a fixed point number with the same amount of decimals as the terminal. + /// @param _beneficiary The address to send the terminal tokens to. + /// @param _memo A memo to pass along to the emitted event. + /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided. + /// @return reclaimAmount The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals. function _redeemTokensOf( address _holder, uint256 _projectId, @@ -757,7 +602,12 @@ abstract contract JBPayoutRedemptionPaymentTerminal is JBRedemptionDelegateAllocation[] memory _delegateAllocations; // Record the redemption. - (_fundingCycle, reclaimAmount, _delegateAllocations, _memo) = store.recordRedemptionFor( + ( + _fundingCycle, + reclaimAmount, + _delegateAllocations, + _memo + ) = IJBSingleTokenPaymentTerminalStore(store).recordRedemptionFor( _holder, _projectId, _tokenCount, @@ -845,27 +695,16 @@ abstract contract JBPayoutRedemptionPaymentTerminal is ); } - /** - @notice - Distributes payouts for a project with the distribution limit of its current funding cycle. - - @dev - Payouts are sent to the preprogrammed splits. Any leftover is sent to the project's owner. - - @dev - 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. - - @dev - All funds distributed outside of this contract or any feeless terminals incure the protocol fee. - - @param _projectId The ID of the project having its payouts distributed. - @param _amount The amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal. - @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency. - @param _minReturnedTokens 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. - @param _memo A memo to pass along to the emitted event. - - @return netLeftoverDistributionAmount The amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal. - */ + /// @notice Distributes payouts for a project with the distribution limit of its current funding cycle. + /// @dev Payouts are sent to the preprogrammed splits. Any leftover is sent to the project's owner. + /// @dev 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. + /// @dev All funds distributed outside of this contract or any feeless terminals incure the protocol fee. + /// @param _projectId The ID of the project having its payouts distributed. + /// @param _amount The amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal. + /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency. + /// @param _minReturnedTokens 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. + /// @param _memo A memo to pass along to the emitted event. + /// @return netLeftoverDistributionAmount The amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal. function _distributePayoutsOf( uint256 _projectId, uint256 _amount, @@ -874,11 +713,14 @@ abstract contract JBPayoutRedemptionPaymentTerminal is string calldata _memo ) internal returns (uint256 netLeftoverDistributionAmount) { // Record the distribution. - (JBFundingCycle memory _fundingCycle, uint256 _distributedAmount) = store.recordDistributionFor( - _projectId, - _amount, - _currency - ); + ( + JBFundingCycle memory _fundingCycle, + uint256 _distributedAmount + ) = IJBSingleTokenPaymentTerminalStore(store).recordDistributionFor( + _projectId, + _amount, + _currency + ); // The amount being distributed must be at least as much as was expected. if (_distributedAmount < _minReturnedTokens) revert INADEQUATE_DISTRIBUTION_AMOUNT(); @@ -959,25 +801,16 @@ abstract contract JBPayoutRedemptionPaymentTerminal is ); } - /** - @notice - Allows a project to send funds from its overflow up to the preconfigured allowance. - - @dev - Only a project's owner or a designated operator can use its allowance. - - @dev - Incurs the protocol fee. - - @param _projectId The ID of the project to use the allowance of. - @param _amount The amount of terminal tokens to use from this project's current allowance, as a fixed point number with the same amount of decimals as this terminal. - @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's overflow allowance currency. - @param _minReturnedTokens The minimum number of tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with 18 decimals. - @param _beneficiary The address to send the funds to. - @param _memo A memo to pass along to the emitted event. - - @return netDistributedAmount The amount of tokens that was distributed to the beneficiary, as a fixed point number with the same amount of decimals as the terminal. - */ + /// @notice Allows a project to send funds from its overflow up to the preconfigured allowance. + /// @dev Only a project's owner or a designated operator can use its allowance. + /// @dev Incurs the protocol fee. + /// @param _projectId The ID of the project to use the allowance of. + /// @param _amount The amount of terminal tokens to use from this project's current allowance, as a fixed point number with the same amount of decimals as this terminal. + /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's overflow allowance currency. + /// @param _minReturnedTokens The minimum number of tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with 18 decimals. + /// @param _beneficiary The address to send the funds to. + /// @param _memo A memo to pass along to the emitted event. + /// @return netDistributedAmount The amount of tokens that was distributed to the beneficiary, as a fixed point number with the same amount of decimals as the terminal. function _useAllowanceOf( uint256 _projectId, uint256 _amount, @@ -987,11 +820,14 @@ abstract contract JBPayoutRedemptionPaymentTerminal is string memory _memo ) internal returns (uint256 netDistributedAmount) { // Record the use of the allowance. - (JBFundingCycle memory _fundingCycle, uint256 _distributedAmount) = store.recordUsedAllowanceOf( - _projectId, - _amount, - _currency - ); + ( + JBFundingCycle memory _fundingCycle, + uint256 _distributedAmount + ) = IJBSingleTokenPaymentTerminalStore(store).recordUsedAllowanceOf( + _projectId, + _amount, + _currency + ); // The amount being withdrawn must be at least as much as was expected. if (_distributedAmount < _minReturnedTokens) revert INADEQUATE_DISTRIBUTION_AMOUNT(); @@ -1038,19 +874,14 @@ abstract contract JBPayoutRedemptionPaymentTerminal is ); } - /** - @notice - Pays out splits for a project's funding cycle configuration. - - @param _projectId The ID of the project for which payout splits are being distributed. - @param _domain The domain of the splits to distribute the payout between. - @param _group The group of the splits to distribute the payout between. - @param _amount The total amount being distributed, as a fixed point number with the same number of decimals as this terminal. - @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE. - - @return leftoverAmount If the leftover amount if the splits don't add up to 100%. - @return feeEligibleDistributionAmount The total amount of distributions that are eligible to have fees taken from. - */ + /// @notice Pays out splits for a project's funding cycle configuration. + /// @param _projectId The ID of the project for which payout splits are being distributed. + /// @param _domain The domain of the splits to distribute the payout between. + /// @param _group The group of the splits to distribute the payout between. + /// @param _amount The total amount being distributed, as a fixed point number with the same number of decimals as this terminal. + /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE. + /// @return leftoverAmount If the leftover amount if the splits don't add up to 100%. + /// @return feeEligibleDistributionAmount The total amount of distributions that are eligible to have fees taken from. function _distributeToPayoutSplitsOf( uint256 _projectId, uint256 _domain, @@ -1240,18 +1071,13 @@ abstract contract JBPayoutRedemptionPaymentTerminal is } } - /** - @notice - Takes a fee into the platform's project, which has an id of _FEE_BENEFICIARY_PROJECT_ID. - - @param _projectId The ID of the project having fees taken from. - @param _fundingCycle The funding cycle during which the fee is being taken. - @param _amount The amount of the fee to take, as a floating point number with 18 decimals. - @param _beneficiary The address to mint the platforms tokens for. - @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE. - - @return feeAmount The amount of the fee taken. - */ + /// @notice Takes a fee into the platform's project, which has an id of _FEE_BENEFICIARY_PROJECT_ID. + /// @param _projectId The ID of the project having fees taken from. + /// @param _fundingCycle The funding cycle during which the fee is being taken. + /// @param _amount The amount of the fee to take, as a floating point number with 18 decimals. + /// @param _beneficiary The address to mint the platforms tokens for. + /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE. + /// @return feeAmount The amount of the fee taken. function _takeFeeFrom( uint256 _projectId, JBFundingCycle memory _fundingCycle, @@ -1274,13 +1100,9 @@ abstract contract JBPayoutRedemptionPaymentTerminal is } } - /** - @notice - Process a fee of the specified amount. - - @param _amount The fee amount, as a floating point number with 18 decimals. - @param _beneficiary The address to mint the platform's tokens for. - */ + /// @notice Process a fee of the specified amount. + /// @param _amount The fee amount, as a floating point number with 18 decimals. + /// @param _beneficiary The address to mint the platform's tokens for. function _processFee(uint256 _amount, address _beneficiary) internal { // Get the terminal for the protocol project. IJBPaymentTerminal _terminal = directory.primaryTerminalOf(_FEE_BENEFICIARY_PROJECT_ID, token); @@ -1318,21 +1140,16 @@ abstract contract JBPayoutRedemptionPaymentTerminal is } } - /** - @notice - Contribute tokens to a project. - - @param _amount The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place. - @param _payer The address making the payment. - @param _projectId The ID of the project being paid. - @param _beneficiary The address to mint tokens for and pass along to the funding cycle's data source and delegate. - @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal. - @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas. - @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate. - @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided. - - @return beneficiaryTokenCount The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals. - */ + /// @notice Contribute tokens to a project. + /// @param _amount The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place. + /// @param _payer The address making the payment. + /// @param _projectId The ID of the project being paid. + /// @param _beneficiary The address to mint tokens for and pass along to the funding cycle's data source and delegate. + /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal. + /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas. + /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate. + /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided. + /// @return beneficiaryTokenCount The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals. function _pay( uint256 _amount, address _payer, @@ -1359,7 +1176,12 @@ abstract contract JBPayoutRedemptionPaymentTerminal is JBTokenAmount memory _bundledAmount = JBTokenAmount(token, _amount, decimals, currency); // Record the payment. - (_fundingCycle, _tokenCount, _delegateAllocations, _memo) = store.recordPaymentFrom( + ( + _fundingCycle, + _tokenCount, + _delegateAllocations, + _memo + ) = IJBSingleTokenPaymentTerminalStore(store).recordPaymentFrom( _payer, _bundledAmount, _projectId, @@ -1451,16 +1273,12 @@ abstract contract JBPayoutRedemptionPaymentTerminal is ); } - /** - @notice - Receives funds belonging to the specified project. - - @param _projectId The ID of the project to which the funds received belong. - @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead. - @param _shouldRefundHeldFees A flag indicating if held fees should be refunded based on the amount being added. - @param _memo A memo to pass along to the emitted event. - @param _metadata Extra data to pass along to the emitted event. - */ + /// @notice Receives funds belonging to the specified project. + /// @param _projectId The ID of the project to which the funds received belong. + /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead. + /// @param _shouldRefundHeldFees A flag indicating if held fees should be refunded based on the amount being added. + /// @param _memo A memo to pass along to the emitted event. + /// @param _metadata Extra data to pass along to the emitted event. function _addToBalanceOf( uint256 _projectId, uint256 _amount, @@ -1472,24 +1290,22 @@ abstract contract JBPayoutRedemptionPaymentTerminal is uint256 _refundedFees = _shouldRefundHeldFees ? _refundHeldFees(_projectId, _amount) : 0; // Record the added funds with any refunded fees. - store.recordAddedBalanceFor(_projectId, _amount + _refundedFees); + IJBSingleTokenPaymentTerminalStore(store).recordAddedBalanceFor( + _projectId, + _amount + _refundedFees + ); emit AddToBalance(_projectId, _amount, _refundedFees, _memo, _metadata, msg.sender); } - /** - @notice - Refund fees based on the specified amount. - - @param _projectId The project for which fees are being refunded. - @param _amount The amount to base the refund on, as a fixed point number with the same amount of decimals as this terminal. - - @return refundedFees How much fees were refunded, as a fixed point number with the same number of decimals as this terminal - */ - function _refundHeldFees(uint256 _projectId, uint256 _amount) - internal - returns (uint256 refundedFees) - { + /// @notice Refund fees based on the specified amount. + /// @param _projectId The project for which fees are being refunded. + /// @param _amount The amount to base the refund on, as a fixed point number with the same amount of decimals as this terminal. + /// @return refundedFees How much fees were refunded, as a fixed point number with the same number of decimals as this terminal + function _refundHeldFees( + uint256 _projectId, + uint256 _amount + ) internal returns (uint256 refundedFees) { // Get a reference to the project's held fees. JBFee[] memory _heldFees = _heldFeesOf[_projectId]; @@ -1537,16 +1353,11 @@ abstract contract JBPayoutRedemptionPaymentTerminal is emit RefundHeldFees(_projectId, _amount, refundedFees, leftoverAmount, msg.sender); } - /** - @notice - Returns the fee amount based on the provided amount for the specified project. - - @param _amount The amount that the fee is based on, as a fixed point number with the same amount of decimals as this terminal. - @param _fee The percentage of the fee, out of MAX_FEE. - @param _feeDiscount The percentage discount that should be applied out of the max amount, out of MAX_FEE_DISCOUNT. - - @return The amount of the fee, as a fixed point number with the same amount of decimals as this terminal. - */ + /// @notice Returns the fee amount based on the provided amount for the specified project. + /// @param _amount The amount that the fee is based on, as a fixed point number with the same amount of decimals as this terminal. + /// @param _fee The percentage of the fee, out of MAX_FEE. + /// @param _feeDiscount The percentage discount that should be applied out of the max amount, out of MAX_FEE_DISCOUNT. + /// @return The amount of the fee, as a fixed point number with the same amount of decimals as this terminal. function _feeAmount( uint256 _amount, uint256 _fee, @@ -1561,14 +1372,9 @@ abstract contract JBPayoutRedemptionPaymentTerminal is _amount - PRBMath.mulDiv(_amount, JBConstants.MAX_FEE, _discountedFee + JBConstants.MAX_FEE); } - /** - @notice - Get the fee discount from the fee gauge for the specified project. - - @param _projectId The ID of the project to get a fee discount for. - - @return feeDiscount The fee discount, which should be interpreted as a percentage out MAX_FEE_DISCOUNT. - */ + /// @notice Get the fee discount from the fee gauge for the specified project. + /// @param _projectId The ID of the project to get a fee discount for. + /// @return feeDiscount The fee discount, which should be interpreted as a percentage out MAX_FEE_DISCOUNT. function _currentFeeDiscount(uint256 _projectId) internal view returns (uint256) { // Can't take a fee if the protocol project doesn't have a terminal that accepts the token. if ( @@ -1577,9 +1383,9 @@ abstract contract JBPayoutRedemptionPaymentTerminal is ) return JBConstants.MAX_FEE_DISCOUNT; // Get the fee discount. - if (feeGauge != IJBFeeGauge(address(0))) + if (feeGauge != address(0)) // If the guage reverts, keep the discount at 0. - try feeGauge.currentDiscountFor(_projectId) returns (uint256 discount) { + try IJBFeeGauge(feeGauge).currentDiscountFor(_projectId) returns (uint256 discount) { // If the fee discount is greater than the max, we ignore the return value if (discount <= JBConstants.MAX_FEE_DISCOUNT) return discount; } catch { diff --git a/contracts/abstract/JBPayoutRedemptionPaymentTerminal3_1.sol b/contracts/abstract/JBPayoutRedemptionPaymentTerminal3_1.sol index 59291d676..cbb9b2b07 100644 --- a/contracts/abstract/JBPayoutRedemptionPaymentTerminal3_1.sol +++ b/contracts/abstract/JBPayoutRedemptionPaymentTerminal3_1.sol @@ -1,39 +1,44 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.16; -import '@openzeppelin/contracts/access/Ownable.sol'; -import '@openzeppelin/contracts/utils/introspection/ERC165Checker.sol'; -import '@paulrberg/contracts/math/PRBMath.sol'; -import './../interfaces/IJBController.sol'; -import './../interfaces/IJBPayoutRedemptionPaymentTerminal3_1.sol'; -import './../libraries/JBConstants.sol'; -import './../libraries/JBCurrencies.sol'; -import './../libraries/JBFixedPointNumber.sol'; -import './../libraries/JBFundingCycleMetadataResolver.sol'; -import './../libraries/JBOperations.sol'; -import './../libraries/JBTokens.sol'; -import './../structs/JBPayDelegateAllocation.sol'; -import './../structs/JBTokenAmount.sol'; -import './JBOperatable.sol'; -import './JBSingleTokenPaymentTerminal.sol'; - -/** - @notice - Generic terminal managing all inflows and outflows of funds into the protocol ecosystem. - - @dev - A project can transfer its funds, along with the power to reconfigure and mint/burn their tokens, from this contract to another allowed terminal of the same token type contract at any time. - - @dev - Adheres to - - IJBPayoutRedemptionPaymentTerminal3_1: General interface for the methods in this contract that interact with the blockchain's state according to the protocol's rules. - - @dev - Inherits from - - JBSingleTokenPaymentTerminal: Generic terminal managing all inflows of funds into the protocol ecosystem for one token. - JBOperatable: Includes convenience functionality for checking a message sender's permissions before executing certain transactions. - Ownable: Includes convenience functionality for checking a message sender's permissions before executing certain transactions. -*/ +import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol'; +import {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol'; +import {ERC165Checker} from '@openzeppelin/contracts/utils/introspection/ERC165Checker.sol'; +import {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol'; +import {IJBAllowanceTerminal3_1} from './../interfaces/IJBAllowanceTerminal3_1.sol'; +import {IJBController} from './../interfaces/IJBController.sol'; +import {IJBDirectory} from './../interfaces/IJBDirectory.sol'; +import {IJBFeeGauge} from './../interfaces/IJBFeeGauge.sol'; +import {IJBPayoutRedemptionPaymentTerminal3_1} from './../interfaces/IJBPayoutRedemptionPaymentTerminal3_1.sol'; +import {IJBSplitAllocator} from './../interfaces/IJBSplitAllocator.sol'; +import {IJBOperatable} from './../interfaces/IJBOperatable.sol'; +import {IJBOperatorStore} from './../interfaces/IJBOperatorStore.sol'; +import {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol'; +import {IJBPayoutTerminal3_1} from './../interfaces/IJBPayoutTerminal3_1.sol'; +import {IJBPrices} from './../interfaces/IJBPrices.sol'; +import {IJBProjects} from './../interfaces/IJBProjects.sol'; +import {IJBRedemptionTerminal} from './../interfaces/IJBRedemptionTerminal.sol'; +import {IJBSingleTokenPaymentTerminalStore} from './../interfaces/IJBSingleTokenPaymentTerminalStore.sol'; +import {IJBSplitsStore} from './../interfaces/IJBSplitsStore.sol'; +import {JBConstants} from './../libraries/JBConstants.sol'; +import {JBCurrencies} from './../libraries/JBCurrencies.sol'; +import {JBFixedPointNumber} from './../libraries/JBFixedPointNumber.sol'; +import {JBFundingCycleMetadataResolver} from './../libraries/JBFundingCycleMetadataResolver.sol'; +import {JBOperations} from './../libraries/JBOperations.sol'; +import {JBTokens} from './../libraries/JBTokens.sol'; +import {JBDidPayData} from './../structs/JBDidPayData.sol'; +import {JBDidRedeemData} from './../structs/JBDidRedeemData.sol'; +import {JBFee} from './../structs/JBFee.sol'; +import {JBFundingCycle} from './../structs/JBFundingCycle.sol'; +import {JBPayDelegateAllocation} from './../structs/JBPayDelegateAllocation.sol'; +import {JBTokenAmount} from './../structs/JBTokenAmount.sol'; +import {JBRedemptionDelegateAllocation} from './../structs/JBRedemptionDelegateAllocation.sol'; +import {JBSplit} from './../structs/JBSplit.sol'; +import {JBSplitAllocationData} from './../structs/JBSplitAllocationData.sol'; +import {JBOperatable} from './JBOperatable.sol'; +import {JBSingleTokenPaymentTerminal} from './JBSingleTokenPaymentTerminal.sol'; + +/// @notice Generic terminal managing all inflows and outflows of funds into the protocol ecosystem. abstract contract JBPayoutRedemptionPaymentTerminal3_1 is JBSingleTokenPaymentTerminal, JBOperatable, @@ -61,10 +66,7 @@ abstract contract JBPayoutRedemptionPaymentTerminal3_1 is // ---------------------------- modifiers ---------------------------- // //*********************************************************************// - /** - @notice - A modifier that verifies this terminal is a terminal of provided project ID. - */ + /// @notice A modifier that verifies this terminal is a terminal of provided project ID. modifier isTerminalOf(uint256 _projectId) { if (!directory.isTerminalOf(_projectId, this)) revert PROJECT_TERMINAL_MISMATCH(); _; @@ -74,136 +76,79 @@ abstract contract JBPayoutRedemptionPaymentTerminal3_1 is // --------------------- internal stored constants ------------------- // //*********************************************************************// - /** - @notice - Maximum fee that can be set for a funding cycle configuration. - - @dev - Out of MAX_FEE (50_000_000 / 1_000_000_000). - */ + /// @notice Maximum fee that can be set for a funding cycle configuration. + /// @dev Out of MAX_FEE (50_000_000 / 1_000_000_000). uint256 internal constant _FEE_CAP = 50_000_000; - /** - @notice - The fee beneficiary project ID is 1, as it should be the first project launched during the deployment process. - */ + /// @notice The fee beneficiary project ID is 1, as it should be the first project launched during the deployment process. uint256 internal constant _FEE_BENEFICIARY_PROJECT_ID = 1; //*********************************************************************// // --------------------- internal stored properties ------------------ // //*********************************************************************// - /** - @notice - Fees that are being held to be processed later. - - _projectId The ID of the project for which fees are being held. - */ + /// @notice Fees that are being held to be processed later. + /// @custom:param _projectId The ID of the project for which fees are being held. mapping(uint256 => JBFee[]) internal _heldFeesOf; //*********************************************************************// // ---------------- public immutable stored properties --------------- // //*********************************************************************// - /** - @notice - Mints ERC-721's that represent project ownership and transfers. - */ + /// @notice Mints ERC-721's that represent project ownership and transfers. IJBProjects public immutable override projects; - /** - @notice - The directory of terminals and controllers for projects. - */ + /// @notice The directory of terminals and controllers for projects. IJBDirectory public immutable override directory; - /** - @notice - The contract that stores splits for each project. - */ + /// @notice The contract that stores splits for each project. IJBSplitsStore public immutable override splitsStore; - /** - @notice - The contract that exposes price feeds. - */ + /// @notice The contract that exposes price feeds. IJBPrices public immutable override prices; - /** - @notice - The contract that stores and manages the terminal's data. - */ - IJBSingleTokenPaymentTerminalStore public immutable override store; + /// @notice The contract that stores and manages the terminal's data. + address public immutable override store; - /** - @notice - The currency to base token issuance on. - - @dev - If this differs from `currency`, there must be a price feed available to convert `currency` to `baseWeightCurrency`. - */ + /// @notice The currency to base token issuance on. + /// @dev If this differs from `currency`, there must be a price feed available to convert `currency` to `baseWeightCurrency`. uint256 public immutable override baseWeightCurrency; - /** - @notice - The group that payout splits coming from this terminal are identified by. - */ + /// @notice The group that payout splits coming from this terminal are identified by. uint256 public immutable override payoutSplitsGroup; //*********************************************************************// // --------------------- public stored properties -------------------- // //*********************************************************************// - /** - @notice - The platform fee percent. - - @dev - Out of MAX_FEE (25_000_000 / 1_000_000_000) - */ + /// @notice The platform fee percent. + /// @dev Out of MAX_FEE (25_000_000 / 1_000_000_000) uint256 public override fee = 25_000_000; // 2.5% - /** - @notice - The data source that returns a discount to apply to a project's fee. - */ - IJBFeeGauge public override feeGauge; + /// @notice The data source that returns a discount to apply to a project's fee. + address public override feeGauge; - /** - @notice - Addresses that can be paid towards from this terminal without incurring a fee. - - @dev - Only addresses that are considered to be contained within the ecosystem can be feeless. Funds sent outside the ecosystem may incur fees despite being stored as feeless. - - _address The address that can be paid toward. - */ + /// @notice Addresses that can be paid towards from this terminal without incurring a fee. + /// @dev Only addresses that are considered to be contained within the ecosystem can be feeless. Funds sent outside the ecosystem may incur fees despite being stored as feeless. + /// @custom:param _address The address that can be paid toward. mapping(address => bool) public override isFeelessAddress; //*********************************************************************// // ------------------------- external views -------------------------- // //*********************************************************************// - /** - @notice - Gets the current overflowed amount in this terminal for a specified project, in terms of ETH. - - @dev - The current overflow is represented as a fixed point number with 18 decimals. - - @param _projectId The ID of the project to get overflow for. - - @return The current amount of ETH overflow that project has in this terminal, as a fixed point number with 18 decimals. - */ - function currentEthOverflowOf(uint256 _projectId) - external - view - virtual - override - returns (uint256) - { + /// @notice Gets the current overflowed amount in this terminal for a specified project, in terms of ETH. + /// @dev The current overflow is represented as a fixed point number with 18 decimals. + /// @param _projectId The ID of the project to get overflow for. + /// @return The current amount of ETH overflow that project has in this terminal, as a fixed point number with 18 decimals. + function currentEthOverflowOf( + uint256 _projectId + ) external view virtual override returns (uint256) { // Get this terminal's current overflow. - uint256 _overflow = store.currentOverflowOf(this, _projectId); + uint256 _overflow = IJBSingleTokenPaymentTerminalStore(store).currentOverflowOf( + this, + _projectId + ); // Adjust the decimals of the fixed point number if needed to have 18 decimals. uint256 _adjustedOverflow = (decimals == 18) @@ -216,19 +161,14 @@ abstract contract JBPayoutRedemptionPaymentTerminal3_1 is ? _adjustedOverflow : PRBMath.mulDiv( _adjustedOverflow, - 10**decimals, + 10 ** decimals, prices.priceFor(currency, JBCurrencies.ETH, decimals) ); } - /** - @notice - The fees that are currently being held to be processed later for each project. - - @param _projectId The ID of the project for which fees are being held. - - @return An array of fees that are being held. - */ + /// @notice The fees that are currently being held to be processed later for each project. + /// @param _projectId The ID of the project for which fees are being held. + /// @return An array of fees that are being held. function heldFeesOf(uint256 _projectId) external view override returns (JBFee[] memory) { return _heldFeesOf[_projectId]; } @@ -237,22 +177,13 @@ abstract contract JBPayoutRedemptionPaymentTerminal3_1 is // -------------------------- public views --------------------------- // //*********************************************************************// - /** - @notice - Indicates if this contract adheres to the specified interface. - - @dev - See {IERC165-supportsInterface}. - - @param _interfaceId The ID of the interface to check for adherance to. - */ - function supportsInterface(bytes4 _interfaceId) - public - view - virtual - override(JBSingleTokenPaymentTerminal, IERC165) - returns (bool) - { + /// @notice Indicates if this contract adheres to the specified interface. + /// @dev See {IERC165-supportsInterface}. + /// @param _interfaceId The ID of the interface to check for adherance to. + /// @return A flag indicating if the provided interface ID is supported. + function supportsInterface( + bytes4 _interfaceId + ) public view virtual override(JBSingleTokenPaymentTerminal, IERC165) returns (bool) { return _interfaceId == type(IJBPayoutRedemptionPaymentTerminal3_1).interfaceId || _interfaceId == type(IJBPayoutTerminal3_1).interfaceId || @@ -266,32 +197,25 @@ abstract contract JBPayoutRedemptionPaymentTerminal3_1 is // -------------------------- internal views ------------------------- // //*********************************************************************// - /** - @notice - Checks the balance of tokens in this contract. - - @return The contract's balance. - */ + /// @notice Checks the balance of tokens in this contract. + /// @return The contract's balance. function _balance() internal view virtual returns (uint256); //*********************************************************************// // -------------------------- constructor ---------------------------- // //*********************************************************************// - /** - @param _token The token that this terminal manages. - @param _decimals The number of decimals the token fixed point amounts are expected to have. - @param _currency The currency that this terminal's token adheres to for price feeds. - @param _baseWeightCurrency The currency to base token issuance on. - @param _payoutSplitsGroup The group that denotes payout splits from this terminal in the splits store. - @param _operatorStore A contract storing operator assignments. - @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 _splitsStore A contract that stores splits for each project. - @param _prices A contract that exposes price feeds. - @param _store A contract that stores the terminal's data. - @param _owner The address that will own this contract. - */ + /// @param _decimals The number of decimals the token fixed point amounts are expected to have. + /// @param _currency The currency that this terminal's token adheres to for price feeds. + /// @param _baseWeightCurrency The currency to base token issuance on. + /// @param _payoutSplitsGroup The group that denotes payout splits from this terminal in the splits store. + /// @param _operatorStore A contract storing operator assignments. + /// @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 _splitsStore A contract that stores splits for each project. + /// @param _prices A contract that exposes price feeds. + /// @param _store A contract that stores the terminal's data. + /// @param _owner The address that will own this contract. constructor( // payable constructor save the gas used to check msg.value==0 address _token, @@ -304,7 +228,7 @@ abstract contract JBPayoutRedemptionPaymentTerminal3_1 is IJBDirectory _directory, IJBSplitsStore _splitsStore, IJBPrices _prices, - IJBSingleTokenPaymentTerminalStore _store, + address _store, address _owner ) payable @@ -326,21 +250,16 @@ abstract contract JBPayoutRedemptionPaymentTerminal3_1 is // ---------------------- external transactions ---------------------- // //*********************************************************************// - /** - @notice - Contribute tokens to a project. - - @param _projectId The ID of the project being paid. - @param _amount The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place. - @param _token The token being paid. This terminal ignores this property since it only manages one token. - @param _beneficiary The address to mint tokens for and pass along to the funding cycle's data source and delegate. - @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal. - @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas. - @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate. - @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided. - - @return The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals. - */ + /// @notice Contribute tokens to a project. + /// @param _projectId The ID of the project being paid. + /// @param _amount The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place. + /// @param _token The token being paid. This terminal ignores this property since it only manages one token. + /// @param _beneficiary The address to mint tokens for and pass along to the funding cycle's data source and delegate. + /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal. + /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas. + /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate. + /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided. + /// @return The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals. function pay( uint256 _projectId, uint256 _amount, @@ -382,24 +301,17 @@ abstract contract JBPayoutRedemptionPaymentTerminal3_1 is ); } - /** - @notice - Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source. - - @dev - Only a token holder or a designated operator can redeem its tokens. - - @param _holder The account to redeem tokens for. - @param _projectId The ID of the project to which the tokens being redeemed belong. - @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals. - @param _token The token being reclaimed. This terminal ignores this property since it only manages one token. - @param _minReturnedTokens The minimum amount of terminal tokens expected in return, as a fixed point number with the same amount of decimals as the terminal. - @param _beneficiary The address to send the terminal tokens to. - @param _memo A memo to pass along to the emitted event. - @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided. - - @return reclaimAmount The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals. - */ + /// @notice Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source. + /// @dev Only a token holder or a designated operator can redeem its tokens. + /// @param _holder The account to redeem tokens for. + /// @param _projectId The ID of the project to which the tokens being redeemed belong. + /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals. + /// @param _token The token being reclaimed. This terminal ignores this property since it only manages one token. + /// @param _minReturnedTokens The minimum amount of terminal tokens expected in return, as a fixed point number with the same amount of decimals as the terminal. + /// @param _beneficiary The address to send the terminal tokens to. + /// @param _memo A memo to pass along to the emitted event. + /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided. + /// @return reclaimAmount The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals. function redeemTokensOf( address _holder, uint256 _projectId, @@ -430,28 +342,17 @@ abstract contract JBPayoutRedemptionPaymentTerminal3_1 is ); } - /** - @notice - Distributes payouts for a project with the distribution limit of its current funding cycle. - - @dev - Payouts are sent to the preprogrammed splits. Any leftover is sent to the project's owner. - - @dev - 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. - - @dev - All funds distributed outside of this contract or any feeless terminals incure the protocol fee. - - @param _projectId The ID of the project having its payouts distributed. - @param _amount The amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal. - @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency. - @param _token The token being distributed. This terminal ignores this property since it only manages one token. - @param _minReturnedTokens 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. - @param _metadata Bytes to send along to the emitted event, if provided. - - @return netLeftoverDistributionAmount The amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal. - */ + /// @notice Distributes payouts for a project with the distribution limit of its current funding cycle. + /// @dev Payouts are sent to the preprogrammed splits. Any leftover is sent to the project's owner. + /// @dev 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. + /// @dev All funds distributed outside of this contract or any feeless terminals incure the protocol fee. + /// @param _projectId The ID of the project having its payouts distributed. + /// @param _amount The amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal. + /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency. + /// @param _token The token being distributed. This terminal ignores this property since it only manages one token. + /// @param _minReturnedTokens 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. + /// @param _metadata Bytes to send along to the emitted event, if provided. + /// @return netLeftoverDistributionAmount The amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal. function distributePayoutsOf( uint256 _projectId, uint256 _amount, @@ -465,27 +366,17 @@ abstract contract JBPayoutRedemptionPaymentTerminal3_1 is return _distributePayoutsOf(_projectId, _amount, _currency, _minReturnedTokens, _metadata); } - /** - @notice - Allows a project to send funds from its overflow up to the preconfigured allowance. - - @dev - Only a project's owner or a designated operator can use its allowance. - - @dev - Incurs the protocol fee. - - @param _projectId The ID of the project to use the allowance of. - @param _amount The amount of terminal tokens to use from this project's current allowance, as a fixed point number with the same amount of decimals as this terminal. - @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's overflow allowance currency. - @param _token The token being distributed. This terminal ignores this property since it only manages one token. - @param _minReturnedTokens The minimum number of tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with 18 decimals. - @param _beneficiary The address to send the funds to. - @param _memo A memo to pass along to the emitted event. - @param _metadata Bytes to send along to the emitted event, if provided. - - @return netDistributedAmount The amount of tokens that was distributed to the beneficiary, as a fixed point number with the same amount of decimals as the terminal. - */ + /// @notice Only a project's owner or a designated operator can use its allowance. + /// @dev Incurs the protocol fee. + /// @param _projectId The ID of the project to use the allowance of. + /// @param _amount The amount of terminal tokens to use from this project's current allowance, as a fixed point number with the same amount of decimals as this terminal. + /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's overflow allowance currency. + /// @param _token The token being distributed. This terminal ignores this property since it only manages one token. + /// @param _minReturnedTokens The minimum number of tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with 18 decimals. + /// @param _beneficiary The address to send the funds to. + /// @param _memo A memo to pass along to the emitted event. + /// @param _metadata Bytes to send along to the emitted event, if provided. + /// @return netDistributedAmount The amount of tokens that was distributed to the beneficiary, as a fixed point number with the same amount of decimals as the terminal. function useAllowanceOf( uint256 _projectId, uint256 _amount, @@ -516,19 +407,15 @@ abstract contract JBPayoutRedemptionPaymentTerminal3_1 is ); } - /** - @notice - Allows a project owner to migrate its funds and operations to a new terminal that accepts the same token type. - - @dev - Only a project's owner or a designated operator can migrate it. - - @param _projectId The ID of the project being migrated. - @param _to The terminal contract that will gain the project's funds. - - @return balance The amount of funds that were migrated, as a fixed point number with the same amount of decimals as this terminal. - */ - function migrate(uint256 _projectId, IJBPaymentTerminal _to) + /// @notice Allows a project owner to migrate its funds and operations to a new terminal that accepts the same token type. + /// @dev Only a project's owner or a designated operator can migrate it. + /// @param _projectId The ID of the project being migrated. + /// @param _to The terminal contract that will gain the project's funds. + /// @return balance The amount of funds that were migrated, as a fixed point number with the same amount of decimals as this terminal. + function migrate( + uint256 _projectId, + IJBPaymentTerminal _to + ) external virtual override @@ -539,7 +426,7 @@ abstract contract JBPayoutRedemptionPaymentTerminal3_1 is if (!_to.acceptsToken(token, _projectId)) revert TERMINAL_TOKENS_INCOMPATIBLE(); // Record the migration in the store. - balance = store.recordMigration(_projectId); + balance = IJBSingleTokenPaymentTerminalStore(store).recordMigration(_projectId); // Transfer the balance if needed. if (balance > 0) { @@ -556,16 +443,12 @@ abstract contract JBPayoutRedemptionPaymentTerminal3_1 is emit Migrate(_projectId, _to, balance, msg.sender); } - /** - @notice - Receives funds belonging to the specified project. - - @param _projectId The ID of the project to which the funds received belong. - @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead. - @param _token The token being paid. This terminal ignores this property since it only manages one currency. - @param _memo A memo to pass along to the emitted event. - @param _metadata Extra data to pass along to the emitted event. - */ + /// @notice Receives funds belonging to the specified project. + /// @param _projectId The ID of the project to which the funds received belong. + /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead. + /// @param _token The token being paid. This terminal ignores this property since it only manages one currency. + /// @param _memo A memo to pass along to the emitted event. + /// @param _metadata Extra data to pass along to the emitted event. function addToBalanceOf( uint256 _projectId, uint256 _amount, @@ -577,16 +460,12 @@ abstract contract JBPayoutRedemptionPaymentTerminal3_1 is addToBalanceOf(_projectId, _amount, _token, false, _memo, _metadata); } - /** - @notice - Process any fees that are being held for the project. - - @dev - Only a project owner, an operator, or the contract's owner can process held fees. - - @param _projectId The ID of the project whos held fees should be processed. - */ - function processFees(uint256 _projectId) + /// @notice Process any fees that are being held for the project. + /// @dev Only a project owner, an operator, or the contract's owner can process held fees. + /// @param _projectId The ID of the project whos held fees should be processed. + function processFees( + uint256 _projectId + ) external virtual override @@ -626,15 +505,9 @@ abstract contract JBPayoutRedemptionPaymentTerminal3_1 is } } - /** - @notice - Allows the fee to be updated. - - @dev - Only the owner of this contract can change the fee. - - @param _fee The new fee, out of MAX_FEE. - */ + /// @notice Allows the fee to be updated. + /// @dev Only the owner of this contract can change the fee. + /// @param _fee The new fee, out of MAX_FEE. function setFee(uint256 _fee) external virtual override onlyOwner { // The provided fee must be within the max. if (_fee > _FEE_CAP) revert FEE_TOO_HIGH(); @@ -645,32 +518,19 @@ abstract contract JBPayoutRedemptionPaymentTerminal3_1 is emit SetFee(_fee, msg.sender); } - /** - @notice - Allows the fee gauge to be updated. - - @dev - Only the owner of this contract can change the fee gauge. - - @param _feeGauge The new fee gauge. - */ - function setFeeGauge(IJBFeeGauge _feeGauge) external virtual override onlyOwner { + /// @notice Allows the fee gauge to be updated. + /// @dev Only the owner of this contract can change the fee gauge. + /// @param _feeGauge The new fee gauge. + function setFeeGauge(address _feeGauge) external virtual override onlyOwner { // Store the new fee gauge. feeGauge = _feeGauge; emit SetFeeGauge(_feeGauge, msg.sender); } - /** - @notice - Sets whether projects operating on this terminal can pay towards the specified address without incurring a fee. - - @dev - Only the owner of this contract can set addresses as feeless. - - @param _address The address that can be paid towards while still bypassing fees. - @param _flag A flag indicating whether the terminal should be feeless or not. - */ + /// @notice Sets whether projects operating on this terminal can pay towards the specified address without incurring a fee. + /// @param _address The address that can be paid towards while still bypassing fees. + /// @param _flag A flag indicating whether the terminal should be feeless or not. function setFeelessAddress(address _address, bool _flag) external virtual override onlyOwner { // Set the flag value. isFeelessAddress[_address] = _flag; @@ -682,17 +542,12 @@ abstract contract JBPayoutRedemptionPaymentTerminal3_1 is // ----------------------- public transactions ----------------------- // //*********************************************************************// - /** - @notice - Receives funds belonging to the specified project. - - @param _projectId The ID of the project to which the funds received belong. - @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead. - @param _token The token being paid. This terminal ignores this property since it only manages one currency. - @param _shouldRefundHeldFees A flag indicating if held fees should be refunded based on the amount being added. - @param _memo A memo to pass along to the emitted event. - @param _metadata Extra data to pass along to the emitted event. - */ + /// @notice Receives funds belonging to the specified project. + /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead. + /// @param _token The token being paid. This terminal ignores this property since it only manages one currency. + /// @param _shouldRefundHeldFees A flag indicating if held fees should be refunded based on the amount being added. + /// @param _memo A memo to pass along to the emitted event. + /// @param _metadata Extra data to pass along to the emitted event. function addToBalanceOf( uint256 _projectId, uint256 _amount, @@ -728,65 +583,42 @@ abstract contract JBPayoutRedemptionPaymentTerminal3_1 is // ---------------------- internal transactions ---------------------- // //*********************************************************************// - /** - @notice - Transfers tokens. - - @param _from The address from which the transfer should originate. - @param _to The address to which the transfer should go. - @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal. - */ - function _transferFrom( - address _from, - address payable _to, - uint256 _amount - ) internal virtual { + /// @notice Transfers tokens. + /// @param _from The address from which the transfer should originate. + /// @param _to The address to which the transfer should go. + /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal. + function _transferFrom(address _from, address payable _to, uint256 _amount) internal virtual { _from; // Prevents unused var compiler and natspec complaints. _to; // Prevents unused var compiler and natspec complaints. _amount; // Prevents unused var compiler and natspec complaints. } - /** - @notice - Logic to be triggered before transferring tokens from this terminal. - - @param _to The address to which the transfer is going. - @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal. - */ + /// @notice Logic to be triggered before transferring tokens from this terminal. + /// @param _to The address to which the transfer is going. + /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal. function _beforeTransferTo(address _to, uint256 _amount) internal virtual { _to; // Prevents unused var compiler and natspec complaints. _amount; // Prevents unused var compiler and natspec complaints. } - /** - @notice - Logic to be triggered if a transfer should be undone - - @param _to The address to which the transfer went. - @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal. - */ + /// @notice Logic to be triggered if a transfer should be undone + /// @param _to The address to which the transfer went. + /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal. function _cancelTransferTo(address _to, uint256 _amount) internal virtual { _to; // Prevents unused var compiler and natspec complaints. _amount; // Prevents unused var compiler and natspec complaints. } - /** - @notice - Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source. - - @dev - Only a token holder or a designated operator can redeem its tokens. - - @param _holder The account to redeem tokens for. - @param _projectId The ID of the project to which the tokens being redeemed belong. - @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals. - @param _minReturnedTokens The minimum amount of terminal tokens expected in return, as a fixed point number with the same amount of decimals as the terminal. - @param _beneficiary The address to send the terminal tokens to. - @param _memo A memo to pass along to the emitted event. - @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided. - - @return reclaimAmount The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals. - */ + /// @notice Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source. + /// @dev Only a token holder or a designated operator can redeem its tokens. + /// @param _holder The account to redeem tokens for. + /// @param _projectId The ID of the project to which the tokens being redeemed belong. + /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals. + /// @param _minReturnedTokens The minimum amount of terminal tokens expected in return, as a fixed point number with the same amount of decimals as the terminal. + /// @param _beneficiary The address to send the terminal tokens to. + /// @param _memo A memo to pass along to the emitted event. + /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided. + /// @return reclaimAmount The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals. function _redeemTokensOf( address _holder, uint256 _projectId, @@ -808,7 +640,12 @@ abstract contract JBPayoutRedemptionPaymentTerminal3_1 is JBRedemptionDelegateAllocation[] memory _delegateAllocations; // Record the redemption. - (_fundingCycle, reclaimAmount, _delegateAllocations, _memo) = store.recordRedemptionFor( + ( + _fundingCycle, + reclaimAmount, + _delegateAllocations, + _memo + ) = IJBSingleTokenPaymentTerminalStore(store).recordRedemptionFor( _holder, _projectId, _tokenCount, @@ -896,27 +733,16 @@ abstract contract JBPayoutRedemptionPaymentTerminal3_1 is ); } - /** - @notice - Distributes payouts for a project with the distribution limit of its current funding cycle. - - @dev - Payouts are sent to the preprogrammed splits. Any leftover is sent to the project's owner. - - @dev - 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. - - @dev - All funds distributed outside of this contract or any feeless terminals incure the protocol fee. - - @param _projectId The ID of the project having its payouts distributed. - @param _amount The amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal. - @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency. - @param _minReturnedTokens 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. - @param _metadata Bytes to send along to the emitted event, if provided. - - @return netLeftoverDistributionAmount The amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal. - */ + /// @notice Distributes payouts for a project with the distribution limit of its current funding cycle. + /// @dev Payouts are sent to the preprogrammed splits. Any leftover is sent to the project's owner. + /// @dev 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. + /// @dev All funds distributed outside of this contract or any feeless terminals incure the protocol fee. + /// @param _projectId The ID of the project having its payouts distributed. + /// @param _amount The amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal. + /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency. + /// @param _minReturnedTokens 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. + /// @param _metadata Bytes to send along to the emitted event, if provided. + /// @return netLeftoverDistributionAmount The amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal. function _distributePayoutsOf( uint256 _projectId, uint256 _amount, @@ -925,11 +751,14 @@ abstract contract JBPayoutRedemptionPaymentTerminal3_1 is bytes calldata _metadata ) internal returns (uint256 netLeftoverDistributionAmount) { // Record the distribution. - (JBFundingCycle memory _fundingCycle, uint256 _distributedAmount) = store.recordDistributionFor( - _projectId, - _amount, - _currency - ); + ( + JBFundingCycle memory _fundingCycle, + uint256 _distributedAmount + ) = IJBSingleTokenPaymentTerminalStore(store).recordDistributionFor( + _projectId, + _amount, + _currency + ); // The amount being distributed must be at least as much as was expected. if (_distributedAmount < _minReturnedTokens) revert INADEQUATE_DISTRIBUTION_AMOUNT(); @@ -1010,26 +839,17 @@ abstract contract JBPayoutRedemptionPaymentTerminal3_1 is ); } - /** - @notice - Allows a project to send funds from its overflow up to the preconfigured allowance. - - @dev - Only a project's owner or a designated operator can use its allowance. - - @dev - Incurs the protocol fee. - - @param _projectId The ID of the project to use the allowance of. - @param _amount The amount of terminal tokens to use from this project's current allowance, as a fixed point number with the same amount of decimals as this terminal. - @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's overflow allowance currency. - @param _minReturnedTokens The minimum number of tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with 18 decimals. - @param _beneficiary The address to send the funds to. - @param _memo A memo to pass along to the emitted event. - @param _metadata Bytes to send along to the emitted event, if provided. - - @return netDistributedAmount The amount of tokens that was distributed to the beneficiary, as a fixed point number with the same amount of decimals as the terminal. - */ + /// @notice Allows a project to send funds from its overflow up to the preconfigured allowance. + /// @dev Only a project's owner or a designated operator can use its allowance. + /// @dev Incurs the protocol fee. + /// @param _projectId The ID of the project to use the allowance of. + /// @param _amount The amount of terminal tokens to use from this project's current allowance, as a fixed point number with the same amount of decimals as this terminal. + /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's overflow allowance currency. + /// @param _minReturnedTokens The minimum number of tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with 18 decimals. + /// @param _beneficiary The address to send the funds to. + /// @param _memo A memo to pass along to the emitted event. + /// @param _metadata Bytes to send along to the emitted event, if provided. + /// @return netDistributedAmount The amount of tokens that was distributed to the beneficiary, as a fixed point number with the same amount of decimals as the terminal. function _useAllowanceOf( uint256 _projectId, uint256 _amount, @@ -1040,11 +860,14 @@ abstract contract JBPayoutRedemptionPaymentTerminal3_1 is bytes calldata _metadata ) internal returns (uint256 netDistributedAmount) { // Record the use of the allowance. - (JBFundingCycle memory _fundingCycle, uint256 _distributedAmount) = store.recordUsedAllowanceOf( - _projectId, - _amount, - _currency - ); + ( + JBFundingCycle memory _fundingCycle, + uint256 _distributedAmount + ) = IJBSingleTokenPaymentTerminalStore(store).recordUsedAllowanceOf( + _projectId, + _amount, + _currency + ); // The amount being withdrawn must be at least as much as was expected. if (_distributedAmount < _minReturnedTokens) revert INADEQUATE_DISTRIBUTION_AMOUNT(); @@ -1092,19 +915,14 @@ abstract contract JBPayoutRedemptionPaymentTerminal3_1 is ); } - /** - @notice - Pays out splits for a project's funding cycle configuration. - - @param _projectId The ID of the project for which payout splits are being distributed. - @param _domain The domain of the splits to distribute the payout between. - @param _group The group of the splits to distribute the payout between. - @param _amount The total amount being distributed, as a fixed point number with the same number of decimals as this terminal. - @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE. - - @return leftoverAmount If the leftover amount if the splits don't add up to 100%. - @return feeEligibleDistributionAmount The total amount of distributions that are eligible to have fees taken from. - */ + /// @notice Pays out splits for a project's funding cycle configuration. + /// @param _projectId The ID of the project for which payout splits are being distributed. + /// @param _domain The domain of the splits to distribute the payout between. + /// @param _group The group of the splits to distribute the payout between. + /// @param _amount The total amount being distributed, as a fixed point number with the same number of decimals as this terminal. + /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE. + /// @return leftoverAmount If the leftover amount if the splits don't add up to 100%. + /// @return feeEligibleDistributionAmount The total amount of distributions that are eligible to have fees taken from. function _distributeToPayoutSplitsOf( uint256 _projectId, uint256 _domain, @@ -1169,16 +987,11 @@ abstract contract JBPayoutRedemptionPaymentTerminal3_1 is } } - /** - @notice - Pays out a split for a project's funding cycle configuration. - - @param _split The split to distribute payouts to. - @param _amount The total amount being distributed to the split, as a fixed point number with the same number of decimals as this terminal. - @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE. - - @return netPayoutAmount The amount sent to the split after subtracting fees. - */ + /// @notice Pays out a split for a project's funding cycle configuration. + /// @param _split The split to distribute payouts to. + /// @param _amount The total amount being distributed to the split, as a fixed point number with the same number of decimals as this terminal. + /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE. + /// @return netPayoutAmount The amount sent to the split after subtracting fees. function _distributeToPayoutSplit( JBSplit memory _split, uint256 _projectId, @@ -1224,15 +1037,14 @@ abstract contract JBPayoutRedemptionPaymentTerminal3_1 is ) ) // If this terminal's token is ETH, send it in msg.value. - try _split.allocator.allocate{value: token == JBTokens.ETH ? netPayoutAmount : 0}(_data) { - - } catch (bytes memory reason) { + try + _split.allocator.allocate{value: token == JBTokens.ETH ? netPayoutAmount : 0}(_data) + {} catch (bytes memory reason) { _reason = reason; _error = 1; } else _error = 2; - if (_error != 0) { // Trigger any inhereted post-transfer cancelation logic. _cancelTransferTo(address(_split.allocator), netPayoutAmount); @@ -1241,9 +1053,15 @@ abstract contract JBPayoutRedemptionPaymentTerminal3_1 is netPayoutAmount = 0; // Add undistributed amount back to project's balance. - store.recordAddedBalanceFor(_projectId, _amount); + IJBSingleTokenPaymentTerminalStore(store).recordAddedBalanceFor(_projectId, _amount); - emit PayoutReverted(_projectId, _split, _amount, _error == 1 ? _reason : abi.encode("IERC165 fail"), msg.sender); + emit PayoutReverted( + _projectId, + _split, + _amount, + _error == 1 ? _reason : abi.encode('IERC165 fail'), + msg.sender + ); } // Otherwise, if a project is specified, make a payment to it. @@ -1293,7 +1111,7 @@ abstract contract JBPayoutRedemptionPaymentTerminal3_1 is netPayoutAmount = 0; // Add undistributed amount back to project's balance. - store.recordAddedBalanceFor(_projectId, _amount); + IJBSingleTokenPaymentTerminalStore(store).recordAddedBalanceFor(_projectId, _amount); emit PayoutReverted(_projectId, _split, _amount, reason, msg.sender); } @@ -1317,7 +1135,7 @@ abstract contract JBPayoutRedemptionPaymentTerminal3_1 is netPayoutAmount = 0; // Add undistributed amount back to project's balance. - store.recordAddedBalanceFor(_projectId, _amount); + IJBSingleTokenPaymentTerminalStore(store).recordAddedBalanceFor(_projectId, _amount); emit PayoutReverted(_projectId, _split, _amount, reason, msg.sender); } @@ -1343,18 +1161,13 @@ abstract contract JBPayoutRedemptionPaymentTerminal3_1 is } } - /** - @notice - Takes a fee into the platform's project, which has an id of _FEE_BENEFICIARY_PROJECT_ID. - - @param _projectId The ID of the project having fees taken from. - @param _fundingCycle The funding cycle during which the fee is being taken. - @param _amount The amount of the fee to take, as a floating point number with 18 decimals. - @param _beneficiary The address to mint the platforms tokens for. - @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE. - - @return feeAmount The amount of the fee taken. - */ + /// @notice Takes a fee into the platform's project, which has an id of _FEE_BENEFICIARY_PROJECT_ID. + /// @param _projectId The ID of the project having fees taken from. + /// @param _fundingCycle The funding cycle during which the fee is being taken. + /// @param _amount The amount of the fee to take, as a floating point number with 18 decimals. + /// @param _beneficiary The address to mint the platforms tokens for. + /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE. + /// @return feeAmount The amount of the fee taken. function _takeFeeFrom( uint256 _projectId, JBFundingCycle memory _fundingCycle, @@ -1377,19 +1190,11 @@ abstract contract JBPayoutRedemptionPaymentTerminal3_1 is } } - /** - @notice - Process a fee of the specified amount. - - @param _amount The fee amount, as a floating point number with 18 decimals. - @param _beneficiary The address to mint the platform's tokens for. - @param _from The project ID the fee is being paid from. - */ - function _processFee( - uint256 _amount, - address _beneficiary, - uint256 _from - ) internal { + /// @notice Process a fee of the specified amount. + /// @param _amount The fee amount, as a floating point number with 18 decimals. + /// @param _beneficiary The address to mint the platform's tokens for. + /// @param _from The project ID the fee is being paid from. + function _processFee(uint256 _amount, address _beneficiary, uint256 _from) internal { // Get the terminal for the protocol project. IJBPaymentTerminal _terminal = directory.primaryTerminalOf(_FEE_BENEFICIARY_PROJECT_ID, token); @@ -1420,27 +1225,22 @@ abstract contract JBPayoutRedemptionPaymentTerminal3_1 is if (address(_terminal) != address(this)) _cancelTransferTo(address(_terminal), _amount); // Add fee amount back to project's balance. - store.recordAddedBalanceFor(_from, _amount); + IJBSingleTokenPaymentTerminalStore(store).recordAddedBalanceFor(_from, _amount); - emit FeeReverted(_from, _FEE_BENEFICIARY_PROJECT_ID, _amount, reason, msg.sender); + emit FeeReverted(_from, _FEE_BENEFICIARY_PROJECT_ID, _amount, reason, msg.sender); } } - /** - @notice - Contribute tokens to a project. - - @param _amount The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place. - @param _payer The address making the payment. - @param _projectId The ID of the project being paid. - @param _beneficiary The address to mint tokens for and pass along to the funding cycle's data source and delegate. - @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal. - @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas. - @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate. - @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided. - - @return beneficiaryTokenCount The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals. - */ + /// @notice Contribute tokens to a project. + /// @param _amount The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place. + /// @param _payer The address making the payment. + /// @param _projectId The ID of the project being paid. + /// @param _beneficiary The address to mint tokens for and pass along to the funding cycle's data source and delegate. + /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal. + /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas. + /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate. + /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided. + /// @return beneficiaryTokenCount The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals. function _pay( uint256 _amount, address _payer, @@ -1467,7 +1267,12 @@ abstract contract JBPayoutRedemptionPaymentTerminal3_1 is JBTokenAmount memory _bundledAmount = JBTokenAmount(token, _amount, decimals, currency); // Record the payment. - (_fundingCycle, _tokenCount, _delegateAllocations, _memo) = store.recordPaymentFrom( + ( + _fundingCycle, + _tokenCount, + _delegateAllocations, + _memo + ) = IJBSingleTokenPaymentTerminalStore(store).recordPaymentFrom( _payer, _bundledAmount, _projectId, @@ -1559,16 +1364,12 @@ abstract contract JBPayoutRedemptionPaymentTerminal3_1 is ); } - /** - @notice - Receives funds belonging to the specified project. - - @param _projectId The ID of the project to which the funds received belong. - @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead. - @param _shouldRefundHeldFees A flag indicating if held fees should be refunded based on the amount being added. - @param _memo A memo to pass along to the emitted event. - @param _metadata Extra data to pass along to the emitted event. - */ + /// @notice Receives funds belonging to the specified project. + /// @param _projectId The ID of the project to which the funds received belong. + /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead. + /// @param _shouldRefundHeldFees A flag indicating if held fees should be refunded based on the amount being added. + /// @param _memo A memo to pass along to the emitted event. + /// @param _metadata Extra data to pass along to the emitted event. function _addToBalanceOf( uint256 _projectId, uint256 _amount, @@ -1580,24 +1381,22 @@ abstract contract JBPayoutRedemptionPaymentTerminal3_1 is uint256 _refundedFees = _shouldRefundHeldFees ? _refundHeldFees(_projectId, _amount) : 0; // Record the added funds with any refunded fees. - store.recordAddedBalanceFor(_projectId, _amount + _refundedFees); + IJBSingleTokenPaymentTerminalStore(store).recordAddedBalanceFor( + _projectId, + _amount + _refundedFees + ); emit AddToBalance(_projectId, _amount, _refundedFees, _memo, _metadata, msg.sender); } - /** - @notice - Refund fees based on the specified amount. - - @param _projectId The project for which fees are being refunded. - @param _amount The amount to base the refund on, as a fixed point number with the same amount of decimals as this terminal. - - @return refundedFees How much fees were refunded, as a fixed point number with the same number of decimals as this terminal - */ - function _refundHeldFees(uint256 _projectId, uint256 _amount) - internal - returns (uint256 refundedFees) - { + /// @notice Refund fees based on the specified amount. + /// @param _projectId The project for which fees are being refunded. + /// @param _amount The amount to base the refund on, as a fixed point number with the same amount of decimals as this terminal. + /// @return refundedFees How much fees were refunded, as a fixed point number with the same number of decimals as this terminal + function _refundHeldFees( + uint256 _projectId, + uint256 _amount + ) internal returns (uint256 refundedFees) { // Get a reference to the project's held fees. JBFee[] memory _heldFees = _heldFeesOf[_projectId]; @@ -1645,16 +1444,11 @@ abstract contract JBPayoutRedemptionPaymentTerminal3_1 is emit RefundHeldFees(_projectId, _amount, refundedFees, leftoverAmount, msg.sender); } - /** - @notice - Returns the fee amount based on the provided amount for the specified project. - - @param _amount The amount that the fee is based on, as a fixed point number with the same amount of decimals as this terminal. - @param _fee The percentage of the fee, out of MAX_FEE. - @param _feeDiscount The percentage discount that should be applied out of the max amount, out of MAX_FEE_DISCOUNT. - - @return The amount of the fee, as a fixed point number with the same amount of decimals as this terminal. - */ + /// @notice Returns the fee amount based on the provided amount for the specified project. + /// @param _amount The amount that the fee is based on, as a fixed point number with the same amount of decimals as this terminal. + /// @param _fee The percentage of the fee, out of MAX_FEE. + /// @param _feeDiscount The percentage discount that should be applied out of the max amount, out of MAX_FEE_DISCOUNT. + /// @return The amount of the fee, as a fixed point number with the same amount of decimals as this terminal. function _feeAmount( uint256 _amount, uint256 _fee, @@ -1669,14 +1463,9 @@ abstract contract JBPayoutRedemptionPaymentTerminal3_1 is _amount - PRBMath.mulDiv(_amount, JBConstants.MAX_FEE, _discountedFee + JBConstants.MAX_FEE); } - /** - @notice - Get the fee discount from the fee gauge for the specified project. - - @param _projectId The ID of the project to get a fee discount for. - - @return feeDiscount The fee discount, which should be interpreted as a percentage out MAX_FEE_DISCOUNT. - */ + /// @notice Get the fee discount from the fee gauge for the specified project. + /// @param _projectId The ID of the project to get a fee discount for. + /// @return feeDiscount The fee discount, which should be interpreted as a percentage out MAX_FEE_DISCOUNT. function _currentFeeDiscount(uint256 _projectId) internal view returns (uint256) { // Can't take a fee if the protocol project doesn't have a terminal that accepts the token. if ( @@ -1685,9 +1474,9 @@ abstract contract JBPayoutRedemptionPaymentTerminal3_1 is ) return JBConstants.MAX_FEE_DISCOUNT; // Get the fee discount. - if (feeGauge != IJBFeeGauge(address(0))) + if (feeGauge != address(0)) // If the guage reverts, keep the discount at 0. - try feeGauge.currentDiscountFor(_projectId) returns (uint256 discount) { + try IJBFeeGauge(feeGauge).currentDiscountFor(_projectId) returns (uint256 discount) { // If the fee discount is greater than the max, we ignore the return value if (discount <= JBConstants.MAX_FEE_DISCOUNT) return discount; } catch { diff --git a/contracts/abstract/JBPayoutRedemptionPaymentTerminal3_1_1.sol b/contracts/abstract/JBPayoutRedemptionPaymentTerminal3_1_1.sol new file mode 100644 index 000000000..535c89145 --- /dev/null +++ b/contracts/abstract/JBPayoutRedemptionPaymentTerminal3_1_1.sol @@ -0,0 +1,1606 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.16; + +import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol'; +import {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol'; +import {ERC165Checker} from '@openzeppelin/contracts/utils/introspection/ERC165Checker.sol'; +import {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol'; +import {JBFeeType} from './../enums/JBFeeType.sol'; +import {IJBAllowanceTerminal3_1} from './../interfaces/IJBAllowanceTerminal3_1.sol'; +import {IJBController} from './../interfaces/IJBController.sol'; +import {IJBDirectory} from './../interfaces/IJBDirectory.sol'; +import {IJBPayoutRedemptionPaymentTerminal3_1} from './../interfaces/IJBPayoutRedemptionPaymentTerminal3_1.sol'; +import {IJBPayoutRedemptionPaymentTerminal3_1_1} from './../interfaces/IJBPayoutRedemptionPaymentTerminal3_1_1.sol'; +import {IJBSplitsStore} from './../interfaces/IJBSplitsStore.sol'; +import {IJBFeeGauge3_1} from './../interfaces/IJBFeeGauge3_1.sol'; +import {IJBOperatable} from './../interfaces/IJBOperatable.sol'; +import {IJBOperatorStore} from './../interfaces/IJBOperatorStore.sol'; +import {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol'; +import {IJBPayoutTerminal3_1} from './../interfaces/IJBPayoutTerminal3_1.sol'; +import {IJBPrices} from './../interfaces/IJBPrices.sol'; +import {IJBProjects} from './../interfaces/IJBProjects.sol'; +import {IJBRedemptionTerminal} from './../interfaces/IJBRedemptionTerminal.sol'; +import {IJBSingleTokenPaymentTerminalStore3_1_1} from './../interfaces/IJBSingleTokenPaymentTerminalStore3_1_1.sol'; +import {IJBSplitAllocator} from './../interfaces/IJBSplitAllocator.sol'; +import {JBConstants} from './../libraries/JBConstants.sol'; +import {JBCurrencies} from './../libraries/JBCurrencies.sol'; +import {JBFixedPointNumber} from './../libraries/JBFixedPointNumber.sol'; +import {JBFundingCycleMetadataResolver} from './../libraries/JBFundingCycleMetadataResolver.sol'; +import {JBOperations} from './../libraries/JBOperations.sol'; +import {JBTokens} from './../libraries/JBTokens.sol'; +import {JBDidRedeemData3_1_1} from './../structs/JBDidRedeemData3_1_1.sol'; +import {JBDidPayData3_1_1} from './../structs/JBDidPayData3_1_1.sol'; +import {JBFee} from './../structs/JBFee.sol'; +import {JBFundingCycle} from './../structs/JBFundingCycle.sol'; +import {JBPayDelegateAllocation3_1_1} from './../structs/JBPayDelegateAllocation3_1_1.sol'; +import {JBRedemptionDelegateAllocation3_1_1} from './../structs/JBRedemptionDelegateAllocation3_1_1.sol'; +import {JBSplit} from './../structs/JBSplit.sol'; +import {JBSplitAllocationData} from './../structs/JBSplitAllocationData.sol'; +import {JBTokenAmount} from './../structs/JBTokenAmount.sol'; +import {JBOperatable} from './JBOperatable.sol'; +import {JBSingleTokenPaymentTerminal} from './JBSingleTokenPaymentTerminal.sol'; + +/// @notice Generic terminal managing all inflows and outflows of funds into the protocol ecosystem. +abstract contract JBPayoutRedemptionPaymentTerminal3_1_1 is + JBSingleTokenPaymentTerminal, + JBOperatable, + Ownable, + IJBPayoutRedemptionPaymentTerminal3_1, + IJBPayoutRedemptionPaymentTerminal3_1_1 +{ + // A library that parses the packed funding cycle metadata into a friendlier format. + using JBFundingCycleMetadataResolver for JBFundingCycle; + + //*********************************************************************// + // --------------------------- custom errors ------------------------- // + //*********************************************************************// + error FEE_TOO_HIGH(); + error INADEQUATE_DISTRIBUTION_AMOUNT(); + error INADEQUATE_RECLAIM_AMOUNT(); + error INADEQUATE_TOKEN_COUNT(); + error NO_MSG_VALUE_ALLOWED(); + error PAY_TO_ZERO_ADDRESS(); + error PROJECT_TERMINAL_MISMATCH(); + error REDEEM_TO_ZERO_ADDRESS(); + error TERMINAL_TOKENS_INCOMPATIBLE(); + + //*********************************************************************// + // --------------------- internal stored constants ------------------- // + //*********************************************************************// + + /// @notice Maximum fee that can be set for a funding cycle configuration. + /// @dev Out of MAX_FEE (50_000_000 / 1_000_000_000). + uint256 internal constant _FEE_CAP = 50_000_000; + + /// @notice The fee beneficiary project ID is 1, as it should be the first project launched during the deployment process. + uint256 internal constant _FEE_BENEFICIARY_PROJECT_ID = 1; + + //*********************************************************************// + // --------------------- internal stored properties ------------------ // + //*********************************************************************// + + /// @notice Fees that are being held to be processed later. + /// @custom:param _projectId The ID of the project for which fees are being held. + mapping(uint256 => JBFee[]) internal _heldFeesOf; + + //*********************************************************************// + // ---------------- public immutable stored properties --------------- // + //*********************************************************************// + + /// @notice Mints ERC-721's that represent project ownership and transfers. + IJBProjects public immutable override projects; + + /// @notice The directory of terminals and controllers for projects. + IJBDirectory public immutable override directory; + + /// @notice The contract that stores splits for each project. + IJBSplitsStore public immutable override splitsStore; + + /// @notice The contract that exposes price feeds. + IJBPrices public immutable override prices; + + /// @notice The contract that stores and manages the terminal's data. + address public immutable override store; + + /// @notice The currency to base token issuance on. + /// @dev If this differs from `currency`, there must be a price feed available to convert `currency` to `baseWeightCurrency`. + uint256 public immutable override baseWeightCurrency; + + /// @notice The group that payout splits coming from this terminal are identified by. + uint256 public immutable override payoutSplitsGroup; + + //*********************************************************************// + // --------------------- public stored properties -------------------- // + //*********************************************************************// + + /// @notice The platform fee percent. + /// @dev Out of MAX_FEE (25_000_000 / 1_000_000_000) + uint256 public override fee = 25_000_000; // 2.5% + + /// @notice The data source that returns a discount to apply to a project's fee. + address public override feeGauge; + + /// @notice Addresses that can be paid towards from this terminal without incurring a fee. + /// @dev Only addresses that are considered to be contained within the ecosystem can be feeless. Funds sent outside the ecosystem may incur fees despite being stored as feeless. + /// @custom:param _address The address that can be paid toward. + mapping(address => bool) public override isFeelessAddress; + + //*********************************************************************// + // ------------------------- external views -------------------------- // + //*********************************************************************// + + /// @notice Gets the current overflowed amount in this terminal for a specified project, in terms of ETH. + /// @dev The current overflow is represented as a fixed point number with 18 decimals. + /// @param _projectId The ID of the project to get overflow for. + /// @return The current amount of ETH overflow that project has in this terminal, as a fixed point number with 18 decimals. + function currentEthOverflowOf( + uint256 _projectId + ) external view virtual override returns (uint256) { + // Get this terminal's current overflow. + uint256 _overflow = IJBSingleTokenPaymentTerminalStore3_1_1(store).currentOverflowOf( + this, + _projectId + ); + + // Adjust the decimals of the fixed point number if needed to have 18 decimals. + uint256 _adjustedOverflow = (decimals == 18) + ? _overflow + : JBFixedPointNumber.adjustDecimals(_overflow, decimals, 18); + + // Return the amount converted to ETH. + return + (currency == JBCurrencies.ETH) + ? _adjustedOverflow + : PRBMath.mulDiv( + _adjustedOverflow, + 10 ** decimals, + prices.priceFor(currency, JBCurrencies.ETH, decimals) + ); + } + + /// @notice The fees that are currently being held to be processed later for each project. + /// @param _projectId The ID of the project for which fees are being held. + /// @return An array of fees that are being held. + function heldFeesOf(uint256 _projectId) external view override returns (JBFee[] memory) { + return _heldFeesOf[_projectId]; + } + + //*********************************************************************// + // -------------------------- public views --------------------------- // + //*********************************************************************// + + /// @notice Indicates if this contract adheres to the specified interface. + /// @dev See {IERC165-supportsInterface}. + /// @param _interfaceId The ID of the interface to check for adherance to. + /// @return A flag indicating if the provided interface ID is supported. + function supportsInterface( + bytes4 _interfaceId + ) public view virtual override(JBSingleTokenPaymentTerminal, IERC165) returns (bool) { + return + _interfaceId == type(IJBPayoutRedemptionPaymentTerminal3_1_1).interfaceId || + _interfaceId == type(IJBPayoutRedemptionPaymentTerminal3_1).interfaceId || + _interfaceId == type(IJBPayoutTerminal3_1).interfaceId || + _interfaceId == type(IJBAllowanceTerminal3_1).interfaceId || + _interfaceId == type(IJBRedemptionTerminal).interfaceId || + _interfaceId == type(IJBOperatable).interfaceId || + super.supportsInterface(_interfaceId); + } + + //*********************************************************************// + // -------------------------- internal views ------------------------- // + //*********************************************************************// + + /// @notice Checks the balance of tokens in this contract. + /// @return The contract's balance. + function _balance() internal view virtual returns (uint256); + + //*********************************************************************// + // -------------------------- constructor ---------------------------- // + //*********************************************************************// + + /// @param _token The token that this terminal manages. + /// @param _decimals The number of decimals the token fixed point amounts are expected to have. + /// @param _currency The currency that this terminal's token adheres to for price feeds. + /// @param _baseWeightCurrency The currency to base token issuance on. + /// @param _payoutSplitsGroup The group that denotes payout splits from this terminal in the splits store. + /// @param _operatorStore A contract storing operator assignments. + /// @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 _splitsStore A contract that stores splits for each project. + /// @param _prices A contract that exposes price feeds. + /// @param _store A contract that stores the terminal's data. + /// @param _owner The address that will own this contract. + constructor( + // payable constructor save the gas used to check msg.value==0 + address _token, + uint256 _decimals, + uint256 _currency, + uint256 _baseWeightCurrency, + uint256 _payoutSplitsGroup, + IJBOperatorStore _operatorStore, + IJBProjects _projects, + IJBDirectory _directory, + IJBSplitsStore _splitsStore, + IJBPrices _prices, + address _store, + address _owner + ) + payable + JBSingleTokenPaymentTerminal(_token, _decimals, _currency) + JBOperatable(_operatorStore) + { + baseWeightCurrency = _baseWeightCurrency; + payoutSplitsGroup = _payoutSplitsGroup; + projects = _projects; + directory = _directory; + splitsStore = _splitsStore; + prices = _prices; + store = _store; + + transferOwnership(_owner); + } + + //*********************************************************************// + // ---------------------- external transactions ---------------------- // + //*********************************************************************// + + /// @notice Contribute tokens to a project. + /// @param _projectId The ID of the project being paid. + /// @param _amount The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place. + /// @param _token The token being paid. This terminal ignores this property since it only manages one token. + /// @param _beneficiary The address to mint tokens for and pass along to the funding cycle's data source and delegate. + /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal. + /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas. + /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate. + /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided. + /// @return The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals. + function pay( + uint256 _projectId, + uint256 _amount, + address _token, + address _beneficiary, + uint256 _minReturnedTokens, + bool _preferClaimedTokens, + string calldata _memo, + bytes calldata _metadata + ) external payable virtual override returns (uint256) { + _token; // Prevents unused var compiler and natspec complaints. + + // valid terminal check + _isTerminalOf(_projectId); + + // ETH shouldn't be sent if this terminal's token isn't ETH. + if (token != JBTokens.ETH) { + if (msg.value != 0) revert NO_MSG_VALUE_ALLOWED(); + + // Get a reference to the balance before receiving tokens. + uint256 _balanceBefore = _balance(); + + // Transfer tokens to this terminal from the msg sender. + _transferFrom(msg.sender, payable(address(this)), _amount); + + // The amount should reflect the change in balance. + _amount = _balance() - _balanceBefore; + } + // If this terminal's token is ETH, override _amount with msg.value. + else _amount = msg.value; + + return + _pay( + _amount, + msg.sender, + _projectId, + _beneficiary, + _minReturnedTokens, + _preferClaimedTokens, + _memo, + _metadata + ); + } + + /// @notice Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source. + /// @dev Only a token holder or a designated operator can redeem its tokens. + /// @param _holder The account to redeem tokens for. + /// @param _projectId The ID of the project to which the tokens being redeemed belong. + /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals. + /// @param _token The token being reclaimed. This terminal ignores this property since it only manages one token. + /// @param _minReturnedTokens The minimum amount of terminal tokens expected in return, as a fixed point number with the same amount of decimals as the terminal. + /// @param _beneficiary The address to send the terminal tokens to. + /// @param _memo A memo to pass along to the emitted event. + /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided. + /// @return reclaimAmount The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals. + function redeemTokensOf( + address _holder, + uint256 _projectId, + uint256 _tokenCount, + address _token, + uint256 _minReturnedTokens, + address payable _beneficiary, + string memory _memo, + bytes memory _metadata + ) + external + virtual + override + requirePermission(_holder, _projectId, JBOperations.REDEEM) + returns (uint256 reclaimAmount) + { + _token; // Prevents unused var compiler and natspec complaints. + + return + _redeemTokensOf( + _holder, + _projectId, + _tokenCount, + _minReturnedTokens, + _beneficiary, + _memo, + _metadata + ); + } + + /// @notice Distributes payouts for a project with the distribution limit of its current funding cycle. + /// @dev Payouts are sent to the preprogrammed splits. Any leftover is sent to the project's owner. + /// @dev 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. + /// @dev All funds distributed outside of this contract or any feeless terminals incure the protocol fee. + /// @param _projectId The ID of the project having its payouts distributed. + /// @param _amount The amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal. + /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency. + /// @param _token The token being distributed. This terminal ignores this property since it only manages one token. + /// @param _minReturnedTokens 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. + /// @param _metadata Bytes to send along to the emitted event, if provided. + /// @return netLeftoverDistributionAmount The amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal. + function distributePayoutsOf( + uint256 _projectId, + uint256 _amount, + uint256 _currency, + address _token, + uint256 _minReturnedTokens, + bytes calldata _metadata + ) external virtual override returns (uint256 netLeftoverDistributionAmount) { + _token; // Prevents unused var compiler and natspec complaints. + + return _distributePayoutsOf(_projectId, _amount, _currency, _minReturnedTokens, _metadata); + } + + /// @notice Allows a project to send funds from its overflow up to the preconfigured allowance. + /// @dev Only a project's owner or a designated operator can use its allowance. + /// @dev Incurs the protocol fee. + /// @param _projectId The ID of the project to use the allowance of. + /// @param _amount The amount of terminal tokens to use from this project's current allowance, as a fixed point number with the same amount of decimals as this terminal. + /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's overflow allowance currency. + /// @param _token The token being distributed. This terminal ignores this property since it only manages one token. + /// @param _minReturnedTokens The minimum number of tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with 18 decimals. + /// @param _beneficiary The address to send the funds to. + /// @param _memo A memo to pass along to the emitted event. + /// @param _metadata Bytes to send along to the emitted event, if provided. + /// @return netDistributedAmount The amount of tokens that was distributed to the beneficiary, as a fixed point number with the same amount of decimals as the terminal. + function useAllowanceOf( + uint256 _projectId, + uint256 _amount, + uint256 _currency, + address _token, + uint256 _minReturnedTokens, + address payable _beneficiary, + string memory _memo, + bytes calldata _metadata + ) + external + virtual + override + requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.USE_ALLOWANCE) + returns (uint256 netDistributedAmount) + { + _token; // Prevents unused var compiler and natspec complaints. + + return + _useAllowanceOf( + _projectId, + _amount, + _currency, + _minReturnedTokens, + _beneficiary, + _memo, + _metadata + ); + } + + /// @notice Allows a project owner to migrate its funds and operations to a new terminal that accepts the same token type. + /// @dev Only a project's owner or a designated operator can migrate it. + /// @param _projectId The ID of the project being migrated. + /// @param _to The terminal contract that will gain the project's funds. + /// @return balance The amount of funds that were migrated, as a fixed point number with the same amount of decimals as this terminal. + function migrate( + uint256 _projectId, + IJBPaymentTerminal _to + ) + external + virtual + override + requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.MIGRATE_TERMINAL) + returns (uint256 balance) + { + // The terminal being migrated to must accept the same token as this terminal. + if (!_to.acceptsToken(token, _projectId)) revert TERMINAL_TOKENS_INCOMPATIBLE(); + + // Record the migration in the store. + balance = IJBSingleTokenPaymentTerminalStore3_1_1(store).recordMigration(_projectId); + + // Transfer the balance if needed. + if (balance != 0) { + // Trigger any inherited pre-transfer logic. + _beforeTransferTo(address(_to), balance); + + // If this terminal's token is ETH, send it in msg.value. + uint256 _payableValue = token == JBTokens.ETH ? balance : 0; + + // Withdraw the balance to transfer to the new terminal; + _to.addToBalanceOf{value: _payableValue}(_projectId, balance, token, '', bytes('')); + } + + emit Migrate(_projectId, _to, balance, msg.sender); + } + + /// @notice Receives funds belonging to the specified project. + /// @param _projectId The ID of the project to which the funds received belong. + /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead. + /// @param _token The token being paid. This terminal ignores this property since it only manages one currency. + /// @param _memo A memo to pass along to the emitted event. + /// @param _metadata Extra data to pass along to the emitted event. + function addToBalanceOf( + uint256 _projectId, + uint256 _amount, + address _token, + string calldata _memo, + bytes calldata _metadata + ) external payable virtual override { + // valid terminal check + _isTerminalOf(_projectId); + + // Do not refund held fees by default. + addToBalanceOf(_projectId, _amount, _token, false, _memo, _metadata); + } + + /// @notice Process any fees that are being held for the project. + /// @dev Only a project owner, an operator, or the contract's owner can process held fees. + /// @param _projectId The ID of the project whos held fees should be processed. + function processFees( + uint256 _projectId + ) + external + virtual + override + requirePermissionAllowingOverride( + projects.ownerOf(_projectId), + _projectId, + JBOperations.PROCESS_FEES, + msg.sender == owner() + ) + { + // Get a reference to the project's held fees. + JBFee[] memory _heldFees = _heldFeesOf[_projectId]; + + // Delete the held fees. + delete _heldFeesOf[_projectId]; + + // Push array length in stack + uint256 _heldFeeLength = _heldFees.length; + + // Keep a reference to the amount. + uint256 _amount; + + // Process each fee. + for (uint256 _i; _i < _heldFeeLength; ) { + // Get the fee amount. + _amount = ( + _heldFees[_i].fee == 0 || _heldFees[_i].feeDiscount == JBConstants.MAX_FEE_DISCOUNT + ? 0 + : _feeAmount(_heldFees[_i].amount, _heldFees[_i].fee, _heldFees[_i].feeDiscount) + ); + + // Process the fee. + _processFee(_amount, _heldFees[_i].beneficiary, _projectId); + + emit ProcessFee(_projectId, _amount, true, _heldFees[_i].beneficiary, msg.sender); + + unchecked { + ++_i; + } + } + } + + /// @notice Allows the fee to be updated. + /// @dev Only the owner of this contract can change the fee. + /// @param _fee The new fee, out of MAX_FEE. + function setFee(uint256 _fee) external virtual override onlyOwner { + // The provided fee must be within the max. + if (_fee > _FEE_CAP) revert FEE_TOO_HIGH(); + + // Store the new fee. + fee = _fee; + + emit SetFee(_fee, msg.sender); + } + + /// @notice Allows the fee gauge to be updated. + /// @dev Only the owner of this contract can change the fee gauge. + /// @param _feeGauge The new fee gauge. + function setFeeGauge(address _feeGauge) external virtual override onlyOwner { + // Store the new fee gauge. + feeGauge = _feeGauge; + + emit SetFeeGauge(_feeGauge, msg.sender); + } + + /// @notice Sets whether projects operating on this terminal can pay towards the specified address without incurring a fee. + /// @dev Only the owner of this contract can set addresses as feeless. + /// @param _address The address that can be paid towards while still bypassing fees. + /// @param _flag A flag indicating whether the terminal should be feeless or not. + function setFeelessAddress(address _address, bool _flag) external virtual override onlyOwner { + // Set the flag value. + isFeelessAddress[_address] = _flag; + + emit SetFeelessAddress(_address, _flag, msg.sender); + } + + //*********************************************************************// + // ----------------------- public transactions ----------------------- // + //*********************************************************************// + + /// @notice Receives funds belonging to the specified project. + /// @param _projectId The ID of the project to which the funds received belong. + /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead. + /// @param _token The token being paid. This terminal ignores this property since it only manages one currency. + /// @param _shouldRefundHeldFees A flag indicating if held fees should be refunded based on the amount being added. + /// @param _memo A memo to pass along to the emitted event. + /// @param _metadata Extra data to pass along to the emitted event. + function addToBalanceOf( + uint256 _projectId, + uint256 _amount, + address _token, + bool _shouldRefundHeldFees, + string calldata _memo, + bytes calldata _metadata + ) public payable virtual override { + // valid terminal check + _isTerminalOf(_projectId); + + _token; // Prevents unused var compiler and natspec complaints. + + // If this terminal's token isn't ETH, make sure no msg.value was sent, then transfer the tokens in from msg.sender. + if (token != JBTokens.ETH) { + // Amount must be greater than 0. + if (msg.value != 0) revert NO_MSG_VALUE_ALLOWED(); + + // Get a reference to the balance before receiving tokens. + uint256 _balanceBefore = _balance(); + + // Transfer tokens to this terminal from the msg sender. + _transferFrom(msg.sender, payable(address(this)), _amount); + + // The amount should reflect the change in balance. + _amount = _balance() - _balanceBefore; + } + // If the terminal's token is ETH, override `_amount` with msg.value. + else _amount = msg.value; + + // Add to balance. + _addToBalanceOf(_projectId, _amount, _shouldRefundHeldFees, _memo, _metadata); + } + + //*********************************************************************// + // ---------------------- internal transactions ---------------------- // + //*********************************************************************// + + /// @notice Transfers tokens. + /// @param _from The address from which the transfer should originate. + /// @param _to The address to which the transfer should go. + /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal. + function _transferFrom(address _from, address payable _to, uint256 _amount) internal virtual { + _from; // Prevents unused var compiler and natspec complaints. + _to; // Prevents unused var compiler and natspec complaints. + _amount; // Prevents unused var compiler and natspec complaints. + } + + /// @notice Logic to be triggered before transferring tokens from this terminal. + /// @param _to The address to which the transfer is going. + /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal. + function _beforeTransferTo(address _to, uint256 _amount) internal virtual { + _to; // Prevents unused var compiler and natspec complaints. + _amount; // Prevents unused var compiler and natspec complaints. + } + + /// @notice Logic to be triggered if a transfer should be undone + /// @param _to The address to which the transfer went. + /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal. + function _cancelTransferTo(address _to, uint256 _amount) internal virtual { + _to; // Prevents unused var compiler and natspec complaints. + _amount; // Prevents unused var compiler and natspec complaints. + } + + /// @notice Verifies this terminal is a terminal of provided project ID. + /// @param _projectId The ID of the project to check if this contract is a terminal of. + function _isTerminalOf(uint256 _projectId) internal view { + if (!directory.isTerminalOf(_projectId, this)) revert PROJECT_TERMINAL_MISMATCH(); + } + + /// @notice Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source. + /// @dev Only a token holder or a designated operator can redeem its tokens. + /// @param _holder The account to redeem tokens for. + /// @param _projectId The ID of the project to which the tokens being redeemed belong. + /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals. + /// @param _minReturnedTokens The minimum amount of terminal tokens expected in return, as a fixed point number with the same amount of decimals as the terminal. + /// @param _beneficiary The address to send the terminal tokens to. + /// @param _memo A memo to pass along to the emitted event. + /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided. + /// @return reclaimAmount The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals. + function _redeemTokensOf( + address _holder, + uint256 _projectId, + uint256 _tokenCount, + uint256 _minReturnedTokens, + address payable _beneficiary, + string memory _memo, + bytes memory _metadata + ) internal returns (uint256 reclaimAmount) { + // Can't send reclaimed funds to the zero address. + if (_beneficiary == address(0)) revert REDEEM_TO_ZERO_ADDRESS(); + + // Define variables that will be needed outside the scoped section below. + // Keep a reference to the funding cycle during which the redemption is being made. + JBFundingCycle memory _fundingCycle; + + // Scoped section prevents stack too deep. `_feeEligibleDistributionAmount`, `_feeDiscount` and `_feePercent` only used within scope. + { + // Keep a reference to the amount being reclaimed that should have fees withheld from. + uint256 _feeEligibleDistributionAmount; + + // Keep a reference to the amount of discount to apply to the fee. + uint256 _feeDiscount; + + // Keep a reference to the fee. + uint256 _feePercent = fee; + + // Scoped section prevents stack too deep. `_delegateAllocations` only used within scope. + { + JBRedemptionDelegateAllocation3_1_1[] memory _delegateAllocations; + + // Record the redemption. + ( + _fundingCycle, + reclaimAmount, + _delegateAllocations, + _memo + ) = IJBSingleTokenPaymentTerminalStore3_1_1(store).recordRedemptionFor( + _holder, + _projectId, + _tokenCount, + _memo, + _metadata + ); + + // Set the reference to the fee discount to apply. No fee if the beneficiary is feeless or if the redemption rate is at its max. + _feeDiscount = isFeelessAddress[_beneficiary] || + (_fundingCycle.redemptionRate() == JBConstants.MAX_REDEMPTION_RATE && + _fundingCycle.ballotRedemptionRate() == JBConstants.MAX_REDEMPTION_RATE) || + _feePercent == 0 + ? JBConstants.MAX_FEE_DISCOUNT + : _currentFeeDiscount(_projectId, JBFeeType.REDEMPTION); + + // The amount being reclaimed must be at least as much as was expected. + if (reclaimAmount < _minReturnedTokens) revert INADEQUATE_RECLAIM_AMOUNT(); + + // Burn the project tokens. + if (_tokenCount != 0) + IJBController(directory.controllerOf(_projectId)).burnTokensOf( + _holder, + _projectId, + _tokenCount, + '', + false + ); + + // If delegate allocations were specified by the data source, fulfill them. + if (_delegateAllocations.length != 0) { + JBDidRedeemData3_1_1 memory _data = JBDidRedeemData3_1_1( + _holder, + _projectId, + _fundingCycle.configuration, + _tokenCount, + JBTokenAmount(token, reclaimAmount, decimals, currency), + JBTokenAmount(token, 0, decimals, currency), + _beneficiary, + _memo, + bytes(''), + _metadata + ); + + // Keep a reference to the allocation. + JBRedemptionDelegateAllocation3_1_1 memory _delegateAllocation; + + // Keep a reference to the fee. + uint256 _delegatedAmountFee; + + // Keep a reference to the number of allocations. + uint256 _numDelegates = _delegateAllocations.length; + + for (uint256 _i; _i < _numDelegates; ) { + // Get a reference to the delegate being iterated on. + _delegateAllocation = _delegateAllocations[_i]; + + // Get the fee for the delegated amount. + _delegatedAmountFee = _feePercent == 0 + ? 0 + : _feeAmount(_delegateAllocation.amount, _feePercent, _feeDiscount); + + // Add the delegated amount to the amount eligible for having a fee taken. + if (_delegatedAmountFee != 0) { + _feeEligibleDistributionAmount += _delegateAllocation.amount; + _delegateAllocation.amount -= _delegatedAmountFee; + } + + // Trigger any inherited pre-transfer logic. + _beforeTransferTo(address(_delegateAllocation.delegate), _delegateAllocation.amount); + + // Pass the correct token forwardedAmount to the delegate + _data.forwardedAmount.value = _delegateAllocation.amount; + + // Pass the correct metadata from the data source. + _data.dataSourceMetadata = _delegateAllocation.metadata; + + _delegateAllocation.delegate.didRedeem{ + value: token == JBTokens.ETH ? _delegateAllocation.amount : 0 + }(_data); + + emit DelegateDidRedeem( + _delegateAllocation.delegate, + _data, + _delegateAllocation.amount, + _delegatedAmountFee, + msg.sender + ); + + unchecked { + ++_i; + } + } + } + } + + // Send the reclaimed funds to the beneficiary. + if (reclaimAmount != 0) { + // Get the fee for the reclaimed amount. + uint256 _reclaimAmountFee = _feeDiscount == JBConstants.MAX_FEE_DISCOUNT + ? 0 + : _feeAmount(reclaimAmount, _feePercent, _feeDiscount); + + if (_reclaimAmountFee != 0) { + _feeEligibleDistributionAmount += reclaimAmount; + reclaimAmount -= _reclaimAmountFee; + } + + // Subtract the fee from the reclaim amount. + if (reclaimAmount != 0) _transferFrom(address(this), _beneficiary, reclaimAmount); + } + + // Take the fee from all outbound reclaimations. + _feeEligibleDistributionAmount != 0 + ? _takeFeeFrom( + _projectId, + false, + _feeEligibleDistributionAmount, + _feePercent, + _beneficiary, + _feeDiscount + ) + : 0; + } + + emit RedeemTokens( + _fundingCycle.configuration, + _fundingCycle.number, + _projectId, + _holder, + _beneficiary, + _tokenCount, + reclaimAmount, + _memo, + _metadata, + msg.sender + ); + } + + /// @notice Distributes payouts for a project with the distribution limit of its current funding cycle. + /// @dev Payouts are sent to the preprogrammed splits. Any leftover is sent to the project's owner. + /// @dev 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. + /// @dev All funds distributed outside of this contract or any feeless terminals incure the protocol fee. + /// @param _projectId The ID of the project having its payouts distributed. + /// @param _amount The amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal. + /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency. + /// @param _minReturnedTokens 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. + /// @param _metadata Bytes to send along to the emitted event, if provided. + /// @return netLeftoverDistributionAmount The amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal. + function _distributePayoutsOf( + uint256 _projectId, + uint256 _amount, + uint256 _currency, + uint256 _minReturnedTokens, + bytes calldata _metadata + ) internal returns (uint256 netLeftoverDistributionAmount) { + // Record the distribution. + ( + JBFundingCycle memory _fundingCycle, + uint256 _distributedAmount + ) = IJBSingleTokenPaymentTerminalStore3_1_1(store).recordDistributionFor( + _projectId, + _amount, + _currency + ); + + // The amount being distributed must be at least as much as was expected. + if (_distributedAmount < _minReturnedTokens) revert INADEQUATE_DISTRIBUTION_AMOUNT(); + + // 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)); + + // Define variables that will be needed outside the scoped section below. + // Keep a reference to the fee amount that was paid. + uint256 _feeTaken; + + // Scoped section prevents stack too deep. `_feePercent`, `_feeDiscount`, `_feeEligibleDistributionAmount`, and `_leftoverDistributionAmount` only used within scope. + { + // Keep a reference to the fee. + uint256 _feePercent = fee; + + // Get the amount of discount that should be applied to any fees taken. + // If the fee is zero, set the discount to 100% for convenience. + uint256 _feeDiscount = _feePercent == 0 + ? JBConstants.MAX_FEE_DISCOUNT + : _currentFeeDiscount(_projectId, JBFeeType.PAYOUT); + + // The amount distributed that is eligible for incurring fees. + uint256 _feeEligibleDistributionAmount; + + // The amount leftover after distributing to the splits. + uint256 _leftoverDistributionAmount; + + // Payout to splits and get a reference to the leftover transfer 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( + _projectId, + _fundingCycle.configuration, + payoutSplitsGroup, + _distributedAmount, + _feePercent, + _feeDiscount + ); + + 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; + } + } + + // Take the fee. + _feeTaken = _feeEligibleDistributionAmount != 0 + ? _takeFeeFrom( + _projectId, + _fundingCycle.shouldHoldFees(), + _feeEligibleDistributionAmount, + _feePercent, + _projectOwner, + _feeDiscount + ) + : 0; + + // 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 - + ( + _feeDiscount == JBConstants.MAX_FEE_DISCOUNT + ? 0 + : _feeAmount(_leftoverDistributionAmount, _feePercent, _feeDiscount) + ); + + // Transfer the amount to the project owner. + _transferFrom(address(this), _projectOwner, netLeftoverDistributionAmount); + } + } + + emit DistributePayouts( + _fundingCycle.configuration, + _fundingCycle.number, + _projectId, + _projectOwner, + _amount, + _distributedAmount, + _feeTaken, + netLeftoverDistributionAmount, + _metadata, + msg.sender + ); + } + + /// @notice Allows a project to send funds from its overflow up to the preconfigured allowance. + /// @dev Only a project's owner or a designated operator can use its allowance. + /// @dev Incurs the protocol fee. + /// @param _projectId The ID of the project to use the allowance of. + /// @param _amount The amount of terminal tokens to use from this project's current allowance, as a fixed point number with the same amount of decimals as this terminal. + /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's overflow allowance currency. + /// @param _minReturnedTokens The minimum number of tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with 18 decimals. + /// @param _beneficiary The address to send the funds to. + /// @param _memo A memo to pass along to the emitted event. + /// @param _metadata Bytes to send along to the emitted event, if provided. + /// @return netDistributedAmount The amount of tokens that was distributed to the beneficiary, as a fixed point number with the same amount of decimals as the terminal. + function _useAllowanceOf( + uint256 _projectId, + uint256 _amount, + uint256 _currency, + uint256 _minReturnedTokens, + address payable _beneficiary, + string memory _memo, + bytes calldata _metadata + ) internal returns (uint256 netDistributedAmount) { + // Record the use of the allowance. + ( + JBFundingCycle memory _fundingCycle, + uint256 _distributedAmount + ) = IJBSingleTokenPaymentTerminalStore3_1_1(store).recordUsedAllowanceOf( + _projectId, + _amount, + _currency + ); + + // The amount being withdrawn must be at least as much as was expected. + if (_distributedAmount < _minReturnedTokens) revert INADEQUATE_DISTRIBUTION_AMOUNT(); + + // Scoped section prevents stack too deep. `_fee`, `_projectOwner`, `_feeDiscount`, and `_netAmount` only used within scope. + { + // Keep a reference to the fee amount that was paid. + uint256 _feeTaken; + + // Keep a reference to the fee. + uint256 _feePercent = fee; + + // Get a reference to the project owner, which will receive tokens from paying the platform fee. + address _projectOwner = projects.ownerOf(_projectId); + + // 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 = _feePercent == 0 || isFeelessAddress[msg.sender] + ? JBConstants.MAX_FEE_DISCOUNT + : _currentFeeDiscount(_projectId, JBFeeType.ALLOWANCE); + + // Take a fee from the `_distributedAmount`, if needed. + _feeTaken = _feeDiscount == JBConstants.MAX_FEE_DISCOUNT + ? 0 + : _takeFeeFrom( + _projectId, + _fundingCycle.shouldHoldFees(), + _distributedAmount, + _feePercent, + _projectOwner, + _feeDiscount + ); + + unchecked { + // The net amount is the withdrawn amount without the fee. + netDistributedAmount = _distributedAmount - _feeTaken; + } + + // Transfer any remaining balance to the beneficiary. + if (netDistributedAmount != 0) + _transferFrom(address(this), _beneficiary, netDistributedAmount); + } + + emit UseAllowance( + _fundingCycle.configuration, + _fundingCycle.number, + _projectId, + _beneficiary, + _amount, + _distributedAmount, + netDistributedAmount, + _memo, + _metadata, + msg.sender + ); + } + + /// @notice Pays out splits for a project's funding cycle configuration. + /// @param _projectId The ID of the project for which payout splits are being distributed. + /// @param _domain The domain of the splits to distribute the payout between. + /// @param _group The group of the splits to distribute the payout between. + /// @param _amount The total amount being distributed, as a fixed point number with the same number of decimals as this terminal. + /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE. + /// @param _feePercent The percent of fees to take, out of MAX_FEE. + /// @return If the leftover amount if the splits don't add up to 100%. + /// @return feeEligibleDistributionAmount The total amount of distributions that are eligible to have fees taken from. + function _distributeToPayoutSplitsOf( + uint256 _projectId, + uint256 _domain, + uint256 _group, + uint256 _amount, + uint256 _feePercent, + uint256 _feeDiscount + ) internal returns (uint256, uint256 feeEligibleDistributionAmount) { + // The total percentage available to split + uint256 _leftoverPercentage = JBConstants.SPLITS_TOTAL_PERCENT; + + // Get a reference to the project's payout splits. + JBSplit[] memory _splits = splitsStore.splitsOf(_projectId, _domain, _group); + + // Keep a reference to the split being iterated on. + JBSplit memory _split; + + // Transfer between all splits. + for (uint256 _i; _i < _splits.length; ) { + // Get a reference to the split being iterated on. + _split = _splits[_i]; + + // The amount to send towards the split. + uint256 _payoutAmount = PRBMath.mulDiv(_amount, _split.percent, _leftoverPercentage); + + // The payout amount substracting any applicable incurred fees. + uint256 _netPayoutAmount = _distributeToPayoutSplit( + _split, + _projectId, + _group, + _payoutAmount, + _feePercent, + _feeDiscount + ); + + // If the split allocator is set as feeless, this distribution is not eligible for a fee. + if (_netPayoutAmount != 0 && _netPayoutAmount != _payoutAmount) + feeEligibleDistributionAmount += _payoutAmount; + + if (_payoutAmount != 0) { + // Subtract from the amount to be sent to the beneficiary. + unchecked { + _amount -= _payoutAmount; + } + } + + unchecked { + // Decrement the leftover percentage. + _leftoverPercentage -= _split.percent; + } + + emit DistributeToPayoutSplit( + _projectId, + _domain, + _group, + _split, + _payoutAmount, + _netPayoutAmount, + msg.sender + ); + + unchecked { + ++_i; + } + } + + return (_amount, feeEligibleDistributionAmount); + } + + /// @notice Pays out a split for a project's funding cycle configuration. + /// @param _split The split to distribute payouts to. + /// @param _amount The total amount being distributed to the split, as a fixed point number with the same number of decimals as this terminal. + /// @param _feePercent The percent of fees to take, out of MAX_FEE. + /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE. + /// @return netPayoutAmount The amount sent to the split after subtracting fees. + function _distributeToPayoutSplit( + JBSplit memory _split, + uint256 _projectId, + uint256 _group, + uint256 _amount, + uint256 _feePercent, + uint256 _feeDiscount + ) internal returns (uint256 netPayoutAmount) { + // By default, the net payout amount is the full amount. This will be adjusted if fees are taken. + netPayoutAmount = _amount; + + // If there's an allocator set, transfer to its `allocate` function. + if (_split.allocator != IJBSplitAllocator(address(0))) { + // This distribution is eligible for a fee since the funds are leaving this contract and the allocator isn't listed as feeless. + if ( + _feeDiscount != JBConstants.MAX_FEE_DISCOUNT && !isFeelessAddress[address(_split.allocator)] + ) { + unchecked { + netPayoutAmount -= _feeAmount(_amount, _feePercent, _feeDiscount); + } + } + + // Trigger any inherited pre-transfer logic. + _beforeTransferTo(address(_split.allocator), netPayoutAmount); + + // Create the data to send to the allocator. + JBSplitAllocationData memory _data = JBSplitAllocationData( + token, + netPayoutAmount, + decimals, + _projectId, + _group, + _split + ); + + // Trigger the allocator's `allocate` function. + bytes memory _reason; + + if ( + ERC165Checker.supportsInterface( + address(_split.allocator), + type(IJBSplitAllocator).interfaceId + ) + ) + // If this terminal's token is ETH, send it in msg.value. + try + _split.allocator.allocate{value: token == JBTokens.ETH ? netPayoutAmount : 0}(_data) + {} catch (bytes memory __reason) { + _reason = __reason.length == 0 ? abi.encode('Allocate fail') : __reason; + } + else { + _reason = abi.encode('IERC165 fail'); + } + + if (_reason.length != 0) { + // Revert the payout. + _revertTransferFrom(_projectId, address(_split.allocator), netPayoutAmount, _amount); + + // Set the net payout amount to 0 to signal the reversion. + netPayoutAmount = 0; + + emit PayoutReverted(_projectId, _split, _amount, _reason, msg.sender); + } + + // Otherwise, if a project is specified, make a payment to it. + } else if (_split.projectId != 0) { + // Get a reference to the Juicebox terminal being used. + IJBPaymentTerminal _terminal = directory.primaryTerminalOf(_split.projectId, token); + + // The project must have a terminal to send funds to. + if (_terminal == IJBPaymentTerminal(address(0))) { + // Set the net payout amount to 0 to signal the reversion. + netPayoutAmount = 0; + + // Revert the payout. + _revertTransferFrom(_projectId, address(0), 0, _amount); + + emit PayoutReverted(_projectId, _split, _amount, 'Terminal not found', msg.sender); + } else { + // This distribution is eligible for a fee since the funds are leaving this contract and the terminal isn't listed as feeless. + if ( + _terminal != this && + _feeDiscount != JBConstants.MAX_FEE_DISCOUNT && + !isFeelessAddress[address(_terminal)] + ) { + unchecked { + netPayoutAmount -= _feeAmount(_amount, _feePercent, _feeDiscount); + } + } + + // Trigger any inherited pre-transfer logic. + _beforeTransferTo(address(_terminal), netPayoutAmount); + + // Add to balance if prefered. + if (_split.preferAddToBalance) + try + _terminal.addToBalanceOf{value: token == JBTokens.ETH ? netPayoutAmount : 0}( + _split.projectId, + netPayoutAmount, + token, + '', + // Send the projectId in the metadata as a referral. + bytes(abi.encodePacked(_projectId)) + ) + {} catch (bytes memory _reason) { + // Revert the payout. + _revertTransferFrom(_projectId, address(_terminal), netPayoutAmount, _amount); + + // Set the net payout amount to 0 to signal the reversion. + netPayoutAmount = 0; + + emit PayoutReverted(_projectId, _split, _amount, _reason, msg.sender); + } + else + try + _terminal.pay{value: token == JBTokens.ETH ? netPayoutAmount : 0}( + _split.projectId, + netPayoutAmount, + token, + _split.beneficiary != address(0) ? _split.beneficiary : msg.sender, + 0, + _split.preferClaimed, + '', + // Send the projectId in the metadata as a referral. + bytes(abi.encodePacked(_projectId)) + ) + {} catch (bytes memory _reason) { + // Revert the payout. + _revertTransferFrom(_projectId, address(_terminal), netPayoutAmount, _amount); + + // Set the net payout amount to 0 to signal the reversion. + netPayoutAmount = 0; + + emit PayoutReverted(_projectId, _split, _amount, _reason, msg.sender); + } + } + } else { + // This distribution is eligible for a fee since the funds are leaving this contract and the beneficiary isn't listed as feeless. + // Don't enforce feeless address for the beneficiary since the funds are leaving the ecosystem. + if (_feeDiscount != JBConstants.MAX_FEE_DISCOUNT) { + unchecked { + netPayoutAmount -= _feeAmount(_amount, _feePercent, _feeDiscount); + } + } + + // If there's a beneficiary, send the funds directly to the beneficiary. Otherwise send to the msg.sender. + _transferFrom( + address(this), + _split.beneficiary != address(0) ? _split.beneficiary : payable(msg.sender), + netPayoutAmount + ); + } + } + + /// @notice Takes a fee into the platform's project, which has an id of _FEE_BENEFICIARY_PROJECT_ID. + /// @param _projectId The ID of the project having fees taken from. + /// @param _shouldHoldFees If fees should be tracked and held back. + /// @param _feePercent The percent of fees to take, out of MAX_FEE. + /// @param _amount The amount of the fee to take, as a floating point number with 18 decimals. + /// @param _beneficiary The address to mint the platforms tokens for. + /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE. + /// @return feeAmount The amount of the fee taken. + function _takeFeeFrom( + uint256 _projectId, + bool _shouldHoldFees, + uint256 _amount, + uint256 _feePercent, + address _beneficiary, + uint256 _feeDiscount + ) internal returns (uint256 feeAmount) { + feeAmount = _feeAmount(_amount, _feePercent, _feeDiscount); + + if (_shouldHoldFees) { + // Store the held fee. + _heldFeesOf[_projectId].push( + JBFee(_amount, uint32(_feePercent), uint32(_feeDiscount), _beneficiary) + ); + + emit HoldFee(_projectId, _amount, _feePercent, _feeDiscount, _beneficiary, msg.sender); + } else { + // Process the fee. + _processFee(feeAmount, _beneficiary, _projectId); // Take the fee. + + emit ProcessFee(_projectId, feeAmount, false, _beneficiary, msg.sender); + } + } + + /// @notice Process a fee of the specified amount. + /// @param _amount The fee amount, as a floating point number with 18 decimals. + /// @param _beneficiary The address to mint the platform's tokens for. + /// @param _from The project ID the fee is being paid from. + function _processFee(uint256 _amount, address _beneficiary, uint256 _from) internal { + // Get the terminal for the protocol project. + IJBPaymentTerminal _terminal = directory.primaryTerminalOf(_FEE_BENEFICIARY_PROJECT_ID, token); + + // Trigger any inherited pre-transfer logic if funds will be transferred. + if (address(_terminal) != address(this)) _beforeTransferTo(address(_terminal), _amount); + + try + // Send the fee. + // If this terminal's token is ETH, send it in msg.value. + _terminal.pay{value: token == JBTokens.ETH ? _amount : 0}( + _FEE_BENEFICIARY_PROJECT_ID, + _amount, + token, + _beneficiary, + 0, + false, + '', + // Send the projectId in the metadata. + bytes(abi.encodePacked(_from)) + ) + {} catch (bytes memory _reason) { + _revertTransferFrom( + _from, + address(_terminal) != address(this) ? address(_terminal) : address(0), + address(_terminal) != address(this) ? _amount : 0, + _amount + ); + emit FeeReverted(_from, _FEE_BENEFICIARY_PROJECT_ID, _amount, _reason, msg.sender); + } + } + + /// @notice Reverts an expected payout. + /// @param _projectId The ID of the project having paying out. + /// @param _expectedDestination The address the payout was expected to go to. + /// @param _allowanceAmount The amount that the destination has been allowed to use. + /// @param _depositAmount The amount of the payout as debited from the project's balance. + function _revertTransferFrom( + uint256 _projectId, + address _expectedDestination, + uint256 _allowanceAmount, + uint256 _depositAmount + ) internal { + // Cancel allowance if needed. + if (_allowanceAmount != 0) _cancelTransferTo(_expectedDestination, _allowanceAmount); + + // Add undistributed amount back to project's balance. + IJBSingleTokenPaymentTerminalStore3_1_1(store).recordAddedBalanceFor( + _projectId, + _depositAmount + ); + } + + /// @notice Contribute tokens to a project. + /// @param _amount The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place. + /// @param _payer The address making the payment. + /// @param _projectId The ID of the project being paid. + /// @param _beneficiary The address to mint tokens for and pass along to the funding cycle's data source and delegate. + /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal. + /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas. + /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate. + /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided. + /// @return beneficiaryTokenCount The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals. + function _pay( + uint256 _amount, + address _payer, + uint256 _projectId, + address _beneficiary, + uint256 _minReturnedTokens, + bool _preferClaimedTokens, + string memory _memo, + bytes memory _metadata + ) internal returns (uint256 beneficiaryTokenCount) { + // Cant send tokens to the zero address. + if (_beneficiary == address(0)) revert PAY_TO_ZERO_ADDRESS(); + + // Define variables that will be needed outside the scoped section below. + // Keep a reference to the funding cycle during which the payment is being made. + JBFundingCycle memory _fundingCycle; + + // Scoped section prevents stack too deep. `_delegateAllocations` and `_tokenCount` only used within scope. + { + JBPayDelegateAllocation3_1_1[] memory _delegateAllocations; + uint256 _tokenCount; + + // Bundle the amount info into a JBTokenAmount struct. + JBTokenAmount memory _bundledAmount = JBTokenAmount(token, _amount, decimals, currency); + + // Record the payment. + ( + _fundingCycle, + _tokenCount, + _delegateAllocations, + _memo + ) = IJBSingleTokenPaymentTerminalStore3_1_1(store).recordPaymentFrom( + _payer, + _bundledAmount, + _projectId, + baseWeightCurrency, + _beneficiary, + _memo, + _metadata + ); + + // Mint the tokens if needed. + if (_tokenCount != 0) + // Set token count to be the number of tokens minted for the beneficiary instead of the total amount. + beneficiaryTokenCount = IJBController(directory.controllerOf(_projectId)).mintTokensOf( + _projectId, + _tokenCount, + _beneficiary, + '', + _preferClaimedTokens, + true + ); + + // The token count for the beneficiary must be greater than or equal to the minimum expected. + if (beneficiaryTokenCount < _minReturnedTokens) revert INADEQUATE_TOKEN_COUNT(); + + // If delegate allocations were specified by the data source, fulfill them. + if (_delegateAllocations.length != 0) { + JBDidPayData3_1_1 memory _data = JBDidPayData3_1_1( + _payer, + _projectId, + _fundingCycle.configuration, + _bundledAmount, + JBTokenAmount(token, 0, decimals, currency), + beneficiaryTokenCount, + _beneficiary, + _preferClaimedTokens, + _memo, + bytes(''), + _metadata + ); + + // Get a reference to the number of delegates to allocate to. + uint256 _numDelegates = _delegateAllocations.length; + + // Keep a reference to the allocation. + JBPayDelegateAllocation3_1_1 memory _delegateAllocation; + + for (uint256 _i; _i < _numDelegates; ) { + // Get a reference to the delegate being iterated on. + _delegateAllocation = _delegateAllocations[_i]; + + // Trigger any inherited pre-transfer logic. + _beforeTransferTo(address(_delegateAllocation.delegate), _delegateAllocation.amount); + + // Pass the correct token forwardedAmount to the delegate + _data.forwardedAmount.value = _delegateAllocation.amount; + + // Pass the correct metadata from the data source. + _data.dataSourceMetadata = _delegateAllocation.metadata; + + _delegateAllocation.delegate.didPay{ + value: token == JBTokens.ETH ? _delegateAllocation.amount : 0 + }(_data); + + emit DelegateDidPay( + _delegateAllocation.delegate, + _data, + _delegateAllocation.amount, + msg.sender + ); + + unchecked { + ++_i; + } + } + } + } + + emit Pay( + _fundingCycle.configuration, + _fundingCycle.number, + _projectId, + _payer, + _beneficiary, + _amount, + beneficiaryTokenCount, + _memo, + _metadata, + msg.sender + ); + } + + /// @notice Receives funds belonging to the specified project. + /// @param _projectId The ID of the project to which the funds received belong. + /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead. + /// @param _shouldRefundHeldFees A flag indicating if held fees should be refunded based on the amount being added. + /// @param _memo A memo to pass along to the emitted event. + /// @param _metadata Extra data to pass along to the emitted event. + function _addToBalanceOf( + uint256 _projectId, + uint256 _amount, + bool _shouldRefundHeldFees, + string memory _memo, + bytes memory _metadata + ) internal { + // Refund any held fees to make sure the project doesn't pay double for funds going in and out of the protocol. + uint256 _refundedFees = _shouldRefundHeldFees ? _refundHeldFees(_projectId, _amount) : 0; + + // Record the added funds with any refunded fees. + IJBSingleTokenPaymentTerminalStore3_1_1(store).recordAddedBalanceFor( + _projectId, + _amount + _refundedFees + ); + + emit AddToBalance(_projectId, _amount, _refundedFees, _memo, _metadata, msg.sender); + } + + /// @notice Refund fees based on the specified amount. + /// @param _projectId The project for which fees are being refunded. + /// @param _amount The amount to base the refund on, as a fixed point number with the same amount of decimals as this terminal. + /// @return refundedFees How much fees were refunded, as a fixed point number with the same number of decimals as this terminal + function _refundHeldFees( + uint256 _projectId, + uint256 _amount + ) internal returns (uint256 refundedFees) { + // Get a reference to the project's held fees. + JBFee[] memory _heldFees = _heldFeesOf[_projectId]; + + // Delete the current held fees. + delete _heldFeesOf[_projectId]; + + // Get a reference to the leftover amount once all fees have been settled. + uint256 leftoverAmount = _amount; + + // Push length in stack + uint256 _heldFeesLength = _heldFees.length; + + // Process each fee. + for (uint256 _i; _i < _heldFeesLength; ) { + if (leftoverAmount == 0) _heldFeesOf[_projectId].push(_heldFees[_i]); + else if (leftoverAmount >= _heldFees[_i].amount) { + unchecked { + leftoverAmount = leftoverAmount - _heldFees[_i].amount; + refundedFees += ( + _heldFees[_i].fee == 0 || _heldFees[_i].feeDiscount == JBConstants.MAX_FEE_DISCOUNT + ? 0 + : _feeAmount(_heldFees[_i].amount, _heldFees[_i].fee, _heldFees[_i].feeDiscount) + ); + } + } else { + unchecked { + _heldFeesOf[_projectId].push( + JBFee( + _heldFees[_i].amount - leftoverAmount, + _heldFees[_i].fee, + _heldFees[_i].feeDiscount, + _heldFees[_i].beneficiary + ) + ); + refundedFees += ( + _heldFees[_i].fee == 0 || _heldFees[_i].feeDiscount == JBConstants.MAX_FEE_DISCOUNT + ? 0 + : _feeAmount(leftoverAmount, _heldFees[_i].fee, _heldFees[_i].feeDiscount) + ); + } + leftoverAmount = 0; + } + + unchecked { + ++_i; + } + } + + emit RefundHeldFees(_projectId, _amount, refundedFees, leftoverAmount, msg.sender); + } + + /// @notice Returns the fee amount based on the provided amount for the specified project. + /// @param _amount The amount that the fee is based on, as a fixed point number with the same amount of decimals as this terminal. + /// @param _fee The percentage of the fee, out of MAX_FEE. + /// @param _feeDiscount The percentage discount that should be applied out of the max amount, out of MAX_FEE_DISCOUNT. + /// @return The amount of the fee, as a fixed point number with the same amount of decimals as this terminal. + function _feeAmount( + uint256 _amount, + uint256 _fee, + uint256 _feeDiscount + ) internal pure returns (uint256) { + // Calculate the discounted fee. + uint256 _discountedFee = _fee - + PRBMath.mulDiv(_fee, _feeDiscount, JBConstants.MAX_FEE_DISCOUNT); + + // The amount of tokens from the `_amount` to pay as a fee. + return + _amount - PRBMath.mulDiv(_amount, JBConstants.MAX_FEE, _discountedFee + JBConstants.MAX_FEE); + } + + /// @notice Get the fee discount from the fee gauge for the specified project. + /// @param _projectId The ID of the project to get a fee discount for. + /// @param _feeType The type of fee the discount is being applied to. + /// @return feeDiscount The fee discount, which should be interpreted as a percentage out MAX_FEE_DISCOUNT. + function _currentFeeDiscount( + uint256 _projectId, + JBFeeType _feeType + ) internal view returns (uint256) { + // Can't take a fee if the protocol project doesn't have a terminal that accepts the token. + if ( + directory.primaryTerminalOf(_FEE_BENEFICIARY_PROJECT_ID, token) == + IJBPaymentTerminal(address(0)) + ) return JBConstants.MAX_FEE_DISCOUNT; + + // Get the fee discount. + if (feeGauge != address(0)) + // If the guage reverts, keep the discount at 0. + try IJBFeeGauge3_1(feeGauge).currentDiscountFor(_projectId, _feeType) returns ( + uint256 discount + ) { + // If the fee discount is greater than the max, we ignore the return value + if (discount <= JBConstants.MAX_FEE_DISCOUNT) return discount; + } catch { + return 0; + } + + return 0; + } +} diff --git a/contracts/abstract/JBSingleTokenPaymentTerminal.sol b/contracts/abstract/JBSingleTokenPaymentTerminal.sol index 482e37b24..81f24dac0 100644 --- a/contracts/abstract/JBSingleTokenPaymentTerminal.sol +++ b/contracts/abstract/JBSingleTokenPaymentTerminal.sol @@ -1,85 +1,52 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.16; -import '@openzeppelin/contracts/utils/introspection/ERC165.sol'; -import './../interfaces/IJBSingleTokenPaymentTerminal.sol'; +import {ERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol'; +import {IERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol'; +import {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol'; +import {IJBSingleTokenPaymentTerminal} from './../interfaces/IJBSingleTokenPaymentTerminal.sol'; -/** - @notice - Generic terminal managing all inflows of funds into the protocol ecosystem for one token. - - @dev - Adheres to - - IJBSingleTokenPaymentTerminals: General interface for the methods in this contract that interact with the blockchain's state according to the protocol's rules. - - @dev - Inherits from - - ERC165: Introspection on interface adherance. -*/ +/// @notice Generic terminal managing all inflows of funds into the protocol ecosystem for one token. abstract contract JBSingleTokenPaymentTerminal is ERC165, IJBSingleTokenPaymentTerminal { //*********************************************************************// // ---------------- public immutable stored properties --------------- // //*********************************************************************// - /** - @notice - The token that this terminal accepts. - */ + /// @notice The token that this terminal accepts. address public immutable override token; - /** - @notice - The number of decimals the token fixed point amounts are expected to have. - */ + /// @notice The number of decimals the token fixed point amounts are expected to have. uint256 public immutable override decimals; - /** - @notice - The currency to use when resolving price feeds for this terminal. - */ + /// @notice The currency to use when resolving price feeds for this terminal. uint256 public immutable override currency; //*********************************************************************// // ------------------------- external views -------------------------- // //*********************************************************************// - /** - @notice - A flag indicating if this terminal accepts the specified token. - - @param _token The token to check if this terminal accepts or not. - @param _projectId The project ID to check for token acceptance. - - @return The flag. - */ + /// @notice A flag indicating if this terminal accepts the specified token. + /// @param _token The token to check if this terminal accepts or not. + /// @param _projectId The project ID to check for token acceptance. + /// @return The flag. function acceptsToken(address _token, uint256 _projectId) external view override returns (bool) { _projectId; // Prevents unused var compiler and natspec complaints. return _token == token; } - /** - @notice - The decimals that should be used in fixed number accounting for the specified token. - - @param _token The token to check for the decimals of. - - @return The number of decimals for the token. - */ + /// @notice The decimals that should be used in fixed number accounting for the specified token. + /// @param _token The token to check for the decimals of. + /// @return The number of decimals for the token. function decimalsForToken(address _token) external view override returns (uint256) { _token; // Prevents unused var compiler and natspec complaints. return decimals; } - /** - @notice - The currency that should be used for the specified token. - - @param _token The token to check for the currency of. - - @return The currency index. - */ + /// @notice The currency that should be used for the specified token. + /// @param _token The token to check for the currency of. + /// @return The currency index. function currencyForToken(address _token) external view override returns (uint256) { _token; // Prevents unused var compiler and natspec complaints. @@ -90,22 +57,13 @@ abstract contract JBSingleTokenPaymentTerminal is ERC165, IJBSingleTokenPaymentT // -------------------------- public views --------------------------- // //*********************************************************************// - /** - @notice - Indicates if this contract adheres to the specified interface. - - @dev - See {IERC165-supportsInterface}. - - @param _interfaceId The ID of the interface to check for adherance to. - */ - function supportsInterface(bytes4 _interfaceId) - public - view - virtual - override(ERC165, IERC165) - returns (bool) - { + /// @notice Indicates if this contract adheres to the specified interface. + /// @dev See {IERC165-supportsInterface}. + /// @param _interfaceId The ID of the interface to check for adherance to. + /// @return A flag indicating if the provided interface ID is supported. + function supportsInterface( + bytes4 _interfaceId + ) public view virtual override(ERC165, IERC165) returns (bool) { return _interfaceId == type(IJBPaymentTerminal).interfaceId || _interfaceId == type(IJBSingleTokenPaymentTerminal).interfaceId || @@ -116,16 +74,10 @@ abstract contract JBSingleTokenPaymentTerminal is ERC165, IJBSingleTokenPaymentT // -------------------------- constructor ---------------------------- // //*********************************************************************// - /** - @param _token The token that this terminal manages. - @param _decimals The number of decimals the token fixed point amounts are expected to have. - @param _currency The currency that this terminal's token adheres to for price feeds. - */ - constructor( - address _token, - uint256 _decimals, - uint256 _currency - ) { + /// @param _token The token that this terminal manages. + /// @param _decimals The number of decimals the token fixed point amounts are expected to have. + /// @param _currency The currency that this terminal's token adheres to for price feeds. + constructor(address _token, uint256 _decimals, uint256 _currency) { token = _token; decimals = _decimals; currency = _currency; diff --git a/contracts/enums/JBFeeType.sol b/contracts/enums/JBFeeType.sol new file mode 100644 index 000000000..b5be65bea --- /dev/null +++ b/contracts/enums/JBFeeType.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +enum JBFeeType { + PAYOUT, + ALLOWANCE, + REDEMPTION +} diff --git a/contracts/interfaces/IJBAllowanceTerminal.sol b/contracts/interfaces/IJBAllowanceTerminal.sol index c5b644951..d78d27c71 100644 --- a/contracts/interfaces/IJBAllowanceTerminal.sol +++ b/contracts/interfaces/IJBAllowanceTerminal.sol @@ -3,12 +3,12 @@ pragma solidity ^0.8.0; interface IJBAllowanceTerminal { function useAllowanceOf( - uint256 _projectId, - uint256 _amount, - uint256 _currency, - address _token, - uint256 _minReturnedTokens, - address payable _beneficiary, - string calldata _memo + uint256 projectId, + uint256 amount, + uint256 currency, + address token, + uint256 minReturnedTokens, + address payable beneficiary, + string calldata memo ) external returns (uint256 netDistributedAmount); } diff --git a/contracts/interfaces/IJBAllowanceTerminal3_1.sol b/contracts/interfaces/IJBAllowanceTerminal3_1.sol index 80f4680d1..944056235 100644 --- a/contracts/interfaces/IJBAllowanceTerminal3_1.sol +++ b/contracts/interfaces/IJBAllowanceTerminal3_1.sol @@ -3,13 +3,13 @@ pragma solidity ^0.8.0; interface IJBAllowanceTerminal3_1 { function useAllowanceOf( - uint256 _projectId, - uint256 _amount, - uint256 _currency, - address _token, - uint256 _minReturnedTokens, - address payable _beneficiary, - string calldata _memo, - bytes calldata _metadata + uint256 projectId, + uint256 amount, + uint256 currency, + address token, + uint256 minReturnedTokens, + address payable beneficiary, + string calldata memo, + bytes calldata metadata ) external returns (uint256 netDistributedAmount); } diff --git a/contracts/interfaces/IJBController.sol b/contracts/interfaces/IJBController.sol index a1f3a9ebb..465f3884d 100644 --- a/contracts/interfaces/IJBController.sol +++ b/contracts/interfaces/IJBController.sol @@ -1,18 +1,22 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import '@openzeppelin/contracts/utils/introspection/IERC165.sol'; -import './../structs/JBFundAccessConstraints.sol'; -import './../structs/JBFundingCycleData.sol'; -import './../structs/JBFundingCycleMetadata.sol'; -import './../structs/JBGroupedSplits.sol'; -import './../structs/JBProjectMetadata.sol'; -import './IJBDirectory.sol'; -import './IJBFundingCycleStore.sol'; -import './IJBMigratable.sol'; -import './IJBPaymentTerminal.sol'; -import './IJBSplitsStore.sol'; -import './IJBTokenStore.sol'; +import {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol'; +import {JBBallotState} from './../enums/JBBallotState.sol'; +import {JBFundAccessConstraints} from './../structs/JBFundAccessConstraints.sol'; +import {JBFundingCycle} from './../structs/JBFundingCycle.sol'; +import {JBFundingCycleData} from './../structs/JBFundingCycleData.sol'; +import {JBFundingCycleMetadata} from './../structs/JBFundingCycleMetadata.sol'; +import {JBGroupedSplits} from './../structs/JBGroupedSplits.sol'; +import {JBProjectMetadata} from './../structs/JBProjectMetadata.sol'; +import {JBSplit} from './../structs/JBSplit.sol'; +import {IJBDirectory} from './IJBDirectory.sol'; +import {IJBFundingCycleStore} from './IJBFundingCycleStore.sol'; +import {IJBMigratable} from './IJBMigratable.sol'; +import {IJBPaymentTerminal} from './IJBPaymentTerminal.sol'; +import {IJBProjects} from './IJBProjects.sol'; +import {IJBSplitsStore} from './IJBSplitsStore.sol'; +import {IJBTokenStore} from './IJBTokenStore.sol'; interface IJBController is IERC165 { event LaunchProject(uint256 configuration, uint256 projectId, string memo, address caller); @@ -86,107 +90,113 @@ interface IJBController is IERC165 { function directory() external view returns (IJBDirectory); - function reservedTokenBalanceOf(uint256 _projectId, uint256 _reservedRate) - external - view - returns (uint256); + function reservedTokenBalanceOf( + uint256 projectId, + uint256 reservedRate + ) external view returns (uint256); function distributionLimitOf( - uint256 _projectId, - uint256 _configuration, - IJBPaymentTerminal _terminal, - address _token + uint256 projectId, + uint256 configuration, + IJBPaymentTerminal terminal, + address token ) external view returns (uint256 distributionLimit, uint256 distributionLimitCurrency); function overflowAllowanceOf( - uint256 _projectId, - uint256 _configuration, - IJBPaymentTerminal _terminal, - address _token + uint256 projectId, + uint256 configuration, + IJBPaymentTerminal terminal, + address token ) external view returns (uint256 overflowAllowance, uint256 overflowAllowanceCurrency); - function totalOutstandingTokensOf(uint256 _projectId, uint256 _reservedRate) - external - view - returns (uint256); + function totalOutstandingTokensOf( + uint256 projectId, + uint256 reservedRate + ) external view returns (uint256); - function getFundingCycleOf(uint256 _projectId, uint256 _configuration) + function getFundingCycleOf( + uint256 projectId, + uint256 configuration + ) external view returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata); - function latestConfiguredFundingCycleOf(uint256 _projectId) + function latestConfiguredFundingCycleOf( + uint256 projectId + ) external view - returns ( - JBFundingCycle memory, - JBFundingCycleMetadata memory metadata, - JBBallotState - ); + returns (JBFundingCycle memory, JBFundingCycleMetadata memory metadata, JBBallotState); - function currentFundingCycleOf(uint256 _projectId) + function currentFundingCycleOf( + uint256 projectId + ) external view returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata); - function queuedFundingCycleOf(uint256 _projectId) + function queuedFundingCycleOf( + uint256 projectId + ) external view returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata); function launchProjectFor( - address _owner, - JBProjectMetadata calldata _projectMetadata, - JBFundingCycleData calldata _data, - JBFundingCycleMetadata calldata _metadata, - uint256 _mustStartAtOrAfter, - JBGroupedSplits[] memory _groupedSplits, - JBFundAccessConstraints[] memory _fundAccessConstraints, - IJBPaymentTerminal[] memory _terminals, - string calldata _memo + address owner, + JBProjectMetadata calldata projectMetadata, + JBFundingCycleData calldata data, + JBFundingCycleMetadata calldata metadata, + uint256 mustStartAtOrAfter, + JBGroupedSplits[] memory groupedSplits, + JBFundAccessConstraints[] memory fundAccessConstraints, + IJBPaymentTerminal[] memory terminals, + string calldata memo ) external returns (uint256 projectId); function launchFundingCyclesFor( - uint256 _projectId, - JBFundingCycleData calldata _data, - JBFundingCycleMetadata calldata _metadata, - uint256 _mustStartAtOrAfter, - JBGroupedSplits[] memory _groupedSplits, - JBFundAccessConstraints[] memory _fundAccessConstraints, - IJBPaymentTerminal[] memory _terminals, - string calldata _memo + uint256 projectId, + JBFundingCycleData calldata data, + JBFundingCycleMetadata calldata metadata, + uint256 mustStartAtOrAfter, + JBGroupedSplits[] memory groupedSplits, + JBFundAccessConstraints[] memory fundAccessConstraints, + IJBPaymentTerminal[] memory terminals, + string calldata memo ) external returns (uint256 configuration); function reconfigureFundingCyclesOf( - uint256 _projectId, - JBFundingCycleData calldata _data, - JBFundingCycleMetadata calldata _metadata, - uint256 _mustStartAtOrAfter, - JBGroupedSplits[] memory _groupedSplits, - JBFundAccessConstraints[] memory _fundAccessConstraints, - string calldata _memo + uint256 projectId, + JBFundingCycleData calldata data, + JBFundingCycleMetadata calldata metadata, + uint256 mustStartAtOrAfter, + JBGroupedSplits[] memory groupedSplits, + JBFundAccessConstraints[] memory fundAccessConstraints, + string calldata memo ) external returns (uint256); function mintTokensOf( - uint256 _projectId, - uint256 _tokenCount, - address _beneficiary, - string calldata _memo, - bool _preferClaimedTokens, - bool _useReservedRate + uint256 projectId, + uint256 tokenCount, + address beneficiary, + string calldata memo, + bool preferClaimedTokens, + bool useReservedRate ) external returns (uint256 beneficiaryTokenCount); function burnTokensOf( - address _holder, - uint256 _projectId, - uint256 _tokenCount, - string calldata _memo, - bool _preferClaimedTokens + address holder, + uint256 projectId, + uint256 tokenCount, + string calldata memo, + bool preferClaimedTokens ) external; - function distributeReservedTokensOf(uint256 _projectId, string memory _memo) - external - returns (uint256); + function distributeReservedTokensOf( + uint256 projectId, + string memory memo + ) external returns (uint256); - function migrate(uint256 _projectId, IJBMigratable _to) external; + function migrate(uint256 projectId, IJBMigratable to) external; } diff --git a/contracts/interfaces/IJBController3_0_1.sol b/contracts/interfaces/IJBController3_0_1.sol index 6d707ff0f..5bc818693 100644 --- a/contracts/interfaces/IJBController3_0_1.sol +++ b/contracts/interfaces/IJBController3_0_1.sol @@ -1,21 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import '@openzeppelin/contracts/utils/introspection/IERC165.sol'; -import './../structs/JBFundAccessConstraints.sol'; -import './../structs/JBFundingCycleData.sol'; -import './../structs/JBFundingCycleMetadata.sol'; -import './../structs/JBGroupedSplits.sol'; -import './../structs/JBProjectMetadata.sol'; -import './IJBController.sol'; -import './IJBDirectory.sol'; -import './IJBFundingCycleStore.sol'; -import './IJBMigratable.sol'; -import './IJBPaymentTerminal.sol'; -import './IJBSplitsStore.sol'; -import './IJBTokenStore.sol'; - interface IJBController3_0_1 { - function reservedTokenBalanceOf(uint256 _projectId) external view returns (uint256); - function totalOutstandingTokensOf(uint256 _projectId) external view returns (uint256); + function reservedTokenBalanceOf(uint256 projectId) external view returns (uint256); + + function totalOutstandingTokensOf(uint256 projectId) external view returns (uint256); } diff --git a/contracts/interfaces/IJBController3_1.sol b/contracts/interfaces/IJBController3_1.sol index 6ad3ef6be..234fc860e 100644 --- a/contracts/interfaces/IJBController3_1.sol +++ b/contracts/interfaces/IJBController3_1.sol @@ -1,20 +1,24 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import '@openzeppelin/contracts/utils/introspection/IERC165.sol'; -import './../structs/JBFundAccessConstraints.sol'; -import './../structs/JBFundingCycleData.sol'; -import './../structs/JBFundingCycleMetadata.sol'; -import './../structs/JBGroupedSplits.sol'; -import './../structs/JBProjectMetadata.sol'; -import './IJBController3_0_1.sol'; -import './IJBDirectory.sol'; -import './IJBFundAccessConstraintsStore.sol'; -import './IJBFundingCycleStore.sol'; -import './IJBMigratable.sol'; -import './IJBPaymentTerminal.sol'; -import './IJBSplitsStore.sol'; -import './IJBTokenStore.sol'; +import {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol'; +import {JBBallotState} from './../enums/JBBallotState.sol'; +import {JBFundAccessConstraints} from './../structs/JBFundAccessConstraints.sol'; +import {JBFundingCycle} from './../structs/JBFundingCycle.sol'; +import {JBFundingCycleData} from './../structs/JBFundingCycleData.sol'; +import {JBFundingCycleMetadata} from './../structs/JBFundingCycleMetadata.sol'; +import {JBGroupedSplits} from './../structs/JBGroupedSplits.sol'; +import {JBProjectMetadata} from './../structs/JBProjectMetadata.sol'; +import {JBSplit} from './../structs/JBSplit.sol'; +import {IJBController3_0_1} from './IJBController3_0_1.sol'; +import {IJBDirectory} from './IJBDirectory.sol'; +import {IJBFundAccessConstraintsStore} from './IJBFundAccessConstraintsStore.sol'; +import {IJBFundingCycleStore} from './IJBFundingCycleStore.sol'; +import {IJBMigratable} from './IJBMigratable.sol'; +import {IJBPaymentTerminal} from './IJBPaymentTerminal.sol'; +import {IJBProjects} from './IJBProjects.sol'; +import {IJBSplitsStore} from './IJBSplitsStore.sol'; +import {IJBTokenStore} from './IJBTokenStore.sol'; interface IJBController3_1 is IJBController3_0_1, IERC165 { event LaunchProject(uint256 configuration, uint256 projectId, string memo, address caller); @@ -82,87 +86,93 @@ interface IJBController3_1 is IJBController3_0_1, IERC165 { function directory() external view returns (IJBDirectory); - function reservedTokenBalanceOf(uint256 _projectId) external view returns (uint256); + function reservedTokenBalanceOf(uint256 projectId) external view returns (uint256); - function totalOutstandingTokensOf(uint256 _projectId) external view returns (uint256); + function totalOutstandingTokensOf(uint256 projectId) external view returns (uint256); - function getFundingCycleOf(uint256 _projectId, uint256 _configuration) + function getFundingCycleOf( + uint256 projectId, + uint256 configuration + ) external view returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata); - function latestConfiguredFundingCycleOf(uint256 _projectId) + function latestConfiguredFundingCycleOf( + uint256 projectId + ) external view - returns ( - JBFundingCycle memory, - JBFundingCycleMetadata memory metadata, - JBBallotState - ); + returns (JBFundingCycle memory, JBFundingCycleMetadata memory metadata, JBBallotState); - function currentFundingCycleOf(uint256 _projectId) + function currentFundingCycleOf( + uint256 projectId + ) external view returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata); - function queuedFundingCycleOf(uint256 _projectId) + function queuedFundingCycleOf( + uint256 projectId + ) external view returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata); function launchProjectFor( - address _owner, - JBProjectMetadata calldata _projectMetadata, - JBFundingCycleData calldata _data, - JBFundingCycleMetadata calldata _metadata, - uint256 _mustStartAtOrAfter, - JBGroupedSplits[] memory _groupedSplits, - JBFundAccessConstraints[] memory _fundAccessConstraints, - IJBPaymentTerminal[] memory _terminals, - string calldata _memo + address owner, + JBProjectMetadata calldata projectMetadata, + JBFundingCycleData calldata data, + JBFundingCycleMetadata calldata metadata, + uint256 mustStartAtOrAfter, + JBGroupedSplits[] memory groupedSplits, + JBFundAccessConstraints[] memory fundAccessConstraints, + IJBPaymentTerminal[] memory terminals, + string calldata memo ) external returns (uint256 projectId); function launchFundingCyclesFor( - uint256 _projectId, - JBFundingCycleData calldata _data, - JBFundingCycleMetadata calldata _metadata, - uint256 _mustStartAtOrAfter, - JBGroupedSplits[] memory _groupedSplits, - JBFundAccessConstraints[] memory _fundAccessConstraints, - IJBPaymentTerminal[] memory _terminals, - string calldata _memo + uint256 projectId, + JBFundingCycleData calldata data, + JBFundingCycleMetadata calldata metadata, + uint256 mustStartAtOrAfter, + JBGroupedSplits[] memory groupedSplits, + JBFundAccessConstraints[] memory fundAccessConstraints, + IJBPaymentTerminal[] memory terminals, + string calldata memo ) external returns (uint256 configuration); function reconfigureFundingCyclesOf( - uint256 _projectId, - JBFundingCycleData calldata _data, - JBFundingCycleMetadata calldata _metadata, - uint256 _mustStartAtOrAfter, - JBGroupedSplits[] memory _groupedSplits, - JBFundAccessConstraints[] memory _fundAccessConstraints, - string calldata _memo + uint256 projectId, + JBFundingCycleData calldata data, + JBFundingCycleMetadata calldata metadata, + uint256 mustStartAtOrAfter, + JBGroupedSplits[] memory groupedSplits, + JBFundAccessConstraints[] memory fundAccessConstraints, + string calldata memo ) external returns (uint256); function mintTokensOf( - uint256 _projectId, - uint256 _tokenCount, - address _beneficiary, - string calldata _memo, - bool _preferClaimedTokens, - bool _useReservedRate + uint256 projectId, + uint256 tokenCount, + address beneficiary, + string calldata memo, + bool preferClaimedTokens, + bool useReservedRate ) external returns (uint256 beneficiaryTokenCount); function burnTokensOf( - address _holder, - uint256 _projectId, - uint256 _tokenCount, - string calldata _memo, - bool _preferClaimedTokens + address holder, + uint256 projectId, + uint256 tokenCount, + string calldata memo, + bool preferClaimedTokens ) external; - function distributeReservedTokensOf(uint256 _projectId, string memory _memo) - external - returns (uint256); + function distributeReservedTokensOf( + uint256 projectId, + string memory memo + ) external returns (uint256); - function migrate(uint256 _projectId, IJBMigratable _to) external; + function migrate(uint256 projectId, IJBMigratable to) external; } diff --git a/contracts/interfaces/IJBControllerUtility.sol b/contracts/interfaces/IJBControllerUtility.sol index fadaf350d..e48be2ff0 100644 --- a/contracts/interfaces/IJBControllerUtility.sol +++ b/contracts/interfaces/IJBControllerUtility.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import './IJBDirectory.sol'; +import {IJBDirectory} from './IJBDirectory.sol'; interface IJBControllerUtility { function directory() external view returns (IJBDirectory); diff --git a/contracts/interfaces/IJBDirectory.sol b/contracts/interfaces/IJBDirectory.sol index 2ea3504d4..95b7e14a3 100644 --- a/contracts/interfaces/IJBDirectory.sol +++ b/contracts/interfaces/IJBDirectory.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import './IJBFundingCycleStore.sol'; -import './IJBPaymentTerminal.sol'; -import './IJBProjects.sol'; +import {IJBFundingCycleStore} from './IJBFundingCycleStore.sol'; +import {IJBPaymentTerminal} from './IJBPaymentTerminal.sol'; +import {IJBProjects} from './IJBProjects.sol'; interface IJBDirectory { event SetController(uint256 indexed projectId, address indexed controller, address caller); @@ -25,31 +25,31 @@ interface IJBDirectory { function fundingCycleStore() external view returns (IJBFundingCycleStore); - function controllerOf(uint256 _projectId) external view returns (address); + function controllerOf(uint256 projectId) external view returns (address); - function isAllowedToSetFirstController(address _address) external view returns (bool); + function isAllowedToSetFirstController(address account) external view returns (bool); - function terminalsOf(uint256 _projectId) external view returns (IJBPaymentTerminal[] memory); + function terminalsOf(uint256 projectId) external view returns (IJBPaymentTerminal[] memory); - function isTerminalOf(uint256 _projectId, IJBPaymentTerminal _terminal) - external - view - returns (bool); + function isTerminalOf( + uint256 projectId, + IJBPaymentTerminal terminal + ) external view returns (bool); - function primaryTerminalOf(uint256 _projectId, address _token) - external - view - returns (IJBPaymentTerminal); + function primaryTerminalOf( + uint256 projectId, + address token + ) external view returns (IJBPaymentTerminal); - function setControllerOf(uint256 _projectId, address _controller) external; + function setControllerOf(uint256 projectId, address controller) external; - function setTerminalsOf(uint256 _projectId, IJBPaymentTerminal[] calldata _terminals) external; + function setTerminalsOf(uint256 projectId, IJBPaymentTerminal[] calldata terminals) external; function setPrimaryTerminalOf( - uint256 _projectId, - address _token, - IJBPaymentTerminal _terminal + uint256 projectId, + address token, + IJBPaymentTerminal terminal ) external; - function setIsAllowedToSetFirstController(address _address, bool _flag) external; + function setIsAllowedToSetFirstController(address account, bool flag) external; } diff --git a/contracts/interfaces/IJBETHERC20ProjectPayerDeployer.sol b/contracts/interfaces/IJBETHERC20ProjectPayerDeployer.sol index 803e2c893..6576fd761 100644 --- a/contracts/interfaces/IJBETHERC20ProjectPayerDeployer.sol +++ b/contracts/interfaces/IJBETHERC20ProjectPayerDeployer.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import './IJBDirectory.sol'; -import './IJBProjectPayer.sol'; +import {IJBDirectory} from './IJBDirectory.sol'; +import {IJBProjectPayer} from './IJBProjectPayer.sol'; interface IJBETHERC20ProjectPayerDeployer { event DeployProjectPayer( @@ -19,12 +19,12 @@ interface IJBETHERC20ProjectPayerDeployer { ); function deployProjectPayer( - uint256 _defaultProjectId, - address payable _defaultBeneficiary, - bool _defaultPreferClaimedTokens, - string memory _defaultMemo, - bytes memory _defaultMetadata, - bool _preferAddToBalance, - address _owner + uint256 defaultProjectId, + address payable defaultBeneficiary, + bool defaultPreferClaimedTokens, + string memory defaultMemo, + bytes memory defaultMetadata, + bool preferAddToBalance, + address owner ) external returns (IJBProjectPayer projectPayer); } diff --git a/contracts/interfaces/IJBETHERC20SplitsPayerDeployer.sol b/contracts/interfaces/IJBETHERC20SplitsPayerDeployer.sol index c704d9675..9c252f6ac 100644 --- a/contracts/interfaces/IJBETHERC20SplitsPayerDeployer.sol +++ b/contracts/interfaces/IJBETHERC20SplitsPayerDeployer.sol @@ -1,8 +1,9 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import './IJBSplitsPayer.sol'; -import './IJBSplitsStore.sol'; +import {IJBSplitsPayer} from './IJBSplitsPayer.sol'; +import {IJBSplitsStore} from './IJBSplitsStore.sol'; +import {JBSplit} from './../structs/JBSplit.sol'; interface IJBETHERC20SplitsPayerDeployer { event DeploySplitsPayer( @@ -22,28 +23,28 @@ interface IJBETHERC20SplitsPayerDeployer { ); function deploySplitsPayer( - uint256 _defaultSplitsProjectId, - uint256 _defaultSplitsDomain, - uint256 _defaultSplitsGroup, - uint256 _defaultProjectId, - address payable _defaultBeneficiary, - bool _defaultPreferClaimedTokens, - string calldata _defaultMemo, - bytes calldata _defaultMetadata, - bool _preferAddToBalance, - address _owner + uint256 defaultSplitsProjectId, + uint256 defaultSplitsDomain, + uint256 defaultSplitsGroup, + uint256 defaultProjectId, + address payable defaultBeneficiary, + bool defaultPreferClaimedTokens, + string calldata defaultMemo, + bytes calldata defaultMetadata, + bool preferAddToBalance, + address owner ) external returns (IJBSplitsPayer splitsPayer); function deploySplitsPayerWithSplits( - uint256 _defaultSplitsProjectId, - JBSplit[] memory _defaultSplits, - IJBSplitsStore _splitsStore, - uint256 _defaultProjectId, - address payable _defaultBeneficiary, - bool _defaultPreferClaimedTokens, - string memory _defaultMemo, - bytes memory _defaultMetadata, - bool _defaultPreferAddToBalance, - address _owner + uint256 defaultSplitsProjectId, + JBSplit[] memory defaultSplits, + IJBSplitsStore splitsStore, + uint256 defaultProjectId, + address payable defaultBeneficiary, + bool defaultPreferClaimedTokens, + string memory defaultMemo, + bytes memory defaultMetadata, + bool defaultPreferAddToBalance, + address owner ) external returns (IJBSplitsPayer splitsPayer); } diff --git a/contracts/interfaces/IJBFeeGauge.sol b/contracts/interfaces/IJBFeeGauge.sol index d0b5cd1f1..1439a75de 100644 --- a/contracts/interfaces/IJBFeeGauge.sol +++ b/contracts/interfaces/IJBFeeGauge.sol @@ -2,5 +2,5 @@ pragma solidity ^0.8.0; interface IJBFeeGauge { - function currentDiscountFor(uint256 _projectId) external view returns (uint256); + function currentDiscountFor(uint256 projectId) external view returns (uint256); } diff --git a/contracts/interfaces/IJBFeeGauge3_1.sol b/contracts/interfaces/IJBFeeGauge3_1.sol new file mode 100644 index 000000000..c1338386d --- /dev/null +++ b/contracts/interfaces/IJBFeeGauge3_1.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {JBFeeType} from './../enums/JBFeeType.sol'; + +interface IJBFeeGauge3_1 { + function currentDiscountFor(uint256 projectId, JBFeeType feeType) external view returns (uint256); +} diff --git a/contracts/interfaces/IJBFeeHoldingTerminal.sol b/contracts/interfaces/IJBFeeHoldingTerminal.sol index b5dbb8089..f815e032a 100644 --- a/contracts/interfaces/IJBFeeHoldingTerminal.sol +++ b/contracts/interfaces/IJBFeeHoldingTerminal.sol @@ -3,11 +3,11 @@ pragma solidity ^0.8.0; interface IJBFeeHoldingTerminal { function addToBalanceOf( - uint256 _projectId, - uint256 _amount, - address _token, - bool _shouldRefundHeldFees, - string calldata _memo, - bytes calldata _metadata + uint256 projectId, + uint256 amount, + address token, + bool shouldRefundHeldFees, + string calldata memo, + bytes calldata metadata ) external payable; } diff --git a/contracts/interfaces/IJBFundAccessConstraintsStore.sol b/contracts/interfaces/IJBFundAccessConstraintsStore.sol index 5c72cc812..cb687a3ad 100644 --- a/contracts/interfaces/IJBFundAccessConstraintsStore.sol +++ b/contracts/interfaces/IJBFundAccessConstraintsStore.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import '@openzeppelin/contracts/utils/introspection/IERC165.sol'; -import './../structs/JBFundAccessConstraints.sol'; -import './IJBPaymentTerminal.sol'; +import {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol'; +import {JBFundAccessConstraints} from './../structs/JBFundAccessConstraints.sol'; +import {IJBPaymentTerminal} from './IJBPaymentTerminal.sol'; interface IJBFundAccessConstraintsStore is IERC165 { event SetFundAccessConstraints( @@ -14,22 +14,22 @@ interface IJBFundAccessConstraintsStore is IERC165 { ); function distributionLimitOf( - uint256 _projectId, - uint256 _configuration, - IJBPaymentTerminal _terminal, - address _token + uint256 projectId, + uint256 configuration, + IJBPaymentTerminal terminal, + address token ) external view returns (uint256 distributionLimit, uint256 distributionLimitCurrency); function overflowAllowanceOf( - uint256 _projectId, - uint256 _configuration, - IJBPaymentTerminal _terminal, - address _token + uint256 projectId, + uint256 configuration, + IJBPaymentTerminal terminal, + address token ) external view returns (uint256 overflowAllowance, uint256 overflowAllowanceCurrency); function setFor( - uint256 _projectId, - uint256 _configuration, - JBFundAccessConstraints[] memory _fundAccessConstaints + uint256 projectId, + uint256 configuration, + JBFundAccessConstraints[] memory fundAccessConstaints ) external; } diff --git a/contracts/interfaces/IJBFundingCycleBallot.sol b/contracts/interfaces/IJBFundingCycleBallot.sol index 1ed25c8ea..de77d6bc3 100644 --- a/contracts/interfaces/IJBFundingCycleBallot.sol +++ b/contracts/interfaces/IJBFundingCycleBallot.sol @@ -1,15 +1,15 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import '@openzeppelin/contracts/utils/introspection/IERC165.sol'; -import './../enums/JBBallotState.sol'; +import {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol'; +import {JBBallotState} from './../enums/JBBallotState.sol'; interface IJBFundingCycleBallot is IERC165 { function duration() external view returns (uint256); function stateOf( - uint256 _projectId, - uint256 _configuration, - uint256 _start + uint256 projectId, + uint256 configuration, + uint256 start ) external view returns (JBBallotState); } diff --git a/contracts/interfaces/IJBFundingCycleDataSource.sol b/contracts/interfaces/IJBFundingCycleDataSource.sol index 838b66797..2e4cde41d 100644 --- a/contracts/interfaces/IJBFundingCycleDataSource.sol +++ b/contracts/interfaces/IJBFundingCycleDataSource.sol @@ -1,46 +1,23 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import '@openzeppelin/contracts/utils/introspection/IERC165.sol'; -import './../structs/JBPayDelegateAllocation.sol'; -import './../structs/JBPayParamsData.sol'; -import './../structs/JBRedeemParamsData.sol'; -import './../structs/JBRedemptionDelegateAllocation.sol'; - -/** - @title - Datasource - - @notice - The datasource is called by JBPaymentTerminal on pay and redemption, and provide an extra layer of logic to use - a custom weight, a custom memo and/or a pay/redeem delegate - - @dev - Adheres to: - IERC165 for adequate interface integration -*/ +import {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol'; +import {JBPayDelegateAllocation} from './../structs/JBPayDelegateAllocation.sol'; +import {JBPayParamsData} from './../structs/JBPayParamsData.sol'; +import {JBRedeemParamsData} from './../structs/JBRedeemParamsData.sol'; +import {JBRedemptionDelegateAllocation} from './../structs/JBRedemptionDelegateAllocation.sol'; + +/// @title Datasource +/// @notice The datasource is called by JBPayoutRedemptionPaymentTerminals on pay and redemption, and provide an extra layer of logic to use a custom weight, a custom memo and/or a pay/redeem delegate interface IJBFundingCycleDataSource is IERC165 { - /** - @notice - The datasource implementation for JBPaymentTerminal.pay(..) - - @param _data the data passed to the data source in terminal.pay(..), as a JBPayParamsData struct: - IJBPaymentTerminal terminal; - address payer; - JBTokenAmount amount; - uint256 projectId; - uint256 currentFundingCycleConfiguration; - address beneficiary; - uint256 weight; - uint256 reservedRate; - string memo; - bytes metadata; - - @return weight the weight to use to override the funding cycle weight - @return memo the memo to override the pay(..) memo - @return delegateAllocations The amount to send to delegates instead of adding to the local balance. - */ - function payParams(JBPayParamsData calldata _data) + /// @notice The datasource implementation for JBPaymentTerminal.pay(..) + /// @param data the data passed to the data source in terminal.pay(..), as a JBPayParamsData struct: + /// @return weight the weight to use to override the funding cycle weight + /// @return memo the memo to override the pay(..) memo + /// @return delegateAllocations The amount to send to delegates instead of adding to the local balance. + function payParams( + JBPayParamsData calldata data + ) external returns ( uint256 weight, @@ -48,30 +25,14 @@ interface IJBFundingCycleDataSource is IERC165 { JBPayDelegateAllocation[] memory delegateAllocations ); - /** - @notice - The datasource implementation for JBPaymentTerminal.redeemTokensOf(..) - - @param _data the data passed to the data source in terminal.redeemTokensOf(..), as a JBRedeemParamsData struct: - IJBPaymentTerminal terminal; - address holder; - uint256 projectId; - uint256 currentFundingCycleConfiguration; - uint256 tokenCount; - uint256 totalSupply; - uint256 overflow; - JBTokenAmount reclaimAmount; - bool useTotalOverflow; - uint256 redemptionRate; - uint256 ballotRedemptionRate; - string memo; - bytes metadata; - - @return reclaimAmount The amount to claim, overriding the terminal logic. - @return memo The memo to override the redeemTokensOf(..) memo. - @return delegateAllocations The amount to send to delegates instead of adding to the beneficiary. - */ - function redeemParams(JBRedeemParamsData calldata _data) + /// @notice The datasource implementation for JBPaymentTerminal.redeemTokensOf(..) + /// @param data the data passed to the data source in terminal.redeemTokensOf(..), as a JBRedeemParamsData struct: + /// @return reclaimAmount The amount to claim, overriding the terminal logic. + /// @return memo The memo to override the redeemTokensOf(..) memo. + /// @return delegateAllocations The amount to send to delegates instead of adding to the beneficiary. + function redeemParams( + JBRedeemParamsData calldata data + ) external returns ( uint256 reclaimAmount, diff --git a/contracts/interfaces/IJBFundingCycleDataSource3_1_1.sol b/contracts/interfaces/IJBFundingCycleDataSource3_1_1.sol new file mode 100644 index 000000000..f4cc5f57f --- /dev/null +++ b/contracts/interfaces/IJBFundingCycleDataSource3_1_1.sol @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol'; +import {JBPayDelegateAllocation3_1_1} from './../structs/JBPayDelegateAllocation3_1_1.sol'; +import {JBPayParamsData} from './../structs/JBPayParamsData.sol'; +import {JBRedeemParamsData} from './../structs/JBRedeemParamsData.sol'; +import {JBRedemptionDelegateAllocation3_1_1} from './../structs/JBRedemptionDelegateAllocation3_1_1.sol'; + +/// @title Datasource +/// @notice The datasource is called by JBPayoutRedemptionPaymentTerminals on pay and redemption, and provide an extra layer of logic to use a custom weight, a custom memo and/or a pay/redeem delegate +interface IJBFundingCycleDataSource3_1_1 is IERC165 { + /// @notice The datasource implementation for JBPaymentTerminal.pay(..) + /// @param data the data passed to the data source in terminal.pay(..), as a JBPayParamsData struct: + /// @return weight the weight to use to override the funding cycle weight + /// @return memo the memo to override the pay(..) memo + /// @return delegateAllocations The amount to send to delegates instead of adding to the local balance. + function payParams( + JBPayParamsData calldata data + ) + external + returns ( + uint256 weight, + string memory memo, + JBPayDelegateAllocation3_1_1[] memory delegateAllocations + ); + + /// @notice The datasource implementation for JBPaymentTerminal.redeemTokensOf(..) + /// @param data the data passed to the data source in terminal.redeemTokensOf(..), as a JBRedeemParamsData struct: + /// @return reclaimAmount The amount to claim, overriding the terminal logic. + /// @return memo The memo to override the redeemTokensOf(..) memo. + /// @return delegateAllocations The amount to send to delegates instead of adding to the beneficiary. + function redeemParams( + JBRedeemParamsData calldata data + ) + external + returns ( + uint256 reclaimAmount, + string memory memo, + JBRedemptionDelegateAllocation3_1_1[] memory delegateAllocations + ); +} diff --git a/contracts/interfaces/IJBFundingCycleStore.sol b/contracts/interfaces/IJBFundingCycleStore.sol index 29f5a6d7f..da63dad4f 100644 --- a/contracts/interfaces/IJBFundingCycleStore.sol +++ b/contracts/interfaces/IJBFundingCycleStore.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import './../enums/JBBallotState.sol'; -import './../structs/JBFundingCycle.sol'; -import './../structs/JBFundingCycleData.sol'; +import {JBBallotState} from './../enums/JBBallotState.sol'; +import {JBFundingCycle} from './../structs/JBFundingCycle.sol'; +import {JBFundingCycleData} from './../structs/JBFundingCycleData.sol'; interface IJBFundingCycleStore { event Configure( @@ -17,28 +17,27 @@ interface IJBFundingCycleStore { event Init(uint256 indexed configuration, uint256 indexed projectId, uint256 indexed basedOn); - function latestConfigurationOf(uint256 _projectId) external view returns (uint256); + function latestConfigurationOf(uint256 projectId) external view returns (uint256); - function get(uint256 _projectId, uint256 _configuration) - external - view - returns (JBFundingCycle memory); + function get( + uint256 projectId, + uint256 configuration + ) external view returns (JBFundingCycle memory); - function latestConfiguredOf(uint256 _projectId) - external - view - returns (JBFundingCycle memory fundingCycle, JBBallotState ballotState); + function latestConfiguredOf( + uint256 projectId + ) external view returns (JBFundingCycle memory fundingCycle, JBBallotState ballotState); - function queuedOf(uint256 _projectId) external view returns (JBFundingCycle memory fundingCycle); + function queuedOf(uint256 projectId) external view returns (JBFundingCycle memory fundingCycle); - function currentOf(uint256 _projectId) external view returns (JBFundingCycle memory fundingCycle); + function currentOf(uint256 projectId) external view returns (JBFundingCycle memory fundingCycle); - function currentBallotStateOf(uint256 _projectId) external view returns (JBBallotState); + function currentBallotStateOf(uint256 projectId) external view returns (JBBallotState); function configureFor( - uint256 _projectId, - JBFundingCycleData calldata _data, - uint256 _metadata, - uint256 _mustStartAtOrAfter + uint256 projectId, + JBFundingCycleData calldata data, + uint256 metadata, + uint256 mustStartAtOrAfter ) external returns (JBFundingCycle memory fundingCycle); } diff --git a/contracts/interfaces/IJBMigratable.sol b/contracts/interfaces/IJBMigratable.sol index 7be360734..457ce729c 100644 --- a/contracts/interfaces/IJBMigratable.sol +++ b/contracts/interfaces/IJBMigratable.sol @@ -2,5 +2,5 @@ pragma solidity ^0.8.0; interface IJBMigratable { - function prepForMigrationOf(uint256 _projectId, address _from) external; + function prepForMigrationOf(uint256 projectId, address from) external; } diff --git a/contracts/interfaces/IJBOperatable.sol b/contracts/interfaces/IJBOperatable.sol index 8fab12872..e43de6fb9 100644 --- a/contracts/interfaces/IJBOperatable.sol +++ b/contracts/interfaces/IJBOperatable.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import './IJBOperatorStore.sol'; +import {IJBOperatorStore} from './IJBOperatorStore.sol'; interface IJBOperatable { function operatorStore() external view returns (IJBOperatorStore); diff --git a/contracts/interfaces/IJBOperatorStore.sol b/contracts/interfaces/IJBOperatorStore.sol index f41df144a..59e6f2b11 100644 --- a/contracts/interfaces/IJBOperatorStore.sol +++ b/contracts/interfaces/IJBOperatorStore.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import './../structs/JBOperatorData.sol'; +import {JBOperatorData} from './../structs/JBOperatorData.sol'; interface IJBOperatorStore { event SetOperator( @@ -13,26 +13,26 @@ interface IJBOperatorStore { ); function permissionsOf( - address _operator, - address _account, - uint256 _domain + address operator, + address account, + uint256 domain ) external view returns (uint256); function hasPermission( - address _operator, - address _account, - uint256 _domain, - uint256 _permissionIndex + address operator, + address account, + uint256 domain, + uint256 permissionIndex ) external view returns (bool); function hasPermissions( - address _operator, - address _account, - uint256 _domain, - uint256[] calldata _permissionIndexes + address operator, + address account, + uint256 domain, + uint256[] calldata permissionIndexes ) external view returns (bool); - function setOperator(JBOperatorData calldata _operatorData) external; + function setOperator(JBOperatorData calldata operatorData) external; - function setOperators(JBOperatorData[] calldata _operatorData) external; + function setOperators(JBOperatorData[] calldata operatorData) external; } diff --git a/contracts/interfaces/IJBPayDelegate.sol b/contracts/interfaces/IJBPayDelegate.sol index 364d8485e..daf881204 100644 --- a/contracts/interfaces/IJBPayDelegate.sol +++ b/contracts/interfaces/IJBPayDelegate.sol @@ -1,39 +1,14 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import '@openzeppelin/contracts/utils/introspection/IERC165.sol'; -import './../structs/JBDidPayData.sol'; +import {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol'; +import {JBDidPayData} from './../structs/JBDidPayData.sol'; -/** - @title - Pay delegate - - @notice - Delegate called after JBTerminal.pay(..) logic completion (if passed by the funding cycle datasource) - - @dev - Adheres to: - IERC165 for adequate interface integration -*/ +/// @title Pay delegate +/// @notice Delegate called after JBTerminal.pay(..) logic completion (if passed by the funding cycle datasource) interface IJBPayDelegate is IERC165 { - /** - @notice - This function is called by JBPaymentTerminal.pay(..), after the execution of its logic - - @dev - Critical business logic should be protected by an appropriate access control - - @param _data the data passed by the terminal, as a JBDidPayData struct: - address payer; - uint256 projectId; - uint256 currentFundingCycleConfiguration; - JBTokenAmount amount; - JBTokenAmount forwardedAmount; - uint256 projectTokenCount; - address beneficiary; - bool preferClaimedTokens; - string memo; - bytes metadata; - */ - function didPay(JBDidPayData calldata _data) external payable; + /// @notice This function is called by JBPaymentTerminal.pay(..), after the execution of its logic + /// @dev Critical business logic should be protected by an appropriate access control + /// @param data the data passed by the terminal, as a JBDidPayData struct: + function didPay(JBDidPayData calldata data) external payable; } diff --git a/contracts/interfaces/IJBPayDelegate3_1_1.sol b/contracts/interfaces/IJBPayDelegate3_1_1.sol new file mode 100644 index 000000000..aac228a07 --- /dev/null +++ b/contracts/interfaces/IJBPayDelegate3_1_1.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol'; +import {JBDidPayData3_1_1} from './../structs/JBDidPayData3_1_1.sol'; + +/// @title Pay delegate +/// @notice Delegate called after JBTerminal.pay(..) logic completion (if passed by the funding cycle datasource) +interface IJBPayDelegate3_1_1 is IERC165 { + /// @notice This function is called by JBPaymentTerminal.pay(..), after the execution of its logic + /// @dev Critical business logic should be protected by an appropriate access control + /// @param data the data passed by the terminal, as a JBDidPayData3_1_1 struct: + function didPay(JBDidPayData3_1_1 calldata data) external payable; +} diff --git a/contracts/interfaces/IJBPaymentTerminal.sol b/contracts/interfaces/IJBPaymentTerminal.sol index 388f0d487..fe0a68125 100644 --- a/contracts/interfaces/IJBPaymentTerminal.sol +++ b/contracts/interfaces/IJBPaymentTerminal.sol @@ -1,34 +1,34 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import '@openzeppelin/contracts/utils/introspection/IERC165.sol'; +import {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol'; interface IJBPaymentTerminal is IERC165 { - function acceptsToken(address _token, uint256 _projectId) external view returns (bool); + function acceptsToken(address token, uint256 projectId) external view returns (bool); - function currencyForToken(address _token) external view returns (uint256); + function currencyForToken(address token) external view returns (uint256); - function decimalsForToken(address _token) external view returns (uint256); + function decimalsForToken(address token) external view returns (uint256); // Return value must be a fixed point number with 18 decimals. - function currentEthOverflowOf(uint256 _projectId) external view returns (uint256); + function currentEthOverflowOf(uint256 projectId) external view returns (uint256); function pay( - uint256 _projectId, - uint256 _amount, - address _token, - address _beneficiary, - uint256 _minReturnedTokens, - bool _preferClaimedTokens, - string calldata _memo, - bytes calldata _metadata + uint256 projectId, + uint256 amount, + address token, + address beneficiary, + uint256 minReturnedTokens, + bool preferClaimedTokens, + string calldata memo, + bytes calldata metadata ) external payable returns (uint256 beneficiaryTokenCount); function addToBalanceOf( - uint256 _projectId, - uint256 _amount, - address _token, - string calldata _memo, - bytes calldata _metadata + uint256 projectId, + uint256 amount, + address token, + string calldata memo, + bytes calldata metadata ) external payable; } diff --git a/contracts/interfaces/IJBPayoutRedemptionPaymentTerminal.sol b/contracts/interfaces/IJBPayoutRedemptionPaymentTerminal.sol index 11d780a0b..bf772138a 100644 --- a/contracts/interfaces/IJBPayoutRedemptionPaymentTerminal.sol +++ b/contracts/interfaces/IJBPayoutRedemptionPaymentTerminal.sol @@ -1,19 +1,20 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import './../structs/JBFee.sol'; -import './IJBAllowanceTerminal.sol'; -import './IJBDirectory.sol'; -import './IJBFeeGauge.sol'; -import './IJBPayDelegate.sol'; -import './IJBPaymentTerminal.sol'; -import './IJBPayoutTerminal.sol'; -import './IJBPrices.sol'; -import './IJBProjects.sol'; -import './IJBRedemptionDelegate.sol'; -import './IJBRedemptionTerminal.sol'; -import './IJBSingleTokenPaymentTerminalStore.sol'; -import './IJBSplitsStore.sol'; +import {JBFee} from './../structs/JBFee.sol'; +import {IJBAllowanceTerminal} from './IJBAllowanceTerminal.sol'; +import {IJBDirectory} from './IJBDirectory.sol'; +import {IJBPayDelegate} from './IJBPayDelegate.sol'; +import {IJBPaymentTerminal} from './IJBPaymentTerminal.sol'; +import {IJBPayoutTerminal} from './IJBPayoutTerminal.sol'; +import {IJBPrices} from './IJBPrices.sol'; +import {IJBProjects} from './IJBProjects.sol'; +import {IJBRedemptionDelegate} from './IJBRedemptionDelegate.sol'; +import {IJBRedemptionTerminal} from './IJBRedemptionTerminal.sol'; +import {IJBSplitsStore} from './IJBSplitsStore.sol'; +import {JBDidPayData} from './../structs/JBDidPayData.sol'; +import {JBDidRedeemData} from './../structs/JBDidRedeemData.sol'; +import {JBSplit} from './../structs/JBSplit.sol'; interface IJBPayoutRedemptionPaymentTerminal is IJBPaymentTerminal, @@ -138,7 +139,7 @@ interface IJBPayoutRedemptionPaymentTerminal is event SetFee(uint256 fee, address caller); - event SetFeeGauge(IJBFeeGauge indexed feeGauge, address caller); + event SetFeeGauge(address indexed feeGauge, address caller); event SetFeelessAddress(address indexed addrs, bool indexed flag, address caller); @@ -150,27 +151,27 @@ interface IJBPayoutRedemptionPaymentTerminal is function prices() external view returns (IJBPrices); - function store() external view returns (IJBSingleTokenPaymentTerminalStore); + function store() external view returns (address); function baseWeightCurrency() external view returns (uint256); function payoutSplitsGroup() external view returns (uint256); - function heldFeesOf(uint256 _projectId) external view returns (JBFee[] memory); + function heldFeesOf(uint256 projectId) external view returns (JBFee[] memory); function fee() external view returns (uint256); - function feeGauge() external view returns (IJBFeeGauge); + function feeGauge() external view returns (address); - function isFeelessAddress(address _contract) external view returns (bool); + function isFeelessAddress(address account) external view returns (bool); - function migrate(uint256 _projectId, IJBPaymentTerminal _to) external returns (uint256 balance); + function migrate(uint256 projectId, IJBPaymentTerminal _to) external returns (uint256 balance); - function processFees(uint256 _projectId) external; + function processFees(uint256 projectId) external; - function setFee(uint256 _fee) external; + function setFee(uint256 fee) external; - function setFeeGauge(IJBFeeGauge _feeGauge) external; + function setFeeGauge(address feeGauge) external; - function setFeelessAddress(address _contract, bool _flag) external; + function setFeelessAddress(address account, bool flag) external; } diff --git a/contracts/interfaces/IJBPayoutRedemptionPaymentTerminal3_1.sol b/contracts/interfaces/IJBPayoutRedemptionPaymentTerminal3_1.sol index 0da0de12c..dd38c2ea7 100644 --- a/contracts/interfaces/IJBPayoutRedemptionPaymentTerminal3_1.sol +++ b/contracts/interfaces/IJBPayoutRedemptionPaymentTerminal3_1.sol @@ -1,20 +1,21 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import './../structs/JBFee.sol'; -import './IJBAllowanceTerminal3_1.sol'; -import './IJBDirectory.sol'; -import './IJBFeeGauge.sol'; -import './IJBFeeHoldingTerminal.sol'; -import './IJBPayDelegate.sol'; -import './IJBPaymentTerminal.sol'; -import './IJBPayoutTerminal3_1.sol'; -import './IJBPrices.sol'; -import './IJBProjects.sol'; -import './IJBRedemptionDelegate.sol'; -import './IJBRedemptionTerminal.sol'; -import './IJBSingleTokenPaymentTerminalStore.sol'; -import './IJBSplitsStore.sol'; +import {JBFee} from './../structs/JBFee.sol'; +import {IJBAllowanceTerminal3_1} from './IJBAllowanceTerminal3_1.sol'; +import {IJBDirectory} from './IJBDirectory.sol'; +import {IJBFeeHoldingTerminal} from './IJBFeeHoldingTerminal.sol'; +import {IJBPayDelegate} from './IJBPayDelegate.sol'; +import {IJBPaymentTerminal} from './IJBPaymentTerminal.sol'; +import {IJBPayoutTerminal3_1} from './IJBPayoutTerminal3_1.sol'; +import {IJBPrices} from './IJBPrices.sol'; +import {IJBProjects} from './IJBProjects.sol'; +import {IJBRedemptionDelegate} from './IJBRedemptionDelegate.sol'; +import {IJBRedemptionTerminal} from './IJBRedemptionTerminal.sol'; +import {IJBSplitsStore} from './IJBSplitsStore.sol'; +import {JBDidPayData} from './../structs/JBDidPayData.sol'; +import {JBDidRedeemData} from './../structs/JBDidRedeemData.sol'; +import {JBSplit} from './../structs/JBSplit.sol'; interface IJBPayoutRedemptionPaymentTerminal3_1 is IJBPaymentTerminal, @@ -142,11 +143,17 @@ interface IJBPayoutRedemptionPaymentTerminal3_1 is event SetFee(uint256 fee, address caller); - event SetFeeGauge(IJBFeeGauge indexed feeGauge, address caller); + event SetFeeGauge(address indexed feeGauge, address caller); event SetFeelessAddress(address indexed addrs, bool indexed flag, address caller); - event PayoutReverted(uint256 indexed projectId, JBSplit split, uint256 amount, bytes reason, address caller); + event PayoutReverted( + uint256 indexed projectId, + JBSplit split, + uint256 amount, + bytes reason, + address caller + ); event FeeReverted( uint256 indexed projectId, @@ -164,27 +171,27 @@ interface IJBPayoutRedemptionPaymentTerminal3_1 is function prices() external view returns (IJBPrices); - function store() external view returns (IJBSingleTokenPaymentTerminalStore); + function store() external view returns (address); function baseWeightCurrency() external view returns (uint256); function payoutSplitsGroup() external view returns (uint256); - function heldFeesOf(uint256 _projectId) external view returns (JBFee[] memory); + function heldFeesOf(uint256 projectId) external view returns (JBFee[] memory); function fee() external view returns (uint256); - function feeGauge() external view returns (IJBFeeGauge); + function feeGauge() external view returns (address); - function isFeelessAddress(address _contract) external view returns (bool); + function isFeelessAddress(address account) external view returns (bool); - function migrate(uint256 _projectId, IJBPaymentTerminal _to) external returns (uint256 balance); + function migrate(uint256 projectId, IJBPaymentTerminal to) external returns (uint256 balance); - function processFees(uint256 _projectId) external; + function processFees(uint256 projectId) external; - function setFee(uint256 _fee) external; + function setFee(uint256 fee) external; - function setFeeGauge(IJBFeeGauge _feeGauge) external; + function setFeeGauge(address feeGauge) external; - function setFeelessAddress(address _contract, bool _flag) external; + function setFeelessAddress(address account, bool flag) external; } diff --git a/contracts/interfaces/IJBPayoutRedemptionPaymentTerminal3_1_1.sol b/contracts/interfaces/IJBPayoutRedemptionPaymentTerminal3_1_1.sol new file mode 100644 index 000000000..ec465e595 --- /dev/null +++ b/contracts/interfaces/IJBPayoutRedemptionPaymentTerminal3_1_1.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {JBFee} from './../structs/JBFee.sol'; +import {JBDidRedeemData3_1_1} from './../structs/JBDidRedeemData3_1_1.sol'; +import {JBDidPayData3_1_1} from './../structs/JBDidPayData3_1_1.sol'; +import {IJBPayDelegate3_1_1} from './IJBPayDelegate3_1_1.sol'; +import {IJBRedemptionDelegate3_1_1} from './IJBRedemptionDelegate3_1_1.sol'; + +interface IJBPayoutRedemptionPaymentTerminal3_1_1 { + event DelegateDidRedeem( + IJBRedemptionDelegate3_1_1 indexed delegate, + JBDidRedeemData3_1_1 data, + uint256 delegatedAmount, + uint256 fee, + address caller + ); + + event DelegateDidPay( + IJBPayDelegate3_1_1 indexed delegate, + JBDidPayData3_1_1 data, + uint256 delegatedAmount, + address caller + ); +} diff --git a/contracts/interfaces/IJBPayoutTerminal.sol b/contracts/interfaces/IJBPayoutTerminal.sol index 358371708..22788fcb6 100644 --- a/contracts/interfaces/IJBPayoutTerminal.sol +++ b/contracts/interfaces/IJBPayoutTerminal.sol @@ -3,11 +3,11 @@ pragma solidity ^0.8.0; interface IJBPayoutTerminal { function distributePayoutsOf( - uint256 _projectId, - uint256 _amount, - uint256 _currency, - address _token, - uint256 _minReturnedTokens, - string calldata _memo + uint256 projectId, + uint256 amount, + uint256 currency, + address token, + uint256 minReturnedTokens, + string calldata memo ) external returns (uint256 netLeftoverDistributionAmount); } diff --git a/contracts/interfaces/IJBPayoutTerminal3_1.sol b/contracts/interfaces/IJBPayoutTerminal3_1.sol index c4f15e784..cbd0349ef 100644 --- a/contracts/interfaces/IJBPayoutTerminal3_1.sol +++ b/contracts/interfaces/IJBPayoutTerminal3_1.sol @@ -3,11 +3,11 @@ pragma solidity ^0.8.0; interface IJBPayoutTerminal3_1 { function distributePayoutsOf( - uint256 _projectId, - uint256 _amount, - uint256 _currency, - address _token, - uint256 _minReturnedTokens, - bytes calldata _metadata + uint256 projectId, + uint256 amount, + uint256 currency, + address token, + uint256 minReturnedTokens, + bytes calldata metadata ) external returns (uint256 netLeftoverDistributionAmount); } diff --git a/contracts/interfaces/IJBPriceFeed.sol b/contracts/interfaces/IJBPriceFeed.sol index c0e3bd708..56362dd40 100644 --- a/contracts/interfaces/IJBPriceFeed.sol +++ b/contracts/interfaces/IJBPriceFeed.sol @@ -2,5 +2,5 @@ pragma solidity ^0.8.0; interface IJBPriceFeed { - function currentPrice(uint256 _targetDecimals) external view returns (uint256); + function currentPrice(uint256 targetDecimals) external view returns (uint256); } diff --git a/contracts/interfaces/IJBPrices.sol b/contracts/interfaces/IJBPrices.sol index cb2f27782..c43dee580 100644 --- a/contracts/interfaces/IJBPrices.sol +++ b/contracts/interfaces/IJBPrices.sol @@ -1,22 +1,18 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import './IJBPriceFeed.sol'; +import {IJBPriceFeed} from './IJBPriceFeed.sol'; interface IJBPrices { event AddFeed(uint256 indexed currency, uint256 indexed base, IJBPriceFeed feed); - function feedFor(uint256 _currency, uint256 _base) external view returns (IJBPriceFeed); + function feedFor(uint256 currency, uint256 base) external view returns (IJBPriceFeed); function priceFor( - uint256 _currency, - uint256 _base, - uint256 _decimals + uint256 currency, + uint256 base, + uint256 decimals ) external view returns (uint256); - function addFeedFor( - uint256 _currency, - uint256 _base, - IJBPriceFeed _priceFeed - ) external; + function addFeedFor(uint256 currency, uint256 base, IJBPriceFeed priceFeed) external; } diff --git a/contracts/interfaces/IJBProjectPayer.sol b/contracts/interfaces/IJBProjectPayer.sol index baa5a900d..9f9aacdb6 100644 --- a/contracts/interfaces/IJBProjectPayer.sol +++ b/contracts/interfaces/IJBProjectPayer.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import '@openzeppelin/contracts/utils/introspection/IERC165.sol'; -import './IJBDirectory.sol'; +import {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol'; +import {IJBDirectory} from './IJBDirectory.sol'; interface IJBProjectPayer is IERC165 { event SetDefaultValues( @@ -32,43 +32,43 @@ interface IJBProjectPayer is IERC165 { function defaultPreferAddToBalance() external view returns (bool); function initialize( - uint256 _defaultProjectId, - address payable _defaultBeneficiary, - bool _defaultPreferClaimedTokens, - string memory _defaultMemo, - bytes memory _defaultMetadata, - bool _defaultPreferAddToBalance, - address _owner + uint256 defaultProjectId, + address payable defaultBeneficiary, + bool defaultPreferClaimedTokens, + string memory defaultMemo, + bytes memory defaultMetadata, + bool defaultPreferAddToBalance, + address owner ) external; function setDefaultValues( - uint256 _projectId, - address payable _beneficiary, - bool _preferClaimedTokens, - string memory _memo, - bytes memory _metadata, - bool _defaultPreferAddToBalance + uint256 projectId, + address payable beneficiary, + bool preferClaimedTokens, + string memory memo, + bytes memory metadata, + bool defaultPreferAddToBalance ) external; function pay( - uint256 _projectId, - address _token, - uint256 _amount, - uint256 _decimals, - address _beneficiary, - uint256 _minReturnedTokens, - bool _preferClaimedTokens, - string memory _memo, - bytes memory _metadata + uint256 projectId, + address token, + uint256 amount, + uint256 decimals, + address beneficiary, + uint256 minReturnedTokens, + bool preferClaimedTokens, + string memory memo, + bytes memory metadata ) external payable; function addToBalanceOf( - uint256 _projectId, - address _token, - uint256 _amount, - uint256 _decimals, - string memory _memo, - bytes memory _metadata + uint256 projectId, + address token, + uint256 amount, + uint256 decimals, + string memory memo, + bytes memory metadata ) external payable; receive() external payable; diff --git a/contracts/interfaces/IJBProjects.sol b/contracts/interfaces/IJBProjects.sol index 0a91b7d29..d0093fac5 100644 --- a/contracts/interfaces/IJBProjects.sol +++ b/contracts/interfaces/IJBProjects.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import '@openzeppelin/contracts/token/ERC721/IERC721.sol'; -import './../structs/JBProjectMetadata.sol'; -import './IJBTokenUriResolver.sol'; +import {IERC721} from '@openzeppelin/contracts/token/ERC721/IERC721.sol'; +import {JBProjectMetadata} from './../structs/JBProjectMetadata.sol'; +import {IJBTokenUriResolver} from './IJBTokenUriResolver.sol'; interface IJBProjects is IERC721 { event Create( @@ -19,18 +19,19 @@ interface IJBProjects is IERC721 { function count() external view returns (uint256); - function metadataContentOf(uint256 _projectId, uint256 _domain) - external - view - returns (string memory); + function metadataContentOf( + uint256 projectId, + uint256 domain + ) external view returns (string memory); function tokenUriResolver() external view returns (IJBTokenUriResolver); - function createFor(address _owner, JBProjectMetadata calldata _metadata) - external - returns (uint256 projectId); + function createFor( + address owner, + JBProjectMetadata calldata metadata + ) external returns (uint256 projectId); - function setMetadataOf(uint256 _projectId, JBProjectMetadata calldata _metadata) external; + function setMetadataOf(uint256 projectId, JBProjectMetadata calldata metadata) external; - function setTokenUriResolver(IJBTokenUriResolver _newResolver) external; + function setTokenUriResolver(IJBTokenUriResolver newResolver) external; } diff --git a/contracts/interfaces/IJBRedemptionDelegate.sol b/contracts/interfaces/IJBRedemptionDelegate.sol index 54234def4..f60653be9 100644 --- a/contracts/interfaces/IJBRedemptionDelegate.sol +++ b/contracts/interfaces/IJBRedemptionDelegate.sol @@ -1,38 +1,14 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import '@openzeppelin/contracts/utils/introspection/IERC165.sol'; -import './../structs/JBDidRedeemData.sol'; +import {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol'; +import {JBDidRedeemData} from './../structs/JBDidRedeemData.sol'; -/** - @title - Redemption delegate - - @notice - Delegate called after JBTerminal.redeemTokensOf(..) logic completion (if passed by the funding cycle datasource) - - @dev - Adheres to: - IERC165 for adequate interface integration -*/ +/// @title Redemption delegate +/// @notice Delegate called after JBTerminal.redeemTokensOf(..) logic completion (if passed by the funding cycle datasource) interface IJBRedemptionDelegate is IERC165 { - /** - @notice - This function is called by JBPaymentTerminal.redeemTokensOf(..), after the execution of its logic - - @dev - Critical business logic should be protected by an appropriate access control - - @param _data the data passed by the terminal, as a JBDidRedeemData struct: - address holder; - uint256 projectId; - uint256 currentFundingCycleConfiguration; - uint256 projectTokenCount; - JBTokenAmount reclaimedAmount; - JBTokenAmount forwardedAmount; - address payable beneficiary; - string memo; - bytes metadata; - */ - function didRedeem(JBDidRedeemData calldata _data) external payable; + /// @notice This function is called by JBPaymentTerminal.redeemTokensOf(..), after the execution of its logic + /// @dev Critical business logic should be protected by an appropriate access control + /// @param data the data passed by the terminal, as a JBDidRedeemData struct: + function didRedeem(JBDidRedeemData calldata data) external payable; } diff --git a/contracts/interfaces/IJBRedemptionDelegate3_1_1.sol b/contracts/interfaces/IJBRedemptionDelegate3_1_1.sol new file mode 100644 index 000000000..669f8c225 --- /dev/null +++ b/contracts/interfaces/IJBRedemptionDelegate3_1_1.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol'; +import {JBDidRedeemData3_1_1} from './../structs/JBDidRedeemData3_1_1.sol'; + +/// @title Redemption delegate +/// @notice Delegate called after JBTerminal.redeemTokensOf(..) logic completion (if passed by the funding cycle datasource) +interface IJBRedemptionDelegate3_1_1 is IERC165 { + /// @notice This function is called by JBPaymentTerminal.redeemTokensOf(..), after the execution of its logic + /// @dev Critical business logic should be protected by an appropriate access control + /// @param data the data passed by the terminal, as a JBDidRedeemData struct: + function didRedeem(JBDidRedeemData3_1_1 calldata data) external payable; +} diff --git a/contracts/interfaces/IJBRedemptionTerminal.sol b/contracts/interfaces/IJBRedemptionTerminal.sol index df8544e13..5b745609a 100644 --- a/contracts/interfaces/IJBRedemptionTerminal.sol +++ b/contracts/interfaces/IJBRedemptionTerminal.sol @@ -3,13 +3,13 @@ pragma solidity ^0.8.0; interface IJBRedemptionTerminal { function redeemTokensOf( - address _holder, - uint256 _projectId, - uint256 _tokenCount, - address _token, - uint256 _minReturnedTokens, - address payable _beneficiary, - string calldata _memo, - bytes calldata _metadata + address holder, + uint256 projectId, + uint256 tokenCount, + address token, + uint256 minReturnedTokens, + address payable beneficiary, + string calldata memo, + bytes calldata metadata ) external returns (uint256 reclaimAmount); } diff --git a/contracts/interfaces/IJBSingleTokenPaymentTerminal.sol b/contracts/interfaces/IJBSingleTokenPaymentTerminal.sol index 83f162ab3..7c53045c8 100644 --- a/contracts/interfaces/IJBSingleTokenPaymentTerminal.sol +++ b/contracts/interfaces/IJBSingleTokenPaymentTerminal.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import './IJBPaymentTerminal.sol'; +import {IJBPaymentTerminal} from './IJBPaymentTerminal.sol'; interface IJBSingleTokenPaymentTerminal is IJBPaymentTerminal { function token() external view returns (address); diff --git a/contracts/interfaces/IJBSingleTokenPaymentTerminalStore.sol b/contracts/interfaces/IJBSingleTokenPaymentTerminalStore.sol index 7cc535903..34740ef68 100644 --- a/contracts/interfaces/IJBSingleTokenPaymentTerminalStore.sol +++ b/contracts/interfaces/IJBSingleTokenPaymentTerminalStore.sol @@ -1,14 +1,14 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import './../structs/JBFundingCycle.sol'; -import './../structs/JBPayDelegateAllocation.sol'; -import './../structs/JBRedemptionDelegateAllocation.sol'; -import './../structs/JBTokenAmount.sol'; -import './IJBDirectory.sol'; -import './IJBFundingCycleStore.sol'; -import './IJBPrices.sol'; -import './IJBSingleTokenPaymentTerminal.sol'; +import {JBFundingCycle} from './../structs/JBFundingCycle.sol'; +import {JBPayDelegateAllocation} from './../structs/JBPayDelegateAllocation.sol'; +import {JBRedemptionDelegateAllocation} from './../structs/JBRedemptionDelegateAllocation.sol'; +import {JBTokenAmount} from './../structs/JBTokenAmount.sol'; +import {IJBDirectory} from './IJBDirectory.sol'; +import {IJBFundingCycleStore} from './IJBFundingCycleStore.sol'; +import {IJBPrices} from './IJBPrices.sol'; +import {IJBSingleTokenPaymentTerminal} from './IJBSingleTokenPaymentTerminal.sol'; interface IJBSingleTokenPaymentTerminalStore { function fundingCycleStore() external view returns (IJBFundingCycleStore); @@ -17,93 +17,93 @@ interface IJBSingleTokenPaymentTerminalStore { function prices() external view returns (IJBPrices); - function balanceOf(IJBSingleTokenPaymentTerminal _terminal, uint256 _projectId) - external - view - returns (uint256); + function balanceOf( + IJBSingleTokenPaymentTerminal terminal, + uint256 projectId + ) external view returns (uint256); function usedDistributionLimitOf( - IJBSingleTokenPaymentTerminal _terminal, - uint256 _projectId, - uint256 _fundingCycleNumber + IJBSingleTokenPaymentTerminal terminal, + uint256 projectId, + uint256 fundingCycleNumber ) external view returns (uint256); function usedOverflowAllowanceOf( - IJBSingleTokenPaymentTerminal _terminal, - uint256 _projectId, - uint256 _fundingCycleConfiguration + IJBSingleTokenPaymentTerminal terminal, + uint256 projectId, + uint256 fundingCycleConfiguration ) external view returns (uint256); - function currentOverflowOf(IJBSingleTokenPaymentTerminal _terminal, uint256 _projectId) - external - view - returns (uint256); + function currentOverflowOf( + IJBSingleTokenPaymentTerminal terminal, + uint256 projectId + ) external view returns (uint256); function currentTotalOverflowOf( - uint256 _projectId, - uint256 _decimals, - uint256 _currency + uint256 projectId, + uint256 decimals, + uint256 currency ) external view returns (uint256); function currentReclaimableOverflowOf( - IJBSingleTokenPaymentTerminal _terminal, - uint256 _projectId, - uint256 _tokenCount, - bool _useTotalOverflow + IJBSingleTokenPaymentTerminal terminal, + uint256 projectId, + uint256 tokenCount, + bool useTotalOverflow ) external view returns (uint256); function currentReclaimableOverflowOf( - uint256 _projectId, - uint256 _tokenCount, - uint256 _totalSupply, - uint256 _overflow + uint256 projectId, + uint256 tokenCount, + uint256 totalSupply, + uint256 overflow ) external view returns (uint256); function recordPaymentFrom( - address _payer, - JBTokenAmount memory _amount, - uint256 _projectId, - uint256 _baseWeightCurrency, - address _beneficiary, - string calldata _memo, - bytes calldata _metadata + address payer, + JBTokenAmount memory amount, + uint256 projectId, + uint256 baseWeightCurrency, + address beneficiary, + string calldata inputMemo, + bytes calldata metadata ) external returns ( JBFundingCycle memory fundingCycle, uint256 tokenCount, JBPayDelegateAllocation[] memory delegateAllocations, - string memory memo + string memory outputMemo ); function recordRedemptionFor( - address _holder, - uint256 _projectId, - uint256 _tokenCount, - string calldata _memo, - bytes calldata _metadata + address holder, + uint256 projectId, + uint256 tokenCount, + string calldata inputMemo, + bytes calldata metadata ) external returns ( JBFundingCycle memory fundingCycle, uint256 reclaimAmount, JBRedemptionDelegateAllocation[] memory delegateAllocations, - string memory memo + string memory outputMemo ); function recordDistributionFor( - uint256 _projectId, - uint256 _amount, - uint256 _currency + uint256 projectId, + uint256 amount, + uint256 currency ) external returns (JBFundingCycle memory fundingCycle, uint256 distributedAmount); function recordUsedAllowanceOf( - uint256 _projectId, - uint256 _amount, - uint256 _currency + uint256 projectId, + uint256 amount, + uint256 currency ) external returns (JBFundingCycle memory fundingCycle, uint256 withdrawnAmount); - function recordAddedBalanceFor(uint256 _projectId, uint256 _amount) external; + function recordAddedBalanceFor(uint256 projectId, uint256 amount) external; - function recordMigration(uint256 _projectId) external returns (uint256 balance); + function recordMigration(uint256 projectId) external returns (uint256 balance); } diff --git a/contracts/interfaces/IJBSingleTokenPaymentTerminalStore3_1_1.sol b/contracts/interfaces/IJBSingleTokenPaymentTerminalStore3_1_1.sol new file mode 100644 index 000000000..9bdaf6ce5 --- /dev/null +++ b/contracts/interfaces/IJBSingleTokenPaymentTerminalStore3_1_1.sol @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {JBFundingCycle} from './../structs/JBFundingCycle.sol'; +import {JBPayDelegateAllocation3_1_1} from './../structs/JBPayDelegateAllocation3_1_1.sol'; +import {JBRedemptionDelegateAllocation3_1_1} from './../structs/JBRedemptionDelegateAllocation3_1_1.sol'; +import {JBTokenAmount} from './../structs/JBTokenAmount.sol'; +import {IJBDirectory} from './IJBDirectory.sol'; +import {IJBFundingCycleStore} from './IJBFundingCycleStore.sol'; +import {IJBPrices} from './IJBPrices.sol'; +import {IJBSingleTokenPaymentTerminal} from './IJBSingleTokenPaymentTerminal.sol'; + +interface IJBSingleTokenPaymentTerminalStore3_1_1 { + function fundingCycleStore() external view returns (IJBFundingCycleStore); + + function directory() external view returns (IJBDirectory); + + function prices() external view returns (IJBPrices); + + function balanceOf( + IJBSingleTokenPaymentTerminal terminal, + uint256 projectId + ) external view returns (uint256); + + function usedDistributionLimitOf( + IJBSingleTokenPaymentTerminal terminal, + uint256 projectId, + uint256 fundingCycleNumber + ) external view returns (uint256); + + function usedOverflowAllowanceOf( + IJBSingleTokenPaymentTerminal terminal, + uint256 projectId, + uint256 fundingCycleConfiguration + ) external view returns (uint256); + + function currentOverflowOf( + IJBSingleTokenPaymentTerminal terminal, + uint256 projectId + ) external view returns (uint256); + + function currentTotalOverflowOf( + uint256 projectId, + uint256 decimals, + uint256 currency + ) external view returns (uint256); + + function currentReclaimableOverflowOf( + IJBSingleTokenPaymentTerminal terminal, + uint256 projectId, + uint256 tokenCount, + bool useTotalOverflow + ) external view returns (uint256); + + function currentReclaimableOverflowOf( + uint256 projectId, + uint256 tokenCount, + uint256 totalSupply, + uint256 overflow + ) external view returns (uint256); + + function recordPaymentFrom( + address payer, + JBTokenAmount memory amount, + uint256 projectId, + uint256 baseWeightCurrency, + address beneficiary, + string calldata inputMemo, + bytes calldata metadata + ) + external + returns ( + JBFundingCycle memory fundingCycle, + uint256 tokenCount, + JBPayDelegateAllocation3_1_1[] memory delegateAllocations, + string memory outputMemo + ); + + function recordRedemptionFor( + address holder, + uint256 projectId, + uint256 tokenCount, + string calldata inputMemo, + bytes calldata metadata + ) + external + returns ( + JBFundingCycle memory fundingCycle, + uint256 reclaimAmount, + JBRedemptionDelegateAllocation3_1_1[] memory delegateAllocations, + string memory outputMemo + ); + + function recordDistributionFor( + uint256 projectId, + uint256 amount, + uint256 currency + ) external returns (JBFundingCycle memory fundingCycle, uint256 distributedAmount); + + function recordUsedAllowanceOf( + uint256 projectId, + uint256 amount, + uint256 currency + ) external returns (JBFundingCycle memory fundingCycle, uint256 withdrawnAmount); + + function recordAddedBalanceFor(uint256 projectId, uint256 amount) external; + + function recordMigration(uint256 projectId) external returns (uint256 balance); +} diff --git a/contracts/interfaces/IJBSplitAllocator.sol b/contracts/interfaces/IJBSplitAllocator.sol index 50c01dd31..7bd0dc7cd 100644 --- a/contracts/interfaces/IJBSplitAllocator.sol +++ b/contracts/interfaces/IJBSplitAllocator.sol @@ -1,39 +1,15 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import '@openzeppelin/contracts/utils/introspection/IERC165.sol'; -import '../structs/JBSplitAllocationData.sol'; +import {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol'; +import {JBSplitAllocationData} from '../structs/JBSplitAllocationData.sol'; -/** - @title - Split allocator - - @notice - Provide a way to process a single split with extra logic - - @dev - Adheres to: - IERC165 for adequate interface integration - - @dev - The contract address should be set as an allocator in the adequate split -*/ +/// @title Split allocator +/// @notice Provide a way to process a single split with extra logic +/// @dev The contract address should be set as an allocator in the adequate split interface IJBSplitAllocator is IERC165 { - /** - @notice - This function is called by JBPaymentTerminal.distributePayoutOf(..), during the processing of the split including it - - @dev - Critical business logic should be protected by an appropriate access control. The token and/or eth are optimistically transfered - to the allocator for its logic. - - @param _data the data passed by the terminal, as a JBSplitAllocationData struct: - address token; - uint256 amount; - uint256 decimals; - uint256 projectId; - uint256 group; - JBSplit split; - */ - function allocate(JBSplitAllocationData calldata _data) external payable; + /// @notice This function is called by JBPaymentTerminal.distributePayoutOf(..), during the processing of the split including it + /// @dev Critical business logic should be protected by an appropriate access control. The token and/or eth are optimistically transfered to the allocator for its logic. + /// @param data the data passed by the terminal, as a JBSplitAllocationData struct: + function allocate(JBSplitAllocationData calldata data) external payable; } diff --git a/contracts/interfaces/IJBSplitsPayer.sol b/contracts/interfaces/IJBSplitsPayer.sol index 327f8df8f..ba991404e 100644 --- a/contracts/interfaces/IJBSplitsPayer.sol +++ b/contracts/interfaces/IJBSplitsPayer.sol @@ -1,10 +1,10 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import '@openzeppelin/contracts/utils/introspection/IERC165.sol'; -import './../structs/JBSplit.sol'; -import './../structs/JBGroupedSplits.sol'; -import './IJBSplitsStore.sol'; +import {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol'; +import {JBSplit} from './../structs/JBSplit.sol'; +import {JBGroupedSplits} from './../structs/JBGroupedSplits.sol'; +import {IJBSplitsStore} from './IJBSplitsStore.sol'; interface IJBSplitsPayer is IERC165 { event SetDefaultSplitsReference( @@ -62,28 +62,24 @@ interface IJBSplitsPayer is IERC165 { function splitsStore() external view returns (IJBSplitsStore); function initialize( - uint256 _defaultSplitsProjectId, - uint256 _defaultSplitsDomain, - uint256 _defaultSplitsGroup, - uint256 _defaultProjectId, - address payable _defaultBeneficiary, - bool _defaultPreferClaimedTokens, - string memory _defaultMemo, - bytes memory _defaultMetadata, - bool _preferAddToBalance, - address _owner + uint256 defaultSplitsProjectId, + uint256 defaultSplitsDomain, + uint256 defaultSplitsGroup, + uint256 defaultProjectId, + address payable defaultBeneficiary, + bool defaultPreferClaimedTokens, + string memory defaultMemo, + bytes memory defaultMetadata, + bool preferAddToBalance, + address owner ) external; - function setDefaultSplitsReference( - uint256 _projectId, - uint256 _domain, - uint256 _group - ) external; + function setDefaultSplitsReference(uint256 projectId, uint256 domain, uint256 group) external; function setDefaultSplits( - uint256 _projectId, - uint256 _domain, - uint256 _group, - JBGroupedSplits[] memory _splitsGroup + uint256 projectId, + uint256 domain, + uint256 group, + JBGroupedSplits[] memory splitsGroup ) external; } diff --git a/contracts/interfaces/IJBSplitsStore.sol b/contracts/interfaces/IJBSplitsStore.sol index 14f258950..6de57b6ee 100644 --- a/contracts/interfaces/IJBSplitsStore.sol +++ b/contracts/interfaces/IJBSplitsStore.sol @@ -1,10 +1,10 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import './../structs/JBGroupedSplits.sol'; -import './../structs/JBSplit.sol'; -import './IJBDirectory.sol'; -import './IJBProjects.sol'; +import {JBGroupedSplits} from './../structs/JBGroupedSplits.sol'; +import {JBSplit} from './../structs/JBSplit.sol'; +import {IJBDirectory} from './IJBDirectory.sol'; +import {IJBProjects} from './IJBProjects.sol'; interface IJBSplitsStore { event SetSplit( @@ -20,14 +20,10 @@ interface IJBSplitsStore { function directory() external view returns (IJBDirectory); function splitsOf( - uint256 _projectId, - uint256 _domain, - uint256 _group + uint256 projectId, + uint256 domain, + uint256 group ) external view returns (JBSplit[] memory); - function set( - uint256 _projectId, - uint256 _domain, - JBGroupedSplits[] memory _groupedSplits - ) external; + function set(uint256 projectId, uint256 domain, JBGroupedSplits[] memory groupedSplits) external; } diff --git a/contracts/interfaces/IJBTerminalUtility.sol b/contracts/interfaces/IJBTerminalUtility.sol index ba66c8066..f015e3e77 100644 --- a/contracts/interfaces/IJBTerminalUtility.sol +++ b/contracts/interfaces/IJBTerminalUtility.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import './IJBDirectory.sol'; +import {IJBDirectory} from './IJBDirectory.sol'; interface IJBPaymentTerminalUtility { function directory() external view returns (IJBDirectory); diff --git a/contracts/interfaces/IJBToken.sol b/contracts/interfaces/IJBToken.sol index 073e48ae3..0c234ad39 100644 --- a/contracts/interfaces/IJBToken.sol +++ b/contracts/interfaces/IJBToken.sol @@ -6,38 +6,17 @@ interface IJBToken { function decimals() external view returns (uint8); - function totalSupply(uint256 _projectId) external view returns (uint256); - - function balanceOf(address _account, uint256 _projectId) external view returns (uint256); - - function mint( - uint256 _projectId, - address _account, - uint256 _amount - ) external; - - function burn( - uint256 _projectId, - address _account, - uint256 _amount - ) external; - - function approve( - uint256, - address _spender, - uint256 _amount - ) external; - - function transfer( - uint256 _projectId, - address _to, - uint256 _amount - ) external; - - function transferFrom( - uint256 _projectId, - address _from, - address _to, - uint256 _amount - ) external; + function totalSupply(uint256 projectId) external view returns (uint256); + + function balanceOf(address account, uint256 projectId) external view returns (uint256); + + function mint(uint256 projectId, address account, uint256 amount) external; + + function burn(uint256 projectId, address account, uint256 amount) external; + + function approve(uint256, address spender, uint256 amount) external; + + function transfer(uint256 projectId, address to, uint256 amount) external; + + function transferFrom(uint256 projectId, address from, address to, uint256 amount) external; } diff --git a/contracts/interfaces/IJBTokenStore.sol b/contracts/interfaces/IJBTokenStore.sol index f067ba040..caa45fab6 100644 --- a/contracts/interfaces/IJBTokenStore.sol +++ b/contracts/interfaces/IJBTokenStore.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import './IJBFundingCycleStore.sol'; -import './IJBProjects.sol'; -import './IJBToken.sol'; +import {IJBFundingCycleStore} from './IJBFundingCycleStore.sol'; +import {IJBProjects} from './IJBProjects.sol'; +import {IJBToken} from './IJBToken.sol'; interface IJBTokenStore { event Issue( @@ -51,52 +51,48 @@ interface IJBTokenStore { address caller ); - function tokenOf(uint256 _projectId) external view returns (IJBToken); + function tokenOf(uint256 projectId) external view returns (IJBToken); function projects() external view returns (IJBProjects); function fundingCycleStore() external view returns (IJBFundingCycleStore); - function unclaimedBalanceOf(address _holder, uint256 _projectId) external view returns (uint256); + function unclaimedBalanceOf(address holder, uint256 projectId) external view returns (uint256); - function unclaimedTotalSupplyOf(uint256 _projectId) external view returns (uint256); + function unclaimedTotalSupplyOf(uint256 projectId) external view returns (uint256); - function totalSupplyOf(uint256 _projectId) external view returns (uint256); + function totalSupplyOf(uint256 projectId) external view returns (uint256); - function balanceOf(address _holder, uint256 _projectId) external view returns (uint256 _result); + function balanceOf(address holder, uint256 projectId) external view returns (uint256 result); function issueFor( - uint256 _projectId, - string calldata _name, - string calldata _symbol + uint256 projectId, + string calldata name, + string calldata symbol ) external returns (IJBToken token); - function setFor(uint256 _projectId, IJBToken _token) external; + function setFor(uint256 projectId, IJBToken token) external; function burnFrom( - address _holder, - uint256 _projectId, - uint256 _amount, - bool _preferClaimedTokens + address holder, + uint256 projectId, + uint256 amount, + bool preferClaimedTokens ) external; function mintFor( - address _holder, - uint256 _projectId, - uint256 _amount, - bool _preferClaimedTokens + address holder, + uint256 projectId, + uint256 amount, + bool preferClaimedTokens ) external; - function claimFor( - address _holder, - uint256 _projectId, - uint256 _amount - ) external; + function claimFor(address holder, uint256 projectId, uint256 amount) external; function transferFrom( - address _holder, - uint256 _projectId, - address _recipient, - uint256 _amount + address holder, + uint256 projectId, + address recipient, + uint256 amount ) external; } diff --git a/contracts/interfaces/IJBTokenUriResolver.sol b/contracts/interfaces/IJBTokenUriResolver.sol index e27929171..95ca1590c 100644 --- a/contracts/interfaces/IJBTokenUriResolver.sol +++ b/contracts/interfaces/IJBTokenUriResolver.sol @@ -2,5 +2,5 @@ pragma solidity ^0.8.0; interface IJBTokenUriResolver { - function getUri(uint256 _projectId) external view returns (string memory tokenUri); + function getUri(uint256 projectId) external view returns (string memory tokenUri); } diff --git a/contracts/libraries/JBConstants.sol b/contracts/libraries/JBConstants.sol index 86b2d5b69..0b9dc82ab 100644 --- a/contracts/libraries/JBConstants.sol +++ b/contracts/libraries/JBConstants.sol @@ -1,10 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -/** - @notice - Global constants used across Juicebox contracts. -*/ +/// @notice Global constants used across Juicebox contracts. library JBConstants { uint256 public constant MAX_RESERVED_RATE = 10_000; uint256 public constant MAX_REDEMPTION_RATE = 10_000; diff --git a/contracts/libraries/JBFundingCycleMetadataResolver.sol b/contracts/libraries/JBFundingCycleMetadataResolver.sol index fb2d288ee..e326de57a 100644 --- a/contracts/libraries/JBFundingCycleMetadataResolver.sol +++ b/contracts/libraries/JBFundingCycleMetadataResolver.sol @@ -1,11 +1,11 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.16; -import './../structs/JBFundingCycle.sol'; -import './../structs/JBFundingCycleMetadata.sol'; -import './../structs/JBGlobalFundingCycleMetadata.sol'; -import './JBConstants.sol'; -import './JBGlobalFundingCycleMetadataResolver.sol'; +import {JBFundingCycle} from './../structs/JBFundingCycle.sol'; +import {JBFundingCycleMetadata} from './../structs/JBFundingCycleMetadata.sol'; +import {JBGlobalFundingCycleMetadata} from './../structs/JBGlobalFundingCycleMetadata.sol'; +import {JBConstants} from './JBConstants.sol'; +import {JBGlobalFundingCycleMetadataResolver} from './JBGlobalFundingCycleMetadataResolver.sol'; library JBFundingCycleMetadataResolver { function global(JBFundingCycle memory _fundingCycle) @@ -110,14 +110,9 @@ library JBFundingCycleMetadataResolver { return uint256(uint8(_fundingCycle.metadata >> 244)); } - /** - @notice - Pack the funding cycle metadata. - - @param _metadata The metadata to validate and pack. - - @return packed The packed uint256 of all metadata params. The first 8 bits specify the version. - */ + /// @notice Pack the funding cycle metadata. + /// @param _metadata The metadata to validate and pack. + /// @return packed The packed uint256 of all metadata params. The first 8 bits specify the version. function packFundingCycleMetadata(JBFundingCycleMetadata memory _metadata) internal pure @@ -167,14 +162,9 @@ library JBFundingCycleMetadataResolver { packed |= _metadata.metadata << 244; } - /** - @notice - Expand the funding cycle metadata. - - @param _fundingCycle The funding cycle having its metadata expanded. - - @return metadata The metadata object. - */ + /// @notice Expand the funding cycle metadata. + /// @param _fundingCycle The funding cycle having its metadata expanded. + /// @return metadata The metadata object. function expandMetadata(JBFundingCycle memory _fundingCycle) internal pure diff --git a/contracts/libraries/JBGlobalFundingCycleMetadataResolver.sol b/contracts/libraries/JBGlobalFundingCycleMetadataResolver.sol index 89e6c685c..96ea97d35 100644 --- a/contracts/libraries/JBGlobalFundingCycleMetadataResolver.sol +++ b/contracts/libraries/JBGlobalFundingCycleMetadataResolver.sol @@ -1,7 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.16; -import './../structs/JBFundingCycleMetadata.sol'; +import {JBFundingCycleMetadata} from './../structs/JBFundingCycleMetadata.sol'; +import {JBGlobalFundingCycleMetadata} from './../structs/JBGlobalFundingCycleMetadata.sol'; library JBGlobalFundingCycleMetadataResolver { function setTerminalsAllowed(uint8 _data) internal pure returns (bool) { @@ -16,19 +17,12 @@ library JBGlobalFundingCycleMetadataResolver { return ((_data >> 2) & 1) == 1; } - /** - @notice - Pack the global funding cycle metadata. - - @param _metadata The metadata to validate and pack. - - @return packed The packed uint256 of all global metadata params. The first 8 bits specify the version. - */ - function packFundingCycleGlobalMetadata(JBGlobalFundingCycleMetadata memory _metadata) - internal - pure - returns (uint256 packed) - { + /// @notice Pack the global funding cycle metadata. + /// @param _metadata The metadata to validate and pack. + /// @return packed The packed uint256 of all global metadata params. The first 8 bits specify the version. + function packFundingCycleGlobalMetadata( + JBGlobalFundingCycleMetadata memory _metadata + ) internal pure returns (uint256 packed) { // allow set terminals in bit 0. if (_metadata.allowSetTerminals) packed |= 1; // allow set controller in bit 1. @@ -37,19 +31,12 @@ library JBGlobalFundingCycleMetadataResolver { if (_metadata.pauseTransfers) packed |= 1 << 2; } - /** - @notice - Expand the global funding cycle metadata. - - @param _packedMetadata The packed metadata to expand. - - @return metadata The global metadata object. - */ - function expandMetadata(uint8 _packedMetadata) - internal - pure - returns (JBGlobalFundingCycleMetadata memory metadata) - { + /// @notice Expand the global funding cycle metadata. + /// @param _packedMetadata The packed metadata to expand. + /// @return metadata The global metadata object. + function expandMetadata( + uint8 _packedMetadata + ) internal pure returns (JBGlobalFundingCycleMetadata memory metadata) { return JBGlobalFundingCycleMetadata( setTerminalsAllowed(_packedMetadata), diff --git a/contracts/libraries/JBTokens.sol b/contracts/libraries/JBTokens.sol index b2c1c9967..8db2d9a51 100644 --- a/contracts/libraries/JBTokens.sol +++ b/contracts/libraries/JBTokens.sol @@ -2,9 +2,6 @@ pragma solidity ^0.8.0; library JBTokens { - /** - @notice - The ETH token address in Juicebox is represented by 0x000000000000000000000000000000000000EEEe. - */ + /// @notice The ETH token address in Juicebox is represented by 0x000000000000000000000000000000000000EEEe. address public constant ETH = address(0x000000000000000000000000000000000000EEEe); } diff --git a/contracts/structs/JBDidPayData.sol b/contracts/structs/JBDidPayData.sol index fb810b290..6183bfde0 100644 --- a/contracts/structs/JBDidPayData.sol +++ b/contracts/structs/JBDidPayData.sol @@ -1,20 +1,18 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import './JBTokenAmount.sol'; +import {JBTokenAmount} from './JBTokenAmount.sol'; -/** - @member payer The address from which the payment originated. - @member projectId The ID of the project for which the payment was made. - @member currentFundingCycleConfiguration The configuration of the funding cycle during which the payment is being made. - @member amount The amount of the payment. Includes the token being paid, the value, the number of decimals included, and the currency of the amount. - @member forwardedAmount The amount of the payment that is being sent to the delegate. Includes the token being paid, the value, the number of decimals included, and the currency of the amount. - @member projectTokenCount The number of project tokens minted for the beneficiary. - @member beneficiary The address to which the tokens were minted. - @member preferClaimedTokens A flag indicating whether the request prefered to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. - @member memo The memo that is being emitted alongside the payment. - @member metadata Extra data to send to the delegate. -*/ +/// @custom:member payer The address from which the payment originated. +/// @custom:member projectId The ID of the project for which the payment was made. +/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the payment is being made. +/// @custom:member amount The amount of the payment. Includes the token being paid, the value, the number of decimals included, and the currency of the amount. +/// @custom:member forwardedAmount The amount of the payment that is being sent to the delegate. Includes the token being paid, the value, the number of decimals included, and the currency of the amount. +/// @custom:member projectTokenCount The number of project tokens minted for the beneficiary. +/// @custom:member beneficiary The address to which the tokens were minted. +/// @custom:member preferClaimedTokens A flag indicating whether the request prefered to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. +/// @custom:member memo The memo that is being emitted alongside the payment. +/// @custom:member metadata Extra data to send to the delegate. struct JBDidPayData { address payer; uint256 projectId; diff --git a/contracts/structs/JBDidPayData3_1_1.sol b/contracts/structs/JBDidPayData3_1_1.sol new file mode 100644 index 000000000..6eaac6627 --- /dev/null +++ b/contracts/structs/JBDidPayData3_1_1.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {JBTokenAmount} from './JBTokenAmount.sol'; + +/// @custom:member payer The address from which the payment originated. +/// @custom:member projectId The ID of the project for which the payment was made. +/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the payment is being made. +/// @custom:member amount The amount of the payment. Includes the token being paid, the value, the number of decimals included, and the currency of the amount. +/// @custom:member forwardedAmount The amount of the payment that is being sent to the delegate. Includes the token being paid, the value, the number of decimals included, and the currency of the amount. +/// @custom:member projectTokenCount The number of project tokens minted for the beneficiary. +/// @custom:member beneficiary The address to which the tokens were minted. +/// @custom:member preferClaimedTokens A flag indicating whether the request prefered to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. +/// @custom:member memo The memo that is being emitted alongside the payment. +/// @custom:member dataSourceMetadata Extra data to send to the delegate sent by the data source. +/// @custom:member payerMetadata Extra data to send to the delegate sent by the payer. +struct JBDidPayData3_1_1 { + address payer; + uint256 projectId; + uint256 currentFundingCycleConfiguration; + JBTokenAmount amount; + JBTokenAmount forwardedAmount; + uint256 projectTokenCount; + address beneficiary; + bool preferClaimedTokens; + string memo; + bytes dataSourceMetadata; + bytes payerMetadata; +} diff --git a/contracts/structs/JBDidRedeemData.sol b/contracts/structs/JBDidRedeemData.sol index 1971daf08..e94cac1e3 100644 --- a/contracts/structs/JBDidRedeemData.sol +++ b/contracts/structs/JBDidRedeemData.sol @@ -1,19 +1,17 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import './JBTokenAmount.sol'; +import {JBTokenAmount} from './JBTokenAmount.sol'; -/** - @member holder The holder of the tokens being redeemed. - @member projectId The ID of the project with which the redeemed tokens are associated. - @member currentFundingCycleConfiguration The configuration of the funding cycle during which the redemption is being made. - @member projectTokenCount The number of project tokens being redeemed. - @member reclaimedAmount The amount reclaimed from the treasury. Includes the token being reclaimed, the value, the number of decimals included, and the currency of the amount. - @member forwardedAmount The amount of the payment that is being sent to the delegate. Includes the token being paid, the value, the number of decimals included, and the currency of the amount. - @member beneficiary The address to which the reclaimed amount will be sent. - @member memo The memo that is being emitted alongside the redemption. - @member metadata Extra data to send to the delegate. -*/ +/// @custom:member holder The holder of the tokens being redeemed. +/// @custom:member projectId The ID of the project with which the redeemed tokens are associated. +/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the redemption is being made. +/// @custom:member projectTokenCount The number of project tokens being redeemed. +/// @custom:member reclaimedAmount The amount reclaimed from the treasury. Includes the token being reclaimed, the value, the number of decimals included, and the currency of the amount. +/// @custom:member forwardedAmount The amount of the payment that is being sent to the delegate. Includes the token being paid, the value, the number of decimals included, and the currency of the amount. +/// @custom:member beneficiary The address to which the reclaimed amount will be sent. +/// @custom:member memo The memo that is being emitted alongside the redemption. +/// @custom:member metadata Extra data to send to the delegate. struct JBDidRedeemData { address holder; uint256 projectId; diff --git a/contracts/structs/JBDidRedeemData3_1_1.sol b/contracts/structs/JBDidRedeemData3_1_1.sol new file mode 100644 index 000000000..444090aea --- /dev/null +++ b/contracts/structs/JBDidRedeemData3_1_1.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {JBTokenAmount} from './JBTokenAmount.sol'; + +/// @custom:member holder The holder of the tokens being redeemed. +/// @custom:member projectId The ID of the project with which the redeemed tokens are associated. +/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the redemption is being made. +/// @custom:member projectTokenCount The number of project tokens being redeemed. +/// @custom:member reclaimedAmount The amount reclaimed from the treasury. Includes the token being reclaimed, the value, the number of decimals included, and the currency of the amount. +/// @custom:member forwardedAmount The amount of the payment that is being sent to the delegate. Includes the token being paid, the value, the number of decimals included, and the currency of the amount. +/// @custom:member beneficiary The address to which the reclaimed amount will be sent. +/// @custom:member memo The memo that is being emitted alongside the redemption. +/// @custom:member dataSourceMetadata Extra data to send to the delegate sent by the data source. +/// @custom:member redeemerMetadata Extra data to send to the delegate sent by the redeemer. +struct JBDidRedeemData3_1_1 { + address holder; + uint256 projectId; + uint256 currentFundingCycleConfiguration; + uint256 projectTokenCount; + JBTokenAmount reclaimedAmount; + JBTokenAmount forwardedAmount; + address payable beneficiary; + string memo; + bytes dataSourceMetadata; + bytes redeemerMetadata; +} diff --git a/contracts/structs/JBFee.sol b/contracts/structs/JBFee.sol index 8d8771715..7a2cd751d 100644 --- a/contracts/structs/JBFee.sol +++ b/contracts/structs/JBFee.sol @@ -1,12 +1,10 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -/** - @member amount The total amount the fee was taken from, as a fixed point number with the same number of decimals as the terminal in which this struct was created. - @member fee The percent of the fee, out of MAX_FEE. - @member feeDiscount The discount of the fee. - @member beneficiary The address that will receive the tokens that are minted as a result of the fee payment. -*/ +/// @custom:member amount The total amount the fee was taken from, as a fixed point number with the same number of decimals as the terminal in which this struct was created. +/// @custom:member fee The percent of the fee, out of MAX_FEE. +/// @custom:member feeDiscount The discount of the fee. +/// @custom:member beneficiary The address that will receive the tokens that are minted as a result of the fee payment. struct JBFee { uint256 amount; uint32 fee; diff --git a/contracts/structs/JBFundAccessConstraints.sol b/contracts/structs/JBFundAccessConstraints.sol index e9e529118..2fd89969d 100644 --- a/contracts/structs/JBFundAccessConstraints.sol +++ b/contracts/structs/JBFundAccessConstraints.sol @@ -1,16 +1,14 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import './../interfaces/IJBPaymentTerminal.sol'; +import {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol'; -/** - @member terminal The terminal within which the distribution limit and the overflow allowance applies. - @member token The token for which the fund access constraints apply. - @member distributionLimit The amount of the distribution limit, as a fixed point number with the same number of decimals as the terminal within which the limit applies. - @member distributionLimitCurrency The currency of the distribution limit. - @member overflowAllowance The amount of the allowance, as a fixed point number with the same number of decimals as the terminal within which the allowance applies. - @member overflowAllowanceCurrency The currency of the overflow allowance. -*/ +/// @custom:member terminal The terminal within which the distribution limit and the overflow allowance applies. +/// @custom:member token The token for which the fund access constraints apply. +/// @custom:member distributionLimit The amount of the distribution limit, as a fixed point number with the same number of decimals as the terminal within which the limit applies. +/// @custom:member distributionLimitCurrency The currency of the distribution limit. +/// @custom:member overflowAllowance The amount of the allowance, as a fixed point number with the same number of decimals as the terminal within which the allowance applies. +/// @custom:member overflowAllowanceCurrency The currency of the overflow allowance. struct JBFundAccessConstraints { IJBPaymentTerminal terminal; address token; diff --git a/contracts/structs/JBFundingCycle.sol b/contracts/structs/JBFundingCycle.sol index ea22cb056..75c0ec623 100644 --- a/contracts/structs/JBFundingCycle.sol +++ b/contracts/structs/JBFundingCycle.sol @@ -1,19 +1,17 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import './../interfaces/IJBFundingCycleBallot.sol'; +import {IJBFundingCycleBallot} from './../interfaces/IJBFundingCycleBallot.sol'; -/** - @member number The funding cycle number for the cycle's project. Each funding cycle has a number that is an increment of the cycle that directly preceded it. Each project's first funding cycle has a number of 1. - @member configuration The timestamp when the parameters for this funding cycle were configured. This value will stay the same for subsequent funding cycles that roll over from an originally configured cycle. - @member basedOn The `configuration` of the funding cycle that was active when this cycle was created. - @member start The timestamp marking the moment from which the funding cycle is considered active. It is a unix timestamp measured in seconds. - @member duration The number of seconds the funding cycle lasts for, after which a new funding cycle will start. A duration of 0 means that the funding cycle will stay active until the project owner explicitly issues a reconfiguration, at which point a new funding cycle will immediately start with the updated properties. If the duration is greater than 0, a project owner cannot make changes to a funding cycle's parameters while it is active – any proposed changes will apply to the subsequent cycle. If no changes are proposed, a funding cycle rolls over to another one with the same properties but new `start` timestamp and a discounted `weight`. - @member weight A fixed point number with 18 decimals that contracts can use to base arbitrary calculations on. For example, payment terminals can use this to determine how many tokens should be minted when a payment is received. - @member discountRate A percent by how much the `weight` of the subsequent funding cycle should be reduced, if the project owner hasn't configured the subsequent funding cycle with an explicit `weight`. If it's 0, each funding cycle will have equal weight. If the number is 90%, the next funding cycle will have a 10% smaller weight. This weight is out of `JBConstants.MAX_DISCOUNT_RATE`. - @member ballot An address of a contract that says whether a proposed reconfiguration should be accepted or rejected. It can be used to create rules around how a project owner can change funding cycle parameters over time. - @member metadata Extra data that can be associated with a funding cycle. -*/ +/// @custom:member number The funding cycle number for the cycle's project. Each funding cycle has a number that is an increment of the cycle that directly preceded it. Each project's first funding cycle has a number of 1. +/// @custom:member configuration The timestamp when the parameters for this funding cycle were configured. This value will stay the same for subsequent funding cycles that roll over from an originally configured cycle. +/// @custom:member basedOn The `configuration` of the funding cycle that was active when this cycle was created. +/// @custom:member start The timestamp marking the moment from which the funding cycle is considered active. It is a unix timestamp measured in seconds. +/// @custom:member duration The number of seconds the funding cycle lasts for, after which a new funding cycle will start. A duration of 0 means that the funding cycle will stay active until the project owner explicitly issues a reconfiguration, at which point a new funding cycle will immediately start with the updated properties. If the duration is greater than 0, a project owner cannot make changes to a funding cycle's parameters while it is active – any proposed changes will apply to the subsequent cycle. If no changes are proposed, a funding cycle rolls over to another one with the same properties but new `start` timestamp and a discounted `weight`. +/// @custom:member weight A fixed point number with 18 decimals that contracts can use to base arbitrary calculations on. For example, payment terminals can use this to determine how many tokens should be minted when a payment is received. +/// @custom:member discountRate A percent by how much the `weight` of the subsequent funding cycle should be reduced, if the project owner hasn't configured the subsequent funding cycle with an explicit `weight`. If it's 0, each funding cycle will have equal weight. If the number is 90%, the next funding cycle will have a 10% smaller weight. This weight is out of `JBConstants.MAX_DISCOUNT_RATE`. +/// @custom:member ballot An address of a contract that says whether a proposed reconfiguration should be accepted or rejected. It can be used to create rules around how a project owner can change funding cycle parameters over time. +/// @custom:member metadata Extra data that can be associated with a funding cycle. struct JBFundingCycle { uint256 number; uint256 configuration; diff --git a/contracts/structs/JBFundingCycleData.sol b/contracts/structs/JBFundingCycleData.sol index a43207528..93791654c 100644 --- a/contracts/structs/JBFundingCycleData.sol +++ b/contracts/structs/JBFundingCycleData.sol @@ -1,14 +1,12 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import './../interfaces/IJBFundingCycleBallot.sol'; +import {IJBFundingCycleBallot} from './../interfaces/IJBFundingCycleBallot.sol'; -/** - @member duration The number of seconds the funding cycle lasts for, after which a new funding cycle will start. A duration of 0 means that the funding cycle will stay active until the project owner explicitly issues a reconfiguration, at which point a new funding cycle will immediately start with the updated properties. If the duration is greater than 0, a project owner cannot make changes to a funding cycle's parameters while it is active – any proposed changes will apply to the subsequent cycle. If no changes are proposed, a funding cycle rolls over to another one with the same properties but new `start` timestamp and a discounted `weight`. - @member weight A fixed point number with 18 decimals that contracts can use to base arbitrary calculations on. For example, payment terminals can use this to determine how many tokens should be minted when a payment is received. - @member discountRate A percent by how much the `weight` of the subsequent funding cycle should be reduced, if the project owner hasn't configured the subsequent funding cycle with an explicit `weight`. If it's 0, each funding cycle will have equal weight. If the number is 90%, the next funding cycle will have a 10% smaller weight. This weight is out of `JBConstants.MAX_DISCOUNT_RATE`. - @member ballot An address of a contract that says whether a proposed reconfiguration should be accepted or rejected. It can be used to create rules around how a project owner can change funding cycle parameters over time. -*/ +/// @custom:member duration The number of seconds the funding cycle lasts for, after which a new funding cycle will start. A duration of 0 means that the funding cycle will stay active until the project owner explicitly issues a reconfiguration, at which point a new funding cycle will immediately start with the updated properties. If the duration is greater than 0, a project owner cannot make changes to a funding cycle's parameters while it is active – any proposed changes will apply to the subsequent cycle. If no changes are proposed, a funding cycle rolls over to another one with the same properties but new `start` timestamp and a discounted `weight`. +/// @custom:member weight A fixed point number with 18 decimals that contracts can use to base arbitrary calculations on. For example, payment terminals can use this to determine how many tokens should be minted when a payment is received. +/// @custom:member discountRate A percent by how much the `weight` of the subsequent funding cycle should be reduced, if the project owner hasn't configured the subsequent funding cycle with an explicit `weight`. If it's 0, each funding cycle will have equal weight. If the number is 90%, the next funding cycle will have a 10% smaller weight. This weight is out of `JBConstants.MAX_DISCOUNT_RATE`. +/// @custom:member ballot An address of a contract that says whether a proposed reconfiguration should be accepted or rejected. It can be used to create rules around how a project owner can change funding cycle parameters over time. struct JBFundingCycleData { uint256 duration; uint256 weight; diff --git a/contracts/structs/JBFundingCycleMetadata.sol b/contracts/structs/JBFundingCycleMetadata.sol index 9cc2bf5cf..0cc5873ec 100644 --- a/contracts/structs/JBFundingCycleMetadata.sol +++ b/contracts/structs/JBFundingCycleMetadata.sol @@ -1,28 +1,26 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import './JBGlobalFundingCycleMetadata.sol'; +import {JBGlobalFundingCycleMetadata} from './JBGlobalFundingCycleMetadata.sol'; -/** - @member global Data used globally in non-migratable ecosystem contracts. - @member reservedRate The reserved rate of the funding cycle. This number is a percentage calculated out of `JBConstants.MAX_RESERVED_RATE`. - @member redemptionRate The redemption rate of the funding cycle. This number is a percentage calculated out of `JBConstants.MAX_REDEMPTION_RATE`. - @member ballotRedemptionRate The redemption rate to use during an active ballot of the funding cycle. This number is a percentage calculated out of `JBConstants.MAX_REDEMPTION_RATE`. - @member pausePay A flag indicating if the pay functionality should be paused during the funding cycle. - @member pauseDistributions A flag indicating if the distribute functionality should be paused during the funding cycle. - @member pauseRedeem A flag indicating if the redeem functionality should be paused during the funding cycle. - @member pauseBurn A flag indicating if the burn functionality should be paused during the funding cycle. - @member allowMinting A flag indicating if minting tokens should be allowed during this funding cycle. - @member allowTerminalMigration A flag indicating if migrating terminals should be allowed during this funding cycle. - @member allowControllerMigration A flag indicating if migrating controllers should be allowed during this funding cycle. - @member holdFees A flag indicating if fees should be held during this funding cycle. - @member preferClaimedTokenOverride A flag indicating if claimed tokens should always be prefered to unclaimed tokens when minting. - @member useTotalOverflowForRedemptions A flag indicating if redemptions should use the project's balance held in all terminals instead of the project's local terminal balance from which the redemption is being fulfilled. - @member useDataSourceForPay A flag indicating if the data source should be used for pay transactions during this funding cycle. - @member useDataSourceForRedeem A flag indicating if the data source should be used for redeem transactions during this funding cycle. - @member dataSource The data source to use during this funding cycle. - @member metadata Metadata of the metadata, up to uint8 in size. -*/ +/// @custom:member global Data used globally in non-migratable ecosystem contracts. +/// @custom:member reservedRate The reserved rate of the funding cycle. This number is a percentage calculated out of `JBConstants.MAX_RESERVED_RATE`. +/// @custom:member redemptionRate The redemption rate of the funding cycle. This number is a percentage calculated out of `JBConstants.MAX_REDEMPTION_RATE`. +/// @custom:member ballotRedemptionRate The redemption rate to use during an active ballot of the funding cycle. This number is a percentage calculated out of `JBConstants.MAX_REDEMPTION_RATE`. +/// @custom:member pausePay A flag indicating if the pay functionality should be paused during the funding cycle. +/// @custom:member pauseDistributions A flag indicating if the distribute functionality should be paused during the funding cycle. +/// @custom:member pauseRedeem A flag indicating if the redeem functionality should be paused during the funding cycle. +/// @custom:member pauseBurn A flag indicating if the burn functionality should be paused during the funding cycle. +/// @custom:member allowMinting A flag indicating if minting tokens should be allowed during this funding cycle. +/// @custom:member allowTerminalMigration A flag indicating if migrating terminals should be allowed during this funding cycle. +/// @custom:member allowControllerMigration A flag indicating if migrating controllers should be allowed during this funding cycle. +/// @custom:member holdFees A flag indicating if fees should be held during this funding cycle. +/// @custom:member preferClaimedTokenOverride A flag indicating if claimed tokens should always be prefered to unclaimed tokens when minting. +/// @custom:member useTotalOverflowForRedemptions A flag indicating if redemptions should use the project's balance held in all terminals instead of the project's local terminal balance from which the redemption is being fulfilled. +/// @custom:member useDataSourceForPay A flag indicating if the data source should be used for pay transactions during this funding cycle. +/// @custom:member useDataSourceForRedeem A flag indicating if the data source should be used for redeem transactions during this funding cycle. +/// @custom:member dataSource The data source to use during this funding cycle. +/// @custom:member metadata Metadata of the metadata, up to uint8 in size. struct JBFundingCycleMetadata { JBGlobalFundingCycleMetadata global; uint256 reservedRate; diff --git a/contracts/structs/JBGlobalFundingCycleMetadata.sol b/contracts/structs/JBGlobalFundingCycleMetadata.sol index ed593015c..967914e48 100644 --- a/contracts/structs/JBGlobalFundingCycleMetadata.sol +++ b/contracts/structs/JBGlobalFundingCycleMetadata.sol @@ -1,11 +1,9 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -/** - @member allowSetTerminals A flag indicating if setting terminals should be allowed during this funding cycle. - @member allowSetController A flag indicating if setting a new controller should be allowed during this funding cycle. - @member pauseTransfers A flag indicating if the project token transfer functionality should be paused during the funding cycle. -*/ +/// @custom:member allowSetTerminals A flag indicating if setting terminals should be allowed during this funding cycle. +/// @custom:member allowSetController A flag indicating if setting a new controller should be allowed during this funding cycle. +/// @custom:member pauseTransfers A flag indicating if the project token transfer functionality should be paused during the funding cycle. struct JBGlobalFundingCycleMetadata { bool allowSetTerminals; bool allowSetController; diff --git a/contracts/structs/JBGroupedSplits.sol b/contracts/structs/JBGroupedSplits.sol index 588ec81a8..4592fa782 100644 --- a/contracts/structs/JBGroupedSplits.sol +++ b/contracts/structs/JBGroupedSplits.sol @@ -1,12 +1,10 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import './JBSplit.sol'; +import {JBSplit} from './JBSplit.sol'; -/** - @member group The group indentifier. - @member splits The splits to associate with the group. -*/ +/// @custom:member group The group indentifier. +/// @custom:member splits The splits to associate with the group. struct JBGroupedSplits { uint256 group; JBSplit[] splits; diff --git a/contracts/structs/JBOperatorData.sol b/contracts/structs/JBOperatorData.sol index d547b0184..a03039f28 100644 --- a/contracts/structs/JBOperatorData.sol +++ b/contracts/structs/JBOperatorData.sol @@ -1,11 +1,9 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -/** - @member operator The address of the operator. - @member domain The domain within which the operator is being given permissions. A domain of 0 is a wildcard domain, which gives an operator access to all domains. - @member permissionIndexes The indexes of the permissions the operator is being given. -*/ +/// @custom:member operator The address of the operator. +/// @custom:member domain The domain within which the operator is being given permissions. A domain of 0 is a wildcard domain, which gives an operator access to all domains. +/// @custom:member permissionIndexes The indexes of the permissions the operator is being given. struct JBOperatorData { address operator; uint256 domain; diff --git a/contracts/structs/JBPayDelegateAllocation.sol b/contracts/structs/JBPayDelegateAllocation.sol index d46e1e7a4..40e736f01 100644 --- a/contracts/structs/JBPayDelegateAllocation.sol +++ b/contracts/structs/JBPayDelegateAllocation.sol @@ -1,12 +1,10 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import '../interfaces/IJBPayDelegate.sol'; +import {IJBPayDelegate} from '../interfaces/IJBPayDelegate.sol'; -/** - @member delegate A delegate contract to use for subsequent calls. - @member amount The amount to send to the delegate. -*/ +/// @custom:member delegate A delegate contract to use for subsequent calls. +/// @custom:member amount The amount to send to the delegate. struct JBPayDelegateAllocation { IJBPayDelegate delegate; uint256 amount; diff --git a/contracts/structs/JBPayDelegateAllocation3_1_1.sol b/contracts/structs/JBPayDelegateAllocation3_1_1.sol new file mode 100644 index 000000000..5410be7ff --- /dev/null +++ b/contracts/structs/JBPayDelegateAllocation3_1_1.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {IJBPayDelegate3_1_1} from '../interfaces/IJBPayDelegate3_1_1.sol'; + +/// @custom:member delegate A delegate contract to use for subsequent calls. +/// @custom:member amount The amount to send to the delegate. +/// @custom:member metadata Metadata to pass the delegate. +struct JBPayDelegateAllocation3_1_1 { + IJBPayDelegate3_1_1 delegate; + uint256 amount; + bytes metadata; +} diff --git a/contracts/structs/JBPayParamsData.sol b/contracts/structs/JBPayParamsData.sol index a843b0be4..b12157c92 100644 --- a/contracts/structs/JBPayParamsData.sol +++ b/contracts/structs/JBPayParamsData.sol @@ -1,21 +1,19 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import './../interfaces/IJBPaymentTerminal.sol'; -import './JBTokenAmount.sol'; +import {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol'; +import {JBTokenAmount} from './JBTokenAmount.sol'; -/** - @member terminal The terminal that is facilitating the payment. - @member payer The address from which the payment originated. - @member amount The amount of the payment. Includes the token being paid, the value, the number of decimals included, and the currency of the amount. - @member projectId The ID of the project being paid. - @member currentFundingCycleConfiguration The configuration of the funding cycle during which the payment is being made. - @member beneficiary The specified address that should be the beneficiary of anything that results from the payment. - @member weight The weight of the funding cycle during which the payment is being made. - @member reservedRate The reserved rate of the funding cycle during which the payment is being made. - @member memo The memo that was sent alongside the payment. - @member metadata Extra data provided by the payer. -*/ +/// @custom:member terminal The terminal that is facilitating the payment. +/// @custom:member payer The address from which the payment originated. +/// @custom:member amount The amount of the payment. Includes the token being paid, the value, the number of decimals included, and the currency of the amount. +/// @custom:member projectId The ID of the project being paid. +/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the payment is being made. +/// @custom:member beneficiary The specified address that should be the beneficiary of anything that results from the payment. +/// @custom:member weight The weight of the funding cycle during which the payment is being made. +/// @custom:member reservedRate The reserved rate of the funding cycle during which the payment is being made. +/// @custom:member memo The memo that was sent alongside the payment. +/// @custom:member metadata Extra data provided by the payer. struct JBPayParamsData { IJBPaymentTerminal terminal; address payer; diff --git a/contracts/structs/JBProjectMetadata.sol b/contracts/structs/JBProjectMetadata.sol index 2356a05e0..8316fe9cd 100644 --- a/contracts/structs/JBProjectMetadata.sol +++ b/contracts/structs/JBProjectMetadata.sol @@ -1,10 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -/** - @member content The metadata content. - @member domain The domain within which the metadata applies. -*/ +/// @custom:member content The metadata content. +/// @custom:member domain The domain within which the metadata applies. struct JBProjectMetadata { string content; uint256 domain; diff --git a/contracts/structs/JBRedeemParamsData.sol b/contracts/structs/JBRedeemParamsData.sol index 540898ba8..54e971d02 100644 --- a/contracts/structs/JBRedeemParamsData.sol +++ b/contracts/structs/JBRedeemParamsData.sol @@ -1,23 +1,21 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import './../interfaces/IJBPaymentTerminal.sol'; -import './JBTokenAmount.sol'; +import {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol'; +import {JBTokenAmount} from './JBTokenAmount.sol'; -/** - @member terminal The terminal that is facilitating the redemption. - @member holder The holder of the tokens being redeemed. - @member projectId The ID of the project whos tokens are being redeemed. - @member currentFundingCycleConfiguration The configuration of the funding cycle during which the redemption is being made. - @member tokenCount The proposed number of tokens being redeemed, as a fixed point number with 18 decimals. - @member totalSupply The total supply of tokens used in the calculation, as a fixed point number with 18 decimals. - @member overflow The amount of overflow used in the reclaim amount calculation. - @member reclaimAmount The amount that should be reclaimed by the redeemer using the protocol's standard bonding curve redemption formula. Includes the token being reclaimed, the reclaim value, the number of decimals included, and the currency of the reclaim amount. - @member useTotalOverflow If overflow across all of a project's terminals is being used when making redemptions. - @member redemptionRate The redemption rate of the funding cycle during which the redemption is being made. - @member memo The proposed memo that is being emitted alongside the redemption. - @member metadata Extra data provided by the redeemer. -*/ +/// @custom:member terminal The terminal that is facilitating the redemption. +/// @custom:member holder The holder of the tokens being redeemed. +/// @custom:member projectId The ID of the project whos tokens are being redeemed. +/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the redemption is being made. +/// @custom:member tokenCount The proposed number of tokens being redeemed, as a fixed point number with 18 decimals. +/// @custom:member totalSupply The total supply of tokens used in the calculation, as a fixed point number with 18 decimals. +/// @custom:member overflow The amount of overflow used in the reclaim amount calculation. +/// @custom:member reclaimAmount The amount that should be reclaimed by the redeemer using the protocol's standard bonding curve redemption formula. Includes the token being reclaimed, the reclaim value, the number of decimals included, and the currency of the reclaim amount. +/// @custom:member useTotalOverflow If overflow across all of a project's terminals is being used when making redemptions. +/// @custom:member redemptionRate The redemption rate of the funding cycle during which the redemption is being made. +/// @custom:member memo The proposed memo that is being emitted alongside the redemption. +/// @custom:member metadata Extra data provided by the redeemer. struct JBRedeemParamsData { IJBPaymentTerminal terminal; address holder; diff --git a/contracts/structs/JBRedemptionDelegateAllocation.sol b/contracts/structs/JBRedemptionDelegateAllocation.sol index 82e1d073f..4f65aa5ac 100644 --- a/contracts/structs/JBRedemptionDelegateAllocation.sol +++ b/contracts/structs/JBRedemptionDelegateAllocation.sol @@ -1,12 +1,10 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import '../interfaces/IJBRedemptionDelegate.sol'; +import {IJBRedemptionDelegate} from '../interfaces/IJBRedemptionDelegate.sol'; -/** - @member delegate A delegate contract to use for subsequent calls. - @member amount The amount to send to the delegate. -*/ +/// @custom:member delegate A delegate contract to use for subsequent calls. +/// @custom:member amount The amount to send to the delegate. struct JBRedemptionDelegateAllocation { IJBRedemptionDelegate delegate; uint256 amount; diff --git a/contracts/structs/JBRedemptionDelegateAllocation3_1_1.sol b/contracts/structs/JBRedemptionDelegateAllocation3_1_1.sol new file mode 100644 index 000000000..4bac0e76e --- /dev/null +++ b/contracts/structs/JBRedemptionDelegateAllocation3_1_1.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {IJBRedemptionDelegate3_1_1} from '../interfaces/IJBRedemptionDelegate3_1_1.sol'; + +/// @custom:member delegate A delegate contract to use for subsequent calls. +/// @custom:member amount The amount to send to the delegate. +/// @custom:member metadata Metadata to pass the delegate. +struct JBRedemptionDelegateAllocation3_1_1 { + IJBRedemptionDelegate3_1_1 delegate; + uint256 amount; + bytes metadata; +} diff --git a/contracts/structs/JBSplit.sol b/contracts/structs/JBSplit.sol index a27f642f4..18727a52e 100644 --- a/contracts/structs/JBSplit.sol +++ b/contracts/structs/JBSplit.sol @@ -1,17 +1,15 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import './../interfaces/IJBSplitAllocator.sol'; +import {IJBSplitAllocator} from './../interfaces/IJBSplitAllocator.sol'; -/** - @member preferClaimed A flag that only has effect if a projectId is also specified, and the project has a token contract attached. If so, this flag indicates if the tokens that result from making a payment to the project should be delivered claimed into the beneficiary's wallet, or unclaimed to save gas. - @member preferAddToBalance A flag indicating if a distribution to a project should prefer triggering it's addToBalance function instead of its pay function. - @member percent The percent of the whole group that this split occupies. This number is out of `JBConstants.SPLITS_TOTAL_PERCENT`. - @member projectId The ID of a project. If an allocator is not set but a projectId is set, funds will be sent to the protocol treasury belonging to the project who's ID is specified. Resulting tokens will be routed to the beneficiary with the claimed token preference respected. - @member beneficiary An address. The role the of the beneficary depends on whether or not projectId is specified, and whether or not an allocator is specified. If allocator is set, the beneficiary will be forwarded to the allocator for it to use. If allocator is not set but projectId is set, the beneficiary is the address to which the project's tokens will be sent that result from a payment to it. If neither allocator or projectId are set, the beneficiary is where the funds from the split will be sent. - @member lockedUntil Specifies if the split should be unchangeable until the specified time, with the exception of extending the locked period. - @member allocator If an allocator is specified, funds will be sent to the allocator contract along with all properties of this split. -*/ +/// @custom:member preferClaimed A flag that only has effect if a projectId is also specified, and the project has a token contract attached. If so, this flag indicates if the tokens that result from making a payment to the project should be delivered claimed into the beneficiary's wallet, or unclaimed to save gas. +/// @custom:member preferAddToBalance A flag indicating if a distribution to a project should prefer triggering it's addToBalance function instead of its pay function. +/// @custom:member percent The percent of the whole group that this split occupies. This number is out of `JBConstants.SPLITS_TOTAL_PERCENT`. +/// @custom:member projectId The ID of a project. If an allocator is not set but a projectId is set, funds will be sent to the protocol treasury belonging to the project who's ID is specified. Resulting tokens will be routed to the beneficiary with the claimed token preference respected. +/// @custom:member beneficiary An address. The role the of the beneficary depends on whether or not projectId is specified, and whether or not an allocator is specified. If allocator is set, the beneficiary will be forwarded to the allocator for it to use. If allocator is not set but projectId is set, the beneficiary is the address to which the project's tokens will be sent that result from a payment to it. If neither allocator or projectId are set, the beneficiary is where the funds from the split will be sent. +/// @custom:member lockedUntil Specifies if the split should be unchangeable until the specified time, with the exception of extending the locked period. +/// @custom:member allocator If an allocator is specified, funds will be sent to the allocator contract along with all properties of this split. struct JBSplit { bool preferClaimed; bool preferAddToBalance; diff --git a/contracts/structs/JBSplitAllocationData.sol b/contracts/structs/JBSplitAllocationData.sol index 4c36cdbce..bbe4428c5 100644 --- a/contracts/structs/JBSplitAllocationData.sol +++ b/contracts/structs/JBSplitAllocationData.sol @@ -1,16 +1,14 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import './JBSplit.sol'; +import {JBSplit} from './JBSplit.sol'; -/** - @member token The token being sent to the split allocator. - @member amount The amount being sent to the split allocator, as a fixed point number. - @member decimals The number of decimals in the amount. - @member projectId The project to which the split belongs. - @member group The group to which the split belongs. - @member split The split that caused the allocation. -*/ +/// @custom:member token The token being sent to the split allocator. +/// @custom:member amount The amount being sent to the split allocator, as a fixed point number. +/// @custom:member decimals The number of decimals in the amount. +/// @custom:member projectId The project to which the split belongs. +/// @custom:member group The group to which the split belongs. +/// @custom:member split The split that caused the allocation. struct JBSplitAllocationData { address token; uint256 amount; diff --git a/contracts/structs/JBTokenAmount.sol b/contracts/structs/JBTokenAmount.sol index aad346678..99f953b09 100644 --- a/contracts/structs/JBTokenAmount.sol +++ b/contracts/structs/JBTokenAmount.sol @@ -1,12 +1,10 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -/* - @member token The token the payment was made in. - @member value The amount of tokens that was paid, as a fixed point number. - @member decimals The number of decimals included in the value fixed point number. - @member currency The expected currency of the value. -**/ +/// @custom:member token The token the payment was made in. +/// @custom:member value The amount of tokens that was paid, as a fixed point number. +/// @custom:member decimals The number of decimals included in the value fixed point number. +/// @custom:member currency The expected currency of the value. struct JBTokenAmount { address token; uint256 value; diff --git a/deploy/v3_1_1.js b/deploy/v3_1_1.js new file mode 100644 index 000000000..aa0d113dc --- /dev/null +++ b/deploy/v3_1_1.js @@ -0,0 +1,264 @@ +const { ethers } = require('hardhat'); + +/** + * Deploys the Juicebox V3.1.1 contract ecosystem. + * + * Example usage: + * + * npx hardhat deploy --network goerli --tags 311 + */ +module.exports = async ({ deployments, getChainId }) => { + console.log('Deploying v3.1.1 contracts...'); + + const { deploy } = deployments; + const [deployer] = await ethers.getSigners(); + + let ownerAddress; + let chainlinkV2UsdEthPriceFeed; + let chainId = await getChainId(); + let baseDeployArgs = { + from: deployer.address, + log: true, + skipIfAlreadyDeployed: true, + }; + + switch (chainId) { + // mainnet + case '1': + ownerAddress = '0xAF28bcB48C40dBC86f52D459A6562F658fc94B1e'; + chainlinkV2UsdEthPriceFeed = '0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419'; + break; + // Goerli + case '5': + ownerAddress = '0x46D623731E179FAF971CdA04fF8c499C95461b3c'; + chainlinkV2UsdEthPriceFeed = '0xD4a33860578De61DBAbDc8BFdb98FD742fA7028e'; + break; + // Sepolia + case '11155111': + ownerAddress = '0xAF28bcB48C40dBC86f52D459A6562F658fc94B1e'; + chainlinkV2UsdEthPriceFeed = '0x694AA1769357215DE4FAC081bf1f309aDC325306'; + break; + // hardhat / localhost + case '31337': + ownerAddress = deployer.address; + + protocolProjectStartsAtOrAfter = 0; + break; + } + + console.log({ ownerAddress }); + + // Deploy a JBOperatorStore contract. + const JBOperatorStore = await deploy('JBOperatorStore', { + ...baseDeployArgs, + args: [], + }); + + // Deploy a JBPrices contract. + const JBPrices = await deploy('JBPrices', { + ...baseDeployArgs, + args: [deployer.address], + }); + + // Deploy a JBProjects contract. + const JBProjects = await deploy('JBProjects', { + ...baseDeployArgs, + args: [JBOperatorStore.address], + }); + + // Get the future address of JBFundingCycleStore + const transactionCount = await deployer.getTransactionCount(); + + const FundingCycleStoreFutureAddress = ethers.utils.getContractAddress({ + from: deployer.address, + nonce: transactionCount + 1, + }); + + // Deploy a JBDirectory. + const JBDirectory = await deploy('JBDirectory', { + ...baseDeployArgs, + args: [ + JBOperatorStore.address, + JBProjects.address, + FundingCycleStoreFutureAddress, + deployer.address, + ], + }); + + // Deploy a JBFundingCycleStore. + const JBFundingCycleStore = await deploy('JBFundingCycleStore', { + ...baseDeployArgs, + contract: 'contracts/JBFundingCycleStore.sol:JBFundingCycleStore', + args: [JBDirectory.address], + }); + + // Deploy a JBTokenStore. + const JBTokenStore = await deploy('JBTokenStore', { + ...baseDeployArgs, + args: [ + JBOperatorStore.address, + JBProjects.address, + JBDirectory.address, + JBFundingCycleStore.address, + ], + }); + + // Deploy a JBSplitStore. + const JBSplitStore = await deploy('JBSplitsStore', { + ...baseDeployArgs, + contract: 'contracts/JBSplitsStore.sol:JBSplitsStore', + args: [JBOperatorStore.address, JBProjects.address, JBDirectory.address], + }); + + // Deploy a fund access constraints store + const JBFundAccessConstraintsStore = await deploy('JBFundAccessConstraintsStore', { + ...baseDeployArgs, + contract: 'contracts/JBFundAccessConstraintsStore.sol:JBFundAccessConstraintsStore', + args: [JBDirectory.address], + }); + + // Deploy a JBController contract. + const JBController = await deploy('JBController3_1', { + ...baseDeployArgs, + contract: 'contracts/JBController3_1.sol:JBController3_1', + args: [ + JBOperatorStore.address, + JBProjects.address, + JBDirectory.address, + JBFundingCycleStore.address, + JBTokenStore.address, + JBSplitStore.address, + JBFundAccessConstraintsStore.address, + ], + }); + + // Deploy a JBSingleTokenPaymentTerminalStore contract. + const JBSingleTokenPaymentTerminalStore = await deploy('JBSingleTokenPaymentTerminalStore3_1_1', { + ...baseDeployArgs, + contract: + 'contracts/JBSingleTokenPaymentTerminalStore3_1_1.sol:JBSingleTokenPaymentTerminalStore3_1_1', + args: [JBDirectory.address, JBFundingCycleStore.address, JBPrices.address], + }); + + // Deploy the currencies library. + const JBCurrencies = await deploy('JBCurrencies', { + ...baseDeployArgs, + args: [], + }); + + // Get references to contract that will have transactions triggered. + const jbDirectoryContract = new ethers.Contract(JBDirectory.address, JBDirectory.abi); + const jbPricesContract = new ethers.Contract(JBPrices.address, JBPrices.abi); + const jbControllerContract = new ethers.Contract(JBController.address, JBController.abi); + const jbProjectsContract = new ethers.Contract(JBProjects.address, JBProjects.abi); + const jbCurrenciesLibrary = new ethers.Contract(JBCurrencies.address, JBCurrencies.abi); + + // Get a reference to USD and ETH currency indexes. + const USD = await jbCurrenciesLibrary.connect(deployer).USD(); + const ETH = await jbCurrenciesLibrary.connect(deployer).ETH(); + + // Deploy a JBETHPaymentTerminal contract. + await deploy('JBETHPaymentTerminal3_1_1', { + ...baseDeployArgs, + contract: 'contracts/JBETHPaymentTerminal3_1_1.sol:JBETHPaymentTerminal3_1_1', + args: [ + ETH, + JBOperatorStore.address, + JBProjects.address, + JBDirectory.address, + JBSplitStore.address, + JBPrices.address, + JBSingleTokenPaymentTerminalStore.address, + ownerAddress, + ], + }); + + // Deploy a JBETHERC20ProjectPayerDeployer contract. + await deploy('JBETHERC20ProjectPayerDeployer', { + ...baseDeployArgs, + args: [JBDirectory.address], + }); + + // Deploy a JBETHERC20SplitsPayerDeployer contract. + await deploy('JBETHERC20SplitsPayerDeployer', { + ...baseDeployArgs, + contract: 'contracts/JBETHERC20SplitsPayerDeployer.sol:JBETHERC20SplitsPayerDeployer', + args: [JBSplitStore.address], + }); + + // Get a reference to an existing ETH/USD feed. + const usdEthFeed = await jbPricesContract.connect(deployer).feedFor(USD, ETH); + + // If needed, deploy an ETH/USD price feed and add it to the store. + if (chainlinkV2UsdEthPriceFeed && usdEthFeed == ethers.constants.AddressZero) { + // Deploy a JBChainlinkV3PriceFeed contract for ETH/USD. + const JBChainlinkV3UsdEthPriceFeed = await deploy('JBChainlinkV3PriceFeed', { + ...baseDeployArgs, + args: [chainlinkV2UsdEthPriceFeed], + }); + + //The base currency is ETH since the feed returns the USD price of 1 ETH. + await jbPricesContract + .connect(deployer) + .addFeedFor(USD, ETH, JBChainlinkV3UsdEthPriceFeed.address); + } + + // If needed, transfer the ownership of the JBPrices to to the multisig. + if ((await jbPricesContract.connect(deployer).owner()) != ownerAddress) { + let tx = await jbPricesContract.connect(deployer).transferOwnership(ownerAddress); + await tx.wait(); + } + + // If needed, transfer the ownership of the JBProjects to to the multisig. + if ((await jbProjectsContract.connect(deployer).owner()) != ownerAddress) { + let tx = await jbProjectsContract.connect(deployer).transferOwnership(ownerAddress); + await tx.wait(); + } + + let isAllowedToSetFirstController = await jbDirectoryContract + .connect(deployer) + .isAllowedToSetFirstController(JBController.address); + + // If needed, allow the controller to set projects' first controller, then transfer the ownership of the JBDirectory to the multisig. + if (!isAllowedToSetFirstController) { + let tx = await jbDirectoryContract + .connect(deployer) + .setIsAllowedToSetFirstController(JBController.address, true); + await tx.wait(); + } + + // If needed, transfer the ownership of the JBDirectory contract to the multisig. + if ((await jbDirectoryContract.connect(deployer).owner()) != ownerAddress) { + let tx = await jbDirectoryContract.connect(deployer).transferOwnership(ownerAddress); + await tx.wait(); + } + + // + // If you want, deploy funding cycle ballot contracts for projects to use. + // + + // // Deploy a JB1DayReconfigurationBufferBallot. + // await deploy('JB1DayReconfigurationBufferBallot', { + // ...baseDeployArgs, + // contract: 'contracts/JBReconfigurationBufferBallot.sol:JBReconfigurationBufferBallot', + // args: [86400], + // }); + + // // Deploy a JB3DayReconfigurationBufferBallot. + // await deploy('JB3DayReconfigurationBufferBallot', { + // ...baseDeployArgs, + // contract: 'contracts/JBReconfigurationBufferBallot.sol:JBReconfigurationBufferBallot', + // args: [259200], + // }); + + // // Deploy a JB7DayReconfigurationBufferBallot. + // await deploy('JB7DayReconfigurationBufferBallot', { + // ...baseDeployArgs, + // contract: 'contracts/JBReconfigurationBufferBallot.sol:JBReconfigurationBufferBallot', + // args: [604800], + // }); + + console.log('Done'); +}; + +module.exports.tags = ['311']; diff --git a/deploy/v3_migration_operator.js b/deploy/v3_migration_operator.js index 7b0095a50..22d29642e 100644 --- a/deploy/v3_migration_operator.js +++ b/deploy/v3_migration_operator.js @@ -43,10 +43,10 @@ module.exports = async ({ deployments, getChainId }) => { // // Deploy the JBMigrationOperator contract. const JBMigrationOperator = await deploy('JBMigrationOperator', { - ...baseDeployArgs, - args: [ - jbDirectory, - ], + ...baseDeployArgs, + args: [ + jbDirectory, + ], }); console.log('Done'); diff --git a/deployments/goerli/JBETHPaymentTerminal3_1_1.json b/deployments/goerli/JBETHPaymentTerminal3_1_1.json new file mode 100644 index 000000000..0f80171b9 --- /dev/null +++ b/deployments/goerli/JBETHPaymentTerminal3_1_1.json @@ -0,0 +1,2574 @@ +{ + "address": "0x82129d4109625F94582bDdF6101a8Cd1a27919f5", + "abi": [ + { + "inputs": [ + { + "internalType": "uint256", + "name": "_baseWeightCurrency", + "type": "uint256" + }, + { + "internalType": "contract IJBOperatorStore", + "name": "_operatorStore", + "type": "address" + }, + { + "internalType": "contract IJBProjects", + "name": "_projects", + "type": "address" + }, + { + "internalType": "contract IJBDirectory", + "name": "_directory", + "type": "address" + }, + { + "internalType": "contract IJBSplitsStore", + "name": "_splitsStore", + "type": "address" + }, + { + "internalType": "contract IJBPrices", + "name": "_prices", + "type": "address" + }, + { + "internalType": "address", + "name": "_store", + "type": "address" + }, + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "FEE_TOO_HIGH", + "type": "error" + }, + { + "inputs": [], + "name": "INADEQUATE_DISTRIBUTION_AMOUNT", + "type": "error" + }, + { + "inputs": [], + "name": "INADEQUATE_RECLAIM_AMOUNT", + "type": "error" + }, + { + "inputs": [], + "name": "INADEQUATE_TOKEN_COUNT", + "type": "error" + }, + { + "inputs": [], + "name": "NO_MSG_VALUE_ALLOWED", + "type": "error" + }, + { + "inputs": [], + "name": "PAY_TO_ZERO_ADDRESS", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "prod1", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "denominator", + "type": "uint256" + } + ], + "name": "PRBMath__MulDivOverflow", + "type": "error" + }, + { + "inputs": [], + "name": "PROJECT_TERMINAL_MISMATCH", + "type": "error" + }, + { + "inputs": [], + "name": "REDEEM_TO_ZERO_ADDRESS", + "type": "error" + }, + { + "inputs": [], + "name": "TERMINAL_TOKENS_INCOMPATIBLE", + "type": "error" + }, + { + "inputs": [], + "name": "UNAUTHORIZED", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "refundedFees", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "string", + "name": "memo", + "type": "string" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "metadata", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "AddToBalance", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract IJBPayDelegate3_1_1", + "name": "delegate", + "type": "address" + }, + { + "components": [ + { + "internalType": "address", + "name": "payer", + "type": "address" + }, + { + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "currentFundingCycleConfiguration", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "decimals", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "currency", + "type": "uint256" + } + ], + "internalType": "struct JBTokenAmount", + "name": "amount", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "decimals", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "currency", + "type": "uint256" + } + ], + "internalType": "struct JBTokenAmount", + "name": "forwardedAmount", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "projectTokenCount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "beneficiary", + "type": "address" + }, + { + "internalType": "bool", + "name": "preferClaimedTokens", + "type": "bool" + }, + { + "internalType": "string", + "name": "memo", + "type": "string" + }, + { + "internalType": "bytes", + "name": "dataSourceMetadata", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "payerMetadata", + "type": "bytes" + } + ], + "indexed": false, + "internalType": "struct JBDidPayData3_1_1", + "name": "data", + "type": "tuple" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "delegatedAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "DelegateDidPay", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract IJBPayDelegate", + "name": "delegate", + "type": "address" + }, + { + "components": [ + { + "internalType": "address", + "name": "payer", + "type": "address" + }, + { + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "currentFundingCycleConfiguration", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "decimals", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "currency", + "type": "uint256" + } + ], + "internalType": "struct JBTokenAmount", + "name": "amount", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "decimals", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "currency", + "type": "uint256" + } + ], + "internalType": "struct JBTokenAmount", + "name": "forwardedAmount", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "projectTokenCount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "beneficiary", + "type": "address" + }, + { + "internalType": "bool", + "name": "preferClaimedTokens", + "type": "bool" + }, + { + "internalType": "string", + "name": "memo", + "type": "string" + }, + { + "internalType": "bytes", + "name": "metadata", + "type": "bytes" + } + ], + "indexed": false, + "internalType": "struct JBDidPayData", + "name": "data", + "type": "tuple" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "delegatedAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "DelegateDidPay", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract IJBRedemptionDelegate3_1_1", + "name": "delegate", + "type": "address" + }, + { + "components": [ + { + "internalType": "address", + "name": "holder", + "type": "address" + }, + { + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "currentFundingCycleConfiguration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "projectTokenCount", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "decimals", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "currency", + "type": "uint256" + } + ], + "internalType": "struct JBTokenAmount", + "name": "reclaimedAmount", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "decimals", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "currency", + "type": "uint256" + } + ], + "internalType": "struct JBTokenAmount", + "name": "forwardedAmount", + "type": "tuple" + }, + { + "internalType": "address payable", + "name": "beneficiary", + "type": "address" + }, + { + "internalType": "string", + "name": "memo", + "type": "string" + }, + { + "internalType": "bytes", + "name": "dataSourceMetadata", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "redeemerMetadata", + "type": "bytes" + } + ], + "indexed": false, + "internalType": "struct JBDidRedeemData3_1_1", + "name": "data", + "type": "tuple" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "delegatedAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "fee", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "DelegateDidRedeem", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract IJBRedemptionDelegate", + "name": "delegate", + "type": "address" + }, + { + "components": [ + { + "internalType": "address", + "name": "holder", + "type": "address" + }, + { + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "currentFundingCycleConfiguration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "projectTokenCount", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "decimals", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "currency", + "type": "uint256" + } + ], + "internalType": "struct JBTokenAmount", + "name": "reclaimedAmount", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "decimals", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "currency", + "type": "uint256" + } + ], + "internalType": "struct JBTokenAmount", + "name": "forwardedAmount", + "type": "tuple" + }, + { + "internalType": "address payable", + "name": "beneficiary", + "type": "address" + }, + { + "internalType": "string", + "name": "memo", + "type": "string" + }, + { + "internalType": "bytes", + "name": "metadata", + "type": "bytes" + } + ], + "indexed": false, + "internalType": "struct JBDidRedeemData", + "name": "data", + "type": "tuple" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "delegatedAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "DelegateDidRedeem", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "fundingCycleConfiguration", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "fundingCycleNumber", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "beneficiary", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "distributedAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "fee", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "beneficiaryDistributionAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "metadata", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "DistributePayouts", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "domain", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "group", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "bool", + "name": "preferClaimed", + "type": "bool" + }, + { + "internalType": "bool", + "name": "preferAddToBalance", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "percent", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "internalType": "address payable", + "name": "beneficiary", + "type": "address" + }, + { + "internalType": "uint256", + "name": "lockedUntil", + "type": "uint256" + }, + { + "internalType": "contract IJBSplitAllocator", + "name": "allocator", + "type": "address" + } + ], + "indexed": false, + "internalType": "struct JBSplit", + "name": "split", + "type": "tuple" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "netAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "DistributeToPayoutSplit", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "feeProjectId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "reason", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "FeeReverted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "fee", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "feeDiscount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "beneficiary", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "HoldFee", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "contract IJBPaymentTerminal", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "Migrate", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "fundingCycleConfiguration", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "fundingCycleNumber", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "payer", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "beneficiary", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "beneficiaryTokenCount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "string", + "name": "memo", + "type": "string" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "metadata", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "Pay", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "bool", + "name": "preferClaimed", + "type": "bool" + }, + { + "internalType": "bool", + "name": "preferAddToBalance", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "percent", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "internalType": "address payable", + "name": "beneficiary", + "type": "address" + }, + { + "internalType": "uint256", + "name": "lockedUntil", + "type": "uint256" + }, + { + "internalType": "contract IJBSplitAllocator", + "name": "allocator", + "type": "address" + } + ], + "indexed": false, + "internalType": "struct JBSplit", + "name": "split", + "type": "tuple" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "reason", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "PayoutReverted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "bool", + "name": "wasHeld", + "type": "bool" + }, + { + "indexed": false, + "internalType": "address", + "name": "beneficiary", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "ProcessFee", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "fundingCycleConfiguration", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "fundingCycleNumber", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "holder", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "beneficiary", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "tokenCount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "reclaimedAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "string", + "name": "memo", + "type": "string" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "metadata", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "RedeemTokens", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "refundedFees", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "leftoverAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "RefundHeldFees", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "fee", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "SetFee", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "feeGauge", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "SetFeeGauge", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "addrs", + "type": "address" + }, + { + "indexed": true, + "internalType": "bool", + "name": "flag", + "type": "bool" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "SetFeelessAddress", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "fundingCycleConfiguration", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "fundingCycleNumber", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "beneficiary", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "distributedAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "netDistributedamount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "string", + "name": "memo", + "type": "string" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "metadata", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "UseAllowance", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + } + ], + "name": "acceptsToken", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_token", + "type": "address" + }, + { + "internalType": "string", + "name": "_memo", + "type": "string" + }, + { + "internalType": "bytes", + "name": "_metadata", + "type": "bytes" + } + ], + "name": "addToBalanceOf", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_token", + "type": "address" + }, + { + "internalType": "bool", + "name": "_shouldRefundHeldFees", + "type": "bool" + }, + { + "internalType": "string", + "name": "_memo", + "type": "string" + }, + { + "internalType": "bytes", + "name": "_metadata", + "type": "bytes" + } + ], + "name": "addToBalanceOf", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "baseWeightCurrency", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "currency", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_token", + "type": "address" + } + ], + "name": "currencyForToken", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + } + ], + "name": "currentEthOverflowOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_token", + "type": "address" + } + ], + "name": "decimalsForToken", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "directory", + "outputs": [ + { + "internalType": "contract IJBDirectory", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_currency", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_minReturnedTokens", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "_metadata", + "type": "bytes" + } + ], + "name": "distributePayoutsOf", + "outputs": [ + { + "internalType": "uint256", + "name": "netLeftoverDistributionAmount", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "fee", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "feeGauge", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + } + ], + "name": "heldFeesOf", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint32", + "name": "fee", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "feeDiscount", + "type": "uint32" + }, + { + "internalType": "address", + "name": "beneficiary", + "type": "address" + } + ], + "internalType": "struct JBFee[]", + "name": "", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "isFeelessAddress", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + }, + { + "internalType": "contract IJBPaymentTerminal", + "name": "_to", + "type": "address" + } + ], + "name": "migrate", + "outputs": [ + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "operatorStore", + "outputs": [ + { + "internalType": "contract IJBOperatorStore", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_token", + "type": "address" + }, + { + "internalType": "address", + "name": "_beneficiary", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_minReturnedTokens", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "_preferClaimedTokens", + "type": "bool" + }, + { + "internalType": "string", + "name": "_memo", + "type": "string" + }, + { + "internalType": "bytes", + "name": "_metadata", + "type": "bytes" + } + ], + "name": "pay", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "payoutSplitsGroup", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "prices", + "outputs": [ + { + "internalType": "contract IJBPrices", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + } + ], + "name": "processFees", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "projects", + "outputs": [ + { + "internalType": "contract IJBProjects", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_holder", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_tokenCount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_minReturnedTokens", + "type": "uint256" + }, + { + "internalType": "address payable", + "name": "_beneficiary", + "type": "address" + }, + { + "internalType": "string", + "name": "_memo", + "type": "string" + }, + { + "internalType": "bytes", + "name": "_metadata", + "type": "bytes" + } + ], + "name": "redeemTokensOf", + "outputs": [ + { + "internalType": "uint256", + "name": "reclaimAmount", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_fee", + "type": "uint256" + } + ], + "name": "setFee", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_feeGauge", + "type": "address" + } + ], + "name": "setFeeGauge", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_address", + "type": "address" + }, + { + "internalType": "bool", + "name": "_flag", + "type": "bool" + } + ], + "name": "setFeelessAddress", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "splitsStore", + "outputs": [ + { + "internalType": "contract IJBSplitsStore", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "store", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "token", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_currency", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_minReturnedTokens", + "type": "uint256" + }, + { + "internalType": "address payable", + "name": "_beneficiary", + "type": "address" + }, + { + "internalType": "string", + "name": "_memo", + "type": "string" + }, + { + "internalType": "bytes", + "name": "_metadata", + "type": "bytes" + } + ], + "name": "useAllowanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "netDistributedAmount", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "transactionHash": "0xd7d9637e04f2a4956b0a1d7eac020739ed3e839bd2cde2bae22be3a38bf11abb", + "receipt": { + "to": null, + "from": "0xc64533F8d8dEbC301cb4791e6ED941Cb38473DE6", + "contractAddress": "0x82129d4109625F94582bDdF6101a8Cd1a27919f5", + "transactionIndex": 64, + "gasUsed": "5083250", + "logsBloom": "0x00000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000081000100000000000000000000000000000008020000000000000000000800000000000000000000000000200000400000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000008000000000000000040000000000000", + "blockHash": "0x86e243ccf5cf1456132ce2fb88592b7e707d29ddf0be0f3627e16fe5075e536e", + "transactionHash": "0xd7d9637e04f2a4956b0a1d7eac020739ed3e839bd2cde2bae22be3a38bf11abb", + "logs": [ + { + "transactionIndex": 64, + "blockNumber": 9266865, + "transactionHash": "0xd7d9637e04f2a4956b0a1d7eac020739ed3e839bd2cde2bae22be3a38bf11abb", + "address": "0x82129d4109625F94582bDdF6101a8Cd1a27919f5", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000c64533f8d8debc301cb4791e6ed941cb38473de6" + ], + "data": "0x", + "logIndex": 173, + "blockHash": "0x86e243ccf5cf1456132ce2fb88592b7e707d29ddf0be0f3627e16fe5075e536e" + }, + { + "transactionIndex": 64, + "blockNumber": 9266865, + "transactionHash": "0xd7d9637e04f2a4956b0a1d7eac020739ed3e839bd2cde2bae22be3a38bf11abb", + "address": "0x82129d4109625F94582bDdF6101a8Cd1a27919f5", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x000000000000000000000000c64533f8d8debc301cb4791e6ed941cb38473de6", + "0x00000000000000000000000046d623731e179faf971cda04ff8c499c95461b3c" + ], + "data": "0x", + "logIndex": 174, + "blockHash": "0x86e243ccf5cf1456132ce2fb88592b7e707d29ddf0be0f3627e16fe5075e536e" + } + ], + "blockNumber": 9266865, + "cumulativeGasUsed": "18519559", + "status": 1, + "byzantium": true + }, + "args": [ + "1", + "0x99dB6b517683237dE9C494bbd17861f3608F3585", + "0x21263a042aFE4bAE34F08Bb318056C181bD96D3b", + "0x8E05bcD2812E1449f0EC3aE24E2C395F533d9A99", + "0xce2Ce2F37fE5B2C2Dd047908B2F61c9c3f707272", + "0x9f0eC91d28fFc54874e9fF11A316Ba2537aCD72C", + "0x5d8eC74256DB2326843714B852df3acE45144492", + "0x46D623731E179FAF971CdA04fF8c499C95461b3c" + ], + "numDeployments": 2, + "solcInputHash": "11cb1f66a0f8213d7bf83deb0ae9d2f7", + "metadata": "{\"compiler\":{\"version\":\"0.8.16+commit.07a7930e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_baseWeightCurrency\",\"type\":\"uint256\"},{\"internalType\":\"contract IJBOperatorStore\",\"name\":\"_operatorStore\",\"type\":\"address\"},{\"internalType\":\"contract IJBProjects\",\"name\":\"_projects\",\"type\":\"address\"},{\"internalType\":\"contract IJBDirectory\",\"name\":\"_directory\",\"type\":\"address\"},{\"internalType\":\"contract IJBSplitsStore\",\"name\":\"_splitsStore\",\"type\":\"address\"},{\"internalType\":\"contract IJBPrices\",\"name\":\"_prices\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_store\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"FEE_TOO_HIGH\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"INADEQUATE_DISTRIBUTION_AMOUNT\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"INADEQUATE_RECLAIM_AMOUNT\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"INADEQUATE_TOKEN_COUNT\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NO_MSG_VALUE_ALLOWED\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PAY_TO_ZERO_ADDRESS\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"prod1\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"denominator\",\"type\":\"uint256\"}],\"name\":\"PRBMath__MulDivOverflow\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PROJECT_TERMINAL_MISMATCH\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"REDEEM_TO_ZERO_ADDRESS\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TERMINAL_TOKENS_INCOMPATIBLE\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UNAUTHORIZED\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"refundedFees\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"memo\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"metadata\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"AddToBalance\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"contract IJBPayDelegate3_1_1\",\"name\":\"delegate\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"payer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"currentFundingCycleConfiguration\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"decimals\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"currency\",\"type\":\"uint256\"}],\"internalType\":\"struct JBTokenAmount\",\"name\":\"amount\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"decimals\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"currency\",\"type\":\"uint256\"}],\"internalType\":\"struct JBTokenAmount\",\"name\":\"forwardedAmount\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"projectTokenCount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"beneficiary\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"preferClaimedTokens\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"memo\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"dataSourceMetadata\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"payerMetadata\",\"type\":\"bytes\"}],\"indexed\":false,\"internalType\":\"struct JBDidPayData3_1_1\",\"name\":\"data\",\"type\":\"tuple\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"delegatedAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"DelegateDidPay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"contract IJBPayDelegate\",\"name\":\"delegate\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"payer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"currentFundingCycleConfiguration\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"decimals\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"currency\",\"type\":\"uint256\"}],\"internalType\":\"struct JBTokenAmount\",\"name\":\"amount\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"decimals\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"currency\",\"type\":\"uint256\"}],\"internalType\":\"struct JBTokenAmount\",\"name\":\"forwardedAmount\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"projectTokenCount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"beneficiary\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"preferClaimedTokens\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"memo\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"metadata\",\"type\":\"bytes\"}],\"indexed\":false,\"internalType\":\"struct JBDidPayData\",\"name\":\"data\",\"type\":\"tuple\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"delegatedAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"DelegateDidPay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"contract IJBRedemptionDelegate3_1_1\",\"name\":\"delegate\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"holder\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"currentFundingCycleConfiguration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"projectTokenCount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"decimals\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"currency\",\"type\":\"uint256\"}],\"internalType\":\"struct JBTokenAmount\",\"name\":\"reclaimedAmount\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"decimals\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"currency\",\"type\":\"uint256\"}],\"internalType\":\"struct JBTokenAmount\",\"name\":\"forwardedAmount\",\"type\":\"tuple\"},{\"internalType\":\"address payable\",\"name\":\"beneficiary\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"memo\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"dataSourceMetadata\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"redeemerMetadata\",\"type\":\"bytes\"}],\"indexed\":false,\"internalType\":\"struct JBDidRedeemData3_1_1\",\"name\":\"data\",\"type\":\"tuple\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"delegatedAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fee\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"DelegateDidRedeem\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"contract IJBRedemptionDelegate\",\"name\":\"delegate\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"holder\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"currentFundingCycleConfiguration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"projectTokenCount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"decimals\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"currency\",\"type\":\"uint256\"}],\"internalType\":\"struct JBTokenAmount\",\"name\":\"reclaimedAmount\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"decimals\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"currency\",\"type\":\"uint256\"}],\"internalType\":\"struct JBTokenAmount\",\"name\":\"forwardedAmount\",\"type\":\"tuple\"},{\"internalType\":\"address payable\",\"name\":\"beneficiary\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"memo\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"metadata\",\"type\":\"bytes\"}],\"indexed\":false,\"internalType\":\"struct JBDidRedeemData\",\"name\":\"data\",\"type\":\"tuple\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"delegatedAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"DelegateDidRedeem\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"fundingCycleConfiguration\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"fundingCycleNumber\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"beneficiary\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"distributedAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fee\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"beneficiaryDistributionAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"metadata\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"DistributePayouts\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"domain\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"group\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"preferClaimed\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"preferAddToBalance\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"percent\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"internalType\":\"address payable\",\"name\":\"beneficiary\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"lockedUntil\",\"type\":\"uint256\"},{\"internalType\":\"contract IJBSplitAllocator\",\"name\":\"allocator\",\"type\":\"address\"}],\"indexed\":false,\"internalType\":\"struct JBSplit\",\"name\":\"split\",\"type\":\"tuple\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"netAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"DistributeToPayoutSplit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"feeProjectId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"reason\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"FeeReverted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"fee\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"feeDiscount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"beneficiary\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"HoldFee\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"contract IJBPaymentTerminal\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"Migrate\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"fundingCycleConfiguration\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"fundingCycleNumber\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"payer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"beneficiary\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"beneficiaryTokenCount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"memo\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"metadata\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"Pay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"preferClaimed\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"preferAddToBalance\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"percent\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"internalType\":\"address payable\",\"name\":\"beneficiary\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"lockedUntil\",\"type\":\"uint256\"},{\"internalType\":\"contract IJBSplitAllocator\",\"name\":\"allocator\",\"type\":\"address\"}],\"indexed\":false,\"internalType\":\"struct JBSplit\",\"name\":\"split\",\"type\":\"tuple\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"reason\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"PayoutReverted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bool\",\"name\":\"wasHeld\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"beneficiary\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"ProcessFee\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"fundingCycleConfiguration\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"fundingCycleNumber\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"holder\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"beneficiary\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokenCount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"reclaimedAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"memo\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"metadata\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"RedeemTokens\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"refundedFees\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"leftoverAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"RefundHeldFees\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fee\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"SetFee\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"feeGauge\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"SetFeeGauge\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"addrs\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bool\",\"name\":\"flag\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"SetFeelessAddress\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"fundingCycleConfiguration\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"fundingCycleNumber\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"beneficiary\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"distributedAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"netDistributedamount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"memo\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"metadata\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"UseAllowance\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"}],\"name\":\"acceptsToken\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"_memo\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"_metadata\",\"type\":\"bytes\"}],\"name\":\"addToBalanceOf\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"_shouldRefundHeldFees\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"_memo\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"_metadata\",\"type\":\"bytes\"}],\"name\":\"addToBalanceOf\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"baseWeightCurrency\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"currency\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"}],\"name\":\"currencyForToken\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"}],\"name\":\"currentEthOverflowOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"}],\"name\":\"decimalsForToken\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"directory\",\"outputs\":[{\"internalType\":\"contract IJBDirectory\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_currency\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_minReturnedTokens\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_metadata\",\"type\":\"bytes\"}],\"name\":\"distributePayoutsOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"netLeftoverDistributionAmount\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"feeGauge\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"}],\"name\":\"heldFeesOf\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"fee\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feeDiscount\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"beneficiary\",\"type\":\"address\"}],\"internalType\":\"struct JBFee[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"isFeelessAddress\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"},{\"internalType\":\"contract IJBPaymentTerminal\",\"name\":\"_to\",\"type\":\"address\"}],\"name\":\"migrate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"operatorStore\",\"outputs\":[{\"internalType\":\"contract IJBOperatorStore\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_beneficiary\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_minReturnedTokens\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"_preferClaimedTokens\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"_memo\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"_metadata\",\"type\":\"bytes\"}],\"name\":\"pay\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"payoutSplitsGroup\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"prices\",\"outputs\":[{\"internalType\":\"contract IJBPrices\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"}],\"name\":\"processFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"projects\",\"outputs\":[{\"internalType\":\"contract IJBProjects\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_holder\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_tokenCount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_minReturnedTokens\",\"type\":\"uint256\"},{\"internalType\":\"address payable\",\"name\":\"_beneficiary\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"_memo\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"_metadata\",\"type\":\"bytes\"}],\"name\":\"redeemTokensOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"reclaimAmount\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_fee\",\"type\":\"uint256\"}],\"name\":\"setFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_feeGauge\",\"type\":\"address\"}],\"name\":\"setFeeGauge\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"_flag\",\"type\":\"bool\"}],\"name\":\"setFeelessAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"splitsStore\",\"outputs\":[{\"internalType\":\"contract IJBSplitsStore\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"store\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"_interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"token\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_currency\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_minReturnedTokens\",\"type\":\"uint256\"},{\"internalType\":\"address payable\",\"name\":\"_beneficiary\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"_memo\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"_metadata\",\"type\":\"bytes\"}],\"name\":\"useAllowanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"netDistributedAmount\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"acceptsToken(address,uint256)\":{\"params\":{\"_projectId\":\"The project ID to check for token acceptance.\",\"_token\":\"The token to check if this terminal accepts or not.\"},\"returns\":{\"_0\":\"The flag.\"}},\"addToBalanceOf(uint256,uint256,address,bool,string,bytes)\":{\"params\":{\"_amount\":\"The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\",\"_memo\":\"A memo to pass along to the emitted event.\",\"_metadata\":\"Extra data to pass along to the emitted event.\",\"_projectId\":\"The ID of the project to which the funds received belong.\",\"_shouldRefundHeldFees\":\"A flag indicating if held fees should be refunded based on the amount being added.\",\"_token\":\"The token being paid. This terminal ignores this property since it only manages one currency.\"}},\"addToBalanceOf(uint256,uint256,address,string,bytes)\":{\"params\":{\"_amount\":\"The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\",\"_memo\":\"A memo to pass along to the emitted event.\",\"_metadata\":\"Extra data to pass along to the emitted event.\",\"_projectId\":\"The ID of the project to which the funds received belong.\",\"_token\":\"The token being paid. This terminal ignores this property since it only manages one currency.\"}},\"constructor\":{\"params\":{\"_baseWeightCurrency\":\"The currency to base token issuance on.\",\"_directory\":\"A contract storing directories of terminals and controllers for each project.\",\"_operatorStore\":\"A contract storing operator assignments.\",\"_owner\":\"The address that will own this contract.\",\"_prices\":\"A contract that exposes price feeds.\",\"_projects\":\"A contract which mints ERC-721's that represent project ownership and transfers.\",\"_splitsStore\":\"A contract that stores splits for each project.\",\"_store\":\"A contract that stores the terminal's data.\"}},\"currencyForToken(address)\":{\"params\":{\"_token\":\"The token to check for the currency of.\"},\"returns\":{\"_0\":\"The currency index.\"}},\"currentEthOverflowOf(uint256)\":{\"details\":\"The current overflow is represented as a fixed point number with 18 decimals.\",\"params\":{\"_projectId\":\"The ID of the project to get overflow for.\"},\"returns\":{\"_0\":\"The current amount of ETH overflow that project has in this terminal, as a fixed point number with 18 decimals.\"}},\"decimalsForToken(address)\":{\"params\":{\"_token\":\"The token to check for the decimals of.\"},\"returns\":{\"_0\":\"The number of decimals for the token.\"}},\"distributePayoutsOf(uint256,uint256,uint256,address,uint256,bytes)\":{\"details\":\"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.\",\"params\":{\"_amount\":\"The amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal.\",\"_currency\":\"The expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency.\",\"_metadata\":\"Bytes to send along to the emitted event, if provided.\",\"_minReturnedTokens\":\"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.\",\"_projectId\":\"The ID of the project having its payouts distributed.\",\"_token\":\"The token being distributed. This terminal ignores this property since it only manages one token.\"},\"returns\":{\"netLeftoverDistributionAmount\":\"The amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal.\"}},\"heldFeesOf(uint256)\":{\"params\":{\"_projectId\":\"The ID of the project for which fees are being held.\"},\"returns\":{\"_0\":\"An array of fees that are being held.\"}},\"migrate(uint256,address)\":{\"details\":\"Only a project's owner or a designated operator can migrate it.\",\"params\":{\"_projectId\":\"The ID of the project being migrated.\",\"_to\":\"The terminal contract that will gain the project's funds.\"},\"returns\":{\"balance\":\"The amount of funds that were migrated, as a fixed point number with the same amount of decimals as this terminal.\"}},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"pay(uint256,uint256,address,address,uint256,bool,string,bytes)\":{\"params\":{\"_amount\":\"The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place.\",\"_beneficiary\":\"The address to mint tokens for and pass along to the funding cycle's data source and delegate.\",\"_memo\":\"A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\",\"_metadata\":\"Bytes to send along to the data source, delegate, and emitted event, if provided.\",\"_minReturnedTokens\":\"The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal.\",\"_preferClaimedTokens\":\"A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\",\"_projectId\":\"The ID of the project being paid.\",\"_token\":\"The token being paid. This terminal ignores this property since it only manages one token.\"},\"returns\":{\"_0\":\"The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals.\"}},\"processFees(uint256)\":{\"details\":\"Only a project owner, an operator, or the contract's owner can process held fees.\",\"params\":{\"_projectId\":\"The ID of the project whos held fees should be processed.\"}},\"redeemTokensOf(address,uint256,uint256,address,uint256,address,string,bytes)\":{\"details\":\"Only a token holder or a designated operator can redeem its tokens.\",\"params\":{\"_beneficiary\":\"The address to send the terminal tokens to.\",\"_holder\":\"The account to redeem tokens for.\",\"_memo\":\"A memo to pass along to the emitted event.\",\"_metadata\":\"Bytes to send along to the data source, delegate, and emitted event, if provided.\",\"_minReturnedTokens\":\"The minimum amount of terminal tokens expected in return, as a fixed point number with the same amount of decimals as the terminal.\",\"_projectId\":\"The ID of the project to which the tokens being redeemed belong.\",\"_token\":\"The token being reclaimed. This terminal ignores this property since it only manages one token.\",\"_tokenCount\":\"The number of project tokens to redeem, as a fixed point number with 18 decimals.\"},\"returns\":{\"reclaimAmount\":\"The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals.\"}},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"setFee(uint256)\":{\"details\":\"Only the owner of this contract can change the fee.\",\"params\":{\"_fee\":\"The new fee, out of MAX_FEE.\"}},\"setFeeGauge(address)\":{\"details\":\"Only the owner of this contract can change the fee gauge.\",\"params\":{\"_feeGauge\":\"The new fee gauge.\"}},\"setFeelessAddress(address,bool)\":{\"details\":\"Only the owner of this contract can set addresses as feeless.\",\"params\":{\"_address\":\"The address that can be paid towards while still bypassing fees.\",\"_flag\":\"A flag indicating whether the terminal should be feeless or not.\"}},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\",\"params\":{\"_interfaceId\":\"The ID of the interface to check for adherance to.\"},\"returns\":{\"_0\":\"A flag indicating if the provided interface ID is supported.\"}},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"},\"useAllowanceOf(uint256,uint256,uint256,address,uint256,address,string,bytes)\":{\"details\":\"Only a project's owner or a designated operator can use its allowance.Incurs the protocol fee.\",\"params\":{\"_amount\":\"The amount of terminal tokens to use from this project's current allowance, as a fixed point number with the same amount of decimals as this terminal.\",\"_beneficiary\":\"The address to send the funds to.\",\"_currency\":\"The expected currency of the amount being distributed. Must match the project's current funding cycle's overflow allowance currency.\",\"_memo\":\"A memo to pass along to the emitted event.\",\"_metadata\":\"Bytes to send along to the emitted event, if provided.\",\"_minReturnedTokens\":\"The minimum number of tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with 18 decimals.\",\"_projectId\":\"The ID of the project to use the allowance of.\",\"_token\":\"The token being distributed. This terminal ignores this property since it only manages one token.\"},\"returns\":{\"netDistributedAmount\":\"The amount of tokens that was distributed to the beneficiary, as a fixed point number with the same amount of decimals as the terminal.\"}}},\"version\":1},\"userdoc\":{\"errors\":{\"PRBMath__MulDivOverflow(uint256,uint256)\":[{\"notice\":\"Emitted when the result overflows uint256.\"}]},\"kind\":\"user\",\"methods\":{\"acceptsToken(address,uint256)\":{\"notice\":\"A flag indicating if this terminal accepts the specified token.\"},\"addToBalanceOf(uint256,uint256,address,bool,string,bytes)\":{\"notice\":\"Receives funds belonging to the specified project.\"},\"addToBalanceOf(uint256,uint256,address,string,bytes)\":{\"notice\":\"Receives funds belonging to the specified project.\"},\"baseWeightCurrency()\":{\"notice\":\"The currency to base token issuance on.\"},\"currency()\":{\"notice\":\"The currency to use when resolving price feeds for this terminal.\"},\"currencyForToken(address)\":{\"notice\":\"The currency that should be used for the specified token.\"},\"currentEthOverflowOf(uint256)\":{\"notice\":\"Gets the current overflowed amount in this terminal for a specified project, in terms of ETH.\"},\"decimals()\":{\"notice\":\"The number of decimals the token fixed point amounts are expected to have.\"},\"decimalsForToken(address)\":{\"notice\":\"The decimals that should be used in fixed number accounting for the specified token.\"},\"directory()\":{\"notice\":\"The directory of terminals and controllers for projects.\"},\"distributePayoutsOf(uint256,uint256,uint256,address,uint256,bytes)\":{\"notice\":\"Distributes payouts for a project with the distribution limit of its current funding cycle.\"},\"fee()\":{\"notice\":\"The platform fee percent.\"},\"feeGauge()\":{\"notice\":\"The data source that returns a discount to apply to a project's fee.\"},\"heldFeesOf(uint256)\":{\"notice\":\"The fees that are currently being held to be processed later for each project.\"},\"isFeelessAddress(address)\":{\"notice\":\"Addresses that can be paid towards from this terminal without incurring a fee.\"},\"migrate(uint256,address)\":{\"notice\":\"Allows a project owner to migrate its funds and operations to a new terminal that accepts the same token type.\"},\"operatorStore()\":{\"notice\":\"A contract storing operator assignments.\"},\"pay(uint256,uint256,address,address,uint256,bool,string,bytes)\":{\"notice\":\"Contribute tokens to a project.\"},\"payoutSplitsGroup()\":{\"notice\":\"The group that payout splits coming from this terminal are identified by.\"},\"prices()\":{\"notice\":\"The contract that exposes price feeds.\"},\"processFees(uint256)\":{\"notice\":\"Process any fees that are being held for the project.\"},\"projects()\":{\"notice\":\"Mints ERC-721's that represent project ownership and transfers.\"},\"redeemTokensOf(address,uint256,uint256,address,uint256,address,string,bytes)\":{\"notice\":\"Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source.\"},\"setFee(uint256)\":{\"notice\":\"Allows the fee to be updated.\"},\"setFeeGauge(address)\":{\"notice\":\"Allows the fee gauge to be updated.\"},\"setFeelessAddress(address,bool)\":{\"notice\":\"Sets whether projects operating on this terminal can pay towards the specified address without incurring a fee.\"},\"splitsStore()\":{\"notice\":\"The contract that stores splits for each project.\"},\"store()\":{\"notice\":\"The contract that stores and manages the terminal's data.\"},\"supportsInterface(bytes4)\":{\"notice\":\"Indicates if this contract adheres to the specified interface.\"},\"token()\":{\"notice\":\"The token that this terminal accepts.\"},\"useAllowanceOf(uint256,uint256,uint256,address,uint256,address,string,bytes)\":{\"notice\":\"Allows a project to send funds from its overflow up to the preconfigured allowance.\"}},\"notice\":\"Manages all inflows and outflows of ETH funds into the protocol ecosystem.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/JBETHPaymentTerminal3_1_1.sol\":\"JBETHPaymentTerminal3_1_1\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n _;\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0x24e0364e503a9bbde94c715d26573a76f14cd2a202d45f96f52134ab806b67b9\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC721/IERC721.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../../utils/introspection/IERC165.sol\\\";\\n\\n/**\\n * @dev Required interface of an ERC721 compliant contract.\\n */\\ninterface IERC721 is IERC165 {\\n /**\\n * @dev Emitted when `tokenId` token is transferred from `from` to `to`.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);\\n\\n /**\\n * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.\\n */\\n event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);\\n\\n /**\\n * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.\\n */\\n event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\\n\\n /**\\n * @dev Returns the number of tokens in ``owner``'s account.\\n */\\n function balanceOf(address owner) external view returns (uint256 balance);\\n\\n /**\\n * @dev Returns the owner of the `tokenId` token.\\n *\\n * Requirements:\\n *\\n * - `tokenId` must exist.\\n */\\n function ownerOf(uint256 tokenId) external view returns (address owner);\\n\\n /**\\n * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\\n * are aware of the ERC721 protocol to prevent tokens from being forever locked.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `tokenId` token must exist and be owned by `from`.\\n * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.\\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\\n *\\n * Emits a {Transfer} event.\\n */\\n function safeTransferFrom(\\n address from,\\n address to,\\n uint256 tokenId\\n ) external;\\n\\n /**\\n * @dev Transfers `tokenId` token from `from` to `to`.\\n *\\n * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `tokenId` token must be owned by `from`.\\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 tokenId\\n ) external;\\n\\n /**\\n * @dev Gives permission to `to` to transfer `tokenId` token to another account.\\n * The approval is cleared when the token is transferred.\\n *\\n * Only a single account can be approved at a time, so approving the zero address clears previous approvals.\\n *\\n * Requirements:\\n *\\n * - The caller must own the token or be an approved operator.\\n * - `tokenId` must exist.\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address to, uint256 tokenId) external;\\n\\n /**\\n * @dev Returns the account approved for `tokenId` token.\\n *\\n * Requirements:\\n *\\n * - `tokenId` must exist.\\n */\\n function getApproved(uint256 tokenId) external view returns (address operator);\\n\\n /**\\n * @dev Approve or remove `operator` as an operator for the caller.\\n * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.\\n *\\n * Requirements:\\n *\\n * - The `operator` cannot be the caller.\\n *\\n * Emits an {ApprovalForAll} event.\\n */\\n function setApprovalForAll(address operator, bool _approved) external;\\n\\n /**\\n * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.\\n *\\n * See {setApprovalForAll}\\n */\\n function isApprovedForAll(address owner, address operator) external view returns (bool);\\n\\n /**\\n * @dev Safely transfers `tokenId` token from `from` to `to`.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `tokenId` token must exist and be owned by `from`.\\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\\n *\\n * Emits a {Transfer} event.\\n */\\n function safeTransferFrom(\\n address from,\\n address to,\\n uint256 tokenId,\\n bytes calldata data\\n ) external;\\n}\\n\",\"keccak256\":\"0x516a22876c1fab47f49b1bc22b4614491cd05338af8bd2e7b382da090a079990\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x3777e696b62134e6177440dbe6e6601c0c156a443f57167194b67e75527439de\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/ERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC165.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC165} interface.\\n *\\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\\n * for the additional interface id that will be supported. For example:\\n *\\n * ```solidity\\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\\n * }\\n * ```\\n *\\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\\n */\\nabstract contract ERC165 is IERC165 {\\n /**\\n * @dev See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n return interfaceId == type(IERC165).interfaceId;\\n }\\n}\\n\",\"keccak256\":\"0xd10975de010d89fd1c78dc5e8a9a7e7f496198085c151648f20cba166b32582b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/ERC165Checker.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165Checker.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC165.sol\\\";\\n\\n/**\\n * @dev Library used to query support of an interface declared via {IERC165}.\\n *\\n * Note that these functions return the actual result of the query: they do not\\n * `revert` if an interface is not supported. It is up to the caller to decide\\n * what to do in these cases.\\n */\\nlibrary ERC165Checker {\\n // As per the EIP-165 spec, no interface should ever match 0xffffffff\\n bytes4 private constant _INTERFACE_ID_INVALID = 0xffffffff;\\n\\n /**\\n * @dev Returns true if `account` supports the {IERC165} interface,\\n */\\n function supportsERC165(address account) internal view returns (bool) {\\n // Any contract that implements ERC165 must explicitly indicate support of\\n // InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid\\n return\\n _supportsERC165Interface(account, type(IERC165).interfaceId) &&\\n !_supportsERC165Interface(account, _INTERFACE_ID_INVALID);\\n }\\n\\n /**\\n * @dev Returns true if `account` supports the interface defined by\\n * `interfaceId`. Support for {IERC165} itself is queried automatically.\\n *\\n * See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) {\\n // query support of both ERC165 as per the spec and support of _interfaceId\\n return supportsERC165(account) && _supportsERC165Interface(account, interfaceId);\\n }\\n\\n /**\\n * @dev Returns a boolean array where each value corresponds to the\\n * interfaces passed in and whether they're supported or not. This allows\\n * you to batch check interfaces for a contract where your expectation\\n * is that some interfaces may not be supported.\\n *\\n * See {IERC165-supportsInterface}.\\n *\\n * _Available since v3.4._\\n */\\n function getSupportedInterfaces(address account, bytes4[] memory interfaceIds)\\n internal\\n view\\n returns (bool[] memory)\\n {\\n // an array of booleans corresponding to interfaceIds and whether they're supported or not\\n bool[] memory interfaceIdsSupported = new bool[](interfaceIds.length);\\n\\n // query support of ERC165 itself\\n if (supportsERC165(account)) {\\n // query support of each interface in interfaceIds\\n for (uint256 i = 0; i < interfaceIds.length; i++) {\\n interfaceIdsSupported[i] = _supportsERC165Interface(account, interfaceIds[i]);\\n }\\n }\\n\\n return interfaceIdsSupported;\\n }\\n\\n /**\\n * @dev Returns true if `account` supports all the interfaces defined in\\n * `interfaceIds`. Support for {IERC165} itself is queried automatically.\\n *\\n * Batch-querying can lead to gas savings by skipping repeated checks for\\n * {IERC165} support.\\n *\\n * See {IERC165-supportsInterface}.\\n */\\n function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) {\\n // query support of ERC165 itself\\n if (!supportsERC165(account)) {\\n return false;\\n }\\n\\n // query support of each interface in _interfaceIds\\n for (uint256 i = 0; i < interfaceIds.length; i++) {\\n if (!_supportsERC165Interface(account, interfaceIds[i])) {\\n return false;\\n }\\n }\\n\\n // all interfaces supported\\n return true;\\n }\\n\\n /**\\n * @notice Query if a contract implements an interface, does not check ERC165 support\\n * @param account The address of the contract to query for support of an interface\\n * @param interfaceId The interface identifier, as specified in ERC-165\\n * @return true if the contract at account indicates support of the interface with\\n * identifier interfaceId, false otherwise\\n * @dev Assumes that account contains a contract that supports ERC165, otherwise\\n * the behavior of this method is undefined. This precondition can be checked\\n * with {supportsERC165}.\\n * Interface identification is specified in ERC-165.\\n */\\n function _supportsERC165Interface(address account, bytes4 interfaceId) private view returns (bool) {\\n bytes memory encodedParams = abi.encodeWithSelector(IERC165.supportsInterface.selector, interfaceId);\\n (bool success, bytes memory result) = account.staticcall{gas: 30000}(encodedParams);\\n if (result.length < 32) return false;\\n return success && abi.decode(result, (bool));\\n }\\n}\\n\",\"keccak256\":\"0xf7291d7213336b00ee7edbf7cd5034778dd7b0bda2a7489e664f1e5cacc6c24e\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/IERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC165 standard, as defined in the\\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\\n *\\n * Implementers can declare support of contract interfaces, which can then be\\n * queried by others ({ERC165Checker}).\\n *\\n * For an implementation, see {ERC165}.\\n */\\ninterface IERC165 {\\n /**\\n * @dev Returns true if this contract implements the interface defined by\\n * `interfaceId`. See the corresponding\\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\\n * to learn more about how these ids are created.\\n *\\n * This function call must use less than 30 000 gas.\\n */\\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\\n}\\n\",\"keccak256\":\"0x447a5f3ddc18419d41ff92b3773fb86471b1db25773e07f877f548918a185bf1\",\"license\":\"MIT\"},\"@paulrberg/contracts/math/PRBMath.sol\":{\"content\":\"// SPDX-License-Identifier: Unlicense\\npragma solidity >=0.8.4;\\n\\nimport \\\"prb-math/contracts/PRBMath.sol\\\";\\n\",\"keccak256\":\"0x42821345981bc0434a90ba2268a2f5278dfe9e38166981d72fc7f3b776a29495\",\"license\":\"Unlicense\"},\"contracts/JBETHPaymentTerminal3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.16;\\n\\nimport {Address} from '@openzeppelin/contracts/utils/Address.sol';\\nimport {JBPayoutRedemptionPaymentTerminal3_1_1} from './abstract/JBPayoutRedemptionPaymentTerminal3_1_1.sol';\\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\\nimport {JBCurrencies} from './libraries/JBCurrencies.sol';\\nimport {JBSplitsGroups} from './libraries/JBSplitsGroups.sol';\\nimport {JBTokens} from './libraries/JBTokens.sol';\\n\\n/// @notice Manages all inflows and outflows of ETH funds into the protocol ecosystem.\\ncontract JBETHPaymentTerminal3_1_1 is JBPayoutRedemptionPaymentTerminal3_1_1 {\\n //*********************************************************************//\\n // -------------------------- internal views ------------------------- //\\n //*********************************************************************//\\n\\n /// @notice Checks the balance of tokens in this contract.\\n /// @return The contract's balance, as a fixed point number with the same amount of decimals as this terminal.\\n function _balance() internal view override returns (uint256) {\\n return address(this).balance;\\n }\\n\\n //*********************************************************************//\\n // -------------------------- constructor ---------------------------- //\\n //*********************************************************************//\\n\\n /// @param _baseWeightCurrency The currency to base token issuance on.\\n /// @param _operatorStore A contract storing operator assignments.\\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\\n /// @param _directory A contract storing directories of terminals and controllers for each project.\\n /// @param _splitsStore A contract that stores splits for each project.\\n /// @param _prices A contract that exposes price feeds.\\n /// @param _store A contract that stores the terminal's data.\\n /// @param _owner The address that will own this contract.\\n constructor(\\n uint256 _baseWeightCurrency,\\n IJBOperatorStore _operatorStore,\\n IJBProjects _projects,\\n IJBDirectory _directory,\\n IJBSplitsStore _splitsStore,\\n IJBPrices _prices,\\n address _store,\\n address _owner\\n )\\n JBPayoutRedemptionPaymentTerminal3_1_1(\\n JBTokens.ETH,\\n 18, // 18 decimals.\\n JBCurrencies.ETH,\\n _baseWeightCurrency,\\n JBSplitsGroups.ETH_PAYOUT,\\n _operatorStore,\\n _projects,\\n _directory,\\n _splitsStore,\\n _prices,\\n _store,\\n _owner\\n )\\n // solhint-disable-next-line no-empty-blocks\\n {\\n\\n }\\n\\n //*********************************************************************//\\n // ---------------------- internal transactions ---------------------- //\\n //*********************************************************************//\\n\\n /// @notice Transfers tokens.\\n /// @param _from The address from which the transfer should originate.\\n /// @param _to The address to which the transfer should go.\\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\\n function _transferFrom(address _from, address payable _to, uint256 _amount) internal override {\\n _from; // Prevents unused var compiler and natspec complaints.\\n\\n Address.sendValue(_to, _amount);\\n }\\n}\\n\",\"keccak256\":\"0x2df0a5c2a17371ce249dae553a919521d9f3037ae397efb68aac726702097060\",\"license\":\"MIT\"},\"contracts/abstract/JBOperatable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.16;\\n\\nimport {IJBOperatable} from './../interfaces/IJBOperatable.sol';\\nimport {IJBOperatorStore} from './../interfaces/IJBOperatorStore.sol';\\n\\n/// @notice Modifiers to allow access to functions based on the message sender's operator status.\\nabstract contract JBOperatable is IJBOperatable {\\n //*********************************************************************//\\n // --------------------------- custom errors -------------------------- //\\n //*********************************************************************//\\n error UNAUTHORIZED();\\n\\n //*********************************************************************//\\n // ---------------------------- modifiers ---------------------------- //\\n //*********************************************************************//\\n\\n /// @notice Only allows the speficied account or an operator of the account to proceed.\\n /// @param _account The account to check for.\\n /// @param _domain The domain namespace to look for an operator within.\\n /// @param _permissionIndex The index of the permission to check for.\\n modifier requirePermission(\\n address _account,\\n uint256 _domain,\\n uint256 _permissionIndex\\n ) {\\n _requirePermission(_account, _domain, _permissionIndex);\\n _;\\n }\\n\\n /// @notice Only allows the speficied account, an operator of the account to proceed, or a truthy override flag.\\n /// @param _account The account to check for.\\n /// @param _domain The domain namespace to look for an operator within.\\n /// @param _permissionIndex The index of the permission to check for.\\n /// @param _override A condition to force allowance for.\\n modifier requirePermissionAllowingOverride(\\n address _account,\\n uint256 _domain,\\n uint256 _permissionIndex,\\n bool _override\\n ) {\\n _requirePermissionAllowingOverride(_account, _domain, _permissionIndex, _override);\\n _;\\n }\\n\\n //*********************************************************************//\\n // ---------------- public immutable stored properties --------------- //\\n //*********************************************************************//\\n\\n /// @notice A contract storing operator assignments.\\n IJBOperatorStore public immutable override operatorStore;\\n\\n //*********************************************************************//\\n // -------------------------- constructor ---------------------------- //\\n //*********************************************************************//\\n\\n /// @param _operatorStore A contract storing operator assignments.\\n constructor(IJBOperatorStore _operatorStore) {\\n operatorStore = _operatorStore;\\n }\\n\\n //*********************************************************************//\\n // -------------------------- internal views ------------------------- //\\n //*********************************************************************//\\n\\n /// @notice Require the message sender is either the account or has the specified permission.\\n /// @param _account The account to allow.\\n /// @param _domain The domain namespace within which the permission index will be checked.\\n /// @param _permissionIndex The permission index that an operator must have within the specified domain to be allowed.\\n function _requirePermission(\\n address _account,\\n uint256 _domain,\\n uint256 _permissionIndex\\n ) internal view {\\n if (\\n msg.sender != _account &&\\n !operatorStore.hasPermission(msg.sender, _account, _domain, _permissionIndex) &&\\n !operatorStore.hasPermission(msg.sender, _account, 0, _permissionIndex)\\n ) revert UNAUTHORIZED();\\n }\\n\\n /// @notice Require the message sender is either the account, has the specified permission, or the override condition is true.\\n /// @param _account The account to allow.\\n /// @param _domain The domain namespace within which the permission index will be checked.\\n /// @param _domain The permission index that an operator must have within the specified domain to be allowed.\\n /// @param _override The override condition to allow.\\n function _requirePermissionAllowingOverride(\\n address _account,\\n uint256 _domain,\\n uint256 _permissionIndex,\\n bool _override\\n ) internal view {\\n if (\\n !_override &&\\n msg.sender != _account &&\\n !operatorStore.hasPermission(msg.sender, _account, _domain, _permissionIndex) &&\\n !operatorStore.hasPermission(msg.sender, _account, 0, _permissionIndex)\\n ) revert UNAUTHORIZED();\\n }\\n}\\n\",\"keccak256\":\"0xed3071b63f3ac427ffcd357a53be2675d405e94e40a7b1bc0475054005807e91\",\"license\":\"MIT\"},\"contracts/abstract/JBPayoutRedemptionPaymentTerminal3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.16;\\n\\nimport {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\\nimport {ERC165Checker} from '@openzeppelin/contracts/utils/introspection/ERC165Checker.sol';\\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\\nimport {JBFeeType} from './../enums/JBFeeType.sol';\\nimport {IJBAllowanceTerminal3_1} from './../interfaces/IJBAllowanceTerminal3_1.sol';\\nimport {IJBController} from './../interfaces/IJBController.sol';\\nimport {IJBDirectory} from './../interfaces/IJBDirectory.sol';\\nimport {IJBPayoutRedemptionPaymentTerminal3_1} from './../interfaces/IJBPayoutRedemptionPaymentTerminal3_1.sol';\\nimport {IJBPayoutRedemptionPaymentTerminal3_1_1} from './../interfaces/IJBPayoutRedemptionPaymentTerminal3_1_1.sol';\\nimport {IJBSplitsStore} from './../interfaces/IJBSplitsStore.sol';\\nimport {IJBFeeGauge3_1} from './../interfaces/IJBFeeGauge3_1.sol';\\nimport {IJBOperatable} from './../interfaces/IJBOperatable.sol';\\nimport {IJBOperatorStore} from './../interfaces/IJBOperatorStore.sol';\\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\\nimport {IJBPayoutTerminal3_1} from './../interfaces/IJBPayoutTerminal3_1.sol';\\nimport {IJBPrices} from './../interfaces/IJBPrices.sol';\\nimport {IJBProjects} from './../interfaces/IJBProjects.sol';\\nimport {IJBRedemptionTerminal} from './../interfaces/IJBRedemptionTerminal.sol';\\nimport {IJBSingleTokenPaymentTerminalStore3_1_1} from './../interfaces/IJBSingleTokenPaymentTerminalStore3_1_1.sol';\\nimport {IJBSplitAllocator} from './../interfaces/IJBSplitAllocator.sol';\\nimport {JBConstants} from './../libraries/JBConstants.sol';\\nimport {JBCurrencies} from './../libraries/JBCurrencies.sol';\\nimport {JBFixedPointNumber} from './../libraries/JBFixedPointNumber.sol';\\nimport {JBFundingCycleMetadataResolver} from './../libraries/JBFundingCycleMetadataResolver.sol';\\nimport {JBOperations} from './../libraries/JBOperations.sol';\\nimport {JBTokens} from './../libraries/JBTokens.sol';\\nimport {JBDidRedeemData3_1_1} from './../structs/JBDidRedeemData3_1_1.sol';\\nimport {JBDidPayData3_1_1} from './../structs/JBDidPayData3_1_1.sol';\\nimport {JBFee} from './../structs/JBFee.sol';\\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\\nimport {JBPayDelegateAllocation3_1_1} from './../structs/JBPayDelegateAllocation3_1_1.sol';\\nimport {JBRedemptionDelegateAllocation3_1_1} from './../structs/JBRedemptionDelegateAllocation3_1_1.sol';\\nimport {JBSplit} from './../structs/JBSplit.sol';\\nimport {JBSplitAllocationData} from './../structs/JBSplitAllocationData.sol';\\nimport {JBTokenAmount} from './../structs/JBTokenAmount.sol';\\nimport {JBOperatable} from './JBOperatable.sol';\\nimport {JBSingleTokenPaymentTerminal} from './JBSingleTokenPaymentTerminal.sol';\\n\\n/// @notice Generic terminal managing all inflows and outflows of funds into the protocol ecosystem.\\nabstract contract JBPayoutRedemptionPaymentTerminal3_1_1 is\\n JBSingleTokenPaymentTerminal,\\n JBOperatable,\\n Ownable,\\n IJBPayoutRedemptionPaymentTerminal3_1,\\n IJBPayoutRedemptionPaymentTerminal3_1_1\\n{\\n // A library that parses the packed funding cycle metadata into a friendlier format.\\n using JBFundingCycleMetadataResolver for JBFundingCycle;\\n\\n //*********************************************************************//\\n // --------------------------- custom errors ------------------------- //\\n //*********************************************************************//\\n error FEE_TOO_HIGH();\\n error INADEQUATE_DISTRIBUTION_AMOUNT();\\n error INADEQUATE_RECLAIM_AMOUNT();\\n error INADEQUATE_TOKEN_COUNT();\\n error NO_MSG_VALUE_ALLOWED();\\n error PAY_TO_ZERO_ADDRESS();\\n error PROJECT_TERMINAL_MISMATCH();\\n error REDEEM_TO_ZERO_ADDRESS();\\n error TERMINAL_TOKENS_INCOMPATIBLE();\\n\\n //*********************************************************************//\\n // --------------------- internal stored constants ------------------- //\\n //*********************************************************************//\\n\\n /// @notice Maximum fee that can be set for a funding cycle configuration.\\n /// @dev Out of MAX_FEE (50_000_000 / 1_000_000_000).\\n uint256 internal constant _FEE_CAP = 50_000_000;\\n\\n /// @notice The fee beneficiary project ID is 1, as it should be the first project launched during the deployment process.\\n uint256 internal constant _FEE_BENEFICIARY_PROJECT_ID = 1;\\n\\n //*********************************************************************//\\n // --------------------- internal stored properties ------------------ //\\n //*********************************************************************//\\n\\n /// @notice Fees that are being held to be processed later.\\n /// @custom:param _projectId The ID of the project for which fees are being held.\\n mapping(uint256 => JBFee[]) internal _heldFeesOf;\\n\\n //*********************************************************************//\\n // ---------------- public immutable stored properties --------------- //\\n //*********************************************************************//\\n\\n /// @notice Mints ERC-721's that represent project ownership and transfers.\\n IJBProjects public immutable override projects;\\n\\n /// @notice The directory of terminals and controllers for projects.\\n IJBDirectory public immutable override directory;\\n\\n /// @notice The contract that stores splits for each project.\\n IJBSplitsStore public immutable override splitsStore;\\n\\n /// @notice The contract that exposes price feeds.\\n IJBPrices public immutable override prices;\\n\\n /// @notice The contract that stores and manages the terminal's data.\\n address public immutable override store;\\n\\n /// @notice The currency to base token issuance on.\\n /// @dev If this differs from `currency`, there must be a price feed available to convert `currency` to `baseWeightCurrency`.\\n uint256 public immutable override baseWeightCurrency;\\n\\n /// @notice The group that payout splits coming from this terminal are identified by.\\n uint256 public immutable override payoutSplitsGroup;\\n\\n //*********************************************************************//\\n // --------------------- public stored properties -------------------- //\\n //*********************************************************************//\\n\\n /// @notice The platform fee percent.\\n /// @dev Out of MAX_FEE (25_000_000 / 1_000_000_000)\\n uint256 public override fee = 25_000_000; // 2.5%\\n\\n /// @notice The data source that returns a discount to apply to a project's fee.\\n address public override feeGauge;\\n\\n /// @notice Addresses that can be paid towards from this terminal without incurring a fee.\\n /// @dev Only addresses that are considered to be contained within the ecosystem can be feeless. Funds sent outside the ecosystem may incur fees despite being stored as feeless.\\n /// @custom:param _address The address that can be paid toward.\\n mapping(address => bool) public override isFeelessAddress;\\n\\n //*********************************************************************//\\n // ------------------------- external views -------------------------- //\\n //*********************************************************************//\\n\\n /// @notice Gets the current overflowed amount in this terminal for a specified project, in terms of ETH.\\n /// @dev The current overflow is represented as a fixed point number with 18 decimals.\\n /// @param _projectId The ID of the project to get overflow for.\\n /// @return The current amount of ETH overflow that project has in this terminal, as a fixed point number with 18 decimals.\\n function currentEthOverflowOf(\\n uint256 _projectId\\n ) external view virtual override returns (uint256) {\\n // Get this terminal's current overflow.\\n uint256 _overflow = IJBSingleTokenPaymentTerminalStore3_1_1(store).currentOverflowOf(\\n this,\\n _projectId\\n );\\n\\n // Adjust the decimals of the fixed point number if needed to have 18 decimals.\\n uint256 _adjustedOverflow = (decimals == 18)\\n ? _overflow\\n : JBFixedPointNumber.adjustDecimals(_overflow, decimals, 18);\\n\\n // Return the amount converted to ETH.\\n return\\n (currency == JBCurrencies.ETH)\\n ? _adjustedOverflow\\n : PRBMath.mulDiv(\\n _adjustedOverflow,\\n 10 ** decimals,\\n prices.priceFor(currency, JBCurrencies.ETH, decimals)\\n );\\n }\\n\\n /// @notice The fees that are currently being held to be processed later for each project.\\n /// @param _projectId The ID of the project for which fees are being held.\\n /// @return An array of fees that are being held.\\n function heldFeesOf(uint256 _projectId) external view override returns (JBFee[] memory) {\\n return _heldFeesOf[_projectId];\\n }\\n\\n //*********************************************************************//\\n // -------------------------- public views --------------------------- //\\n //*********************************************************************//\\n\\n /// @notice Indicates if this contract adheres to the specified interface.\\n /// @dev See {IERC165-supportsInterface}.\\n /// @param _interfaceId The ID of the interface to check for adherance to.\\n /// @return A flag indicating if the provided interface ID is supported.\\n function supportsInterface(\\n bytes4 _interfaceId\\n ) public view virtual override(JBSingleTokenPaymentTerminal, IERC165) returns (bool) {\\n return\\n _interfaceId == type(IJBPayoutRedemptionPaymentTerminal3_1_1).interfaceId ||\\n _interfaceId == type(IJBPayoutRedemptionPaymentTerminal3_1).interfaceId ||\\n _interfaceId == type(IJBPayoutTerminal3_1).interfaceId ||\\n _interfaceId == type(IJBAllowanceTerminal3_1).interfaceId ||\\n _interfaceId == type(IJBRedemptionTerminal).interfaceId ||\\n _interfaceId == type(IJBOperatable).interfaceId ||\\n super.supportsInterface(_interfaceId);\\n }\\n\\n //*********************************************************************//\\n // -------------------------- internal views ------------------------- //\\n //*********************************************************************//\\n\\n /// @notice Checks the balance of tokens in this contract.\\n /// @return The contract's balance.\\n function _balance() internal view virtual returns (uint256);\\n\\n //*********************************************************************//\\n // -------------------------- constructor ---------------------------- //\\n //*********************************************************************//\\n\\n /// @param _token The token that this terminal manages.\\n /// @param _decimals The number of decimals the token fixed point amounts are expected to have.\\n /// @param _currency The currency that this terminal's token adheres to for price feeds.\\n /// @param _baseWeightCurrency The currency to base token issuance on.\\n /// @param _payoutSplitsGroup The group that denotes payout splits from this terminal in the splits store.\\n /// @param _operatorStore A contract storing operator assignments.\\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\\n /// @param _directory A contract storing directories of terminals and controllers for each project.\\n /// @param _splitsStore A contract that stores splits for each project.\\n /// @param _prices A contract that exposes price feeds.\\n /// @param _store A contract that stores the terminal's data.\\n /// @param _owner The address that will own this contract.\\n constructor(\\n // payable constructor save the gas used to check msg.value==0\\n address _token,\\n uint256 _decimals,\\n uint256 _currency,\\n uint256 _baseWeightCurrency,\\n uint256 _payoutSplitsGroup,\\n IJBOperatorStore _operatorStore,\\n IJBProjects _projects,\\n IJBDirectory _directory,\\n IJBSplitsStore _splitsStore,\\n IJBPrices _prices,\\n address _store,\\n address _owner\\n )\\n payable\\n JBSingleTokenPaymentTerminal(_token, _decimals, _currency)\\n JBOperatable(_operatorStore)\\n {\\n baseWeightCurrency = _baseWeightCurrency;\\n payoutSplitsGroup = _payoutSplitsGroup;\\n projects = _projects;\\n directory = _directory;\\n splitsStore = _splitsStore;\\n prices = _prices;\\n store = _store;\\n\\n transferOwnership(_owner);\\n }\\n\\n //*********************************************************************//\\n // ---------------------- external transactions ---------------------- //\\n //*********************************************************************//\\n\\n /// @notice Contribute tokens to a project.\\n /// @param _projectId The ID of the project being paid.\\n /// @param _amount The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place.\\n /// @param _token The token being paid. This terminal ignores this property since it only manages one token.\\n /// @param _beneficiary The address to mint tokens for and pass along to the funding cycle's data source and delegate.\\n /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal.\\n /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\\n /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\\n /// @return The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals.\\n function pay(\\n uint256 _projectId,\\n uint256 _amount,\\n address _token,\\n address _beneficiary,\\n uint256 _minReturnedTokens,\\n bool _preferClaimedTokens,\\n string calldata _memo,\\n bytes calldata _metadata\\n ) external payable virtual override returns (uint256) {\\n _token; // Prevents unused var compiler and natspec complaints.\\n\\n // valid terminal check\\n _isTerminalOf(_projectId);\\n\\n // ETH shouldn't be sent if this terminal's token isn't ETH.\\n if (token != JBTokens.ETH) {\\n if (msg.value != 0) revert NO_MSG_VALUE_ALLOWED();\\n\\n // Get a reference to the balance before receiving tokens.\\n uint256 _balanceBefore = _balance();\\n\\n // Transfer tokens to this terminal from the msg sender.\\n _transferFrom(msg.sender, payable(address(this)), _amount);\\n\\n // The amount should reflect the change in balance.\\n _amount = _balance() - _balanceBefore;\\n }\\n // If this terminal's token is ETH, override _amount with msg.value.\\n else _amount = msg.value;\\n\\n return\\n _pay(\\n _amount,\\n msg.sender,\\n _projectId,\\n _beneficiary,\\n _minReturnedTokens,\\n _preferClaimedTokens,\\n _memo,\\n _metadata\\n );\\n }\\n\\n /// @notice Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source.\\n /// @dev Only a token holder or a designated operator can redeem its tokens.\\n /// @param _holder The account to redeem tokens for.\\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\\n /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals.\\n /// @param _token The token being reclaimed. This terminal ignores this property since it only manages one token.\\n /// @param _minReturnedTokens The minimum amount of terminal tokens expected in return, as a fixed point number with the same amount of decimals as the terminal.\\n /// @param _beneficiary The address to send the terminal tokens to.\\n /// @param _memo A memo to pass along to the emitted event.\\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\\n /// @return reclaimAmount The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals.\\n function redeemTokensOf(\\n address _holder,\\n uint256 _projectId,\\n uint256 _tokenCount,\\n address _token,\\n uint256 _minReturnedTokens,\\n address payable _beneficiary,\\n string memory _memo,\\n bytes memory _metadata\\n )\\n external\\n virtual\\n override\\n requirePermission(_holder, _projectId, JBOperations.REDEEM)\\n returns (uint256 reclaimAmount)\\n {\\n _token; // Prevents unused var compiler and natspec complaints.\\n\\n return\\n _redeemTokensOf(\\n _holder,\\n _projectId,\\n _tokenCount,\\n _minReturnedTokens,\\n _beneficiary,\\n _memo,\\n _metadata\\n );\\n }\\n\\n /// @notice Distributes payouts for a project with the distribution limit of its current funding cycle.\\n /// @dev Payouts are sent to the preprogrammed splits. Any leftover is sent to the project's owner.\\n /// @dev 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.\\n /// @dev All funds distributed outside of this contract or any feeless terminals incure the protocol fee.\\n /// @param _projectId The ID of the project having its payouts distributed.\\n /// @param _amount The amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal.\\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency.\\n /// @param _token The token being distributed. This terminal ignores this property since it only manages one token.\\n /// @param _minReturnedTokens 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.\\n /// @param _metadata Bytes to send along to the emitted event, if provided.\\n /// @return netLeftoverDistributionAmount The amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal.\\n function distributePayoutsOf(\\n uint256 _projectId,\\n uint256 _amount,\\n uint256 _currency,\\n address _token,\\n uint256 _minReturnedTokens,\\n bytes calldata _metadata\\n ) external virtual override returns (uint256 netLeftoverDistributionAmount) {\\n _token; // Prevents unused var compiler and natspec complaints.\\n\\n return _distributePayoutsOf(_projectId, _amount, _currency, _minReturnedTokens, _metadata);\\n }\\n\\n /// @notice Allows a project to send funds from its overflow up to the preconfigured allowance.\\n /// @dev Only a project's owner or a designated operator can use its allowance.\\n /// @dev Incurs the protocol fee.\\n /// @param _projectId The ID of the project to use the allowance of.\\n /// @param _amount The amount of terminal tokens to use from this project's current allowance, as a fixed point number with the same amount of decimals as this terminal.\\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's overflow allowance currency.\\n /// @param _token The token being distributed. This terminal ignores this property since it only manages one token.\\n /// @param _minReturnedTokens The minimum number of tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with 18 decimals.\\n /// @param _beneficiary The address to send the funds to.\\n /// @param _memo A memo to pass along to the emitted event.\\n /// @param _metadata Bytes to send along to the emitted event, if provided.\\n /// @return netDistributedAmount The amount of tokens that was distributed to the beneficiary, as a fixed point number with the same amount of decimals as the terminal.\\n function useAllowanceOf(\\n uint256 _projectId,\\n uint256 _amount,\\n uint256 _currency,\\n address _token,\\n uint256 _minReturnedTokens,\\n address payable _beneficiary,\\n string memory _memo,\\n bytes calldata _metadata\\n )\\n external\\n virtual\\n override\\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.USE_ALLOWANCE)\\n returns (uint256 netDistributedAmount)\\n {\\n _token; // Prevents unused var compiler and natspec complaints.\\n\\n return\\n _useAllowanceOf(\\n _projectId,\\n _amount,\\n _currency,\\n _minReturnedTokens,\\n _beneficiary,\\n _memo,\\n _metadata\\n );\\n }\\n\\n /// @notice Allows a project owner to migrate its funds and operations to a new terminal that accepts the same token type.\\n /// @dev Only a project's owner or a designated operator can migrate it.\\n /// @param _projectId The ID of the project being migrated.\\n /// @param _to The terminal contract that will gain the project's funds.\\n /// @return balance The amount of funds that were migrated, as a fixed point number with the same amount of decimals as this terminal.\\n function migrate(\\n uint256 _projectId,\\n IJBPaymentTerminal _to\\n )\\n external\\n virtual\\n override\\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.MIGRATE_TERMINAL)\\n returns (uint256 balance)\\n {\\n // The terminal being migrated to must accept the same token as this terminal.\\n if (!_to.acceptsToken(token, _projectId)) revert TERMINAL_TOKENS_INCOMPATIBLE();\\n\\n // Record the migration in the store.\\n balance = IJBSingleTokenPaymentTerminalStore3_1_1(store).recordMigration(_projectId);\\n\\n // Transfer the balance if needed.\\n if (balance != 0) {\\n // Trigger any inherited pre-transfer logic.\\n _beforeTransferTo(address(_to), balance);\\n\\n // If this terminal's token is ETH, send it in msg.value.\\n uint256 _payableValue = token == JBTokens.ETH ? balance : 0;\\n\\n // Withdraw the balance to transfer to the new terminal;\\n _to.addToBalanceOf{value: _payableValue}(_projectId, balance, token, '', bytes(''));\\n }\\n\\n emit Migrate(_projectId, _to, balance, msg.sender);\\n }\\n\\n /// @notice Receives funds belonging to the specified project.\\n /// @param _projectId The ID of the project to which the funds received belong.\\n /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\\n /// @param _token The token being paid. This terminal ignores this property since it only manages one currency.\\n /// @param _memo A memo to pass along to the emitted event.\\n /// @param _metadata Extra data to pass along to the emitted event.\\n function addToBalanceOf(\\n uint256 _projectId,\\n uint256 _amount,\\n address _token,\\n string calldata _memo,\\n bytes calldata _metadata\\n ) external payable virtual override {\\n // valid terminal check\\n _isTerminalOf(_projectId);\\n\\n // Do not refund held fees by default.\\n addToBalanceOf(_projectId, _amount, _token, false, _memo, _metadata);\\n }\\n\\n /// @notice Process any fees that are being held for the project.\\n /// @dev Only a project owner, an operator, or the contract's owner can process held fees.\\n /// @param _projectId The ID of the project whos held fees should be processed.\\n function processFees(\\n uint256 _projectId\\n )\\n external\\n virtual\\n override\\n requirePermissionAllowingOverride(\\n projects.ownerOf(_projectId),\\n _projectId,\\n JBOperations.PROCESS_FEES,\\n msg.sender == owner()\\n )\\n {\\n // Get a reference to the project's held fees.\\n JBFee[] memory _heldFees = _heldFeesOf[_projectId];\\n\\n // Delete the held fees.\\n delete _heldFeesOf[_projectId];\\n\\n // Push array length in stack\\n uint256 _heldFeeLength = _heldFees.length;\\n\\n // Keep a reference to the amount.\\n uint256 _amount;\\n\\n // Process each fee.\\n for (uint256 _i; _i < _heldFeeLength; ) {\\n // Get the fee amount.\\n _amount = (\\n _heldFees[_i].fee == 0 || _heldFees[_i].feeDiscount == JBConstants.MAX_FEE_DISCOUNT\\n ? 0\\n : _feeAmount(_heldFees[_i].amount, _heldFees[_i].fee, _heldFees[_i].feeDiscount)\\n );\\n\\n // Process the fee.\\n _processFee(_amount, _heldFees[_i].beneficiary, _projectId);\\n\\n emit ProcessFee(_projectId, _amount, true, _heldFees[_i].beneficiary, msg.sender);\\n\\n unchecked {\\n ++_i;\\n }\\n }\\n }\\n\\n /// @notice Allows the fee to be updated.\\n /// @dev Only the owner of this contract can change the fee.\\n /// @param _fee The new fee, out of MAX_FEE.\\n function setFee(uint256 _fee) external virtual override onlyOwner {\\n // The provided fee must be within the max.\\n if (_fee > _FEE_CAP) revert FEE_TOO_HIGH();\\n\\n // Store the new fee.\\n fee = _fee;\\n\\n emit SetFee(_fee, msg.sender);\\n }\\n\\n /// @notice Allows the fee gauge to be updated.\\n /// @dev Only the owner of this contract can change the fee gauge.\\n /// @param _feeGauge The new fee gauge.\\n function setFeeGauge(address _feeGauge) external virtual override onlyOwner {\\n // Store the new fee gauge.\\n feeGauge = _feeGauge;\\n\\n emit SetFeeGauge(_feeGauge, msg.sender);\\n }\\n\\n /// @notice Sets whether projects operating on this terminal can pay towards the specified address without incurring a fee.\\n /// @dev Only the owner of this contract can set addresses as feeless.\\n /// @param _address The address that can be paid towards while still bypassing fees.\\n /// @param _flag A flag indicating whether the terminal should be feeless or not.\\n function setFeelessAddress(address _address, bool _flag) external virtual override onlyOwner {\\n // Set the flag value.\\n isFeelessAddress[_address] = _flag;\\n\\n emit SetFeelessAddress(_address, _flag, msg.sender);\\n }\\n\\n //*********************************************************************//\\n // ----------------------- public transactions ----------------------- //\\n //*********************************************************************//\\n\\n /// @notice Receives funds belonging to the specified project.\\n /// @param _projectId The ID of the project to which the funds received belong.\\n /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\\n /// @param _token The token being paid. This terminal ignores this property since it only manages one currency.\\n /// @param _shouldRefundHeldFees A flag indicating if held fees should be refunded based on the amount being added.\\n /// @param _memo A memo to pass along to the emitted event.\\n /// @param _metadata Extra data to pass along to the emitted event.\\n function addToBalanceOf(\\n uint256 _projectId,\\n uint256 _amount,\\n address _token,\\n bool _shouldRefundHeldFees,\\n string calldata _memo,\\n bytes calldata _metadata\\n ) public payable virtual override {\\n // valid terminal check\\n _isTerminalOf(_projectId);\\n\\n _token; // Prevents unused var compiler and natspec complaints.\\n\\n // If this terminal's token isn't ETH, make sure no msg.value was sent, then transfer the tokens in from msg.sender.\\n if (token != JBTokens.ETH) {\\n // Amount must be greater than 0.\\n if (msg.value != 0) revert NO_MSG_VALUE_ALLOWED();\\n\\n // Get a reference to the balance before receiving tokens.\\n uint256 _balanceBefore = _balance();\\n\\n // Transfer tokens to this terminal from the msg sender.\\n _transferFrom(msg.sender, payable(address(this)), _amount);\\n\\n // The amount should reflect the change in balance.\\n _amount = _balance() - _balanceBefore;\\n }\\n // If the terminal's token is ETH, override `_amount` with msg.value.\\n else _amount = msg.value;\\n\\n // Add to balance.\\n _addToBalanceOf(_projectId, _amount, _shouldRefundHeldFees, _memo, _metadata);\\n }\\n\\n //*********************************************************************//\\n // ---------------------- internal transactions ---------------------- //\\n //*********************************************************************//\\n\\n /// @notice Transfers tokens.\\n /// @param _from The address from which the transfer should originate.\\n /// @param _to The address to which the transfer should go.\\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\\n function _transferFrom(address _from, address payable _to, uint256 _amount) internal virtual {\\n _from; // Prevents unused var compiler and natspec complaints.\\n _to; // Prevents unused var compiler and natspec complaints.\\n _amount; // Prevents unused var compiler and natspec complaints.\\n }\\n\\n /// @notice Logic to be triggered before transferring tokens from this terminal.\\n /// @param _to The address to which the transfer is going.\\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\\n function _beforeTransferTo(address _to, uint256 _amount) internal virtual {\\n _to; // Prevents unused var compiler and natspec complaints.\\n _amount; // Prevents unused var compiler and natspec complaints.\\n }\\n\\n /// @notice Logic to be triggered if a transfer should be undone\\n /// @param _to The address to which the transfer went.\\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\\n function _cancelTransferTo(address _to, uint256 _amount) internal virtual {\\n _to; // Prevents unused var compiler and natspec complaints.\\n _amount; // Prevents unused var compiler and natspec complaints.\\n }\\n\\n /// @notice Verifies this terminal is a terminal of provided project ID.\\n /// @param _projectId The ID of the project to check if this contract is a terminal of.\\n function _isTerminalOf(uint256 _projectId) internal view {\\n if (!directory.isTerminalOf(_projectId, this)) revert PROJECT_TERMINAL_MISMATCH();\\n }\\n\\n /// @notice Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source.\\n /// @dev Only a token holder or a designated operator can redeem its tokens.\\n /// @param _holder The account to redeem tokens for.\\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\\n /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals.\\n /// @param _minReturnedTokens The minimum amount of terminal tokens expected in return, as a fixed point number with the same amount of decimals as the terminal.\\n /// @param _beneficiary The address to send the terminal tokens to.\\n /// @param _memo A memo to pass along to the emitted event.\\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\\n /// @return reclaimAmount The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals.\\n function _redeemTokensOf(\\n address _holder,\\n uint256 _projectId,\\n uint256 _tokenCount,\\n uint256 _minReturnedTokens,\\n address payable _beneficiary,\\n string memory _memo,\\n bytes memory _metadata\\n ) internal returns (uint256 reclaimAmount) {\\n // Can't send reclaimed funds to the zero address.\\n if (_beneficiary == address(0)) revert REDEEM_TO_ZERO_ADDRESS();\\n\\n // Define variables that will be needed outside the scoped section below.\\n // Keep a reference to the funding cycle during which the redemption is being made.\\n JBFundingCycle memory _fundingCycle;\\n\\n // Scoped section prevents stack too deep. `_feeEligibleDistributionAmount`, `_feeDiscount` and `_feePercent` only used within scope.\\n {\\n // Keep a reference to the amount being reclaimed that should have fees withheld from.\\n uint256 _feeEligibleDistributionAmount;\\n\\n // Keep a reference to the amount of discount to apply to the fee.\\n uint256 _feeDiscount;\\n\\n // Keep a reference to the fee.\\n uint256 _feePercent = fee;\\n\\n // Scoped section prevents stack too deep. `_delegateAllocations` only used within scope.\\n {\\n JBRedemptionDelegateAllocation3_1_1[] memory _delegateAllocations;\\n\\n // Record the redemption.\\n (\\n _fundingCycle,\\n reclaimAmount,\\n _delegateAllocations,\\n _memo\\n ) = IJBSingleTokenPaymentTerminalStore3_1_1(store).recordRedemptionFor(\\n _holder,\\n _projectId,\\n _tokenCount,\\n _memo,\\n _metadata\\n );\\n\\n // Set the reference to the fee discount to apply. No fee if the beneficiary is feeless or if the redemption rate is at its max.\\n _feeDiscount = isFeelessAddress[_beneficiary] ||\\n (_fundingCycle.redemptionRate() == JBConstants.MAX_REDEMPTION_RATE &&\\n _fundingCycle.ballotRedemptionRate() == JBConstants.MAX_REDEMPTION_RATE) ||\\n _feePercent == 0\\n ? JBConstants.MAX_FEE_DISCOUNT\\n : _currentFeeDiscount(_projectId, JBFeeType.REDEMPTION);\\n\\n // The amount being reclaimed must be at least as much as was expected.\\n if (reclaimAmount < _minReturnedTokens) revert INADEQUATE_RECLAIM_AMOUNT();\\n\\n // Burn the project tokens.\\n if (_tokenCount != 0)\\n IJBController(directory.controllerOf(_projectId)).burnTokensOf(\\n _holder,\\n _projectId,\\n _tokenCount,\\n '',\\n false\\n );\\n\\n // If delegate allocations were specified by the data source, fulfill them.\\n if (_delegateAllocations.length != 0) {\\n JBDidRedeemData3_1_1 memory _data = JBDidRedeemData3_1_1(\\n _holder,\\n _projectId,\\n _fundingCycle.configuration,\\n _tokenCount,\\n JBTokenAmount(token, reclaimAmount, decimals, currency),\\n JBTokenAmount(token, 0, decimals, currency),\\n _beneficiary,\\n _memo,\\n bytes(''),\\n _metadata\\n );\\n\\n // Keep a reference to the allocation.\\n JBRedemptionDelegateAllocation3_1_1 memory _delegateAllocation;\\n\\n // Keep a reference to the fee.\\n uint256 _delegatedAmountFee;\\n\\n // Keep a reference to the number of allocations.\\n uint256 _numDelegates = _delegateAllocations.length;\\n\\n for (uint256 _i; _i < _numDelegates; ) {\\n // Get a reference to the delegate being iterated on.\\n _delegateAllocation = _delegateAllocations[_i];\\n\\n // Get the fee for the delegated amount.\\n _delegatedAmountFee = _feePercent == 0\\n ? 0\\n : _feeAmount(_delegateAllocation.amount, _feePercent, _feeDiscount);\\n\\n // Add the delegated amount to the amount eligible for having a fee taken.\\n if (_delegatedAmountFee != 0) {\\n _feeEligibleDistributionAmount += _delegateAllocation.amount;\\n _delegateAllocation.amount -= _delegatedAmountFee;\\n }\\n\\n // Trigger any inherited pre-transfer logic.\\n _beforeTransferTo(address(_delegateAllocation.delegate), _delegateAllocation.amount);\\n\\n // Pass the correct token forwardedAmount to the delegate\\n _data.forwardedAmount.value = _delegateAllocation.amount;\\n\\n // Pass the correct metadata from the data source.\\n _data.dataSourceMetadata = _delegateAllocation.metadata;\\n\\n _delegateAllocation.delegate.didRedeem{\\n value: token == JBTokens.ETH ? _delegateAllocation.amount : 0\\n }(_data);\\n\\n emit DelegateDidRedeem(\\n _delegateAllocation.delegate,\\n _data,\\n _delegateAllocation.amount,\\n _delegatedAmountFee,\\n msg.sender\\n );\\n\\n unchecked {\\n ++_i;\\n }\\n }\\n }\\n }\\n\\n // Send the reclaimed funds to the beneficiary.\\n if (reclaimAmount != 0) {\\n // Get the fee for the reclaimed amount.\\n uint256 _reclaimAmountFee = _feeDiscount == JBConstants.MAX_FEE_DISCOUNT\\n ? 0\\n : _feeAmount(reclaimAmount, _feePercent, _feeDiscount);\\n\\n if (_reclaimAmountFee != 0) {\\n _feeEligibleDistributionAmount += reclaimAmount;\\n reclaimAmount -= _reclaimAmountFee;\\n }\\n\\n // Subtract the fee from the reclaim amount.\\n if (reclaimAmount != 0) _transferFrom(address(this), _beneficiary, reclaimAmount);\\n }\\n\\n // Take the fee from all outbound reclaimations.\\n _feeEligibleDistributionAmount != 0\\n ? _takeFeeFrom(\\n _projectId,\\n false,\\n _feeEligibleDistributionAmount,\\n _feePercent,\\n _beneficiary,\\n _feeDiscount\\n )\\n : 0;\\n }\\n\\n emit RedeemTokens(\\n _fundingCycle.configuration,\\n _fundingCycle.number,\\n _projectId,\\n _holder,\\n _beneficiary,\\n _tokenCount,\\n reclaimAmount,\\n _memo,\\n _metadata,\\n msg.sender\\n );\\n }\\n\\n /// @notice Distributes payouts for a project with the distribution limit of its current funding cycle.\\n /// @dev Payouts are sent to the preprogrammed splits. Any leftover is sent to the project's owner.\\n /// @dev 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.\\n /// @dev All funds distributed outside of this contract or any feeless terminals incure the protocol fee.\\n /// @param _projectId The ID of the project having its payouts distributed.\\n /// @param _amount The amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal.\\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency.\\n /// @param _minReturnedTokens 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.\\n /// @param _metadata Bytes to send along to the emitted event, if provided.\\n /// @return netLeftoverDistributionAmount The amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal.\\n function _distributePayoutsOf(\\n uint256 _projectId,\\n uint256 _amount,\\n uint256 _currency,\\n uint256 _minReturnedTokens,\\n bytes calldata _metadata\\n ) internal returns (uint256 netLeftoverDistributionAmount) {\\n // Record the distribution.\\n (\\n JBFundingCycle memory _fundingCycle,\\n uint256 _distributedAmount\\n ) = IJBSingleTokenPaymentTerminalStore3_1_1(store).recordDistributionFor(\\n _projectId,\\n _amount,\\n _currency\\n );\\n\\n // The amount being distributed must be at least as much as was expected.\\n if (_distributedAmount < _minReturnedTokens) revert INADEQUATE_DISTRIBUTION_AMOUNT();\\n\\n // Get a reference to the project owner, which will receive tokens from paying the platform fee\\n // and receive any extra distributable funds not allocated to payout splits.\\n address payable _projectOwner = payable(projects.ownerOf(_projectId));\\n\\n // Define variables that will be needed outside the scoped section below.\\n // Keep a reference to the fee amount that was paid.\\n uint256 _feeTaken;\\n\\n // Scoped section prevents stack too deep. `_feePercent`, `_feeDiscount`, `_feeEligibleDistributionAmount`, and `_leftoverDistributionAmount` only used within scope.\\n {\\n // Keep a reference to the fee.\\n uint256 _feePercent = fee;\\n\\n // Get the amount of discount that should be applied to any fees taken.\\n // If the fee is zero, set the discount to 100% for convenience.\\n uint256 _feeDiscount = _feePercent == 0\\n ? JBConstants.MAX_FEE_DISCOUNT\\n : _currentFeeDiscount(_projectId, JBFeeType.PAYOUT);\\n\\n // The amount distributed that is eligible for incurring fees.\\n uint256 _feeEligibleDistributionAmount;\\n\\n // The amount leftover after distributing to the splits.\\n uint256 _leftoverDistributionAmount;\\n\\n // Payout to splits and get a reference to the leftover transfer amount after all splits have been paid.\\n // Also get a reference to the amount that was distributed to splits from which fees should be taken.\\n (_leftoverDistributionAmount, _feeEligibleDistributionAmount) = _distributeToPayoutSplitsOf(\\n _projectId,\\n _fundingCycle.configuration,\\n payoutSplitsGroup,\\n _distributedAmount,\\n _feePercent,\\n _feeDiscount\\n );\\n\\n if (_feeDiscount != JBConstants.MAX_FEE_DISCOUNT) {\\n // Leftover distribution amount is also eligible for a fee since the funds are going out of the ecosystem to _beneficiary.\\n unchecked {\\n _feeEligibleDistributionAmount += _leftoverDistributionAmount;\\n }\\n }\\n\\n // Take the fee.\\n _feeTaken = _feeEligibleDistributionAmount != 0\\n ? _takeFeeFrom(\\n _projectId,\\n _fundingCycle.shouldHoldFees(),\\n _feeEligibleDistributionAmount,\\n _feePercent,\\n _projectOwner,\\n _feeDiscount\\n )\\n : 0;\\n\\n // Transfer any remaining balance to the project owner and update returned leftover accordingly.\\n if (_leftoverDistributionAmount != 0) {\\n // Subtract the fee from the net leftover amount.\\n netLeftoverDistributionAmount =\\n _leftoverDistributionAmount -\\n (\\n _feeDiscount == JBConstants.MAX_FEE_DISCOUNT\\n ? 0\\n : _feeAmount(_leftoverDistributionAmount, _feePercent, _feeDiscount)\\n );\\n\\n // Transfer the amount to the project owner.\\n _transferFrom(address(this), _projectOwner, netLeftoverDistributionAmount);\\n }\\n }\\n\\n emit DistributePayouts(\\n _fundingCycle.configuration,\\n _fundingCycle.number,\\n _projectId,\\n _projectOwner,\\n _amount,\\n _distributedAmount,\\n _feeTaken,\\n netLeftoverDistributionAmount,\\n _metadata,\\n msg.sender\\n );\\n }\\n\\n /// @notice Allows a project to send funds from its overflow up to the preconfigured allowance.\\n /// @dev Only a project's owner or a designated operator can use its allowance.\\n /// @dev Incurs the protocol fee.\\n /// @param _projectId The ID of the project to use the allowance of.\\n /// @param _amount The amount of terminal tokens to use from this project's current allowance, as a fixed point number with the same amount of decimals as this terminal.\\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's overflow allowance currency.\\n /// @param _minReturnedTokens The minimum number of tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with 18 decimals.\\n /// @param _beneficiary The address to send the funds to.\\n /// @param _memo A memo to pass along to the emitted event.\\n /// @param _metadata Bytes to send along to the emitted event, if provided.\\n /// @return netDistributedAmount The amount of tokens that was distributed to the beneficiary, as a fixed point number with the same amount of decimals as the terminal.\\n function _useAllowanceOf(\\n uint256 _projectId,\\n uint256 _amount,\\n uint256 _currency,\\n uint256 _minReturnedTokens,\\n address payable _beneficiary,\\n string memory _memo,\\n bytes calldata _metadata\\n ) internal returns (uint256 netDistributedAmount) {\\n // Record the use of the allowance.\\n (\\n JBFundingCycle memory _fundingCycle,\\n uint256 _distributedAmount\\n ) = IJBSingleTokenPaymentTerminalStore3_1_1(store).recordUsedAllowanceOf(\\n _projectId,\\n _amount,\\n _currency\\n );\\n\\n // The amount being withdrawn must be at least as much as was expected.\\n if (_distributedAmount < _minReturnedTokens) revert INADEQUATE_DISTRIBUTION_AMOUNT();\\n\\n // Scoped section prevents stack too deep. `_fee`, `_projectOwner`, `_feeDiscount`, and `_netAmount` only used within scope.\\n {\\n // Keep a reference to the fee amount that was paid.\\n uint256 _feeTaken;\\n\\n // Keep a reference to the fee.\\n uint256 _feePercent = fee;\\n\\n // Get a reference to the project owner, which will receive tokens from paying the platform fee.\\n address _projectOwner = projects.ownerOf(_projectId);\\n\\n // Get the amount of discount that should be applied to any fees taken.\\n // 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.\\n uint256 _feeDiscount = _feePercent == 0 || isFeelessAddress[msg.sender]\\n ? JBConstants.MAX_FEE_DISCOUNT\\n : _currentFeeDiscount(_projectId, JBFeeType.ALLOWANCE);\\n\\n // Take a fee from the `_distributedAmount`, if needed.\\n _feeTaken = _feeDiscount == JBConstants.MAX_FEE_DISCOUNT\\n ? 0\\n : _takeFeeFrom(\\n _projectId,\\n _fundingCycle.shouldHoldFees(),\\n _distributedAmount,\\n _feePercent,\\n _projectOwner,\\n _feeDiscount\\n );\\n\\n unchecked {\\n // The net amount is the withdrawn amount without the fee.\\n netDistributedAmount = _distributedAmount - _feeTaken;\\n }\\n\\n // Transfer any remaining balance to the beneficiary.\\n if (netDistributedAmount != 0)\\n _transferFrom(address(this), _beneficiary, netDistributedAmount);\\n }\\n\\n emit UseAllowance(\\n _fundingCycle.configuration,\\n _fundingCycle.number,\\n _projectId,\\n _beneficiary,\\n _amount,\\n _distributedAmount,\\n netDistributedAmount,\\n _memo,\\n _metadata,\\n msg.sender\\n );\\n }\\n\\n /// @notice Pays out splits for a project's funding cycle configuration.\\n /// @param _projectId The ID of the project for which payout splits are being distributed.\\n /// @param _domain The domain of the splits to distribute the payout between.\\n /// @param _group The group of the splits to distribute the payout between.\\n /// @param _amount The total amount being distributed, as a fixed point number with the same number of decimals as this terminal.\\n /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE.\\n /// @param _feePercent The percent of fees to take, out of MAX_FEE.\\n /// @return If the leftover amount if the splits don't add up to 100%.\\n /// @return feeEligibleDistributionAmount The total amount of distributions that are eligible to have fees taken from.\\n function _distributeToPayoutSplitsOf(\\n uint256 _projectId,\\n uint256 _domain,\\n uint256 _group,\\n uint256 _amount,\\n uint256 _feePercent,\\n uint256 _feeDiscount\\n ) internal returns (uint256, uint256 feeEligibleDistributionAmount) {\\n // The total percentage available to split\\n uint256 _leftoverPercentage = JBConstants.SPLITS_TOTAL_PERCENT;\\n\\n // Get a reference to the project's payout splits.\\n JBSplit[] memory _splits = splitsStore.splitsOf(_projectId, _domain, _group);\\n\\n // Keep a reference to the split being iterated on.\\n JBSplit memory _split;\\n\\n // Transfer between all splits.\\n for (uint256 _i; _i < _splits.length; ) {\\n // Get a reference to the split being iterated on.\\n _split = _splits[_i];\\n\\n // The amount to send towards the split.\\n uint256 _payoutAmount = PRBMath.mulDiv(_amount, _split.percent, _leftoverPercentage);\\n\\n // The payout amount substracting any applicable incurred fees.\\n uint256 _netPayoutAmount = _distributeToPayoutSplit(\\n _split,\\n _projectId,\\n _group,\\n _payoutAmount,\\n _feePercent,\\n _feeDiscount\\n );\\n\\n // If the split allocator is set as feeless, this distribution is not eligible for a fee.\\n if (_netPayoutAmount != 0 && _netPayoutAmount != _payoutAmount)\\n feeEligibleDistributionAmount += _payoutAmount;\\n\\n if (_payoutAmount != 0) {\\n // Subtract from the amount to be sent to the beneficiary.\\n unchecked {\\n _amount -= _payoutAmount;\\n }\\n }\\n\\n unchecked {\\n // Decrement the leftover percentage.\\n _leftoverPercentage -= _split.percent;\\n }\\n\\n emit DistributeToPayoutSplit(\\n _projectId,\\n _domain,\\n _group,\\n _split,\\n _payoutAmount,\\n _netPayoutAmount,\\n msg.sender\\n );\\n\\n unchecked {\\n ++_i;\\n }\\n }\\n\\n return (_amount, feeEligibleDistributionAmount);\\n }\\n\\n /// @notice Pays out a split for a project's funding cycle configuration.\\n /// @param _split The split to distribute payouts to.\\n /// @param _amount The total amount being distributed to the split, as a fixed point number with the same number of decimals as this terminal.\\n /// @param _feePercent The percent of fees to take, out of MAX_FEE.\\n /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE.\\n /// @return netPayoutAmount The amount sent to the split after subtracting fees.\\n function _distributeToPayoutSplit(\\n JBSplit memory _split,\\n uint256 _projectId,\\n uint256 _group,\\n uint256 _amount,\\n uint256 _feePercent,\\n uint256 _feeDiscount\\n ) internal returns (uint256 netPayoutAmount) {\\n // By default, the net payout amount is the full amount. This will be adjusted if fees are taken.\\n netPayoutAmount = _amount;\\n\\n // If there's an allocator set, transfer to its `allocate` function.\\n if (_split.allocator != IJBSplitAllocator(address(0))) {\\n // This distribution is eligible for a fee since the funds are leaving this contract and the allocator isn't listed as feeless.\\n if (\\n _feeDiscount != JBConstants.MAX_FEE_DISCOUNT && !isFeelessAddress[address(_split.allocator)]\\n ) {\\n unchecked {\\n netPayoutAmount -= _feeAmount(_amount, _feePercent, _feeDiscount);\\n }\\n }\\n\\n // Trigger any inherited pre-transfer logic.\\n _beforeTransferTo(address(_split.allocator), netPayoutAmount);\\n\\n // Create the data to send to the allocator.\\n JBSplitAllocationData memory _data = JBSplitAllocationData(\\n token,\\n netPayoutAmount,\\n decimals,\\n _projectId,\\n _group,\\n _split\\n );\\n\\n // Trigger the allocator's `allocate` function.\\n bytes memory _reason;\\n\\n if (\\n ERC165Checker.supportsInterface(\\n address(_split.allocator),\\n type(IJBSplitAllocator).interfaceId\\n )\\n )\\n // If this terminal's token is ETH, send it in msg.value.\\n try\\n _split.allocator.allocate{value: token == JBTokens.ETH ? netPayoutAmount : 0}(_data)\\n {} catch (bytes memory __reason) {\\n _reason = __reason.length == 0 ? abi.encode('Allocate fail') : __reason;\\n }\\n else {\\n _reason = abi.encode('IERC165 fail');\\n }\\n\\n if (_reason.length != 0) {\\n // Revert the payout.\\n _revertTransferFrom(_projectId, address(_split.allocator), netPayoutAmount, _amount);\\n\\n // Set the net payout amount to 0 to signal the reversion.\\n netPayoutAmount = 0;\\n\\n emit PayoutReverted(_projectId, _split, _amount, _reason, msg.sender);\\n }\\n\\n // Otherwise, if a project is specified, make a payment to it.\\n } else if (_split.projectId != 0) {\\n // Get a reference to the Juicebox terminal being used.\\n IJBPaymentTerminal _terminal = directory.primaryTerminalOf(_split.projectId, token);\\n\\n // The project must have a terminal to send funds to.\\n if (_terminal == IJBPaymentTerminal(address(0))) {\\n // Set the net payout amount to 0 to signal the reversion.\\n netPayoutAmount = 0;\\n\\n // Revert the payout.\\n _revertTransferFrom(_projectId, address(0), 0, _amount);\\n\\n emit PayoutReverted(_projectId, _split, _amount, 'Terminal not found', msg.sender);\\n } else {\\n // This distribution is eligible for a fee since the funds are leaving this contract and the terminal isn't listed as feeless.\\n if (\\n _terminal != this &&\\n _feeDiscount != JBConstants.MAX_FEE_DISCOUNT &&\\n !isFeelessAddress[address(_terminal)]\\n ) {\\n unchecked {\\n netPayoutAmount -= _feeAmount(_amount, _feePercent, _feeDiscount);\\n }\\n }\\n\\n // Trigger any inherited pre-transfer logic.\\n _beforeTransferTo(address(_terminal), netPayoutAmount);\\n\\n // Add to balance if prefered.\\n if (_split.preferAddToBalance)\\n try\\n _terminal.addToBalanceOf{value: token == JBTokens.ETH ? netPayoutAmount : 0}(\\n _split.projectId,\\n netPayoutAmount,\\n token,\\n '',\\n // Send the projectId in the metadata as a referral.\\n bytes(abi.encodePacked(_projectId))\\n )\\n {} catch (bytes memory _reason) {\\n // Revert the payout.\\n _revertTransferFrom(_projectId, address(_terminal), netPayoutAmount, _amount);\\n\\n // Set the net payout amount to 0 to signal the reversion.\\n netPayoutAmount = 0;\\n\\n emit PayoutReverted(_projectId, _split, _amount, _reason, msg.sender);\\n }\\n else\\n try\\n _terminal.pay{value: token == JBTokens.ETH ? netPayoutAmount : 0}(\\n _split.projectId,\\n netPayoutAmount,\\n token,\\n _split.beneficiary != address(0) ? _split.beneficiary : msg.sender,\\n 0,\\n _split.preferClaimed,\\n '',\\n // Send the projectId in the metadata as a referral.\\n bytes(abi.encodePacked(_projectId))\\n )\\n {} catch (bytes memory _reason) {\\n // Revert the payout.\\n _revertTransferFrom(_projectId, address(_terminal), netPayoutAmount, _amount);\\n\\n // Set the net payout amount to 0 to signal the reversion.\\n netPayoutAmount = 0;\\n\\n emit PayoutReverted(_projectId, _split, _amount, _reason, msg.sender);\\n }\\n }\\n } else {\\n // This distribution is eligible for a fee since the funds are leaving this contract and the beneficiary isn't listed as feeless.\\n // Don't enforce feeless address for the beneficiary since the funds are leaving the ecosystem.\\n if (_feeDiscount != JBConstants.MAX_FEE_DISCOUNT) {\\n unchecked {\\n netPayoutAmount -= _feeAmount(_amount, _feePercent, _feeDiscount);\\n }\\n }\\n\\n // If there's a beneficiary, send the funds directly to the beneficiary. Otherwise send to the msg.sender.\\n _transferFrom(\\n address(this),\\n _split.beneficiary != address(0) ? _split.beneficiary : payable(msg.sender),\\n netPayoutAmount\\n );\\n }\\n }\\n\\n /// @notice Takes a fee into the platform's project, which has an id of _FEE_BENEFICIARY_PROJECT_ID.\\n /// @param _projectId The ID of the project having fees taken from.\\n /// @param _shouldHoldFees If fees should be tracked and held back.\\n /// @param _feePercent The percent of fees to take, out of MAX_FEE.\\n /// @param _amount The amount of the fee to take, as a floating point number with 18 decimals.\\n /// @param _beneficiary The address to mint the platforms tokens for.\\n /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE.\\n /// @return feeAmount The amount of the fee taken.\\n function _takeFeeFrom(\\n uint256 _projectId,\\n bool _shouldHoldFees,\\n uint256 _amount,\\n uint256 _feePercent,\\n address _beneficiary,\\n uint256 _feeDiscount\\n ) internal returns (uint256 feeAmount) {\\n feeAmount = _feeAmount(_amount, _feePercent, _feeDiscount);\\n\\n if (_shouldHoldFees) {\\n // Store the held fee.\\n _heldFeesOf[_projectId].push(\\n JBFee(_amount, uint32(_feePercent), uint32(_feeDiscount), _beneficiary)\\n );\\n\\n emit HoldFee(_projectId, _amount, _feePercent, _feeDiscount, _beneficiary, msg.sender);\\n } else {\\n // Process the fee.\\n _processFee(feeAmount, _beneficiary, _projectId); // Take the fee.\\n\\n emit ProcessFee(_projectId, feeAmount, false, _beneficiary, msg.sender);\\n }\\n }\\n\\n /// @notice Process a fee of the specified amount.\\n /// @param _amount The fee amount, as a floating point number with 18 decimals.\\n /// @param _beneficiary The address to mint the platform's tokens for.\\n /// @param _from The project ID the fee is being paid from.\\n function _processFee(uint256 _amount, address _beneficiary, uint256 _from) internal {\\n // Get the terminal for the protocol project.\\n IJBPaymentTerminal _terminal = directory.primaryTerminalOf(_FEE_BENEFICIARY_PROJECT_ID, token);\\n\\n // Trigger any inherited pre-transfer logic if funds will be transferred.\\n if (address(_terminal) != address(this)) _beforeTransferTo(address(_terminal), _amount);\\n\\n try\\n // Send the fee.\\n // If this terminal's token is ETH, send it in msg.value.\\n _terminal.pay{value: token == JBTokens.ETH ? _amount : 0}(\\n _FEE_BENEFICIARY_PROJECT_ID,\\n _amount,\\n token,\\n _beneficiary,\\n 0,\\n false,\\n '',\\n // Send the projectId in the metadata.\\n bytes(abi.encodePacked(_from))\\n )\\n {} catch (bytes memory _reason) {\\n _revertTransferFrom(\\n _from,\\n address(_terminal) != address(this) ? address(_terminal) : address(0),\\n address(_terminal) != address(this) ? _amount : 0,\\n _amount\\n );\\n emit FeeReverted(_from, _FEE_BENEFICIARY_PROJECT_ID, _amount, _reason, msg.sender);\\n }\\n }\\n\\n /// @notice Reverts an expected payout.\\n /// @param _projectId The ID of the project having paying out.\\n /// @param _expectedDestination The address the payout was expected to go to.\\n /// @param _allowanceAmount The amount that the destination has been allowed to use.\\n /// @param _depositAmount The amount of the payout as debited from the project's balance.\\n function _revertTransferFrom(\\n uint256 _projectId,\\n address _expectedDestination,\\n uint256 _allowanceAmount,\\n uint256 _depositAmount\\n ) internal {\\n // Cancel allowance if needed.\\n if (_allowanceAmount != 0) _cancelTransferTo(_expectedDestination, _allowanceAmount);\\n\\n // Add undistributed amount back to project's balance.\\n IJBSingleTokenPaymentTerminalStore3_1_1(store).recordAddedBalanceFor(\\n _projectId,\\n _depositAmount\\n );\\n }\\n\\n /// @notice Contribute tokens to a project.\\n /// @param _amount The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place.\\n /// @param _payer The address making the payment.\\n /// @param _projectId The ID of the project being paid.\\n /// @param _beneficiary The address to mint tokens for and pass along to the funding cycle's data source and delegate.\\n /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal.\\n /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\\n /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\\n /// @return beneficiaryTokenCount The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals.\\n function _pay(\\n uint256 _amount,\\n address _payer,\\n uint256 _projectId,\\n address _beneficiary,\\n uint256 _minReturnedTokens,\\n bool _preferClaimedTokens,\\n string memory _memo,\\n bytes memory _metadata\\n ) internal returns (uint256 beneficiaryTokenCount) {\\n // Cant send tokens to the zero address.\\n if (_beneficiary == address(0)) revert PAY_TO_ZERO_ADDRESS();\\n\\n // Define variables that will be needed outside the scoped section below.\\n // Keep a reference to the funding cycle during which the payment is being made.\\n JBFundingCycle memory _fundingCycle;\\n\\n // Scoped section prevents stack too deep. `_delegateAllocations` and `_tokenCount` only used within scope.\\n {\\n JBPayDelegateAllocation3_1_1[] memory _delegateAllocations;\\n uint256 _tokenCount;\\n\\n // Bundle the amount info into a JBTokenAmount struct.\\n JBTokenAmount memory _bundledAmount = JBTokenAmount(token, _amount, decimals, currency);\\n\\n // Record the payment.\\n (\\n _fundingCycle,\\n _tokenCount,\\n _delegateAllocations,\\n _memo\\n ) = IJBSingleTokenPaymentTerminalStore3_1_1(store).recordPaymentFrom(\\n _payer,\\n _bundledAmount,\\n _projectId,\\n baseWeightCurrency,\\n _beneficiary,\\n _memo,\\n _metadata\\n );\\n\\n // Mint the tokens if needed.\\n if (_tokenCount != 0)\\n // Set token count to be the number of tokens minted for the beneficiary instead of the total amount.\\n beneficiaryTokenCount = IJBController(directory.controllerOf(_projectId)).mintTokensOf(\\n _projectId,\\n _tokenCount,\\n _beneficiary,\\n '',\\n _preferClaimedTokens,\\n true\\n );\\n\\n // The token count for the beneficiary must be greater than or equal to the minimum expected.\\n if (beneficiaryTokenCount < _minReturnedTokens) revert INADEQUATE_TOKEN_COUNT();\\n\\n // If delegate allocations were specified by the data source, fulfill them.\\n if (_delegateAllocations.length != 0) {\\n JBDidPayData3_1_1 memory _data = JBDidPayData3_1_1(\\n _payer,\\n _projectId,\\n _fundingCycle.configuration,\\n _bundledAmount,\\n JBTokenAmount(token, 0, decimals, currency),\\n beneficiaryTokenCount,\\n _beneficiary,\\n _preferClaimedTokens,\\n _memo,\\n bytes(''),\\n _metadata\\n );\\n\\n // Get a reference to the number of delegates to allocate to.\\n uint256 _numDelegates = _delegateAllocations.length;\\n\\n // Keep a reference to the allocation.\\n JBPayDelegateAllocation3_1_1 memory _delegateAllocation;\\n\\n for (uint256 _i; _i < _numDelegates; ) {\\n // Get a reference to the delegate being iterated on.\\n _delegateAllocation = _delegateAllocations[_i];\\n\\n // Trigger any inherited pre-transfer logic.\\n _beforeTransferTo(address(_delegateAllocation.delegate), _delegateAllocation.amount);\\n\\n // Pass the correct token forwardedAmount to the delegate\\n _data.forwardedAmount.value = _delegateAllocation.amount;\\n\\n // Pass the correct metadata from the data source.\\n _data.dataSourceMetadata = _delegateAllocation.metadata;\\n\\n _delegateAllocation.delegate.didPay{\\n value: token == JBTokens.ETH ? _delegateAllocation.amount : 0\\n }(_data);\\n\\n emit DelegateDidPay(\\n _delegateAllocation.delegate,\\n _data,\\n _delegateAllocation.amount,\\n msg.sender\\n );\\n\\n unchecked {\\n ++_i;\\n }\\n }\\n }\\n }\\n\\n emit Pay(\\n _fundingCycle.configuration,\\n _fundingCycle.number,\\n _projectId,\\n _payer,\\n _beneficiary,\\n _amount,\\n beneficiaryTokenCount,\\n _memo,\\n _metadata,\\n msg.sender\\n );\\n }\\n\\n /// @notice Receives funds belonging to the specified project.\\n /// @param _projectId The ID of the project to which the funds received belong.\\n /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\\n /// @param _shouldRefundHeldFees A flag indicating if held fees should be refunded based on the amount being added.\\n /// @param _memo A memo to pass along to the emitted event.\\n /// @param _metadata Extra data to pass along to the emitted event.\\n function _addToBalanceOf(\\n uint256 _projectId,\\n uint256 _amount,\\n bool _shouldRefundHeldFees,\\n string memory _memo,\\n bytes memory _metadata\\n ) internal {\\n // Refund any held fees to make sure the project doesn't pay double for funds going in and out of the protocol.\\n uint256 _refundedFees = _shouldRefundHeldFees ? _refundHeldFees(_projectId, _amount) : 0;\\n\\n // Record the added funds with any refunded fees.\\n IJBSingleTokenPaymentTerminalStore3_1_1(store).recordAddedBalanceFor(\\n _projectId,\\n _amount + _refundedFees\\n );\\n\\n emit AddToBalance(_projectId, _amount, _refundedFees, _memo, _metadata, msg.sender);\\n }\\n\\n /// @notice Refund fees based on the specified amount.\\n /// @param _projectId The project for which fees are being refunded.\\n /// @param _amount The amount to base the refund on, as a fixed point number with the same amount of decimals as this terminal.\\n /// @return refundedFees How much fees were refunded, as a fixed point number with the same number of decimals as this terminal\\n function _refundHeldFees(\\n uint256 _projectId,\\n uint256 _amount\\n ) internal returns (uint256 refundedFees) {\\n // Get a reference to the project's held fees.\\n JBFee[] memory _heldFees = _heldFeesOf[_projectId];\\n\\n // Delete the current held fees.\\n delete _heldFeesOf[_projectId];\\n\\n // Get a reference to the leftover amount once all fees have been settled.\\n uint256 leftoverAmount = _amount;\\n\\n // Push length in stack\\n uint256 _heldFeesLength = _heldFees.length;\\n\\n // Process each fee.\\n for (uint256 _i; _i < _heldFeesLength; ) {\\n if (leftoverAmount == 0) _heldFeesOf[_projectId].push(_heldFees[_i]);\\n else if (leftoverAmount >= _heldFees[_i].amount) {\\n unchecked {\\n leftoverAmount = leftoverAmount - _heldFees[_i].amount;\\n refundedFees += (\\n _heldFees[_i].fee == 0 || _heldFees[_i].feeDiscount == JBConstants.MAX_FEE_DISCOUNT\\n ? 0\\n : _feeAmount(_heldFees[_i].amount, _heldFees[_i].fee, _heldFees[_i].feeDiscount)\\n );\\n }\\n } else {\\n unchecked {\\n _heldFeesOf[_projectId].push(\\n JBFee(\\n _heldFees[_i].amount - leftoverAmount,\\n _heldFees[_i].fee,\\n _heldFees[_i].feeDiscount,\\n _heldFees[_i].beneficiary\\n )\\n );\\n refundedFees += (\\n _heldFees[_i].fee == 0 || _heldFees[_i].feeDiscount == JBConstants.MAX_FEE_DISCOUNT\\n ? 0\\n : _feeAmount(leftoverAmount, _heldFees[_i].fee, _heldFees[_i].feeDiscount)\\n );\\n }\\n leftoverAmount = 0;\\n }\\n\\n unchecked {\\n ++_i;\\n }\\n }\\n\\n emit RefundHeldFees(_projectId, _amount, refundedFees, leftoverAmount, msg.sender);\\n }\\n\\n /// @notice Returns the fee amount based on the provided amount for the specified project.\\n /// @param _amount The amount that the fee is based on, as a fixed point number with the same amount of decimals as this terminal.\\n /// @param _fee The percentage of the fee, out of MAX_FEE.\\n /// @param _feeDiscount The percentage discount that should be applied out of the max amount, out of MAX_FEE_DISCOUNT.\\n /// @return The amount of the fee, as a fixed point number with the same amount of decimals as this terminal.\\n function _feeAmount(\\n uint256 _amount,\\n uint256 _fee,\\n uint256 _feeDiscount\\n ) internal pure returns (uint256) {\\n // Calculate the discounted fee.\\n uint256 _discountedFee = _fee -\\n PRBMath.mulDiv(_fee, _feeDiscount, JBConstants.MAX_FEE_DISCOUNT);\\n\\n // The amount of tokens from the `_amount` to pay as a fee.\\n return\\n _amount - PRBMath.mulDiv(_amount, JBConstants.MAX_FEE, _discountedFee + JBConstants.MAX_FEE);\\n }\\n\\n /// @notice Get the fee discount from the fee gauge for the specified project.\\n /// @param _projectId The ID of the project to get a fee discount for.\\n /// @param _feeType The type of fee the discount is being applied to.\\n /// @return feeDiscount The fee discount, which should be interpreted as a percentage out MAX_FEE_DISCOUNT.\\n function _currentFeeDiscount(\\n uint256 _projectId,\\n JBFeeType _feeType\\n ) internal view returns (uint256) {\\n // Can't take a fee if the protocol project doesn't have a terminal that accepts the token.\\n if (\\n directory.primaryTerminalOf(_FEE_BENEFICIARY_PROJECT_ID, token) ==\\n IJBPaymentTerminal(address(0))\\n ) return JBConstants.MAX_FEE_DISCOUNT;\\n\\n // Get the fee discount.\\n if (feeGauge != address(0))\\n // If the guage reverts, keep the discount at 0.\\n try IJBFeeGauge3_1(feeGauge).currentDiscountFor(_projectId, _feeType) returns (\\n uint256 discount\\n ) {\\n // If the fee discount is greater than the max, we ignore the return value\\n if (discount <= JBConstants.MAX_FEE_DISCOUNT) return discount;\\n } catch {\\n return 0;\\n }\\n\\n return 0;\\n }\\n}\\n\",\"keccak256\":\"0xac6578a64c8c0544d26442921ae6b577f86e3f18e6338c7eda9ee2f5eb2c927d\",\"license\":\"MIT\"},\"contracts/abstract/JBSingleTokenPaymentTerminal.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.16;\\n\\nimport {ERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol';\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol';\\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\\nimport {IJBSingleTokenPaymentTerminal} from './../interfaces/IJBSingleTokenPaymentTerminal.sol';\\n\\n/// @notice Generic terminal managing all inflows of funds into the protocol ecosystem for one token.\\nabstract contract JBSingleTokenPaymentTerminal is ERC165, IJBSingleTokenPaymentTerminal {\\n //*********************************************************************//\\n // ---------------- public immutable stored properties --------------- //\\n //*********************************************************************//\\n\\n /// @notice The token that this terminal accepts.\\n address public immutable override token;\\n\\n /// @notice The number of decimals the token fixed point amounts are expected to have.\\n uint256 public immutable override decimals;\\n\\n /// @notice The currency to use when resolving price feeds for this terminal.\\n uint256 public immutable override currency;\\n\\n //*********************************************************************//\\n // ------------------------- external views -------------------------- //\\n //*********************************************************************//\\n\\n /// @notice A flag indicating if this terminal accepts the specified token.\\n /// @param _token The token to check if this terminal accepts or not.\\n /// @param _projectId The project ID to check for token acceptance.\\n /// @return The flag.\\n function acceptsToken(address _token, uint256 _projectId) external view override returns (bool) {\\n _projectId; // Prevents unused var compiler and natspec complaints.\\n\\n return _token == token;\\n }\\n\\n /// @notice The decimals that should be used in fixed number accounting for the specified token.\\n /// @param _token The token to check for the decimals of.\\n /// @return The number of decimals for the token.\\n function decimalsForToken(address _token) external view override returns (uint256) {\\n _token; // Prevents unused var compiler and natspec complaints.\\n\\n return decimals;\\n }\\n\\n /// @notice The currency that should be used for the specified token.\\n /// @param _token The token to check for the currency of.\\n /// @return The currency index.\\n function currencyForToken(address _token) external view override returns (uint256) {\\n _token; // Prevents unused var compiler and natspec complaints.\\n\\n return currency;\\n }\\n\\n //*********************************************************************//\\n // -------------------------- public views --------------------------- //\\n //*********************************************************************//\\n\\n /// @notice Indicates if this contract adheres to the specified interface.\\n /// @dev See {IERC165-supportsInterface}.\\n /// @param _interfaceId The ID of the interface to check for adherance to.\\n /// @return A flag indicating if the provided interface ID is supported.\\n function supportsInterface(\\n bytes4 _interfaceId\\n ) public view virtual override(ERC165, IERC165) returns (bool) {\\n return\\n _interfaceId == type(IJBPaymentTerminal).interfaceId ||\\n _interfaceId == type(IJBSingleTokenPaymentTerminal).interfaceId ||\\n super.supportsInterface(_interfaceId);\\n }\\n\\n //*********************************************************************//\\n // -------------------------- constructor ---------------------------- //\\n //*********************************************************************//\\n\\n /// @param _token The token that this terminal manages.\\n /// @param _decimals The number of decimals the token fixed point amounts are expected to have.\\n /// @param _currency The currency that this terminal's token adheres to for price feeds.\\n constructor(address _token, uint256 _decimals, uint256 _currency) {\\n token = _token;\\n decimals = _decimals;\\n currency = _currency;\\n }\\n}\\n\",\"keccak256\":\"0x27bd0b9e8170f16bc1318d6dee16aa3273e7d8f6cb8b80d7d905d0dce93e307c\",\"license\":\"MIT\"},\"contracts/enums/JBBallotState.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nenum JBBallotState {\\n Active,\\n Approved,\\n Failed\\n}\\n\",\"keccak256\":\"0x891fcac63470398b3a11239da7feba6b07d640809fcefd2404303b823d7378f8\",\"license\":\"MIT\"},\"contracts/enums/JBFeeType.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nenum JBFeeType {\\n PAYOUT,\\n ALLOWANCE,\\n REDEMPTION\\n}\\n\",\"keccak256\":\"0x02418e9bd3cce5ccf5a76822909558c61672719767bffe16490256268b05cb22\",\"license\":\"MIT\"},\"contracts/interfaces/IJBAllowanceTerminal3_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IJBAllowanceTerminal3_1 {\\n function useAllowanceOf(\\n uint256 projectId,\\n uint256 amount,\\n uint256 currency,\\n address token,\\n uint256 minReturnedTokens,\\n address payable beneficiary,\\n string calldata memo,\\n bytes calldata metadata\\n ) external returns (uint256 netDistributedAmount);\\n}\\n\",\"keccak256\":\"0x3d9f7edf01473dd1bf444c2c9c2cae93e5980e17134e77efd50ad1723fa66559\",\"license\":\"MIT\"},\"contracts/interfaces/IJBController.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\\nimport {JBBallotState} from './../enums/JBBallotState.sol';\\nimport {JBFundAccessConstraints} from './../structs/JBFundAccessConstraints.sol';\\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\\nimport {JBFundingCycleData} from './../structs/JBFundingCycleData.sol';\\nimport {JBFundingCycleMetadata} from './../structs/JBFundingCycleMetadata.sol';\\nimport {JBGroupedSplits} from './../structs/JBGroupedSplits.sol';\\nimport {JBProjectMetadata} from './../structs/JBProjectMetadata.sol';\\nimport {JBSplit} from './../structs/JBSplit.sol';\\nimport {IJBDirectory} from './IJBDirectory.sol';\\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\\nimport {IJBMigratable} from './IJBMigratable.sol';\\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\\nimport {IJBProjects} from './IJBProjects.sol';\\nimport {IJBSplitsStore} from './IJBSplitsStore.sol';\\nimport {IJBTokenStore} from './IJBTokenStore.sol';\\n\\ninterface IJBController is IERC165 {\\n event LaunchProject(uint256 configuration, uint256 projectId, string memo, address caller);\\n\\n event LaunchFundingCycles(uint256 configuration, uint256 projectId, string memo, address caller);\\n\\n event ReconfigureFundingCycles(\\n uint256 configuration,\\n uint256 projectId,\\n string memo,\\n address caller\\n );\\n\\n event SetFundAccessConstraints(\\n uint256 indexed fundingCycleConfiguration,\\n uint256 indexed fundingCycleNumber,\\n uint256 indexed projectId,\\n JBFundAccessConstraints constraints,\\n address caller\\n );\\n\\n event DistributeReservedTokens(\\n uint256 indexed fundingCycleConfiguration,\\n uint256 indexed fundingCycleNumber,\\n uint256 indexed projectId,\\n address beneficiary,\\n uint256 tokenCount,\\n uint256 beneficiaryTokenCount,\\n string memo,\\n address caller\\n );\\n\\n event DistributeToReservedTokenSplit(\\n uint256 indexed projectId,\\n uint256 indexed domain,\\n uint256 indexed group,\\n JBSplit split,\\n uint256 tokenCount,\\n address caller\\n );\\n\\n event MintTokens(\\n address indexed beneficiary,\\n uint256 indexed projectId,\\n uint256 tokenCount,\\n uint256 beneficiaryTokenCount,\\n string memo,\\n uint256 reservedRate,\\n address caller\\n );\\n\\n event BurnTokens(\\n address indexed holder,\\n uint256 indexed projectId,\\n uint256 tokenCount,\\n string memo,\\n address caller\\n );\\n\\n event Migrate(uint256 indexed projectId, IJBMigratable to, address caller);\\n\\n event PrepMigration(uint256 indexed projectId, address from, address caller);\\n\\n function projects() external view returns (IJBProjects);\\n\\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\\n\\n function tokenStore() external view returns (IJBTokenStore);\\n\\n function splitsStore() external view returns (IJBSplitsStore);\\n\\n function directory() external view returns (IJBDirectory);\\n\\n function reservedTokenBalanceOf(\\n uint256 projectId,\\n uint256 reservedRate\\n ) external view returns (uint256);\\n\\n function distributionLimitOf(\\n uint256 projectId,\\n uint256 configuration,\\n IJBPaymentTerminal terminal,\\n address token\\n ) external view returns (uint256 distributionLimit, uint256 distributionLimitCurrency);\\n\\n function overflowAllowanceOf(\\n uint256 projectId,\\n uint256 configuration,\\n IJBPaymentTerminal terminal,\\n address token\\n ) external view returns (uint256 overflowAllowance, uint256 overflowAllowanceCurrency);\\n\\n function totalOutstandingTokensOf(\\n uint256 projectId,\\n uint256 reservedRate\\n ) external view returns (uint256);\\n\\n function getFundingCycleOf(\\n uint256 projectId,\\n uint256 configuration\\n )\\n external\\n view\\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata);\\n\\n function latestConfiguredFundingCycleOf(\\n uint256 projectId\\n )\\n external\\n view\\n returns (JBFundingCycle memory, JBFundingCycleMetadata memory metadata, JBBallotState);\\n\\n function currentFundingCycleOf(\\n uint256 projectId\\n )\\n external\\n view\\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata);\\n\\n function queuedFundingCycleOf(\\n uint256 projectId\\n )\\n external\\n view\\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata);\\n\\n function launchProjectFor(\\n address owner,\\n JBProjectMetadata calldata projectMetadata,\\n JBFundingCycleData calldata data,\\n JBFundingCycleMetadata calldata metadata,\\n uint256 mustStartAtOrAfter,\\n JBGroupedSplits[] memory groupedSplits,\\n JBFundAccessConstraints[] memory fundAccessConstraints,\\n IJBPaymentTerminal[] memory terminals,\\n string calldata memo\\n ) external returns (uint256 projectId);\\n\\n function launchFundingCyclesFor(\\n uint256 projectId,\\n JBFundingCycleData calldata data,\\n JBFundingCycleMetadata calldata metadata,\\n uint256 mustStartAtOrAfter,\\n JBGroupedSplits[] memory groupedSplits,\\n JBFundAccessConstraints[] memory fundAccessConstraints,\\n IJBPaymentTerminal[] memory terminals,\\n string calldata memo\\n ) external returns (uint256 configuration);\\n\\n function reconfigureFundingCyclesOf(\\n uint256 projectId,\\n JBFundingCycleData calldata data,\\n JBFundingCycleMetadata calldata metadata,\\n uint256 mustStartAtOrAfter,\\n JBGroupedSplits[] memory groupedSplits,\\n JBFundAccessConstraints[] memory fundAccessConstraints,\\n string calldata memo\\n ) external returns (uint256);\\n\\n function mintTokensOf(\\n uint256 projectId,\\n uint256 tokenCount,\\n address beneficiary,\\n string calldata memo,\\n bool preferClaimedTokens,\\n bool useReservedRate\\n ) external returns (uint256 beneficiaryTokenCount);\\n\\n function burnTokensOf(\\n address holder,\\n uint256 projectId,\\n uint256 tokenCount,\\n string calldata memo,\\n bool preferClaimedTokens\\n ) external;\\n\\n function distributeReservedTokensOf(\\n uint256 projectId,\\n string memory memo\\n ) external returns (uint256);\\n\\n function migrate(uint256 projectId, IJBMigratable to) external;\\n}\\n\",\"keccak256\":\"0x6ebcb31173eff32f16f2f1fa6979a9dad0d7fac51e34441fafffa5e097ad507f\",\"license\":\"MIT\"},\"contracts/interfaces/IJBDirectory.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\\nimport {IJBProjects} from './IJBProjects.sol';\\n\\ninterface IJBDirectory {\\n event SetController(uint256 indexed projectId, address indexed controller, address caller);\\n\\n event AddTerminal(uint256 indexed projectId, IJBPaymentTerminal indexed terminal, address caller);\\n\\n event SetTerminals(uint256 indexed projectId, IJBPaymentTerminal[] terminals, address caller);\\n\\n event SetPrimaryTerminal(\\n uint256 indexed projectId,\\n address indexed token,\\n IJBPaymentTerminal indexed terminal,\\n address caller\\n );\\n\\n event SetIsAllowedToSetFirstController(address indexed addr, bool indexed flag, address caller);\\n\\n function projects() external view returns (IJBProjects);\\n\\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\\n\\n function controllerOf(uint256 projectId) external view returns (address);\\n\\n function isAllowedToSetFirstController(address account) external view returns (bool);\\n\\n function terminalsOf(uint256 projectId) external view returns (IJBPaymentTerminal[] memory);\\n\\n function isTerminalOf(\\n uint256 projectId,\\n IJBPaymentTerminal terminal\\n ) external view returns (bool);\\n\\n function primaryTerminalOf(\\n uint256 projectId,\\n address token\\n ) external view returns (IJBPaymentTerminal);\\n\\n function setControllerOf(uint256 projectId, address controller) external;\\n\\n function setTerminalsOf(uint256 projectId, IJBPaymentTerminal[] calldata terminals) external;\\n\\n function setPrimaryTerminalOf(\\n uint256 projectId,\\n address token,\\n IJBPaymentTerminal terminal\\n ) external;\\n\\n function setIsAllowedToSetFirstController(address account, bool flag) external;\\n}\\n\",\"keccak256\":\"0x490d5fe691ee7d9c9179fa19964de279882176513d92f3efc0aa98dc34799d1c\",\"license\":\"MIT\"},\"contracts/interfaces/IJBFeeGauge3_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBFeeType} from './../enums/JBFeeType.sol';\\n\\ninterface IJBFeeGauge3_1 {\\n function currentDiscountFor(uint256 projectId, JBFeeType feeType) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0xcf64e4b203422b50c968e890e3cf8621b63014e59dc8be25f13884c316f95266\",\"license\":\"MIT\"},\"contracts/interfaces/IJBFeeHoldingTerminal.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IJBFeeHoldingTerminal {\\n function addToBalanceOf(\\n uint256 projectId,\\n uint256 amount,\\n address token,\\n bool shouldRefundHeldFees,\\n string calldata memo,\\n bytes calldata metadata\\n ) external payable;\\n}\\n\",\"keccak256\":\"0xdda2332beec8a4f7f5ecd45a660b11796516933998b397c5d05ae639b5755454\",\"license\":\"MIT\"},\"contracts/interfaces/IJBFundingCycleBallot.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\\nimport {JBBallotState} from './../enums/JBBallotState.sol';\\n\\ninterface IJBFundingCycleBallot is IERC165 {\\n function duration() external view returns (uint256);\\n\\n function stateOf(\\n uint256 projectId,\\n uint256 configuration,\\n uint256 start\\n ) external view returns (JBBallotState);\\n}\\n\",\"keccak256\":\"0x729b4a700618f890e434d31ef9252e1cce9d0473fe7f8f070872df5b348bed23\",\"license\":\"MIT\"},\"contracts/interfaces/IJBFundingCycleStore.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBBallotState} from './../enums/JBBallotState.sol';\\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\\nimport {JBFundingCycleData} from './../structs/JBFundingCycleData.sol';\\n\\ninterface IJBFundingCycleStore {\\n event Configure(\\n uint256 indexed configuration,\\n uint256 indexed projectId,\\n JBFundingCycleData data,\\n uint256 metadata,\\n uint256 mustStartAtOrAfter,\\n address caller\\n );\\n\\n event Init(uint256 indexed configuration, uint256 indexed projectId, uint256 indexed basedOn);\\n\\n function latestConfigurationOf(uint256 projectId) external view returns (uint256);\\n\\n function get(\\n uint256 projectId,\\n uint256 configuration\\n ) external view returns (JBFundingCycle memory);\\n\\n function latestConfiguredOf(\\n uint256 projectId\\n ) external view returns (JBFundingCycle memory fundingCycle, JBBallotState ballotState);\\n\\n function queuedOf(uint256 projectId) external view returns (JBFundingCycle memory fundingCycle);\\n\\n function currentOf(uint256 projectId) external view returns (JBFundingCycle memory fundingCycle);\\n\\n function currentBallotStateOf(uint256 projectId) external view returns (JBBallotState);\\n\\n function configureFor(\\n uint256 projectId,\\n JBFundingCycleData calldata data,\\n uint256 metadata,\\n uint256 mustStartAtOrAfter\\n ) external returns (JBFundingCycle memory fundingCycle);\\n}\\n\",\"keccak256\":\"0x524350f6c6fcb45eaf927f4e6d13cd2f5029c2b858233bb9a338fe411ce34dab\",\"license\":\"MIT\"},\"contracts/interfaces/IJBMigratable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IJBMigratable {\\n function prepForMigrationOf(uint256 projectId, address from) external;\\n}\\n\",\"keccak256\":\"0xdee578477bbb7a66e9a1735e45a7795e95cfd374d85f55b61b3302476844c418\",\"license\":\"MIT\"},\"contracts/interfaces/IJBOperatable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBOperatorStore} from './IJBOperatorStore.sol';\\n\\ninterface IJBOperatable {\\n function operatorStore() external view returns (IJBOperatorStore);\\n}\\n\",\"keccak256\":\"0xe083d0c1b181e5c38cf3f03f97dd782f913710bf8cc54411eb4b6e7ec4c5a0c8\",\"license\":\"MIT\"},\"contracts/interfaces/IJBOperatorStore.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBOperatorData} from './../structs/JBOperatorData.sol';\\n\\ninterface IJBOperatorStore {\\n event SetOperator(\\n address indexed operator,\\n address indexed account,\\n uint256 indexed domain,\\n uint256[] permissionIndexes,\\n uint256 packed\\n );\\n\\n function permissionsOf(\\n address operator,\\n address account,\\n uint256 domain\\n ) external view returns (uint256);\\n\\n function hasPermission(\\n address operator,\\n address account,\\n uint256 domain,\\n uint256 permissionIndex\\n ) external view returns (bool);\\n\\n function hasPermissions(\\n address operator,\\n address account,\\n uint256 domain,\\n uint256[] calldata permissionIndexes\\n ) external view returns (bool);\\n\\n function setOperator(JBOperatorData calldata operatorData) external;\\n\\n function setOperators(JBOperatorData[] calldata operatorData) external;\\n}\\n\",\"keccak256\":\"0xb6ce539d040601d7e4b1cec567c64d93e5b14d5fa249e04dd67cf222c4431678\",\"license\":\"MIT\"},\"contracts/interfaces/IJBPayDelegate.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\\nimport {JBDidPayData} from './../structs/JBDidPayData.sol';\\n\\n/// @title Pay delegate\\n/// @notice Delegate called after JBTerminal.pay(..) logic completion (if passed by the funding cycle datasource)\\ninterface IJBPayDelegate is IERC165 {\\n /// @notice This function is called by JBPaymentTerminal.pay(..), after the execution of its logic\\n /// @dev Critical business logic should be protected by an appropriate access control\\n /// @param data the data passed by the terminal, as a JBDidPayData struct:\\n function didPay(JBDidPayData calldata data) external payable;\\n}\\n\",\"keccak256\":\"0x2321bc8e990c5e2cb4236e0ca68e7e556306b6aa3ba10fa19ff018039d6d1a02\",\"license\":\"MIT\"},\"contracts/interfaces/IJBPayDelegate3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\\nimport {JBDidPayData3_1_1} from './../structs/JBDidPayData3_1_1.sol';\\n\\n/// @title Pay delegate\\n/// @notice Delegate called after JBTerminal.pay(..) logic completion (if passed by the funding cycle datasource)\\ninterface IJBPayDelegate3_1_1 is IERC165 {\\n /// @notice This function is called by JBPaymentTerminal.pay(..), after the execution of its logic\\n /// @dev Critical business logic should be protected by an appropriate access control\\n /// @param data the data passed by the terminal, as a JBDidPayData3_1_1 struct:\\n function didPay(JBDidPayData3_1_1 calldata data) external payable;\\n}\\n\",\"keccak256\":\"0x9448d24cd9c559b44c468c6a76d850f6eaadf31446db903092a2f32503a67294\",\"license\":\"MIT\"},\"contracts/interfaces/IJBPaymentTerminal.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\\n\\ninterface IJBPaymentTerminal is IERC165 {\\n function acceptsToken(address token, uint256 projectId) external view returns (bool);\\n\\n function currencyForToken(address token) external view returns (uint256);\\n\\n function decimalsForToken(address token) external view returns (uint256);\\n\\n // Return value must be a fixed point number with 18 decimals.\\n function currentEthOverflowOf(uint256 projectId) external view returns (uint256);\\n\\n function pay(\\n uint256 projectId,\\n uint256 amount,\\n address token,\\n address beneficiary,\\n uint256 minReturnedTokens,\\n bool preferClaimedTokens,\\n string calldata memo,\\n bytes calldata metadata\\n ) external payable returns (uint256 beneficiaryTokenCount);\\n\\n function addToBalanceOf(\\n uint256 projectId,\\n uint256 amount,\\n address token,\\n string calldata memo,\\n bytes calldata metadata\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x273bc1fa373fac08e5635fce7d38fd92e9fabba353568b3f7a5be54c01fe4d27\",\"license\":\"MIT\"},\"contracts/interfaces/IJBPayoutRedemptionPaymentTerminal3_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBFee} from './../structs/JBFee.sol';\\nimport {IJBAllowanceTerminal3_1} from './IJBAllowanceTerminal3_1.sol';\\nimport {IJBDirectory} from './IJBDirectory.sol';\\nimport {IJBFeeHoldingTerminal} from './IJBFeeHoldingTerminal.sol';\\nimport {IJBPayDelegate} from './IJBPayDelegate.sol';\\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\\nimport {IJBPayoutTerminal3_1} from './IJBPayoutTerminal3_1.sol';\\nimport {IJBPrices} from './IJBPrices.sol';\\nimport {IJBProjects} from './IJBProjects.sol';\\nimport {IJBRedemptionDelegate} from './IJBRedemptionDelegate.sol';\\nimport {IJBRedemptionTerminal} from './IJBRedemptionTerminal.sol';\\nimport {IJBSplitsStore} from './IJBSplitsStore.sol';\\nimport {JBDidPayData} from './../structs/JBDidPayData.sol';\\nimport {JBDidRedeemData} from './../structs/JBDidRedeemData.sol';\\nimport {JBSplit} from './../structs/JBSplit.sol';\\n\\ninterface IJBPayoutRedemptionPaymentTerminal3_1 is\\n IJBPaymentTerminal,\\n IJBPayoutTerminal3_1,\\n IJBAllowanceTerminal3_1,\\n IJBRedemptionTerminal,\\n IJBFeeHoldingTerminal\\n{\\n event AddToBalance(\\n uint256 indexed projectId,\\n uint256 amount,\\n uint256 refundedFees,\\n string memo,\\n bytes metadata,\\n address caller\\n );\\n\\n event Migrate(\\n uint256 indexed projectId,\\n IJBPaymentTerminal indexed to,\\n uint256 amount,\\n address caller\\n );\\n\\n event DistributePayouts(\\n uint256 indexed fundingCycleConfiguration,\\n uint256 indexed fundingCycleNumber,\\n uint256 indexed projectId,\\n address beneficiary,\\n uint256 amount,\\n uint256 distributedAmount,\\n uint256 fee,\\n uint256 beneficiaryDistributionAmount,\\n bytes metadata,\\n address caller\\n );\\n\\n event UseAllowance(\\n uint256 indexed fundingCycleConfiguration,\\n uint256 indexed fundingCycleNumber,\\n uint256 indexed projectId,\\n address beneficiary,\\n uint256 amount,\\n uint256 distributedAmount,\\n uint256 netDistributedamount,\\n string memo,\\n bytes metadata,\\n address caller\\n );\\n\\n event HoldFee(\\n uint256 indexed projectId,\\n uint256 indexed amount,\\n uint256 indexed fee,\\n uint256 feeDiscount,\\n address beneficiary,\\n address caller\\n );\\n\\n event ProcessFee(\\n uint256 indexed projectId,\\n uint256 indexed amount,\\n bool indexed wasHeld,\\n address beneficiary,\\n address caller\\n );\\n\\n event RefundHeldFees(\\n uint256 indexed projectId,\\n uint256 indexed amount,\\n uint256 indexed refundedFees,\\n uint256 leftoverAmount,\\n address caller\\n );\\n\\n event Pay(\\n uint256 indexed fundingCycleConfiguration,\\n uint256 indexed fundingCycleNumber,\\n uint256 indexed projectId,\\n address payer,\\n address beneficiary,\\n uint256 amount,\\n uint256 beneficiaryTokenCount,\\n string memo,\\n bytes metadata,\\n address caller\\n );\\n\\n event DelegateDidPay(\\n IJBPayDelegate indexed delegate,\\n JBDidPayData data,\\n uint256 delegatedAmount,\\n address caller\\n );\\n\\n event RedeemTokens(\\n uint256 indexed fundingCycleConfiguration,\\n uint256 indexed fundingCycleNumber,\\n uint256 indexed projectId,\\n address holder,\\n address beneficiary,\\n uint256 tokenCount,\\n uint256 reclaimedAmount,\\n string memo,\\n bytes metadata,\\n address caller\\n );\\n\\n event DelegateDidRedeem(\\n IJBRedemptionDelegate indexed delegate,\\n JBDidRedeemData data,\\n uint256 delegatedAmount,\\n address caller\\n );\\n\\n event DistributeToPayoutSplit(\\n uint256 indexed projectId,\\n uint256 indexed domain,\\n uint256 indexed group,\\n JBSplit split,\\n uint256 amount,\\n uint256 netAmount,\\n address caller\\n );\\n\\n event SetFee(uint256 fee, address caller);\\n\\n event SetFeeGauge(address indexed feeGauge, address caller);\\n\\n event SetFeelessAddress(address indexed addrs, bool indexed flag, address caller);\\n\\n event PayoutReverted(\\n uint256 indexed projectId,\\n JBSplit split,\\n uint256 amount,\\n bytes reason,\\n address caller\\n );\\n\\n event FeeReverted(\\n uint256 indexed projectId,\\n uint256 indexed feeProjectId,\\n uint256 amount,\\n bytes reason,\\n address caller\\n );\\n\\n function projects() external view returns (IJBProjects);\\n\\n function splitsStore() external view returns (IJBSplitsStore);\\n\\n function directory() external view returns (IJBDirectory);\\n\\n function prices() external view returns (IJBPrices);\\n\\n function store() external view returns (address);\\n\\n function baseWeightCurrency() external view returns (uint256);\\n\\n function payoutSplitsGroup() external view returns (uint256);\\n\\n function heldFeesOf(uint256 projectId) external view returns (JBFee[] memory);\\n\\n function fee() external view returns (uint256);\\n\\n function feeGauge() external view returns (address);\\n\\n function isFeelessAddress(address account) external view returns (bool);\\n\\n function migrate(uint256 projectId, IJBPaymentTerminal to) external returns (uint256 balance);\\n\\n function processFees(uint256 projectId) external;\\n\\n function setFee(uint256 fee) external;\\n\\n function setFeeGauge(address feeGauge) external;\\n\\n function setFeelessAddress(address account, bool flag) external;\\n}\\n\",\"keccak256\":\"0xa96558c3623b7a9e71df7a6034af14b9e3bbd34cdc02c9b36136eb1b4b88da00\",\"license\":\"MIT\"},\"contracts/interfaces/IJBPayoutRedemptionPaymentTerminal3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBFee} from './../structs/JBFee.sol';\\nimport {JBDidRedeemData3_1_1} from './../structs/JBDidRedeemData3_1_1.sol';\\nimport {JBDidPayData3_1_1} from './../structs/JBDidPayData3_1_1.sol';\\nimport {IJBPayDelegate3_1_1} from './IJBPayDelegate3_1_1.sol';\\nimport {IJBRedemptionDelegate3_1_1} from './IJBRedemptionDelegate3_1_1.sol';\\n\\ninterface IJBPayoutRedemptionPaymentTerminal3_1_1 {\\n event DelegateDidRedeem(\\n IJBRedemptionDelegate3_1_1 indexed delegate,\\n JBDidRedeemData3_1_1 data,\\n uint256 delegatedAmount,\\n uint256 fee,\\n address caller\\n );\\n\\n event DelegateDidPay(\\n IJBPayDelegate3_1_1 indexed delegate,\\n JBDidPayData3_1_1 data,\\n uint256 delegatedAmount,\\n address caller\\n );\\n}\\n\",\"keccak256\":\"0x66908701a06aa3b692a75873567cb14f4c9999ed6c42519ae5564a643fd65f15\",\"license\":\"MIT\"},\"contracts/interfaces/IJBPayoutTerminal3_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IJBPayoutTerminal3_1 {\\n function distributePayoutsOf(\\n uint256 projectId,\\n uint256 amount,\\n uint256 currency,\\n address token,\\n uint256 minReturnedTokens,\\n bytes calldata metadata\\n ) external returns (uint256 netLeftoverDistributionAmount);\\n}\\n\",\"keccak256\":\"0x2e0b8c37a451f1723296af656bd4982d4e5339ce76061eb63bb5f57b235bdc44\",\"license\":\"MIT\"},\"contracts/interfaces/IJBPriceFeed.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IJBPriceFeed {\\n function currentPrice(uint256 targetDecimals) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0x9328b2b52bc112641f3a6167c8cf242831a52c85016ce1310626bdc3489bded7\",\"license\":\"MIT\"},\"contracts/interfaces/IJBPrices.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBPriceFeed} from './IJBPriceFeed.sol';\\n\\ninterface IJBPrices {\\n event AddFeed(uint256 indexed currency, uint256 indexed base, IJBPriceFeed feed);\\n\\n function feedFor(uint256 currency, uint256 base) external view returns (IJBPriceFeed);\\n\\n function priceFor(\\n uint256 currency,\\n uint256 base,\\n uint256 decimals\\n ) external view returns (uint256);\\n\\n function addFeedFor(uint256 currency, uint256 base, IJBPriceFeed priceFeed) external;\\n}\\n\",\"keccak256\":\"0xc1623499fa541b15891e27a59288e03360ce78c7933d28bf575b48b68ce4981c\",\"license\":\"MIT\"},\"contracts/interfaces/IJBProjects.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC721} from '@openzeppelin/contracts/token/ERC721/IERC721.sol';\\nimport {JBProjectMetadata} from './../structs/JBProjectMetadata.sol';\\nimport {IJBTokenUriResolver} from './IJBTokenUriResolver.sol';\\n\\ninterface IJBProjects is IERC721 {\\n event Create(\\n uint256 indexed projectId,\\n address indexed owner,\\n JBProjectMetadata metadata,\\n address caller\\n );\\n\\n event SetMetadata(uint256 indexed projectId, JBProjectMetadata metadata, address caller);\\n\\n event SetTokenUriResolver(IJBTokenUriResolver indexed resolver, address caller);\\n\\n function count() external view returns (uint256);\\n\\n function metadataContentOf(\\n uint256 projectId,\\n uint256 domain\\n ) external view returns (string memory);\\n\\n function tokenUriResolver() external view returns (IJBTokenUriResolver);\\n\\n function createFor(\\n address owner,\\n JBProjectMetadata calldata metadata\\n ) external returns (uint256 projectId);\\n\\n function setMetadataOf(uint256 projectId, JBProjectMetadata calldata metadata) external;\\n\\n function setTokenUriResolver(IJBTokenUriResolver newResolver) external;\\n}\\n\",\"keccak256\":\"0x00235f20975e6a9465ac921076c85125a3834e29893f93f93e287a89f9e6b915\",\"license\":\"MIT\"},\"contracts/interfaces/IJBRedemptionDelegate.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\\nimport {JBDidRedeemData} from './../structs/JBDidRedeemData.sol';\\n\\n/// @title Redemption delegate\\n/// @notice Delegate called after JBTerminal.redeemTokensOf(..) logic completion (if passed by the funding cycle datasource)\\ninterface IJBRedemptionDelegate is IERC165 {\\n /// @notice This function is called by JBPaymentTerminal.redeemTokensOf(..), after the execution of its logic\\n /// @dev Critical business logic should be protected by an appropriate access control\\n /// @param data the data passed by the terminal, as a JBDidRedeemData struct:\\n function didRedeem(JBDidRedeemData calldata data) external payable;\\n}\\n\",\"keccak256\":\"0xd70f498197187982962b9e6a5b7572bb6b2c524228a267b01758f7e50a827387\",\"license\":\"MIT\"},\"contracts/interfaces/IJBRedemptionDelegate3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\\nimport {JBDidRedeemData3_1_1} from './../structs/JBDidRedeemData3_1_1.sol';\\n\\n/// @title Redemption delegate\\n/// @notice Delegate called after JBTerminal.redeemTokensOf(..) logic completion (if passed by the funding cycle datasource)\\ninterface IJBRedemptionDelegate3_1_1 is IERC165 {\\n /// @notice This function is called by JBPaymentTerminal.redeemTokensOf(..), after the execution of its logic\\n /// @dev Critical business logic should be protected by an appropriate access control\\n /// @param data the data passed by the terminal, as a JBDidRedeemData struct:\\n function didRedeem(JBDidRedeemData3_1_1 calldata data) external payable;\\n}\\n\",\"keccak256\":\"0x6034773b78e98902625563bd176a97267e729cb5205d25b06e8a2262b131c0d8\",\"license\":\"MIT\"},\"contracts/interfaces/IJBRedemptionTerminal.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IJBRedemptionTerminal {\\n function redeemTokensOf(\\n address holder,\\n uint256 projectId,\\n uint256 tokenCount,\\n address token,\\n uint256 minReturnedTokens,\\n address payable beneficiary,\\n string calldata memo,\\n bytes calldata metadata\\n ) external returns (uint256 reclaimAmount);\\n}\\n\",\"keccak256\":\"0x5e6bbbfe81a6cc151ca7e7ce603e4adb861ba8eb0bd4a35a9f12e29795b161f5\",\"license\":\"MIT\"},\"contracts/interfaces/IJBSingleTokenPaymentTerminal.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\\n\\ninterface IJBSingleTokenPaymentTerminal is IJBPaymentTerminal {\\n function token() external view returns (address);\\n\\n function currency() external view returns (uint256);\\n\\n function decimals() external view returns (uint256);\\n}\\n\",\"keccak256\":\"0x8e00670c66dea368dc523615425c2a79fcee10ec3c3355bf94feb82638172b3f\",\"license\":\"MIT\"},\"contracts/interfaces/IJBSingleTokenPaymentTerminalStore3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\\nimport {JBPayDelegateAllocation3_1_1} from './../structs/JBPayDelegateAllocation3_1_1.sol';\\nimport {JBRedemptionDelegateAllocation3_1_1} from './../structs/JBRedemptionDelegateAllocation3_1_1.sol';\\nimport {JBTokenAmount} from './../structs/JBTokenAmount.sol';\\nimport {IJBDirectory} from './IJBDirectory.sol';\\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\\nimport {IJBPrices} from './IJBPrices.sol';\\nimport {IJBSingleTokenPaymentTerminal} from './IJBSingleTokenPaymentTerminal.sol';\\n\\ninterface IJBSingleTokenPaymentTerminalStore3_1_1 {\\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\\n\\n function directory() external view returns (IJBDirectory);\\n\\n function prices() external view returns (IJBPrices);\\n\\n function balanceOf(\\n IJBSingleTokenPaymentTerminal terminal,\\n uint256 projectId\\n ) external view returns (uint256);\\n\\n function usedDistributionLimitOf(\\n IJBSingleTokenPaymentTerminal terminal,\\n uint256 projectId,\\n uint256 fundingCycleNumber\\n ) external view returns (uint256);\\n\\n function usedOverflowAllowanceOf(\\n IJBSingleTokenPaymentTerminal terminal,\\n uint256 projectId,\\n uint256 fundingCycleConfiguration\\n ) external view returns (uint256);\\n\\n function currentOverflowOf(\\n IJBSingleTokenPaymentTerminal terminal,\\n uint256 projectId\\n ) external view returns (uint256);\\n\\n function currentTotalOverflowOf(\\n uint256 projectId,\\n uint256 decimals,\\n uint256 currency\\n ) external view returns (uint256);\\n\\n function currentReclaimableOverflowOf(\\n IJBSingleTokenPaymentTerminal terminal,\\n uint256 projectId,\\n uint256 tokenCount,\\n bool useTotalOverflow\\n ) external view returns (uint256);\\n\\n function currentReclaimableOverflowOf(\\n uint256 projectId,\\n uint256 tokenCount,\\n uint256 totalSupply,\\n uint256 overflow\\n ) external view returns (uint256);\\n\\n function recordPaymentFrom(\\n address payer,\\n JBTokenAmount memory amount,\\n uint256 projectId,\\n uint256 baseWeightCurrency,\\n address beneficiary,\\n string calldata inputMemo,\\n bytes calldata metadata\\n )\\n external\\n returns (\\n JBFundingCycle memory fundingCycle,\\n uint256 tokenCount,\\n JBPayDelegateAllocation3_1_1[] memory delegateAllocations,\\n string memory outputMemo\\n );\\n\\n function recordRedemptionFor(\\n address holder,\\n uint256 projectId,\\n uint256 tokenCount,\\n string calldata inputMemo,\\n bytes calldata metadata\\n )\\n external\\n returns (\\n JBFundingCycle memory fundingCycle,\\n uint256 reclaimAmount,\\n JBRedemptionDelegateAllocation3_1_1[] memory delegateAllocations,\\n string memory outputMemo\\n );\\n\\n function recordDistributionFor(\\n uint256 projectId,\\n uint256 amount,\\n uint256 currency\\n ) external returns (JBFundingCycle memory fundingCycle, uint256 distributedAmount);\\n\\n function recordUsedAllowanceOf(\\n uint256 projectId,\\n uint256 amount,\\n uint256 currency\\n ) external returns (JBFundingCycle memory fundingCycle, uint256 withdrawnAmount);\\n\\n function recordAddedBalanceFor(uint256 projectId, uint256 amount) external;\\n\\n function recordMigration(uint256 projectId) external returns (uint256 balance);\\n}\\n\",\"keccak256\":\"0xf009c9fb787cda2a18805b9a9e2105c7f1309ade1eac3af229816cfd27ba1d64\",\"license\":\"MIT\"},\"contracts/interfaces/IJBSplitAllocator.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\\nimport {JBSplitAllocationData} from '../structs/JBSplitAllocationData.sol';\\n\\n/// @title Split allocator\\n/// @notice Provide a way to process a single split with extra logic\\n/// @dev The contract address should be set as an allocator in the adequate split\\ninterface IJBSplitAllocator is IERC165 {\\n /// @notice This function is called by JBPaymentTerminal.distributePayoutOf(..), during the processing of the split including it\\n /// @dev Critical business logic should be protected by an appropriate access control. The token and/or eth are optimistically transfered to the allocator for its logic.\\n /// @param data the data passed by the terminal, as a JBSplitAllocationData struct:\\n function allocate(JBSplitAllocationData calldata data) external payable;\\n}\\n\",\"keccak256\":\"0x1643b444409d91858eb86f67abf3d757d2deb3ccd7265eb8e68d6ffdac083de6\",\"license\":\"MIT\"},\"contracts/interfaces/IJBSplitsStore.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBGroupedSplits} from './../structs/JBGroupedSplits.sol';\\nimport {JBSplit} from './../structs/JBSplit.sol';\\nimport {IJBDirectory} from './IJBDirectory.sol';\\nimport {IJBProjects} from './IJBProjects.sol';\\n\\ninterface IJBSplitsStore {\\n event SetSplit(\\n uint256 indexed projectId,\\n uint256 indexed domain,\\n uint256 indexed group,\\n JBSplit split,\\n address caller\\n );\\n\\n function projects() external view returns (IJBProjects);\\n\\n function directory() external view returns (IJBDirectory);\\n\\n function splitsOf(\\n uint256 projectId,\\n uint256 domain,\\n uint256 group\\n ) external view returns (JBSplit[] memory);\\n\\n function set(uint256 projectId, uint256 domain, JBGroupedSplits[] memory groupedSplits) external;\\n}\\n\",\"keccak256\":\"0x3ce0eb12f10282481a3bf86e62b368bcff254081088cfabb20353d60cfadbc7a\",\"license\":\"MIT\"},\"contracts/interfaces/IJBToken.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IJBToken {\\n function projectId() external view returns (uint256);\\n\\n function decimals() external view returns (uint8);\\n\\n function totalSupply(uint256 projectId) external view returns (uint256);\\n\\n function balanceOf(address account, uint256 projectId) external view returns (uint256);\\n\\n function mint(uint256 projectId, address account, uint256 amount) external;\\n\\n function burn(uint256 projectId, address account, uint256 amount) external;\\n\\n function approve(uint256, address spender, uint256 amount) external;\\n\\n function transfer(uint256 projectId, address to, uint256 amount) external;\\n\\n function transferFrom(uint256 projectId, address from, address to, uint256 amount) external;\\n}\\n\",\"keccak256\":\"0xeefe58d140e4e13f255d5c7c5cdf5ba66dd00835f04015c446ff224f8ad14c34\",\"license\":\"MIT\"},\"contracts/interfaces/IJBTokenStore.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\\nimport {IJBProjects} from './IJBProjects.sol';\\nimport {IJBToken} from './IJBToken.sol';\\n\\ninterface IJBTokenStore {\\n event Issue(\\n uint256 indexed projectId,\\n IJBToken indexed token,\\n string name,\\n string symbol,\\n address caller\\n );\\n\\n event Mint(\\n address indexed holder,\\n uint256 indexed projectId,\\n uint256 amount,\\n bool tokensWereClaimed,\\n bool preferClaimedTokens,\\n address caller\\n );\\n\\n event Burn(\\n address indexed holder,\\n uint256 indexed projectId,\\n uint256 amount,\\n uint256 initialUnclaimedBalance,\\n uint256 initialClaimedBalance,\\n bool preferClaimedTokens,\\n address caller\\n );\\n\\n event Claim(\\n address indexed holder,\\n uint256 indexed projectId,\\n uint256 initialUnclaimedBalance,\\n uint256 amount,\\n address caller\\n );\\n\\n event Set(uint256 indexed projectId, IJBToken indexed newToken, address caller);\\n\\n event Transfer(\\n address indexed holder,\\n uint256 indexed projectId,\\n address indexed recipient,\\n uint256 amount,\\n address caller\\n );\\n\\n function tokenOf(uint256 projectId) external view returns (IJBToken);\\n\\n function projects() external view returns (IJBProjects);\\n\\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\\n\\n function unclaimedBalanceOf(address holder, uint256 projectId) external view returns (uint256);\\n\\n function unclaimedTotalSupplyOf(uint256 projectId) external view returns (uint256);\\n\\n function totalSupplyOf(uint256 projectId) external view returns (uint256);\\n\\n function balanceOf(address holder, uint256 projectId) external view returns (uint256 result);\\n\\n function issueFor(\\n uint256 projectId,\\n string calldata name,\\n string calldata symbol\\n ) external returns (IJBToken token);\\n\\n function setFor(uint256 projectId, IJBToken token) external;\\n\\n function burnFrom(\\n address holder,\\n uint256 projectId,\\n uint256 amount,\\n bool preferClaimedTokens\\n ) external;\\n\\n function mintFor(\\n address holder,\\n uint256 projectId,\\n uint256 amount,\\n bool preferClaimedTokens\\n ) external;\\n\\n function claimFor(address holder, uint256 projectId, uint256 amount) external;\\n\\n function transferFrom(\\n address holder,\\n uint256 projectId,\\n address recipient,\\n uint256 amount\\n ) external;\\n}\\n\",\"keccak256\":\"0x4db7bb4fe824dc9bfbc997ea3e07f42be8900bcad4e0b991e726c23c2de84ba4\",\"license\":\"MIT\"},\"contracts/interfaces/IJBTokenUriResolver.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IJBTokenUriResolver {\\n function getUri(uint256 projectId) external view returns (string memory tokenUri);\\n}\\n\",\"keccak256\":\"0xc7c9537184a1a36bc30874e5ac29b0fbccf45a99d40806837cfe30d6d9a1c84a\",\"license\":\"MIT\"},\"contracts/libraries/JBConstants.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/// @notice Global constants used across Juicebox contracts.\\nlibrary JBConstants {\\n uint256 public constant MAX_RESERVED_RATE = 10_000;\\n uint256 public constant MAX_REDEMPTION_RATE = 10_000;\\n uint256 public constant MAX_DISCOUNT_RATE = 1_000_000_000;\\n uint256 public constant SPLITS_TOTAL_PERCENT = 1_000_000_000;\\n uint256 public constant MAX_FEE = 1_000_000_000;\\n uint256 public constant MAX_FEE_DISCOUNT = 1_000_000_000;\\n}\\n\",\"keccak256\":\"0x7f2741e86062c5019f51d7e1a7b192ec1880d7e15a9a1589362ae7424de3003b\",\"license\":\"MIT\"},\"contracts/libraries/JBCurrencies.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nlibrary JBCurrencies {\\n uint256 public constant ETH = 1;\\n uint256 public constant USD = 2;\\n}\\n\",\"keccak256\":\"0x7e417ff25c173608ee4fe6d9fc3dcd5e1458c78c889af12bac47b1189a436076\",\"license\":\"MIT\"},\"contracts/libraries/JBFixedPointNumber.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.16;\\n\\nlibrary JBFixedPointNumber {\\n function adjustDecimals(\\n uint256 _value,\\n uint256 _decimals,\\n uint256 _targetDecimals\\n ) internal pure returns (uint256) {\\n // If decimals need adjusting, multiply or divide the price by the decimal adjuster to get the normalized result.\\n if (_targetDecimals == _decimals) return _value;\\n else if (_targetDecimals > _decimals) return _value * 10**(_targetDecimals - _decimals);\\n else return _value / 10**(_decimals - _targetDecimals);\\n }\\n}\\n\",\"keccak256\":\"0x18efac48269f3a3bd7e9a1c770776f950e0afa86769e6f8b128002c3b8c6742c\",\"license\":\"MIT\"},\"contracts/libraries/JBFundingCycleMetadataResolver.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.16;\\n\\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\\nimport {JBFundingCycleMetadata} from './../structs/JBFundingCycleMetadata.sol';\\nimport {JBGlobalFundingCycleMetadata} from './../structs/JBGlobalFundingCycleMetadata.sol';\\nimport {JBConstants} from './JBConstants.sol';\\nimport {JBGlobalFundingCycleMetadataResolver} from './JBGlobalFundingCycleMetadataResolver.sol';\\n\\nlibrary JBFundingCycleMetadataResolver {\\n function global(JBFundingCycle memory _fundingCycle)\\n internal\\n pure\\n returns (JBGlobalFundingCycleMetadata memory)\\n {\\n return JBGlobalFundingCycleMetadataResolver.expandMetadata(uint8(_fundingCycle.metadata >> 8));\\n }\\n\\n function reservedRate(JBFundingCycle memory _fundingCycle) internal pure returns (uint256) {\\n return uint256(uint16(_fundingCycle.metadata >> 24));\\n }\\n\\n function redemptionRate(JBFundingCycle memory _fundingCycle) internal pure returns (uint256) {\\n // Redemption rate is a number 0-10000. It's inverse was stored so the most common case of 100% results in no storage needs.\\n return JBConstants.MAX_REDEMPTION_RATE - uint256(uint16(_fundingCycle.metadata >> 40));\\n }\\n\\n function ballotRedemptionRate(JBFundingCycle memory _fundingCycle)\\n internal\\n pure\\n returns (uint256)\\n {\\n // Redemption rate is a number 0-10000. It's inverse was stored so the most common case of 100% results in no storage needs.\\n return JBConstants.MAX_REDEMPTION_RATE - uint256(uint16(_fundingCycle.metadata >> 56));\\n }\\n\\n function payPaused(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\\n return ((_fundingCycle.metadata >> 72) & 1) == 1;\\n }\\n\\n function distributionsPaused(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\\n return ((_fundingCycle.metadata >> 73) & 1) == 1;\\n }\\n\\n function redeemPaused(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\\n return ((_fundingCycle.metadata >> 74) & 1) == 1;\\n }\\n\\n function burnPaused(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\\n return ((_fundingCycle.metadata >> 75) & 1) == 1;\\n }\\n\\n function mintingAllowed(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\\n return ((_fundingCycle.metadata >> 76) & 1) == 1;\\n }\\n\\n function terminalMigrationAllowed(JBFundingCycle memory _fundingCycle)\\n internal\\n pure\\n returns (bool)\\n {\\n return ((_fundingCycle.metadata >> 77) & 1) == 1;\\n }\\n\\n function controllerMigrationAllowed(JBFundingCycle memory _fundingCycle)\\n internal\\n pure\\n returns (bool)\\n {\\n return ((_fundingCycle.metadata >> 78) & 1) == 1;\\n }\\n\\n function shouldHoldFees(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\\n return ((_fundingCycle.metadata >> 79) & 1) == 1;\\n }\\n\\n function preferClaimedTokenOverride(JBFundingCycle memory _fundingCycle)\\n internal\\n pure\\n returns (bool)\\n {\\n return ((_fundingCycle.metadata >> 80) & 1) == 1;\\n }\\n\\n function useTotalOverflowForRedemptions(JBFundingCycle memory _fundingCycle)\\n internal\\n pure\\n returns (bool)\\n {\\n return ((_fundingCycle.metadata >> 81) & 1) == 1;\\n }\\n\\n function useDataSourceForPay(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\\n return (_fundingCycle.metadata >> 82) & 1 == 1;\\n }\\n\\n function useDataSourceForRedeem(JBFundingCycle memory _fundingCycle)\\n internal\\n pure\\n returns (bool)\\n {\\n return (_fundingCycle.metadata >> 83) & 1 == 1;\\n }\\n\\n function dataSource(JBFundingCycle memory _fundingCycle) internal pure returns (address) {\\n return address(uint160(_fundingCycle.metadata >> 84));\\n }\\n\\n function metadata(JBFundingCycle memory _fundingCycle) internal pure returns (uint256) {\\n return uint256(uint8(_fundingCycle.metadata >> 244));\\n }\\n\\n /// @notice Pack the funding cycle metadata.\\n /// @param _metadata The metadata to validate and pack.\\n /// @return packed The packed uint256 of all metadata params. The first 8 bits specify the version. \\n function packFundingCycleMetadata(JBFundingCycleMetadata memory _metadata)\\n internal\\n pure\\n returns (uint256 packed)\\n {\\n // version 1 in the bits 0-7 (8 bits).\\n packed = 1;\\n // global metadta in bits 8-23 (16 bits).\\n packed |=\\n JBGlobalFundingCycleMetadataResolver.packFundingCycleGlobalMetadata(_metadata.global) <<\\n 8;\\n // reserved rate in bits 24-39 (16 bits).\\n packed |= _metadata.reservedRate << 24;\\n // redemption rate in bits 40-55 (16 bits).\\n // redemption rate is a number 0-10000. Store the reverse so the most common case of 100% results in no storage needs.\\n packed |= (JBConstants.MAX_REDEMPTION_RATE - _metadata.redemptionRate) << 40;\\n // ballot redemption rate rate in bits 56-71 (16 bits).\\n // ballot redemption rate is a number 0-10000. Store the reverse so the most common case of 100% results in no storage needs.\\n packed |= (JBConstants.MAX_REDEMPTION_RATE - _metadata.ballotRedemptionRate) << 56;\\n // pause pay in bit 72.\\n if (_metadata.pausePay) packed |= 1 << 72;\\n // pause tap in bit 73.\\n if (_metadata.pauseDistributions) packed |= 1 << 73;\\n // pause redeem in bit 74.\\n if (_metadata.pauseRedeem) packed |= 1 << 74;\\n // pause burn in bit 75.\\n if (_metadata.pauseBurn) packed |= 1 << 75;\\n // allow minting in bit 76.\\n if (_metadata.allowMinting) packed |= 1 << 76;\\n // allow terminal migration in bit 77.\\n if (_metadata.allowTerminalMigration) packed |= 1 << 77;\\n // allow controller migration in bit 78.\\n if (_metadata.allowControllerMigration) packed |= 1 << 78;\\n // hold fees in bit 79.\\n if (_metadata.holdFees) packed |= 1 << 79;\\n // prefer claimed token override in bit 80.\\n if (_metadata.preferClaimedTokenOverride) packed |= 1 << 80;\\n // useTotalOverflowForRedemptions in bit 81.\\n if (_metadata.useTotalOverflowForRedemptions) packed |= 1 << 81;\\n // use pay data source in bit 82.\\n if (_metadata.useDataSourceForPay) packed |= 1 << 82;\\n // use redeem data source in bit 83.\\n if (_metadata.useDataSourceForRedeem) packed |= 1 << 83;\\n // data source address in bits 84-243.\\n packed |= uint256(uint160(address(_metadata.dataSource))) << 84;\\n // metadata in bits 244-252 (8 bits).\\n packed |= _metadata.metadata << 244;\\n }\\n\\n /// @notice Expand the funding cycle metadata.\\n /// @param _fundingCycle The funding cycle having its metadata expanded.\\n /// @return metadata The metadata object. \\n function expandMetadata(JBFundingCycle memory _fundingCycle)\\n internal\\n pure\\n returns (JBFundingCycleMetadata memory)\\n {\\n return\\n JBFundingCycleMetadata(\\n global(_fundingCycle),\\n reservedRate(_fundingCycle),\\n redemptionRate(_fundingCycle),\\n ballotRedemptionRate(_fundingCycle),\\n payPaused(_fundingCycle),\\n distributionsPaused(_fundingCycle),\\n redeemPaused(_fundingCycle),\\n burnPaused(_fundingCycle),\\n mintingAllowed(_fundingCycle),\\n terminalMigrationAllowed(_fundingCycle),\\n controllerMigrationAllowed(_fundingCycle),\\n shouldHoldFees(_fundingCycle),\\n preferClaimedTokenOverride(_fundingCycle),\\n useTotalOverflowForRedemptions(_fundingCycle),\\n useDataSourceForPay(_fundingCycle),\\n useDataSourceForRedeem(_fundingCycle),\\n dataSource(_fundingCycle),\\n metadata(_fundingCycle)\\n );\\n }\\n}\\n\",\"keccak256\":\"0xedb0b93d5578ca5a21ab55f65274e441513bce982b04ffc76f26e627abfbbe0c\",\"license\":\"MIT\"},\"contracts/libraries/JBGlobalFundingCycleMetadataResolver.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.16;\\n\\nimport {JBFundingCycleMetadata} from './../structs/JBFundingCycleMetadata.sol';\\nimport {JBGlobalFundingCycleMetadata} from './../structs/JBGlobalFundingCycleMetadata.sol';\\n\\nlibrary JBGlobalFundingCycleMetadataResolver {\\n function setTerminalsAllowed(uint8 _data) internal pure returns (bool) {\\n return (_data & 1) == 1;\\n }\\n\\n function setControllerAllowed(uint8 _data) internal pure returns (bool) {\\n return ((_data >> 1) & 1) == 1;\\n }\\n\\n function transfersPaused(uint8 _data) internal pure returns (bool) {\\n return ((_data >> 2) & 1) == 1;\\n }\\n\\n /// @notice Pack the global funding cycle metadata.\\n /// @param _metadata The metadata to validate and pack.\\n /// @return packed The packed uint256 of all global metadata params. The first 8 bits specify the version.\\n function packFundingCycleGlobalMetadata(\\n JBGlobalFundingCycleMetadata memory _metadata\\n ) internal pure returns (uint256 packed) {\\n // allow set terminals in bit 0.\\n if (_metadata.allowSetTerminals) packed |= 1;\\n // allow set controller in bit 1.\\n if (_metadata.allowSetController) packed |= 1 << 1;\\n // pause transfers in bit 2.\\n if (_metadata.pauseTransfers) packed |= 1 << 2;\\n }\\n\\n /// @notice Expand the global funding cycle metadata.\\n /// @param _packedMetadata The packed metadata to expand.\\n /// @return metadata The global metadata object.\\n function expandMetadata(\\n uint8 _packedMetadata\\n ) internal pure returns (JBGlobalFundingCycleMetadata memory metadata) {\\n return\\n JBGlobalFundingCycleMetadata(\\n setTerminalsAllowed(_packedMetadata),\\n setControllerAllowed(_packedMetadata),\\n transfersPaused(_packedMetadata)\\n );\\n }\\n}\\n\",\"keccak256\":\"0x8a016001787db05e3bbd442db7eaa3f49f1d3a3210d2b5c6e52254a241f3b161\",\"license\":\"MIT\"},\"contracts/libraries/JBOperations.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nlibrary JBOperations {\\n uint256 public constant RECONFIGURE = 1;\\n uint256 public constant REDEEM = 2;\\n uint256 public constant MIGRATE_CONTROLLER = 3;\\n uint256 public constant MIGRATE_TERMINAL = 4;\\n uint256 public constant PROCESS_FEES = 5;\\n uint256 public constant SET_METADATA = 6;\\n uint256 public constant ISSUE = 7;\\n uint256 public constant SET_TOKEN = 8;\\n uint256 public constant MINT = 9;\\n uint256 public constant BURN = 10;\\n uint256 public constant CLAIM = 11;\\n uint256 public constant TRANSFER = 12;\\n uint256 public constant REQUIRE_CLAIM = 13; // unused in v3\\n uint256 public constant SET_CONTROLLER = 14;\\n uint256 public constant SET_TERMINALS = 15;\\n uint256 public constant SET_PRIMARY_TERMINAL = 16;\\n uint256 public constant USE_ALLOWANCE = 17;\\n uint256 public constant SET_SPLITS = 18;\\n}\\n\",\"keccak256\":\"0x7f8e501e6890297f4015b1c27cebdb44fadbf21204bea1f3162f5388c060f690\",\"license\":\"MIT\"},\"contracts/libraries/JBSplitsGroups.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nlibrary JBSplitsGroups {\\n uint256 public constant ETH_PAYOUT = 1;\\n uint256 public constant RESERVED_TOKENS = 2;\\n}\\n\",\"keccak256\":\"0x4183db6087bd8db645fc3a0d3d8afb0d6356e003650793f63c301ebbbae47269\",\"license\":\"MIT\"},\"contracts/libraries/JBTokens.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nlibrary JBTokens {\\n /// @notice The ETH token address in Juicebox is represented by 0x000000000000000000000000000000000000EEEe.\\n address public constant ETH = address(0x000000000000000000000000000000000000EEEe);\\n}\\n\",\"keccak256\":\"0x9e724a7e65c6d6e01e7f0c1419d750307ed6ce8bc29bbd959e029bcdd4b4e479\",\"license\":\"MIT\"},\"contracts/structs/JBDidPayData.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBTokenAmount} from './JBTokenAmount.sol';\\n\\n/// @custom:member payer The address from which the payment originated.\\n/// @custom:member projectId The ID of the project for which the payment was made.\\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the payment is being made.\\n/// @custom:member amount The amount of the payment. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\\n/// @custom:member forwardedAmount The amount of the payment that is being sent to the delegate. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\\n/// @custom:member projectTokenCount The number of project tokens minted for the beneficiary.\\n/// @custom:member beneficiary The address to which the tokens were minted.\\n/// @custom:member preferClaimedTokens A flag indicating whether the request prefered to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract.\\n/// @custom:member memo The memo that is being emitted alongside the payment.\\n/// @custom:member metadata Extra data to send to the delegate.\\nstruct JBDidPayData {\\n address payer;\\n uint256 projectId;\\n uint256 currentFundingCycleConfiguration;\\n JBTokenAmount amount;\\n JBTokenAmount forwardedAmount;\\n uint256 projectTokenCount;\\n address beneficiary;\\n bool preferClaimedTokens;\\n string memo;\\n bytes metadata;\\n}\\n\",\"keccak256\":\"0x235e117009bfb825d14c5433fa46f777fa512400df74e76290e869d4c3d8b26e\",\"license\":\"MIT\"},\"contracts/structs/JBDidPayData3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBTokenAmount} from './JBTokenAmount.sol';\\n\\n/// @custom:member payer The address from which the payment originated.\\n/// @custom:member projectId The ID of the project for which the payment was made.\\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the payment is being made.\\n/// @custom:member amount The amount of the payment. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\\n/// @custom:member forwardedAmount The amount of the payment that is being sent to the delegate. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\\n/// @custom:member projectTokenCount The number of project tokens minted for the beneficiary.\\n/// @custom:member beneficiary The address to which the tokens were minted.\\n/// @custom:member preferClaimedTokens A flag indicating whether the request prefered to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract.\\n/// @custom:member memo The memo that is being emitted alongside the payment.\\n/// @custom:member dataSourceMetadata Extra data to send to the delegate sent by the data source.\\n/// @custom:member payerMetadata Extra data to send to the delegate sent by the payer.\\nstruct JBDidPayData3_1_1 {\\n address payer;\\n uint256 projectId;\\n uint256 currentFundingCycleConfiguration;\\n JBTokenAmount amount;\\n JBTokenAmount forwardedAmount;\\n uint256 projectTokenCount;\\n address beneficiary;\\n bool preferClaimedTokens;\\n string memo;\\n bytes dataSourceMetadata;\\n bytes payerMetadata;\\n}\\n\",\"keccak256\":\"0x2e659555149ff14c045b749b1d1a3156b8296ab08375ac2abec92afc43bf3acf\",\"license\":\"MIT\"},\"contracts/structs/JBDidRedeemData.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBTokenAmount} from './JBTokenAmount.sol';\\n\\n/// @custom:member holder The holder of the tokens being redeemed.\\n/// @custom:member projectId The ID of the project with which the redeemed tokens are associated.\\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the redemption is being made.\\n/// @custom:member projectTokenCount The number of project tokens being redeemed.\\n/// @custom:member reclaimedAmount The amount reclaimed from the treasury. Includes the token being reclaimed, the value, the number of decimals included, and the currency of the amount.\\n/// @custom:member forwardedAmount The amount of the payment that is being sent to the delegate. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\\n/// @custom:member beneficiary The address to which the reclaimed amount will be sent.\\n/// @custom:member memo The memo that is being emitted alongside the redemption.\\n/// @custom:member metadata Extra data to send to the delegate.\\nstruct JBDidRedeemData {\\n address holder;\\n uint256 projectId;\\n uint256 currentFundingCycleConfiguration;\\n uint256 projectTokenCount;\\n JBTokenAmount reclaimedAmount;\\n JBTokenAmount forwardedAmount;\\n address payable beneficiary;\\n string memo;\\n bytes metadata;\\n}\\n\",\"keccak256\":\"0xee0c3728a39069f5a2a9b25c120739da5cae4c4e6fd0cae371a961a9d1367549\",\"license\":\"MIT\"},\"contracts/structs/JBDidRedeemData3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBTokenAmount} from './JBTokenAmount.sol';\\n\\n/// @custom:member holder The holder of the tokens being redeemed.\\n/// @custom:member projectId The ID of the project with which the redeemed tokens are associated.\\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the redemption is being made.\\n/// @custom:member projectTokenCount The number of project tokens being redeemed.\\n/// @custom:member reclaimedAmount The amount reclaimed from the treasury. Includes the token being reclaimed, the value, the number of decimals included, and the currency of the amount.\\n/// @custom:member forwardedAmount The amount of the payment that is being sent to the delegate. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\\n/// @custom:member beneficiary The address to which the reclaimed amount will be sent.\\n/// @custom:member memo The memo that is being emitted alongside the redemption.\\n/// @custom:member dataSourceMetadata Extra data to send to the delegate sent by the data source.\\n/// @custom:member redeemerMetadata Extra data to send to the delegate sent by the redeemer.\\nstruct JBDidRedeemData3_1_1 {\\n address holder;\\n uint256 projectId;\\n uint256 currentFundingCycleConfiguration;\\n uint256 projectTokenCount;\\n JBTokenAmount reclaimedAmount;\\n JBTokenAmount forwardedAmount;\\n address payable beneficiary;\\n string memo;\\n bytes dataSourceMetadata;\\n bytes redeemerMetadata;\\n}\\n\",\"keccak256\":\"0x23848d41aa179d16e9b7033befd3a855d43f6a009e24030c2ba1bb5b06cb3924\",\"license\":\"MIT\"},\"contracts/structs/JBFee.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/// @custom:member amount The total amount the fee was taken from, as a fixed point number with the same number of decimals as the terminal in which this struct was created.\\n/// @custom:member fee The percent of the fee, out of MAX_FEE.\\n/// @custom:member feeDiscount The discount of the fee.\\n/// @custom:member beneficiary The address that will receive the tokens that are minted as a result of the fee payment.\\nstruct JBFee {\\n uint256 amount;\\n uint32 fee;\\n uint32 feeDiscount;\\n address beneficiary;\\n}\\n\",\"keccak256\":\"0xd105627d21718704db798df0b958e6223fb2d79854e72cda2bfa9eca0630c1f6\",\"license\":\"MIT\"},\"contracts/structs/JBFundAccessConstraints.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\\n\\n/// @custom:member terminal The terminal within which the distribution limit and the overflow allowance applies.\\n/// @custom:member token The token for which the fund access constraints apply.\\n/// @custom:member distributionLimit The amount of the distribution limit, as a fixed point number with the same number of decimals as the terminal within which the limit applies.\\n/// @custom:member distributionLimitCurrency The currency of the distribution limit.\\n/// @custom:member overflowAllowance The amount of the allowance, as a fixed point number with the same number of decimals as the terminal within which the allowance applies.\\n/// @custom:member overflowAllowanceCurrency The currency of the overflow allowance.\\nstruct JBFundAccessConstraints {\\n IJBPaymentTerminal terminal;\\n address token;\\n uint256 distributionLimit;\\n uint256 distributionLimitCurrency;\\n uint256 overflowAllowance;\\n uint256 overflowAllowanceCurrency;\\n}\\n\",\"keccak256\":\"0xbef975eb73e58c00eaaa7abbd449db545056b049907bb2034aefcdde10bcf11f\",\"license\":\"MIT\"},\"contracts/structs/JBFundingCycle.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBFundingCycleBallot} from './../interfaces/IJBFundingCycleBallot.sol';\\n\\n/// @custom:member number The funding cycle number for the cycle's project. Each funding cycle has a number that is an increment of the cycle that directly preceded it. Each project's first funding cycle has a number of 1.\\n/// @custom:member configuration The timestamp when the parameters for this funding cycle were configured. This value will stay the same for subsequent funding cycles that roll over from an originally configured cycle.\\n/// @custom:member basedOn The `configuration` of the funding cycle that was active when this cycle was created.\\n/// @custom:member start The timestamp marking the moment from which the funding cycle is considered active. It is a unix timestamp measured in seconds.\\n/// @custom:member duration The number of seconds the funding cycle lasts for, after which a new funding cycle will start. A duration of 0 means that the funding cycle will stay active until the project owner explicitly issues a reconfiguration, at which point a new funding cycle will immediately start with the updated properties. If the duration is greater than 0, a project owner cannot make changes to a funding cycle's parameters while it is active \\u2013 any proposed changes will apply to the subsequent cycle. If no changes are proposed, a funding cycle rolls over to another one with the same properties but new `start` timestamp and a discounted `weight`.\\n/// @custom:member weight A fixed point number with 18 decimals that contracts can use to base arbitrary calculations on. For example, payment terminals can use this to determine how many tokens should be minted when a payment is received.\\n/// @custom:member discountRate A percent by how much the `weight` of the subsequent funding cycle should be reduced, if the project owner hasn't configured the subsequent funding cycle with an explicit `weight`. If it's 0, each funding cycle will have equal weight. If the number is 90%, the next funding cycle will have a 10% smaller weight. This weight is out of `JBConstants.MAX_DISCOUNT_RATE`.\\n/// @custom:member ballot An address of a contract that says whether a proposed reconfiguration should be accepted or rejected. It can be used to create rules around how a project owner can change funding cycle parameters over time.\\n/// @custom:member metadata Extra data that can be associated with a funding cycle.\\nstruct JBFundingCycle {\\n uint256 number;\\n uint256 configuration;\\n uint256 basedOn;\\n uint256 start;\\n uint256 duration;\\n uint256 weight;\\n uint256 discountRate;\\n IJBFundingCycleBallot ballot;\\n uint256 metadata;\\n}\\n\",\"keccak256\":\"0x01d2ee9ae017694097985a08a36421b6801d96badd16e38c6085f3a5ac796ed1\",\"license\":\"MIT\"},\"contracts/structs/JBFundingCycleData.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBFundingCycleBallot} from './../interfaces/IJBFundingCycleBallot.sol';\\n\\n/// @custom:member duration The number of seconds the funding cycle lasts for, after which a new funding cycle will start. A duration of 0 means that the funding cycle will stay active until the project owner explicitly issues a reconfiguration, at which point a new funding cycle will immediately start with the updated properties. If the duration is greater than 0, a project owner cannot make changes to a funding cycle's parameters while it is active \\u2013 any proposed changes will apply to the subsequent cycle. If no changes are proposed, a funding cycle rolls over to another one with the same properties but new `start` timestamp and a discounted `weight`.\\n/// @custom:member weight A fixed point number with 18 decimals that contracts can use to base arbitrary calculations on. For example, payment terminals can use this to determine how many tokens should be minted when a payment is received.\\n/// @custom:member discountRate A percent by how much the `weight` of the subsequent funding cycle should be reduced, if the project owner hasn't configured the subsequent funding cycle with an explicit `weight`. If it's 0, each funding cycle will have equal weight. If the number is 90%, the next funding cycle will have a 10% smaller weight. This weight is out of `JBConstants.MAX_DISCOUNT_RATE`.\\n/// @custom:member ballot An address of a contract that says whether a proposed reconfiguration should be accepted or rejected. It can be used to create rules around how a project owner can change funding cycle parameters over time.\\nstruct JBFundingCycleData {\\n uint256 duration;\\n uint256 weight;\\n uint256 discountRate;\\n IJBFundingCycleBallot ballot;\\n}\\n\",\"keccak256\":\"0x3cd9257969fdd54bee497b01be2c623e33c941306662002b3b88fa0ab8a27db5\",\"license\":\"MIT\"},\"contracts/structs/JBFundingCycleMetadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBGlobalFundingCycleMetadata} from './JBGlobalFundingCycleMetadata.sol';\\n\\n/// @custom:member global Data used globally in non-migratable ecosystem contracts.\\n/// @custom:member reservedRate The reserved rate of the funding cycle. This number is a percentage calculated out of `JBConstants.MAX_RESERVED_RATE`.\\n/// @custom:member redemptionRate The redemption rate of the funding cycle. This number is a percentage calculated out of `JBConstants.MAX_REDEMPTION_RATE`.\\n/// @custom:member ballotRedemptionRate The redemption rate to use during an active ballot of the funding cycle. This number is a percentage calculated out of `JBConstants.MAX_REDEMPTION_RATE`.\\n/// @custom:member pausePay A flag indicating if the pay functionality should be paused during the funding cycle.\\n/// @custom:member pauseDistributions A flag indicating if the distribute functionality should be paused during the funding cycle.\\n/// @custom:member pauseRedeem A flag indicating if the redeem functionality should be paused during the funding cycle.\\n/// @custom:member pauseBurn A flag indicating if the burn functionality should be paused during the funding cycle.\\n/// @custom:member allowMinting A flag indicating if minting tokens should be allowed during this funding cycle.\\n/// @custom:member allowTerminalMigration A flag indicating if migrating terminals should be allowed during this funding cycle.\\n/// @custom:member allowControllerMigration A flag indicating if migrating controllers should be allowed during this funding cycle.\\n/// @custom:member holdFees A flag indicating if fees should be held during this funding cycle.\\n/// @custom:member preferClaimedTokenOverride A flag indicating if claimed tokens should always be prefered to unclaimed tokens when minting.\\n/// @custom:member useTotalOverflowForRedemptions A flag indicating if redemptions should use the project's balance held in all terminals instead of the project's local terminal balance from which the redemption is being fulfilled.\\n/// @custom:member useDataSourceForPay A flag indicating if the data source should be used for pay transactions during this funding cycle.\\n/// @custom:member useDataSourceForRedeem A flag indicating if the data source should be used for redeem transactions during this funding cycle.\\n/// @custom:member dataSource The data source to use during this funding cycle.\\n/// @custom:member metadata Metadata of the metadata, up to uint8 in size.\\nstruct JBFundingCycleMetadata {\\n JBGlobalFundingCycleMetadata global;\\n uint256 reservedRate;\\n uint256 redemptionRate;\\n uint256 ballotRedemptionRate;\\n bool pausePay;\\n bool pauseDistributions;\\n bool pauseRedeem;\\n bool pauseBurn;\\n bool allowMinting;\\n bool allowTerminalMigration;\\n bool allowControllerMigration;\\n bool holdFees;\\n bool preferClaimedTokenOverride;\\n bool useTotalOverflowForRedemptions;\\n bool useDataSourceForPay;\\n bool useDataSourceForRedeem;\\n address dataSource;\\n uint256 metadata;\\n}\\n\",\"keccak256\":\"0x477bbd36c94da3f56fac6c8c60b2e2e3c5b8fc557a880b5359980bc556ccd300\",\"license\":\"MIT\"},\"contracts/structs/JBGlobalFundingCycleMetadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/// @custom:member allowSetTerminals A flag indicating if setting terminals should be allowed during this funding cycle.\\n/// @custom:member allowSetController A flag indicating if setting a new controller should be allowed during this funding cycle.\\n/// @custom:member pauseTransfers A flag indicating if the project token transfer functionality should be paused during the funding cycle.\\nstruct JBGlobalFundingCycleMetadata {\\n bool allowSetTerminals;\\n bool allowSetController;\\n bool pauseTransfers;\\n}\\n\",\"keccak256\":\"0x5f95bce22550c69bb7b1ee17279d51415ae8bae10c5b759c8b88f0b0aba854ed\",\"license\":\"MIT\"},\"contracts/structs/JBGroupedSplits.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBSplit} from './JBSplit.sol';\\n\\n/// @custom:member group The group indentifier.\\n/// @custom:member splits The splits to associate with the group.\\nstruct JBGroupedSplits {\\n uint256 group;\\n JBSplit[] splits;\\n}\\n\",\"keccak256\":\"0x71fcdbff5cd055cee8d06b73568c44cedda8f5a2351e7d8ce9dd71d8a1f914a8\",\"license\":\"MIT\"},\"contracts/structs/JBOperatorData.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/// @custom:member operator The address of the operator.\\n/// @custom:member domain The domain within which the operator is being given permissions. A domain of 0 is a wildcard domain, which gives an operator access to all domains.\\n/// @custom:member permissionIndexes The indexes of the permissions the operator is being given.\\nstruct JBOperatorData {\\n address operator;\\n uint256 domain;\\n uint256[] permissionIndexes;\\n}\\n\",\"keccak256\":\"0x77fba183d08748c7b75a12425f987b1b48f6bbfec0284517ffaf261429b45a7c\",\"license\":\"MIT\"},\"contracts/structs/JBPayDelegateAllocation3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBPayDelegate3_1_1} from '../interfaces/IJBPayDelegate3_1_1.sol';\\n\\n/// @custom:member delegate A delegate contract to use for subsequent calls.\\n/// @custom:member amount The amount to send to the delegate.\\n/// @custom:member metadata Metadata to pass the delegate.\\nstruct JBPayDelegateAllocation3_1_1 {\\n IJBPayDelegate3_1_1 delegate;\\n uint256 amount;\\n bytes metadata;\\n}\\n\",\"keccak256\":\"0x8d87206a7015af9ec9e5fc059e39bfcea44aa007f8812213c6fd489d0a9c2e17\",\"license\":\"MIT\"},\"contracts/structs/JBProjectMetadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/// @custom:member content The metadata content.\\n/// @custom:member domain The domain within which the metadata applies.\\nstruct JBProjectMetadata {\\n string content;\\n uint256 domain;\\n}\\n\",\"keccak256\":\"0x9545ea42927f3451c9d901a2f7ab7c1aeef3242e5ed2b75521a90225a5a0f891\",\"license\":\"MIT\"},\"contracts/structs/JBRedemptionDelegateAllocation3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBRedemptionDelegate3_1_1} from '../interfaces/IJBRedemptionDelegate3_1_1.sol';\\n\\n/// @custom:member delegate A delegate contract to use for subsequent calls.\\n/// @custom:member amount The amount to send to the delegate.\\n/// @custom:member metadata Metadata to pass the delegate.\\nstruct JBRedemptionDelegateAllocation3_1_1 {\\n IJBRedemptionDelegate3_1_1 delegate;\\n uint256 amount;\\n bytes metadata;\\n}\\n\",\"keccak256\":\"0x16d2b586f4591b0d18324f233b4d4a13c6dc687b5f2c5becadbedbbdc373cdc4\",\"license\":\"MIT\"},\"contracts/structs/JBSplit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBSplitAllocator} from './../interfaces/IJBSplitAllocator.sol';\\n\\n/// @custom:member preferClaimed A flag that only has effect if a projectId is also specified, and the project has a token contract attached. If so, this flag indicates if the tokens that result from making a payment to the project should be delivered claimed into the beneficiary's wallet, or unclaimed to save gas.\\n/// @custom:member preferAddToBalance A flag indicating if a distribution to a project should prefer triggering it's addToBalance function instead of its pay function.\\n/// @custom:member percent The percent of the whole group that this split occupies. This number is out of `JBConstants.SPLITS_TOTAL_PERCENT`.\\n/// @custom:member projectId The ID of a project. If an allocator is not set but a projectId is set, funds will be sent to the protocol treasury belonging to the project who's ID is specified. Resulting tokens will be routed to the beneficiary with the claimed token preference respected.\\n/// @custom:member beneficiary An address. The role the of the beneficary depends on whether or not projectId is specified, and whether or not an allocator is specified. If allocator is set, the beneficiary will be forwarded to the allocator for it to use. If allocator is not set but projectId is set, the beneficiary is the address to which the project's tokens will be sent that result from a payment to it. If neither allocator or projectId are set, the beneficiary is where the funds from the split will be sent.\\n/// @custom:member lockedUntil Specifies if the split should be unchangeable until the specified time, with the exception of extending the locked period.\\n/// @custom:member allocator If an allocator is specified, funds will be sent to the allocator contract along with all properties of this split.\\nstruct JBSplit {\\n bool preferClaimed;\\n bool preferAddToBalance;\\n uint256 percent;\\n uint256 projectId;\\n address payable beneficiary;\\n uint256 lockedUntil;\\n IJBSplitAllocator allocator;\\n}\\n\",\"keccak256\":\"0x7bf3f79f95cf6211dcdcf5af68ddc963f2304379ea50a5feaf27c645879fe3fe\",\"license\":\"MIT\"},\"contracts/structs/JBSplitAllocationData.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBSplit} from './JBSplit.sol';\\n\\n/// @custom:member token The token being sent to the split allocator.\\n/// @custom:member amount The amount being sent to the split allocator, as a fixed point number.\\n/// @custom:member decimals The number of decimals in the amount.\\n/// @custom:member projectId The project to which the split belongs.\\n/// @custom:member group The group to which the split belongs.\\n/// @custom:member split The split that caused the allocation.\\nstruct JBSplitAllocationData {\\n address token;\\n uint256 amount;\\n uint256 decimals;\\n uint256 projectId;\\n uint256 group;\\n JBSplit split;\\n}\\n\",\"keccak256\":\"0x85dcbcad02f315a1a3cc44140ffc77fdfbcafed7089eab55ffb66f1bebc2b40b\",\"license\":\"MIT\"},\"contracts/structs/JBTokenAmount.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/// @custom:member token The token the payment was made in.\\n/// @custom:member value The amount of tokens that was paid, as a fixed point number.\\n/// @custom:member decimals The number of decimals included in the value fixed point number.\\n/// @custom:member currency The expected currency of the value.\\nstruct JBTokenAmount {\\n address token;\\n uint256 value;\\n uint256 decimals;\\n uint256 currency;\\n}\\n\",\"keccak256\":\"0x9317f1f47aef544de592a48a4b20fa3d54586d988c8bb7420b40076920ea200d\",\"license\":\"MIT\"},\"prb-math/contracts/PRBMath.sol\":{\"content\":\"// SPDX-License-Identifier: Unlicense\\npragma solidity >=0.8.4;\\n\\n/// @notice Emitted when the result overflows uint256.\\nerror PRBMath__MulDivFixedPointOverflow(uint256 prod1);\\n\\n/// @notice Emitted when the result overflows uint256.\\nerror PRBMath__MulDivOverflow(uint256 prod1, uint256 denominator);\\n\\n/// @notice Emitted when one of the inputs is type(int256).min.\\nerror PRBMath__MulDivSignedInputTooSmall();\\n\\n/// @notice Emitted when the intermediary absolute result overflows int256.\\nerror PRBMath__MulDivSignedOverflow(uint256 rAbs);\\n\\n/// @notice Emitted when the input is MIN_SD59x18.\\nerror PRBMathSD59x18__AbsInputTooSmall();\\n\\n/// @notice Emitted when ceiling a number overflows SD59x18.\\nerror PRBMathSD59x18__CeilOverflow(int256 x);\\n\\n/// @notice Emitted when one of the inputs is MIN_SD59x18.\\nerror PRBMathSD59x18__DivInputTooSmall();\\n\\n/// @notice Emitted when one of the intermediary unsigned results overflows SD59x18.\\nerror PRBMathSD59x18__DivOverflow(uint256 rAbs);\\n\\n/// @notice Emitted when the input is greater than 133.084258667509499441.\\nerror PRBMathSD59x18__ExpInputTooBig(int256 x);\\n\\n/// @notice Emitted when the input is greater than 192.\\nerror PRBMathSD59x18__Exp2InputTooBig(int256 x);\\n\\n/// @notice Emitted when flooring a number underflows SD59x18.\\nerror PRBMathSD59x18__FloorUnderflow(int256 x);\\n\\n/// @notice Emitted when converting a basic integer to the fixed-point format overflows SD59x18.\\nerror PRBMathSD59x18__FromIntOverflow(int256 x);\\n\\n/// @notice Emitted when converting a basic integer to the fixed-point format underflows SD59x18.\\nerror PRBMathSD59x18__FromIntUnderflow(int256 x);\\n\\n/// @notice Emitted when the product of the inputs is negative.\\nerror PRBMathSD59x18__GmNegativeProduct(int256 x, int256 y);\\n\\n/// @notice Emitted when multiplying the inputs overflows SD59x18.\\nerror PRBMathSD59x18__GmOverflow(int256 x, int256 y);\\n\\n/// @notice Emitted when the input is less than or equal to zero.\\nerror PRBMathSD59x18__LogInputTooSmall(int256 x);\\n\\n/// @notice Emitted when one of the inputs is MIN_SD59x18.\\nerror PRBMathSD59x18__MulInputTooSmall();\\n\\n/// @notice Emitted when the intermediary absolute result overflows SD59x18.\\nerror PRBMathSD59x18__MulOverflow(uint256 rAbs);\\n\\n/// @notice Emitted when the intermediary absolute result overflows SD59x18.\\nerror PRBMathSD59x18__PowuOverflow(uint256 rAbs);\\n\\n/// @notice Emitted when the input is negative.\\nerror PRBMathSD59x18__SqrtNegativeInput(int256 x);\\n\\n/// @notice Emitted when the calculating the square root overflows SD59x18.\\nerror PRBMathSD59x18__SqrtOverflow(int256 x);\\n\\n/// @notice Emitted when addition overflows UD60x18.\\nerror PRBMathUD60x18__AddOverflow(uint256 x, uint256 y);\\n\\n/// @notice Emitted when ceiling a number overflows UD60x18.\\nerror PRBMathUD60x18__CeilOverflow(uint256 x);\\n\\n/// @notice Emitted when the input is greater than 133.084258667509499441.\\nerror PRBMathUD60x18__ExpInputTooBig(uint256 x);\\n\\n/// @notice Emitted when the input is greater than 192.\\nerror PRBMathUD60x18__Exp2InputTooBig(uint256 x);\\n\\n/// @notice Emitted when converting a basic integer to the fixed-point format format overflows UD60x18.\\nerror PRBMathUD60x18__FromUintOverflow(uint256 x);\\n\\n/// @notice Emitted when multiplying the inputs overflows UD60x18.\\nerror PRBMathUD60x18__GmOverflow(uint256 x, uint256 y);\\n\\n/// @notice Emitted when the input is less than 1.\\nerror PRBMathUD60x18__LogInputTooSmall(uint256 x);\\n\\n/// @notice Emitted when the calculating the square root overflows UD60x18.\\nerror PRBMathUD60x18__SqrtOverflow(uint256 x);\\n\\n/// @notice Emitted when subtraction underflows UD60x18.\\nerror PRBMathUD60x18__SubUnderflow(uint256 x, uint256 y);\\n\\n/// @dev Common mathematical functions used in both PRBMathSD59x18 and PRBMathUD60x18. Note that this shared library\\n/// does not always assume the signed 59.18-decimal fixed-point or the unsigned 60.18-decimal fixed-point\\n/// representation. When it does not, it is explicitly mentioned in the NatSpec documentation.\\nlibrary PRBMath {\\n /// STRUCTS ///\\n\\n struct SD59x18 {\\n int256 value;\\n }\\n\\n struct UD60x18 {\\n uint256 value;\\n }\\n\\n /// STORAGE ///\\n\\n /// @dev How many trailing decimals can be represented.\\n uint256 internal constant SCALE = 1e18;\\n\\n /// @dev Largest power of two divisor of SCALE.\\n uint256 internal constant SCALE_LPOTD = 262144;\\n\\n /// @dev SCALE inverted mod 2^256.\\n uint256 internal constant SCALE_INVERSE =\\n 78156646155174841979727994598816262306175212592076161876661_508869554232690281;\\n\\n /// FUNCTIONS ///\\n\\n /// @notice Calculates the binary exponent of x using the binary fraction method.\\n /// @dev Has to use 192.64-bit fixed-point numbers.\\n /// See https://ethereum.stackexchange.com/a/96594/24693.\\n /// @param x The exponent as an unsigned 192.64-bit fixed-point number.\\n /// @return result The result as an unsigned 60.18-decimal fixed-point number.\\n function exp2(uint256 x) internal pure returns (uint256 result) {\\n unchecked {\\n // Start from 0.5 in the 192.64-bit fixed-point format.\\n result = 0x800000000000000000000000000000000000000000000000;\\n\\n // Multiply the result by root(2, 2^-i) when the bit at position i is 1. None of the intermediary results overflows\\n // because the initial result is 2^191 and all magic factors are less than 2^65.\\n if (x & 0x8000000000000000 > 0) {\\n result = (result * 0x16A09E667F3BCC909) >> 64;\\n }\\n if (x & 0x4000000000000000 > 0) {\\n result = (result * 0x1306FE0A31B7152DF) >> 64;\\n }\\n if (x & 0x2000000000000000 > 0) {\\n result = (result * 0x1172B83C7D517ADCE) >> 64;\\n }\\n if (x & 0x1000000000000000 > 0) {\\n result = (result * 0x10B5586CF9890F62A) >> 64;\\n }\\n if (x & 0x800000000000000 > 0) {\\n result = (result * 0x1059B0D31585743AE) >> 64;\\n }\\n if (x & 0x400000000000000 > 0) {\\n result = (result * 0x102C9A3E778060EE7) >> 64;\\n }\\n if (x & 0x200000000000000 > 0) {\\n result = (result * 0x10163DA9FB33356D8) >> 64;\\n }\\n if (x & 0x100000000000000 > 0) {\\n result = (result * 0x100B1AFA5ABCBED61) >> 64;\\n }\\n if (x & 0x80000000000000 > 0) {\\n result = (result * 0x10058C86DA1C09EA2) >> 64;\\n }\\n if (x & 0x40000000000000 > 0) {\\n result = (result * 0x1002C605E2E8CEC50) >> 64;\\n }\\n if (x & 0x20000000000000 > 0) {\\n result = (result * 0x100162F3904051FA1) >> 64;\\n }\\n if (x & 0x10000000000000 > 0) {\\n result = (result * 0x1000B175EFFDC76BA) >> 64;\\n }\\n if (x & 0x8000000000000 > 0) {\\n result = (result * 0x100058BA01FB9F96D) >> 64;\\n }\\n if (x & 0x4000000000000 > 0) {\\n result = (result * 0x10002C5CC37DA9492) >> 64;\\n }\\n if (x & 0x2000000000000 > 0) {\\n result = (result * 0x1000162E525EE0547) >> 64;\\n }\\n if (x & 0x1000000000000 > 0) {\\n result = (result * 0x10000B17255775C04) >> 64;\\n }\\n if (x & 0x800000000000 > 0) {\\n result = (result * 0x1000058B91B5BC9AE) >> 64;\\n }\\n if (x & 0x400000000000 > 0) {\\n result = (result * 0x100002C5C89D5EC6D) >> 64;\\n }\\n if (x & 0x200000000000 > 0) {\\n result = (result * 0x10000162E43F4F831) >> 64;\\n }\\n if (x & 0x100000000000 > 0) {\\n result = (result * 0x100000B1721BCFC9A) >> 64;\\n }\\n if (x & 0x80000000000 > 0) {\\n result = (result * 0x10000058B90CF1E6E) >> 64;\\n }\\n if (x & 0x40000000000 > 0) {\\n result = (result * 0x1000002C5C863B73F) >> 64;\\n }\\n if (x & 0x20000000000 > 0) {\\n result = (result * 0x100000162E430E5A2) >> 64;\\n }\\n if (x & 0x10000000000 > 0) {\\n result = (result * 0x1000000B172183551) >> 64;\\n }\\n if (x & 0x8000000000 > 0) {\\n result = (result * 0x100000058B90C0B49) >> 64;\\n }\\n if (x & 0x4000000000 > 0) {\\n result = (result * 0x10000002C5C8601CC) >> 64;\\n }\\n if (x & 0x2000000000 > 0) {\\n result = (result * 0x1000000162E42FFF0) >> 64;\\n }\\n if (x & 0x1000000000 > 0) {\\n result = (result * 0x10000000B17217FBB) >> 64;\\n }\\n if (x & 0x800000000 > 0) {\\n result = (result * 0x1000000058B90BFCE) >> 64;\\n }\\n if (x & 0x400000000 > 0) {\\n result = (result * 0x100000002C5C85FE3) >> 64;\\n }\\n if (x & 0x200000000 > 0) {\\n result = (result * 0x10000000162E42FF1) >> 64;\\n }\\n if (x & 0x100000000 > 0) {\\n result = (result * 0x100000000B17217F8) >> 64;\\n }\\n if (x & 0x80000000 > 0) {\\n result = (result * 0x10000000058B90BFC) >> 64;\\n }\\n if (x & 0x40000000 > 0) {\\n result = (result * 0x1000000002C5C85FE) >> 64;\\n }\\n if (x & 0x20000000 > 0) {\\n result = (result * 0x100000000162E42FF) >> 64;\\n }\\n if (x & 0x10000000 > 0) {\\n result = (result * 0x1000000000B17217F) >> 64;\\n }\\n if (x & 0x8000000 > 0) {\\n result = (result * 0x100000000058B90C0) >> 64;\\n }\\n if (x & 0x4000000 > 0) {\\n result = (result * 0x10000000002C5C860) >> 64;\\n }\\n if (x & 0x2000000 > 0) {\\n result = (result * 0x1000000000162E430) >> 64;\\n }\\n if (x & 0x1000000 > 0) {\\n result = (result * 0x10000000000B17218) >> 64;\\n }\\n if (x & 0x800000 > 0) {\\n result = (result * 0x1000000000058B90C) >> 64;\\n }\\n if (x & 0x400000 > 0) {\\n result = (result * 0x100000000002C5C86) >> 64;\\n }\\n if (x & 0x200000 > 0) {\\n result = (result * 0x10000000000162E43) >> 64;\\n }\\n if (x & 0x100000 > 0) {\\n result = (result * 0x100000000000B1721) >> 64;\\n }\\n if (x & 0x80000 > 0) {\\n result = (result * 0x10000000000058B91) >> 64;\\n }\\n if (x & 0x40000 > 0) {\\n result = (result * 0x1000000000002C5C8) >> 64;\\n }\\n if (x & 0x20000 > 0) {\\n result = (result * 0x100000000000162E4) >> 64;\\n }\\n if (x & 0x10000 > 0) {\\n result = (result * 0x1000000000000B172) >> 64;\\n }\\n if (x & 0x8000 > 0) {\\n result = (result * 0x100000000000058B9) >> 64;\\n }\\n if (x & 0x4000 > 0) {\\n result = (result * 0x10000000000002C5D) >> 64;\\n }\\n if (x & 0x2000 > 0) {\\n result = (result * 0x1000000000000162E) >> 64;\\n }\\n if (x & 0x1000 > 0) {\\n result = (result * 0x10000000000000B17) >> 64;\\n }\\n if (x & 0x800 > 0) {\\n result = (result * 0x1000000000000058C) >> 64;\\n }\\n if (x & 0x400 > 0) {\\n result = (result * 0x100000000000002C6) >> 64;\\n }\\n if (x & 0x200 > 0) {\\n result = (result * 0x10000000000000163) >> 64;\\n }\\n if (x & 0x100 > 0) {\\n result = (result * 0x100000000000000B1) >> 64;\\n }\\n if (x & 0x80 > 0) {\\n result = (result * 0x10000000000000059) >> 64;\\n }\\n if (x & 0x40 > 0) {\\n result = (result * 0x1000000000000002C) >> 64;\\n }\\n if (x & 0x20 > 0) {\\n result = (result * 0x10000000000000016) >> 64;\\n }\\n if (x & 0x10 > 0) {\\n result = (result * 0x1000000000000000B) >> 64;\\n }\\n if (x & 0x8 > 0) {\\n result = (result * 0x10000000000000006) >> 64;\\n }\\n if (x & 0x4 > 0) {\\n result = (result * 0x10000000000000003) >> 64;\\n }\\n if (x & 0x2 > 0) {\\n result = (result * 0x10000000000000001) >> 64;\\n }\\n if (x & 0x1 > 0) {\\n result = (result * 0x10000000000000001) >> 64;\\n }\\n\\n // We're doing two things at the same time:\\n //\\n // 1. Multiply the result by 2^n + 1, where \\\"2^n\\\" is the integer part and the one is added to account for\\n // the fact that we initially set the result to 0.5. This is accomplished by subtracting from 191\\n // rather than 192.\\n // 2. Convert the result to the unsigned 60.18-decimal fixed-point format.\\n //\\n // This works because 2^(191-ip) = 2^ip / 2^191, where \\\"ip\\\" is the integer part \\\"2^n\\\".\\n result *= SCALE;\\n result >>= (191 - (x >> 64));\\n }\\n }\\n\\n /// @notice Finds the zero-based index of the first one in the binary representation of x.\\n /// @dev See the note on msb in the \\\"Find First Set\\\" Wikipedia article https://en.wikipedia.org/wiki/Find_first_set\\n /// @param x The uint256 number for which to find the index of the most significant bit.\\n /// @return msb The index of the most significant bit as an uint256.\\n function mostSignificantBit(uint256 x) internal pure returns (uint256 msb) {\\n if (x >= 2**128) {\\n x >>= 128;\\n msb += 128;\\n }\\n if (x >= 2**64) {\\n x >>= 64;\\n msb += 64;\\n }\\n if (x >= 2**32) {\\n x >>= 32;\\n msb += 32;\\n }\\n if (x >= 2**16) {\\n x >>= 16;\\n msb += 16;\\n }\\n if (x >= 2**8) {\\n x >>= 8;\\n msb += 8;\\n }\\n if (x >= 2**4) {\\n x >>= 4;\\n msb += 4;\\n }\\n if (x >= 2**2) {\\n x >>= 2;\\n msb += 2;\\n }\\n if (x >= 2**1) {\\n // No need to shift x any more.\\n msb += 1;\\n }\\n }\\n\\n /// @notice Calculates floor(x*y\\u00f7denominator) with full precision.\\n ///\\n /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv.\\n ///\\n /// Requirements:\\n /// - The denominator cannot be zero.\\n /// - The result must fit within uint256.\\n ///\\n /// Caveats:\\n /// - This function does not work with fixed-point numbers.\\n ///\\n /// @param x The multiplicand as an uint256.\\n /// @param y The multiplier as an uint256.\\n /// @param denominator The divisor as an uint256.\\n /// @return result The result as an uint256.\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator\\n ) internal pure returns (uint256 result) {\\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\\n // variables such that product = prod1 * 2^256 + prod0.\\n uint256 prod0; // Least significant 256 bits of the product\\n uint256 prod1; // Most significant 256 bits of the product\\n assembly {\\n let mm := mulmod(x, y, not(0))\\n prod0 := mul(x, y)\\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\\n }\\n\\n // Handle non-overflow cases, 256 by 256 division.\\n if (prod1 == 0) {\\n unchecked {\\n result = prod0 / denominator;\\n }\\n return result;\\n }\\n\\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\\n if (prod1 >= denominator) {\\n revert PRBMath__MulDivOverflow(prod1, denominator);\\n }\\n\\n ///////////////////////////////////////////////\\n // 512 by 256 division.\\n ///////////////////////////////////////////////\\n\\n // Make division exact by subtracting the remainder from [prod1 prod0].\\n uint256 remainder;\\n assembly {\\n // Compute remainder using mulmod.\\n remainder := mulmod(x, y, denominator)\\n\\n // Subtract 256 bit number from 512 bit number.\\n prod1 := sub(prod1, gt(remainder, prod0))\\n prod0 := sub(prod0, remainder)\\n }\\n\\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\\n // See https://cs.stackexchange.com/q/138556/92363.\\n unchecked {\\n // Does not overflow because the denominator cannot be zero at this stage in the function.\\n uint256 lpotdod = denominator & (~denominator + 1);\\n assembly {\\n // Divide denominator by lpotdod.\\n denominator := div(denominator, lpotdod)\\n\\n // Divide [prod1 prod0] by lpotdod.\\n prod0 := div(prod0, lpotdod)\\n\\n // Flip lpotdod such that it is 2^256 / lpotdod. If lpotdod is zero, then it becomes one.\\n lpotdod := add(div(sub(0, lpotdod), lpotdod), 1)\\n }\\n\\n // Shift in bits from prod1 into prod0.\\n prod0 |= prod1 * lpotdod;\\n\\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\\n // four bits. That is, denominator * inv = 1 mod 2^4.\\n uint256 inverse = (3 * denominator) ^ 2;\\n\\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\\n // in modular arithmetic, doubling the correct bits in each step.\\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\\n\\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\\n // is no longer required.\\n result = prod0 * inverse;\\n return result;\\n }\\n }\\n\\n /// @notice Calculates floor(x*y\\u00f71e18) with full precision.\\n ///\\n /// @dev Variant of \\\"mulDiv\\\" with constant folding, i.e. in which the denominator is always 1e18. Before returning the\\n /// final result, we add 1 if (x * y) % SCALE >= HALF_SCALE. Without this, 6.6e-19 would be truncated to 0 instead of\\n /// being rounded to 1e-18. See \\\"Listing 6\\\" and text above it at https://accu.org/index.php/journals/1717.\\n ///\\n /// Requirements:\\n /// - The result must fit within uint256.\\n ///\\n /// Caveats:\\n /// - The body is purposely left uncommented; see the NatSpec comments in \\\"PRBMath.mulDiv\\\" to understand how this works.\\n /// - It is assumed that the result can never be type(uint256).max when x and y solve the following two equations:\\n /// 1. x * y = type(uint256).max * SCALE\\n /// 2. (x * y) % SCALE >= SCALE / 2\\n ///\\n /// @param x The multiplicand as an unsigned 60.18-decimal fixed-point number.\\n /// @param y The multiplier as an unsigned 60.18-decimal fixed-point number.\\n /// @return result The result as an unsigned 60.18-decimal fixed-point number.\\n function mulDivFixedPoint(uint256 x, uint256 y) internal pure returns (uint256 result) {\\n uint256 prod0;\\n uint256 prod1;\\n assembly {\\n let mm := mulmod(x, y, not(0))\\n prod0 := mul(x, y)\\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\\n }\\n\\n if (prod1 >= SCALE) {\\n revert PRBMath__MulDivFixedPointOverflow(prod1);\\n }\\n\\n uint256 remainder;\\n uint256 roundUpUnit;\\n assembly {\\n remainder := mulmod(x, y, SCALE)\\n roundUpUnit := gt(remainder, 499999999999999999)\\n }\\n\\n if (prod1 == 0) {\\n unchecked {\\n result = (prod0 / SCALE) + roundUpUnit;\\n return result;\\n }\\n }\\n\\n assembly {\\n result := add(\\n mul(\\n or(\\n div(sub(prod0, remainder), SCALE_LPOTD),\\n mul(sub(prod1, gt(remainder, prod0)), add(div(sub(0, SCALE_LPOTD), SCALE_LPOTD), 1))\\n ),\\n SCALE_INVERSE\\n ),\\n roundUpUnit\\n )\\n }\\n }\\n\\n /// @notice Calculates floor(x*y\\u00f7denominator) with full precision.\\n ///\\n /// @dev An extension of \\\"mulDiv\\\" for signed numbers. Works by computing the signs and the absolute values separately.\\n ///\\n /// Requirements:\\n /// - None of the inputs can be type(int256).min.\\n /// - The result must fit within int256.\\n ///\\n /// @param x The multiplicand as an int256.\\n /// @param y The multiplier as an int256.\\n /// @param denominator The divisor as an int256.\\n /// @return result The result as an int256.\\n function mulDivSigned(\\n int256 x,\\n int256 y,\\n int256 denominator\\n ) internal pure returns (int256 result) {\\n if (x == type(int256).min || y == type(int256).min || denominator == type(int256).min) {\\n revert PRBMath__MulDivSignedInputTooSmall();\\n }\\n\\n // Get hold of the absolute values of x, y and the denominator.\\n uint256 ax;\\n uint256 ay;\\n uint256 ad;\\n unchecked {\\n ax = x < 0 ? uint256(-x) : uint256(x);\\n ay = y < 0 ? uint256(-y) : uint256(y);\\n ad = denominator < 0 ? uint256(-denominator) : uint256(denominator);\\n }\\n\\n // Compute the absolute value of (x*y)\\u00f7denominator. The result must fit within int256.\\n uint256 rAbs = mulDiv(ax, ay, ad);\\n if (rAbs > uint256(type(int256).max)) {\\n revert PRBMath__MulDivSignedOverflow(rAbs);\\n }\\n\\n // Get the signs of x, y and the denominator.\\n uint256 sx;\\n uint256 sy;\\n uint256 sd;\\n assembly {\\n sx := sgt(x, sub(0, 1))\\n sy := sgt(y, sub(0, 1))\\n sd := sgt(denominator, sub(0, 1))\\n }\\n\\n // XOR over sx, sy and sd. This is checking whether there are one or three negative signs in the inputs.\\n // If yes, the result should be negative.\\n result = sx ^ sy ^ sd == 0 ? -int256(rAbs) : int256(rAbs);\\n }\\n\\n /// @notice Calculates the square root of x, rounding down.\\n /// @dev Uses the Babylonian method https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method.\\n ///\\n /// Caveats:\\n /// - This function does not work with fixed-point numbers.\\n ///\\n /// @param x The uint256 number for which to calculate the square root.\\n /// @return result The result as an uint256.\\n function sqrt(uint256 x) internal pure returns (uint256 result) {\\n if (x == 0) {\\n return 0;\\n }\\n\\n // Set the initial guess to the closest power of two that is higher than x.\\n uint256 xAux = uint256(x);\\n result = 1;\\n if (xAux >= 0x100000000000000000000000000000000) {\\n xAux >>= 128;\\n result <<= 64;\\n }\\n if (xAux >= 0x10000000000000000) {\\n xAux >>= 64;\\n result <<= 32;\\n }\\n if (xAux >= 0x100000000) {\\n xAux >>= 32;\\n result <<= 16;\\n }\\n if (xAux >= 0x10000) {\\n xAux >>= 16;\\n result <<= 8;\\n }\\n if (xAux >= 0x100) {\\n xAux >>= 8;\\n result <<= 4;\\n }\\n if (xAux >= 0x10) {\\n xAux >>= 4;\\n result <<= 2;\\n }\\n if (xAux >= 0x8) {\\n result <<= 1;\\n }\\n\\n // The operations can never overflow because the result is max 2^127 when it enters this block.\\n unchecked {\\n result = (result + x / result) >> 1;\\n result = (result + x / result) >> 1;\\n result = (result + x / result) >> 1;\\n result = (result + x / result) >> 1;\\n result = (result + x / result) >> 1;\\n result = (result + x / result) >> 1;\\n result = (result + x / result) >> 1; // Seven iterations should be enough\\n uint256 roundedDownResult = x / result;\\n return result >= roundedDownResult ? roundedDownResult : result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x62cbabae4910e168e99b9c2c3e3b5c9c7ad5e7abd961dcc63b7ea3d83d8ea87e\",\"license\":\"Unlicense\"}},\"version\":1}", + "bytecode": "0x6101e060405263017d78406002553480156200001a57600080fd5b5060405162005f4a38038062005f4a8339810160408190526200003d916200020a565b61eeee6080819052601260a0819052600160c08190526001600160a01b038a1660e0528a818b8b8b8b8b8b8b6200007433620000cf565b6101a08990526101c08890526001600160a01b0380871661010052858116610120528481166101405283811661016052821661018052620000b5816200011f565b5050505050505050505050505050505050505050620002bf565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000546001600160a01b031633146200017f5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064015b60405180910390fd5b6001600160a01b038116620001e65760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840162000176565b620001f181620000cf565b50565b6001600160a01b0381168114620001f157600080fd5b600080600080600080600080610100898b0312156200022857600080fd5b8851975060208901516200023c81620001f4565b60408a01519097506200024f81620001f4565b60608a01519096506200026281620001f4565b60808a01519095506200027581620001f4565b60a08a01519094506200028881620001f4565b60c08a01519093506200029b81620001f4565b60e08a0151909250620002ae81620001f4565b809150509295985092959890939650565b60805160a05160c05160e05161010051610120516101405161016051610180516101a0516101c051615a2f6200051b600039600081816103cf015261206e01526000818161030701526118d00152600081816104f701528181610ad5015281816112fc0152818161189e01528181611f19015281816126250152818161298701528181612a9401526136d101526000818161065601526114810152600081816102bb01526133a801526000818161060f0152818161173b01528181611981015281816123ce01528181612bdf0152818161324e0152613ea80152600081816104a50152818161099001528181610e7d0152818161123101528181611fc501526126df01526000818161056b01528181611dad01528181611e4901528181612200015261229c0152600081816102660152818161070e015281816113cc0152818161142e0152818161187801528181611b5401528181612d750152612e0501526000818161033b015281816105db0152818161136d01528181611399015281816113f90152818161145b0152818161185201528181611b2e01528181612d4f01528181612ddf0152613c5c0152600081816106cc015281816107620152818161087e01528181610a2801528181610b5601528181610bc9015281816115130152818161181d01528181611af801528181611c46015281816123a30152818161245a0152818161249501528181612d1a01528181612da901528181612f320152818161322101528181613c2701528181613ccf01528181613ed5015281816140300152818161406e015281816141a301526141e70152615a2f6000f3fe6080604052600436106101f95760003560e01c80638da5cb5b1161010d578063c715967a116100a0578063df21a7dd1161006f578063df21a7dd146106ae578063e5a6b10f146106fc578063f2fde38b14610730578063fc0c546a14610750578063fe663f0f1461078457600080fd5b8063c715967a14610631578063d3419bf314610644578063d6dacc5314610678578063ddca3f431461069857600080fd5b8063ad007d63116100dc578063ad007d6314610559578063b631b5001461058d578063b7bad1b1146105bd578063c41c2f24146105fd57600080fd5b80638da5cb5b146104c7578063975057e7146104e5578063a02f801c14610519578063a32e1e961461053957600080fd5b80634a4305c011610190578063715018a61161015f578063715018a6146104115780637258002c1461042657806389701db5146104465780638af56094146104665780638b79543c1461049357600080fd5b80634a4305c01461037d578063637913ac1461039d57806366248b86146103bd57806369fe0e2d146103f157600080fd5b80632bdfe004116101cc5780632bdfe004146102a95780632d1a5903146102f5578063313ce56714610329578063405b84fa1461035d57600080fd5b806301ffc9a7146101fe5780630cf8e858146102335780631982d679146102485780631ebc263f14610296575b600080fd5b34801561020a57600080fd5b5061021e6102193660046144ec565b6107a4565b60405190151581526020015b60405180910390f35b610246610241366004614573565b61084e565b005b34801561025457600080fd5b50610288610263366004614608565b507f000000000000000000000000000000000000000000000000000000000000000090565b60405190815260200161022a565b6102886102a4366004614633565b610871565b3480156102b557600080fd5b506102dd7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200161022a565b34801561030157600080fd5b506102887f000000000000000000000000000000000000000000000000000000000000000081565b34801561033557600080fd5b506102887f000000000000000000000000000000000000000000000000000000000000000081565b34801561036957600080fd5b506102886103783660046146fa565b610977565b34801561038957600080fd5b5061028861039836600461472a565b610c73565b3480156103a957600080fd5b506102466103b8366004614608565b610c8f565b3480156103c957600080fd5b506102887f000000000000000000000000000000000000000000000000000000000000000081565b3480156103fd57600080fd5b5061024661040c366004614793565b610d16565b34801561041d57600080fd5b50610246610da5565b34801561043257600080fd5b506102466104413660046147ac565b610ddb565b34801561045257600080fd5b50610246610461366004614793565b610e67565b34801561047257600080fd5b50610486610481366004614793565b61116b565b60405161022a91906147da565b34801561049f57600080fd5b506102dd7f000000000000000000000000000000000000000000000000000000000000000081565b3480156104d357600080fd5b506000546001600160a01b03166102dd565b3480156104f157600080fd5b506102dd7f000000000000000000000000000000000000000000000000000000000000000081565b34801561052557600080fd5b50610288610534366004614980565b611218565b34801561054557600080fd5b50610288610554366004614793565b6112d3565b34801561056557600080fd5b506102dd7f000000000000000000000000000000000000000000000000000000000000000081565b34801561059957600080fd5b5061021e6105a8366004614608565b60046020526000908152604090205460ff1681565b3480156105c957600080fd5b506102886105d8366004614608565b507f000000000000000000000000000000000000000000000000000000000000000090565b34801561060957600080fd5b506102dd7f000000000000000000000000000000000000000000000000000000000000000081565b61024661063f366004614a38565b611508565b34801561065057600080fd5b506102dd7f000000000000000000000000000000000000000000000000000000000000000081565b34801561068457600080fd5b506003546102dd906001600160a01b031681565b3480156106a457600080fd5b5061028860025481565b3480156106ba57600080fd5b5061021e6106c9366004614adf565b507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b34801561070857600080fd5b506102887f000000000000000000000000000000000000000000000000000000000000000081565b34801561073c57600080fd5b5061024661074b366004614608565b611604565b34801561075c57600080fd5b506102dd7f000000000000000000000000000000000000000000000000000000000000000081565b34801561079057600080fd5b5061028861079f366004614b0b565b61169f565b60006001600160e01b0319821615806107cd57506001600160e01b0319821663edb527eb60e01b145b806107e857506001600160e01b031982166301290c1760e61b145b8061080357506001600160e01b0319821663280be00760e21b145b8061081e57506001600160e01b0319821663fe663f0f60e01b145b8061083957506001600160e01b0319821663ad007d6360e01b145b806108485750610848826116cf565b92915050565b6108578761171f565b610868878787600088888888611508565b50505050505050565b600061087c8b61171f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031661eeee146108eb5734156108cd57604051635e7e9adf60e11b815260040160405180910390fd5b476108d933308d6117cb565b6108e38147614bd9565b9a50506108ef565b3499505b6109688a338d8b8b8b8b8b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8f018190048102820181019092528d815292508d91508c90819084018382808284376000920191909152506117da92505050565b9b9a5050505050505050505050565b6040516331a9108f60e11b8152600481018390526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636352211e90602401602060405180830381865afa1580156109df573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a039190614bec565b836004610a11838383611d82565b60405163df21a7dd60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301526024820188905286169063df21a7dd90604401602060405180830381865afa158015610a7e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aa29190614c09565b610abf5760405163581010ed60e01b815260040160405180910390fd5b604051636bb6a5ad60e01b8152600481018790527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636bb6a5ad906024016020604051808303816000875af1158015610b26573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b4a9190614c26565b93508315610c255760007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031661eeee14610b8d576000610b8f565b845b6040805160208101825260008152905163019f1d0b60e31b81529192506001600160a01b03881691630cf8e858918491610bf1918c918b917f000000000000000000000000000000000000000000000000000000000000000091600401614c8f565b6000604051808303818588803b158015610c0a57600080fd5b505af1158015610c1e573d6000803e3d6000fd5b5050505050505b604080518581523360208201526001600160a01b0387169188917fa7519e5f94697b7f53e97c5eb46a0c730a296ab686ab8fd333835c5f735784eb910160405180910390a350505092915050565b6000610c83888888878787611ee6565b98975050505050505050565b6000546001600160a01b03163314610cc25760405162461bcd60e51b8152600401610cb990614cca565b60405180910390fd5b600380546001600160a01b0319166001600160a01b0383169081179091556040513381527f0a9a80fe9716605b3e52abb3d792d6a4e7816d6afc02a5a4ef023081feaf9f609060200160405180910390a250565b6000546001600160a01b03163314610d405760405162461bcd60e51b8152600401610cb990614cca565b6302faf080811115610d65576040516345fbd9c160e01b815260040160405180910390fd5b6002819055604080518281523360208201527fd7414e590e1cb532989ab2a34c8f4c2c17f7ab6f006efeeaef2e87cd5008c202910160405180910390a150565b6000546001600160a01b03163314610dcf5760405162461bcd60e51b8152600401610cb990614cca565b610dd9600061217b565b565b6000546001600160a01b03163314610e055760405162461bcd60e51b8152600401610cb990614cca565b6001600160a01b038216600081815260046020908152604091829020805460ff191685151590811790915591513381529192917fa2653e25a502c023a5830d0de847ef6f458387865b1f4f575d7594f9f2c0d71e910160405180910390a35050565b6040516331a9108f60e11b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636352211e90602401602060405180830381865afa158015610ecc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ef09190614bec565b816005610f056000546001600160a01b031690565b6001600160a01b0316336001600160a01b031614610f25848484846121cb565b600085815260016020908152604080832080548251818502810185019093528083529192909190849084015b82821015610fbe57600084815260209081902060408051608081018252600286029092018054835260019081015463ffffffff8082168587015264010000000082041692840192909252600160401b9091046001600160a01b031660608301529083529092019101610f51565b5050506000888152600160205260408120929350610fdd92915061444b565b80516000805b8281101561116057838181518110610ffd57610ffd614cff565b60200260200101516020015163ffffffff16600014806110435750633b9aca0084828151811061102f5761102f614cff565b60200260200101516040015163ffffffff16145b6110ba576110b584828151811061105c5761105c614cff565b60200260200101516000015185838151811061107a5761107a614cff565b60200260200101516020015163ffffffff1686848151811061109e5761109e614cff565b60200260200101516040015163ffffffff1661233f565b6110bd565b60005b91506110e7828583815181106110d5576110d5614cff565b6020026020010151606001518b612385565b60011515828a7fcf0c92a2c6d7c42f488326b0cb900104b99984b6b218db81cd29371364a3525187858151811061112057611120614cff565b602002602001015160600151336040516111509291906001600160a01b0392831681529116602082015260400190565b60405180910390a4600101610fe3565b505050505050505050565b606060016000838152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b8282101561120d57600084815260209081902060408051608081018252600286029092018054835260019081015463ffffffff8082168587015264010000000082041692840192909252600160401b9091046001600160a01b0316606083015290835290920191016111a0565b505050509050919050565b6040516331a9108f60e11b8152600481018a90526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636352211e90602401602060405180830381865afa158015611280573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112a49190614bec565b8a60116112b2838383611d82565b6112c28d8d8d8c8c8c8c8c6125f2565b9d9c50505050505050505050505050565b60405163035240c760e61b81523060048201526024810182905260009081906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063d49031c090604401602060405180830381865afa158015611343573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113679190614c26565b905060007f00000000000000000000000000000000000000000000000000000000000000006012146113c4576113bf827f00000000000000000000000000000000000000000000000000000000000000006012612839565b6113c6565b815b905060017f0000000000000000000000000000000000000000000000000000000000000000146114fe576114f98161141f7f0000000000000000000000000000000000000000000000000000000000000000600a614df9565b604051635268657960e11b81527f00000000000000000000000000000000000000000000000000000000000000006004820152600160248201527f000000000000000000000000000000000000000000000000000000000000000060448201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a4d0caf290606401602060405180830381865afa1580156114d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114f49190614c26565b612896565b611500565b805b949350505050565b6115118861171f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031661eeee1461158057341561156257604051635e7e9adf60e11b815260040160405180910390fd5b4761156e33308a6117cb565b6115788147614bd9565b975050611584565b3496505b6115fa88888787878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8b01819004810282018101909252898152925089915088908190840183828082843760009201919091525061296392505050565b5050505050505050565b6000546001600160a01b0316331461162e5760405162461bcd60e51b8152600401610cb990614cca565b6001600160a01b0381166116935760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610cb9565b61169c8161217b565b50565b6000888860026116b0838383611d82565b6116bf8c8c8c8b8b8b8b612a55565b9c9b505050505050505050505050565b60006001600160e01b0319821663301cdc3960e21b148061170057506001600160e01b0319821663144b000160e11b145b8061084857506301ffc9a760e01b6001600160e01b0319831614610848565b604051636e49181f60e01b8152600481018290523060248201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636e49181f90604401602060405180830381865afa15801561178a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117ae9190614c09565b61169c57604051631b1d5a5960e31b815260040160405180910390fd5b6117d582826130ea565b505050565b60006001600160a01b0386166118035760405163a762251360e01b815260040160405180910390fd5b61180b61446c565b606060008060405180608001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020018e81526020017f000000000000000000000000000000000000000000000000000000000000000081526020017f000000000000000000000000000000000000000000000000000000000000000081525090507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632fa1b3918d838e7f00000000000000000000000000000000000000000000000000000000000000008f8d8d6040518863ffffffff1660e01b81526004016119149796959493929190614e31565b6000604051808303816000875af1158015611933573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261195b9190810190614f95565b995091955090935091508115611a9057604051632eec7b5560e11b8152600481018c90527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635dd8f6aa90602401602060405180830381865afa1580156119d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119f49190614bec565b604051638ae9c07b60e01b8152600481018d9052602481018490526001600160a01b038c8116604483015260c06064830152600060c48301528a15156084830152600160a48301529190911690638ae9c07b9060e4016020604051808303816000875af1158015611a69573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a8d9190614c26565b94505b88851015611ab157604051633dca309360e11b815260040160405180910390fd5b825115611d245760006040518061016001604052808e6001600160a01b031681526020018d81526020018660200151815260200183815260200160405180608001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602001600081526020017f000000000000000000000000000000000000000000000000000000000000000081526020017f000000000000000000000000000000000000000000000000000000000000000081525081526020018781526020018c6001600160a01b031681526020018a15158152602001898152602001604051806020016040528060008152508152602001888152509050600084519050611bec604051806060016040528060006001600160a01b0316815260200160008152602001606081525090565b60005b82811015611d1f57868181518110611c0957611c09614cff565b60209081029190910101519150602080830151608086015190910152604082015161012085015281516001600160a01b0390811690636b204943907f00000000000000000000000000000000000000000000000000000000000000001661eeee14611c75576000611c7b565b83602001515b866040518363ffffffff1660e01b8152600401611c9891906151b0565b6000604051808303818588803b158015611cb157600080fd5b505af1158015611cc5573d6000803e3d6000fd5b505050505081600001516001600160a01b03167f232bbbe420e7bac6f941dc82678daec2b4c712378d91e864b69aab6e26cdd42485846020015133604051611d0f939291906151c3565b60405180910390a2600101611bef565b505050505b50505087816000015182602001517f133161f1c9161488f777ab9a26aae91d47c0d9a3fafb398960f138db02c737978c8b8f888b8b33604051611d6d97969594939291906151f6565b60405180910390a45098975050505050505050565b336001600160a01b03841614801590611e2b575060405163c161c93f60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063c161c93f90611de8903390879087908790600401615256565b602060405180830381865afa158015611e05573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e299190614c09565b155b8015611ec8575060405163c161c93f60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063c161c93f90611e8590339087906000908790600401615256565b602060405180830381865afa158015611ea2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ec69190614c09565b155b156117d55760405163075fd2b160e01b815260040160405180910390fd5b60405163c664459760e01b8152600481018790526024810186905260448101859052600090819081906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063c664459790606401610140604051808303816000875af1158015611f63573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f87919061527f565b9150915085811015611fac5760405163b01493c160e01b815260040160405180910390fd5b6040516331a9108f60e11b8152600481018a90526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636352211e90602401602060405180830381865afa158015612014573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120389190614bec565b600254909150600090818115612058576120538d6000613203565b61205e565b633b9aca005b90506000806120958f89602001517f00000000000000000000000000000000000000000000000000000000000000008a8888613377565b92509050633b9aca0083146120a957908101905b816000036120b85760006120dc565b6120dc8f6120d38a61010001516001604f9190911c81161490565b84878a88613537565b9450801561211957633b9aca0083146120ff576120fa81858561233f565b612102565b60005b61210c9082614bd9565b985061211930878b6117cb565b505050508a846000015185602001517fc41a8d26c70cfcf1b9ea10f82482ac947b8be5bea2750bc729af844bbfde1e28858e88878c8f8f336040516121659897969594939291906152d7565b60405180910390a4505050509695505050505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b801580156121e25750336001600160a01b03851614155b801561227e575060405163c161c93f60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063c161c93f9061223b903390889088908890600401615256565b602060405180830381865afa158015612258573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061227c9190614c09565b155b801561231b575060405163c161c93f60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063c161c93f906122d890339088906000908890600401615256565b602060405180830381865afa1580156122f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123199190614c09565b155b156123395760405163075fd2b160e01b815260040160405180910390fd5b50505050565b6000806123518484633b9aca00612896565b61235b9085614bd9565b905061237085633b9aca006114f4818561532a565b61237a9086614bd9565b9150505b9392505050565b604051630862026560e41b8152600160048201526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660248301526000917f000000000000000000000000000000000000000000000000000000000000000090911690638620265090604401602060405180830381865afa158015612417573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061243b9190614bec565b9050806001600160a01b0316631ebc263f61eeee6001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03161461248e576000612490565b855b6001877f0000000000000000000000000000000000000000000000000000000000000000886000808a6040516020016124cb91815260200190565b6040516020818303038152906040526040518963ffffffff1660e01b81526004016124fc979695949392919061533d565b60206040518083038185885af193505050508015612537575060408051601f3d908101601f1916820190925261253491810190614c26565b60015b6125eb573d808015612565576040519150601f19603f3d011682016040523d82523d6000602084013e61256a565b606091505b506125a783306001600160a01b03851603612586576000612588565b835b306001600160a01b0386160361259f5760006125a1565b875b886136b4565b6001837f80a889d08f0d59eb962335b57fb1d5b29e86e3d23f15087b5541fddf15422bbe8784336040516125dd93929190615395565b60405180910390a350612339565b5050505050565b604051632538671560e01b8152600481018990526024810188905260448101879052600090819081906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690632538671590606401610140604051808303816000875af115801561266f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612693919061527f565b91509150878110156126b85760405163b01493c160e01b815260040160405180910390fd5b6002546040516331a9108f60e11b8152600481018d90526000919082906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690636352211e90602401602060405180830381865afa158015612726573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061274a9190614bec565b9050600082158061276a57503360009081526004602052604090205460ff165b61277e576127798f6001613203565b612784565b633b9aca005b9050633b9aca0081146127ba576127b58f6127ac8861010001516001604f9190911c81161490565b87868686613537565b6127bd565b60005b93508385039650866000146127d7576127d7308c896117cb565b505050508a826000015183602001517f2eeee47c6d8d31c3523c3aa07b4c3e3795db36be4c04546ef3e30a5102f568e18a8e86898d8d8d336040516128239897969594939291906153c6565b60405180910390a4505098975050505050505050565b600082820361284957508261237e565b828211156128775761285b8383614bd9565b61286690600a614df9565b6128709085615426565b905061237e565b6128818284614bd9565b61288c90600a614df9565b612870908561545b565b60008080600019858709858702925082811083820303915050806000036128d0578382816128c6576128c6615445565b049250505061237e565b8381106128fa57604051631dcf306360e21b81526004810182905260248101859052604401610cb9565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60008361297157600061297b565b61297b8686613731565b90506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663e7c8e3e3876129b7848961532a565b6040516001600160e01b031960e085901b16815260048101929092526024820152604401600060405180830381600087803b1580156129f557600080fd5b505af1158015612a09573d6000803e3d6000fd5b50505050857f9ecaf7fc3dfffd6867c175d6e684b1f1e3aef019398ba8db2c1ffab4a09db2538683868633604051612a4595949392919061547d565b60405180910390a2505050505050565b60006001600160a01b038416612a7e57604051637ba50db360e11b815260040160405180910390fd5b612a8661446c565b6000806000600254905060607f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a2df1f958e8e8e8c8c6040518663ffffffff1660e01b8152600401612ae69594939291906154c9565b6000604051808303816000875af1158015612b05573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612b2d9190810190615508565b6001600160a01b038d16600090815260046020526040902054909b5091985091965090915060ff1680612b7d5750612710612b6786613b85565b148015612b7d5750612710612b7b86613ba2565b145b80612b86575081155b612b9a57612b958c6002613203565b612ba0565b633b9aca005b925089861015612bc35760405163f896960b60e01b815260040160405180910390fd5b8a15612cd357604051632eec7b5560e11b8152600481018d90527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635dd8f6aa90602401602060405180830381865afa158015612c2e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c529190614bec565b604051631665bc0f60e01b81526001600160a01b038f81166004830152602482018f9052604482018e905260a06064830152600060a4830181905260848301529190911690631665bc0f9060c401600060405180830381600087803b158015612cba57600080fd5b505af1158015612cce573d6000803e3d6000fd5b505050505b8051156130135760006040518061014001604052808f6001600160a01b031681526020018e8152602001876020015181526020018d815260200160405180608001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020018a81526020017f000000000000000000000000000000000000000000000000000000000000000081526020017f0000000000000000000000000000000000000000000000000000000000000000815250815260200160405180608001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602001600081526020017f000000000000000000000000000000000000000000000000000000000000000081526020017f000000000000000000000000000000000000000000000000000000000000000081525081526020018b6001600160a01b031681526020018a8152602001604051806020016040528060008152508152602001898152509050612e89604051806060016040528060006001600160a01b0316815260200160008152602001606081525090565b8251600090815b8181101561300d57858181518110612eaa57612eaa614cff565b6020026020010151935086600014612ed057612ecb8460200151888a61233f565b612ed3565b60005b92508215612f02576020840151612eea908a61532a565b98508284602001818151612efe9190614bd9565b9052505b60208085015160a087015190910152604084015161010086015283516001600160a01b0390811690630bf46e59907f00000000000000000000000000000000000000000000000000000000000000001661eeee14612f61576000612f67565b85602001515b876040518363ffffffff1660e01b8152600401612f8491906156da565b6000604051808303818588803b158015612f9d57600080fd5b505af1158015612fb1573d6000803e3d6000fd5b505050505083600001516001600160a01b03167f6596068545b2541b0aff5579d91f991d0fe5957df8e2082483ef361953e1f9978686602001518633604051612ffd94939291906156ed565b60405180910390a2600101612e90565b50505050505b50841561306e576000633b9aca0083146130375761303286838561233f565b61303a565b60005b9050801561305b5761304c868561532a565b93506130588187614bd9565b95505b851561306c5761306c308a886117cb565b505b8260000361307d57600061308c565b61308c8b600085848c87613537565b5050505087816000015182602001517f2be10f2a0203c77d0fcaa9fd6484a8a1d6904de31cd820587f60c1c8c338c8148c898c888b8b336040516130d697969594939291906151f6565b60405180910390a450979650505050505050565b8047101561313a5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e63650000006044820152606401610cb9565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114613187576040519150601f19603f3d011682016040523d82523d6000602084013e61318c565b606091505b50509050806117d55760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d617920686176652072657665727465640000000000006064820152608401610cb9565b604051630862026560e41b8152600160048201526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116602483015260009182917f00000000000000000000000000000000000000000000000000000000000000001690638620265090604401602060405180830381865afa158015613295573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132b99190614bec565b6001600160a01b0316036132d25750633b9aca00610848565b6003546001600160a01b03161561336e5760035460405163192dd60960e01b81526001600160a01b039091169063192dd609906133159086908690600401615725565b602060405180830381865afa92505050801561334e575060408051601f3d908101601f1916820190925261334b91810190614c26565b60015b61335a57506000610848565b633b9aca00811161336c579050610848565b505b50600092915050565b6040516369e11cc560e01b81526004810187905260248101869052604481018590526000908190633b9aca009082907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906369e11cc590606401600060405180830381865afa1580156133f7573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261341f9190810190615757565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081018290529192505b82518110156135255782818151811061347657613476614cff565b6020026020010151915060006134918a846040015187612896565b905060006134a3848f8e858e8e613bbf565b905080158015906134b45750818114155b156134c6576134c3828861532a565b96505b81156134d257818b039a505b8360400151860395508b8d8f7f0d31ab573f6daa4b1edba8d31973b4ba9f98fbfecc47010c1533eeefd2a1225a8786863360405161351394939291906158b4565b60405180910390a4505060010161345b565b50879450505050965096945050505050565b600061354485858461233f565b9050851561365657600087815260016020818152604080842081516080810183528a815263ffffffff808b168286019081528982168386019081526001600160a01b03808d16606086019081528654808b018855968b5297909920935160029095029093019384555192909501805491519451909616600160401b02600160401b600160e01b03199486166401000000000267ffffffffffffffff199092169290951691909117179190911691909117909155518490869089907f77813be0661650ddc1a5193ff2837df4162b251cb432651e2c060c3fc39756be90613649908790899033909283526001600160a01b03918216602084015216604082015260600190565b60405180910390a46136aa565b613661818489612385565b604080516001600160a01b038516815233602082015260009183918a917fcf0c92a2c6d7c42f488326b0cb900104b99984b6b218db81cd29371364a35251910160405180910390a45b9695505050505050565b60405163e7c8e3e360e01b815260048101859052602481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063e7c8e3e390604401600060405180830381600087803b15801561371d57600080fd5b505af11580156115fa573d6000803e3d6000fd5b600082815260016020908152604080832080548251818502810185019093528083528493849084015b828210156137c757600084815260209081902060408051608081018252600286029092018054835260019081015463ffffffff8082168587015264010000000082041692840192909252600160401b9091046001600160a01b03166060830152908352909201910161375a565b50505060008681526001602052604081209293506137e692915061444b565b8051839060005b81811015613b3d57826000036138ac576000878152600160205260409020845185908390811061381f5761381f614cff565b60209081029190910181015182546001818101855560009485529383902082516002909202019081559181015191909201805460408401516060909401516001600160a01b0316600160401b02600160401b600160e01b031963ffffffff9586166401000000000267ffffffffffffffff1990931695909416949094171791909116919091179055613b35565b8381815181106138be576138be614cff565b6020026020010151600001518310613974578381815181106138e2576138e2614cff565b6020026020010151600001518303925083818151811061390457613904614cff565b60200260200101516020015163ffffffff166000148061394a5750633b9aca0084828151811061393657613936614cff565b60200260200101516040015163ffffffff16145b6139685761396384828151811061105c5761105c614cff565b61396b565b60005b85019450613b35565b600160008881526020019081526020016000206040518060800160405280858785815181106139a5576139a5614cff565b6020026020010151600001510381526020018684815181106139c9576139c9614cff565b60200260200101516020015163ffffffff1681526020018684815181106139f2576139f2614cff565b60200260200101516040015163ffffffff168152602001868481518110613a1b57613a1b614cff565b6020908102919091018101516060908101516001600160a01b0390811690935284546001818101875560009687529583902085516002909202019081559184015191909401805460408501519490950151909216600160401b02600160401b600160e01b031963ffffffff9485166401000000000267ffffffffffffffff19909616949092169390931793909317929092161790558351849082908110613ac457613ac4614cff565b60200260200101516020015163ffffffff1660001480613b0a5750633b9aca00848281518110613af657613af6614cff565b60200260200101516040015163ffffffff16145b613b2957613b248385838151811061107a5761107a614cff565b613b2c565b60005b85019450600092505b6001016137ed565b50604080518381523360208201528591879189917f59860d79d97c1fce2be7f987915c631471f4b08f671200463cc40a3380194ffb910160405180910390a450505092915050565b60006028826101000151901c61ffff166127106108489190614bd9565b60006038826101000151901c61ffff166127106108489190614bd9565b60c086015183906001600160a01b031615613e7f57633b9aca008214158015613c05575060c08701516001600160a01b031660009081526004602052604090205460ff16155b15613c1857613c1584848461233f565b90035b60006040518060c001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020018381526020017f000000000000000000000000000000000000000000000000000000000000000081526020018881526020018781526020018981525090506060613ca98960c00151634eba05fd60e11b61431d565b15613ddc578860c001516001600160a01b0316639d740bfa61eeee6001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614613d03576000613d05565b845b846040518363ffffffff1660e01b8152600401613d2291906158e9565b6000604051808303818588803b158015613d3b57600080fd5b505af193505050508015613d4d575060015b613dd7573d808015613d7b576040519150601f19603f3d011682016040523d82523d6000602084013e613d80565b606091505b50805115613d8e5780613dcf565b604051602001613dbf906020808252600d908201526c105b1b1bd8d85d194819985a5b609a1b604082015260600190565b6040516020818303038152906040525b915050613e1e565b613e1e565b604051602001613e0c906020808252600c908201526b12515490cc4d8d4819985a5b60a21b604082015260600190565b60405160208183030381529060405290505b805115613e7857613e35888a60c0015185896136b4565b60009250877f290b5df59e172593762964e4f8ed2b4a9192d3197bfd2be4bae123908f8007968a888433604051613e6f949392919061593d565b60405180910390a25b50506136aa565b6060870151156142da576060870151604051630862026560e41b81526000916001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691638620265091613f0f917f0000000000000000000000000000000000000000000000000000000000000000906004019182526001600160a01b0316602082015260400190565b602060405180830381865afa158015613f2c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f509190614bec565b90506001600160a01b038116613fb25760009150613f7187600080886136b4565b867f290b5df59e172593762964e4f8ed2b4a9192d3197bfd2be4bae123908f800796898733604051613fa593929190615980565b60405180910390a26142d4565b6001600160a01b0381163014801590613fcf5750633b9aca008314155b8015613ff457506001600160a01b03811660009081526004602052604090205460ff16155b156140095761400485858561233f565b820391505b87602001511561418657806001600160a01b0316630cf8e85861eeee6001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614614064576000614066565b835b8a60600151857f00000000000000000000000000000000000000000000000000000000000000008c6040516020016140a091815260200190565b6040516020818303038152906040526040518663ffffffff1660e01b81526004016140ce9493929190614c8f565b6000604051808303818588803b1580156140e757600080fd5b505af1935050505080156140f9575060015b614181573d808015614127576040519150601f19603f3d011682016040523d82523d6000602084013e61412c565b606091505b50614139888385896136b4565b60009250877f290b5df59e172593762964e4f8ed2b4a9192d3197bfd2be4bae123908f8007968a888433604051614173949392919061593d565b60405180910390a2506142d4565b6142d4565b806001600160a01b0316631ebc263f61eeee6001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316146141d75760006141d9565b835b60608b015160808c015186907f0000000000000000000000000000000000000000000000000000000000000000906001600160a01b031661421a5733614220565b8d608001515b60008f600001518f60405160200161423a91815260200190565b6040516020818303038152906040526040518963ffffffff1660e01b815260040161426b979695949392919061533d565b60206040518083038185885af1935050505080156142a6575060408051601f3d908101601f191682019092526142a391810190614c26565b60015b613e78573d808015614127576040519150601f19603f3d011682016040523d82523d6000602084013e61412c565b506136aa565b633b9aca0082146142f3576142f084848461233f565b90035b60808701516136aa9030906001600160a01b03166143115733614317565b88608001515b836117cb565b600061432883614339565b801561237e575061237e838361436c565b600061434c826301ffc9a760e01b61436c565b80156108485750614365826001600160e01b031961436c565b1592915050565b604080516001600160e01b0319831660248083019190915282518083039091018152604490910182526020810180516001600160e01b03166301ffc9a760e01b179052905160009190829081906001600160a01b03871690617530906143d39086906159dd565b6000604051808303818686fa925050503d806000811461440f576040519150601f19603f3d011682016040523d82523d6000602084013e614414565b606091505b509150915060208151101561442f5760009350505050610848565b8180156136aa5750808060200190518101906136aa9190614c09565b508054600082556002029060005260206000209081019061169c91906144c1565b6040518061012001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b03168152602001600081525090565b5b808211156144e857600081556001810180546001600160e01b03191690556002016144c2565b5090565b6000602082840312156144fe57600080fd5b81356001600160e01b03198116811461237e57600080fd5b6001600160a01b038116811461169c57600080fd5b60008083601f84011261453d57600080fd5b5081356001600160401b0381111561455457600080fd5b60208301915083602082850101111561456c57600080fd5b9250929050565b600080600080600080600060a0888a03121561458e57600080fd5b873596506020880135955060408801356145a781614516565b945060608801356001600160401b03808211156145c357600080fd5b6145cf8b838c0161452b565b909650945060808a01359150808211156145e857600080fd5b506145f58a828b0161452b565b989b979a50959850939692959293505050565b60006020828403121561461a57600080fd5b813561237e81614516565b801515811461169c57600080fd5b6000806000806000806000806000806101008b8d03121561465357600080fd5b8a35995060208b0135985060408b013561466c81614516565b975060608b013561467c81614516565b965060808b0135955060a08b013561469381614625565b945060c08b01356001600160401b03808211156146af57600080fd5b6146bb8e838f0161452b565b909650945060e08d01359150808211156146d457600080fd5b506146e18d828e0161452b565b915080935050809150509295989b9194979a5092959850565b6000806040838503121561470d57600080fd5b82359150602083013561471f81614516565b809150509250929050565b600080600080600080600060c0888a03121561474557600080fd5b873596506020880135955060408801359450606088013561476581614516565b93506080880135925060a08801356001600160401b0381111561478757600080fd5b6145f58a828b0161452b565b6000602082840312156147a557600080fd5b5035919050565b600080604083850312156147bf57600080fd5b82356147ca81614516565b9150602083013561471f81614625565b602080825282518282018190526000919060409081850190868401855b82811015614843578151805185528681015163ffffffff908116888701528682015116868601526060908101516001600160a01b031690850152608090930192908501906001016147f7565b5091979650505050505050565b634e487b7160e01b600052604160045260246000fd5b60405161012081016001600160401b038111828210171561488957614889614850565b60405290565b604051606081016001600160401b038111828210171561488957614889614850565b60405160e081016001600160401b038111828210171561488957614889614850565b604051601f8201601f191681016001600160401b03811182821017156148fb576148fb614850565b604052919050565b60006001600160401b0382111561491c5761491c614850565b50601f01601f191660200190565b600082601f83011261493b57600080fd5b813561494e61494982614903565b6148d3565b81815284602083860101111561496357600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060008060006101008a8c03121561499f57600080fd5b8935985060208a0135975060408a0135965060608a01356149bf81614516565b955060808a0135945060a08a01356149d681614516565b935060c08a01356001600160401b03808211156149f257600080fd5b6149fe8d838e0161492a565b945060e08c0135915080821115614a1457600080fd5b50614a218c828d0161452b565b915080935050809150509295985092959850929598565b60008060008060008060008060c0898b031215614a5457600080fd5b88359750602089013596506040890135614a6d81614516565b95506060890135614a7d81614625565b945060808901356001600160401b0380821115614a9957600080fd5b614aa58c838d0161452b565b909650945060a08b0135915080821115614abe57600080fd5b50614acb8b828c0161452b565b999c989b5096995094979396929594505050565b60008060408385031215614af257600080fd5b8235614afd81614516565b946020939093013593505050565b600080600080600080600080610100898b031215614b2857600080fd5b8835614b3381614516565b975060208901359650604089013595506060890135614b5181614516565b94506080890135935060a0890135614b6881614516565b925060c08901356001600160401b0380821115614b8457600080fd5b614b908c838d0161492a565b935060e08b0135915080821115614ba657600080fd5b50614bb38b828c0161492a565b9150509295985092959890939650565b634e487b7160e01b600052601160045260246000fd5b8181038181111561084857610848614bc3565b600060208284031215614bfe57600080fd5b815161237e81614516565b600060208284031215614c1b57600080fd5b815161237e81614625565b600060208284031215614c3857600080fd5b5051919050565b60005b83811015614c5a578181015183820152602001614c42565b50506000910152565b60008151808452614c7b816020860160208601614c3f565b601f01601f19169290920160200192915050565b84815283602082015260018060a01b038316604082015260a06060820152600060a082015260c0608082015260006136aa60c0830184614c63565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b634e487b7160e01b600052603260045260246000fd5b600181815b80851115614d50578160001904821115614d3657614d36614bc3565b80851615614d4357918102915b93841c9390800290614d1a565b509250929050565b600082614d6757506001610848565b81614d7457506000610848565b8160018114614d8a5760028114614d9457614db0565b6001915050610848565b60ff841115614da557614da5614bc3565b50506001821b610848565b5060208310610133831016604e8410600b8410161715614dd3575081810a610848565b614ddd8383614d15565b8060001904821115614df157614df1614bc3565b029392505050565b600061237e8383614d58565b80516001600160a01b031682526020808201519083015260408082015190830152606090810151910152565b6001600160a01b03888116825260009061014090614e52602085018b614e05565b8860a08501528760c085015280871660e08501525080610100840152614e7a81840186614c63565b9050828103610120840152614e8f8185614c63565b9a9950505050505050505050565b8051614ea881614516565b919050565b60006101208284031215614ec057600080fd5b614ec8614866565b9050815181526020820151602082015260408201516040820152606082015160608201526080820151608082015260a082015160a082015260c082015160c0820152614f1660e08301614e9d565b60e082015261010080830151818301525092915050565b60006001600160401b03821115614f4657614f46614850565b5060051b60200190565b600082601f830112614f6157600080fd5b8151614f6f61494982614903565b818152846020838601011115614f8457600080fd5b611500826020830160208701614c3f565b6000806000806101808587031215614fac57600080fd5b614fb68686614ead565b935061012085015192506101408501516001600160401b0380821115614fdb57600080fd5b818701915087601f830112614fef57600080fd5b8151614ffd61494982614f2d565b8082825260208201915060208360051b86010192508a83111561501f57600080fd5b602085015b838110156150a95780518581111561503b57600080fd5b86016060818e03601f1901121561505157600080fd5b61505961488f565b602082015161506781614516565b81526040820151602082015260608201518781111561508557600080fd5b6150948f602083860101614f50565b60408301525084525060209283019201615024565b506101608a015190965093505050808211156150c457600080fd5b506150d187828801614f50565b91505092959194509250565b80516001600160a01b031682526000610220602083015160208501526040830151604085015260608301516151156060860182614e05565b50608083015161512860e0860182614e05565b5060a083015161016085015260c08301516001600160a01b031661018085015260e083015115156101a08501526101008301516101c0850182905261516f82860182614c63565b9150506101208301518482036101e086015261518b8282614c63565b9150506101408301518482036102008601526151a78282614c63565b95945050505050565b60208152600061237e60208301846150dd565b6060815260006151d660608301866150dd565b6020830194909452506001600160a01b0391909116604090910152919050565b600060018060a01b03808a168352808916602084015287604084015286606084015260e0608084015261522c60e0840187614c63565b83810360a085015261523e8187614c63565b92505080841660c08401525098975050505050505050565b6001600160a01b0394851681529290931660208301526040820152606081019190915260800190565b600080610140838503121561529357600080fd5b61529d8484614ead565b915061012083015190509250929050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b600060018060a01b03808b16835289602084015288604084015287606084015286608084015260e060a084015261531260e0840186886152ae565b915080841660c0840152509998505050505050505050565b8082018082111561084857610848614bc3565b878152602081018790526001600160a01b038681166040830152851660608201526080810184905282151560a082015261010060c08201819052600090820181905261012060e08301819052614e8f81840185614c63565b8381526060602082015260006153ae6060830185614c63565b905060018060a01b0383166040830152949350505050565b600060018060a01b03808b16835289602084015288604084015287606084015260e060808401526153fa60e0840188614c63565b83810360a085015261540d8187896152ae565b92505080841660c0840152509998505050505050505050565b600081600019048311821515161561544057615440614bc3565b500290565b634e487b7160e01b600052601260045260246000fd5b60008261547857634e487b7160e01b600052601260045260246000fd5b500490565b85815284602082015260a06040820152600061549c60a0830186614c63565b82810360608401526154ae8186614c63565b91505060018060a01b03831660808301529695505050505050565b60018060a01b038616815284602082015283604082015260a0606082015260006154f660a0830185614c63565b8281036080840152610c838185614c63565b600080600080610180858703121561551f57600080fd5b6155298686614ead565b935061012085015192506101408501516001600160401b038082111561554e57600080fd5b818701915087601f83011261556257600080fd5b815161557061494982614f2d565b8082825260208201915060208360051b86010192508a83111561559257600080fd5b602085015b838110156150a9578051858111156155ae57600080fd5b86016060818e03601f190112156155c457600080fd5b6155cc61488f565b60208201516155da81614516565b8152604082015160208201526060820151878111156155f857600080fd5b6156078f602083860101614f50565b60408301525084525060209283019201615597565b80516001600160a01b031682526000610200602083015160208501526040830151604085015260608301516060850152608083015161565e6080860182614e05565b5060a083015161010061567381870183614e05565b60c08501516001600160a01b031661018087015260e08501516101a0870184905291506156a283870183614c63565b9250808501519150508482036101c08601526156be8282614c63565b9150506101208301518482036101e08601526151a78282614c63565b60208152600061237e602083018461561c565b608081526000615700608083018761561c565b60208301959095525060408101929092526001600160a01b0316606090910152919050565b828152604081016003831061574a57634e487b7160e01b600052602160045260246000fd5b8260208301529392505050565b6000602080838503121561576a57600080fd5b82516001600160401b0381111561578057600080fd5b8301601f8101851361579157600080fd5b805161579f61494982614f2d565b81815260e091820283018401918482019190888411156157be57600080fd5b938501935b838510156158545780858a0312156157db5760008081fd5b6157e36148b1565b85516157ee81614625565b8152858701516157fd81614625565b81880152604086810151908201526060808701519082015260808087015161582481614516565b9082015260a0868101519082015260c08087015161584181614516565b90820152835293840193918501916157c3565b50979650505050505050565b80511515825260208082015115159083015260408082015190830152606080820151908301526080808201516001600160a01b039081169184019190915260a0808301519084015260c09182015116910152565b61014081016158c38287615860565b60e08201949094526101008101929092526001600160a01b031661012090910152919050565b81516001600160a01b031681526020808301519082015260408083015190820152606080830151908201526080808301519082015260a08281015161018083019161593690840182615860565b5092915050565b600061014061594c8388615860565b8560e08401528061010084015261596581840186614c63565b91505060018060a01b03831661012083015295945050505050565b600061014061598f8387615860565b60e08301949094525061010081018390526012928101929092527115195c9b5a5b985b081b9bdd08199bdd5b9960721b6101608301526001600160a01b031661012082015261018001919050565b600082516159ef818460208701614c3f565b919091019291505056fea2646970667358221220558248dbc04ea10c612e57468002e5730c490a4a5abc710d603914a962691a5464736f6c63430008100033", + "deployedBytecode": "0x6080604052600436106101f95760003560e01c80638da5cb5b1161010d578063c715967a116100a0578063df21a7dd1161006f578063df21a7dd146106ae578063e5a6b10f146106fc578063f2fde38b14610730578063fc0c546a14610750578063fe663f0f1461078457600080fd5b8063c715967a14610631578063d3419bf314610644578063d6dacc5314610678578063ddca3f431461069857600080fd5b8063ad007d63116100dc578063ad007d6314610559578063b631b5001461058d578063b7bad1b1146105bd578063c41c2f24146105fd57600080fd5b80638da5cb5b146104c7578063975057e7146104e5578063a02f801c14610519578063a32e1e961461053957600080fd5b80634a4305c011610190578063715018a61161015f578063715018a6146104115780637258002c1461042657806389701db5146104465780638af56094146104665780638b79543c1461049357600080fd5b80634a4305c01461037d578063637913ac1461039d57806366248b86146103bd57806369fe0e2d146103f157600080fd5b80632bdfe004116101cc5780632bdfe004146102a95780632d1a5903146102f5578063313ce56714610329578063405b84fa1461035d57600080fd5b806301ffc9a7146101fe5780630cf8e858146102335780631982d679146102485780631ebc263f14610296575b600080fd5b34801561020a57600080fd5b5061021e6102193660046144ec565b6107a4565b60405190151581526020015b60405180910390f35b610246610241366004614573565b61084e565b005b34801561025457600080fd5b50610288610263366004614608565b507f000000000000000000000000000000000000000000000000000000000000000090565b60405190815260200161022a565b6102886102a4366004614633565b610871565b3480156102b557600080fd5b506102dd7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200161022a565b34801561030157600080fd5b506102887f000000000000000000000000000000000000000000000000000000000000000081565b34801561033557600080fd5b506102887f000000000000000000000000000000000000000000000000000000000000000081565b34801561036957600080fd5b506102886103783660046146fa565b610977565b34801561038957600080fd5b5061028861039836600461472a565b610c73565b3480156103a957600080fd5b506102466103b8366004614608565b610c8f565b3480156103c957600080fd5b506102887f000000000000000000000000000000000000000000000000000000000000000081565b3480156103fd57600080fd5b5061024661040c366004614793565b610d16565b34801561041d57600080fd5b50610246610da5565b34801561043257600080fd5b506102466104413660046147ac565b610ddb565b34801561045257600080fd5b50610246610461366004614793565b610e67565b34801561047257600080fd5b50610486610481366004614793565b61116b565b60405161022a91906147da565b34801561049f57600080fd5b506102dd7f000000000000000000000000000000000000000000000000000000000000000081565b3480156104d357600080fd5b506000546001600160a01b03166102dd565b3480156104f157600080fd5b506102dd7f000000000000000000000000000000000000000000000000000000000000000081565b34801561052557600080fd5b50610288610534366004614980565b611218565b34801561054557600080fd5b50610288610554366004614793565b6112d3565b34801561056557600080fd5b506102dd7f000000000000000000000000000000000000000000000000000000000000000081565b34801561059957600080fd5b5061021e6105a8366004614608565b60046020526000908152604090205460ff1681565b3480156105c957600080fd5b506102886105d8366004614608565b507f000000000000000000000000000000000000000000000000000000000000000090565b34801561060957600080fd5b506102dd7f000000000000000000000000000000000000000000000000000000000000000081565b61024661063f366004614a38565b611508565b34801561065057600080fd5b506102dd7f000000000000000000000000000000000000000000000000000000000000000081565b34801561068457600080fd5b506003546102dd906001600160a01b031681565b3480156106a457600080fd5b5061028860025481565b3480156106ba57600080fd5b5061021e6106c9366004614adf565b507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b34801561070857600080fd5b506102887f000000000000000000000000000000000000000000000000000000000000000081565b34801561073c57600080fd5b5061024661074b366004614608565b611604565b34801561075c57600080fd5b506102dd7f000000000000000000000000000000000000000000000000000000000000000081565b34801561079057600080fd5b5061028861079f366004614b0b565b61169f565b60006001600160e01b0319821615806107cd57506001600160e01b0319821663edb527eb60e01b145b806107e857506001600160e01b031982166301290c1760e61b145b8061080357506001600160e01b0319821663280be00760e21b145b8061081e57506001600160e01b0319821663fe663f0f60e01b145b8061083957506001600160e01b0319821663ad007d6360e01b145b806108485750610848826116cf565b92915050565b6108578761171f565b610868878787600088888888611508565b50505050505050565b600061087c8b61171f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031661eeee146108eb5734156108cd57604051635e7e9adf60e11b815260040160405180910390fd5b476108d933308d6117cb565b6108e38147614bd9565b9a50506108ef565b3499505b6109688a338d8b8b8b8b8b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8f018190048102820181019092528d815292508d91508c90819084018382808284376000920191909152506117da92505050565b9b9a5050505050505050505050565b6040516331a9108f60e11b8152600481018390526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636352211e90602401602060405180830381865afa1580156109df573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a039190614bec565b836004610a11838383611d82565b60405163df21a7dd60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301526024820188905286169063df21a7dd90604401602060405180830381865afa158015610a7e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aa29190614c09565b610abf5760405163581010ed60e01b815260040160405180910390fd5b604051636bb6a5ad60e01b8152600481018790527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636bb6a5ad906024016020604051808303816000875af1158015610b26573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b4a9190614c26565b93508315610c255760007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031661eeee14610b8d576000610b8f565b845b6040805160208101825260008152905163019f1d0b60e31b81529192506001600160a01b03881691630cf8e858918491610bf1918c918b917f000000000000000000000000000000000000000000000000000000000000000091600401614c8f565b6000604051808303818588803b158015610c0a57600080fd5b505af1158015610c1e573d6000803e3d6000fd5b5050505050505b604080518581523360208201526001600160a01b0387169188917fa7519e5f94697b7f53e97c5eb46a0c730a296ab686ab8fd333835c5f735784eb910160405180910390a350505092915050565b6000610c83888888878787611ee6565b98975050505050505050565b6000546001600160a01b03163314610cc25760405162461bcd60e51b8152600401610cb990614cca565b60405180910390fd5b600380546001600160a01b0319166001600160a01b0383169081179091556040513381527f0a9a80fe9716605b3e52abb3d792d6a4e7816d6afc02a5a4ef023081feaf9f609060200160405180910390a250565b6000546001600160a01b03163314610d405760405162461bcd60e51b8152600401610cb990614cca565b6302faf080811115610d65576040516345fbd9c160e01b815260040160405180910390fd5b6002819055604080518281523360208201527fd7414e590e1cb532989ab2a34c8f4c2c17f7ab6f006efeeaef2e87cd5008c202910160405180910390a150565b6000546001600160a01b03163314610dcf5760405162461bcd60e51b8152600401610cb990614cca565b610dd9600061217b565b565b6000546001600160a01b03163314610e055760405162461bcd60e51b8152600401610cb990614cca565b6001600160a01b038216600081815260046020908152604091829020805460ff191685151590811790915591513381529192917fa2653e25a502c023a5830d0de847ef6f458387865b1f4f575d7594f9f2c0d71e910160405180910390a35050565b6040516331a9108f60e11b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636352211e90602401602060405180830381865afa158015610ecc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ef09190614bec565b816005610f056000546001600160a01b031690565b6001600160a01b0316336001600160a01b031614610f25848484846121cb565b600085815260016020908152604080832080548251818502810185019093528083529192909190849084015b82821015610fbe57600084815260209081902060408051608081018252600286029092018054835260019081015463ffffffff8082168587015264010000000082041692840192909252600160401b9091046001600160a01b031660608301529083529092019101610f51565b5050506000888152600160205260408120929350610fdd92915061444b565b80516000805b8281101561116057838181518110610ffd57610ffd614cff565b60200260200101516020015163ffffffff16600014806110435750633b9aca0084828151811061102f5761102f614cff565b60200260200101516040015163ffffffff16145b6110ba576110b584828151811061105c5761105c614cff565b60200260200101516000015185838151811061107a5761107a614cff565b60200260200101516020015163ffffffff1686848151811061109e5761109e614cff565b60200260200101516040015163ffffffff1661233f565b6110bd565b60005b91506110e7828583815181106110d5576110d5614cff565b6020026020010151606001518b612385565b60011515828a7fcf0c92a2c6d7c42f488326b0cb900104b99984b6b218db81cd29371364a3525187858151811061112057611120614cff565b602002602001015160600151336040516111509291906001600160a01b0392831681529116602082015260400190565b60405180910390a4600101610fe3565b505050505050505050565b606060016000838152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b8282101561120d57600084815260209081902060408051608081018252600286029092018054835260019081015463ffffffff8082168587015264010000000082041692840192909252600160401b9091046001600160a01b0316606083015290835290920191016111a0565b505050509050919050565b6040516331a9108f60e11b8152600481018a90526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636352211e90602401602060405180830381865afa158015611280573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112a49190614bec565b8a60116112b2838383611d82565b6112c28d8d8d8c8c8c8c8c6125f2565b9d9c50505050505050505050505050565b60405163035240c760e61b81523060048201526024810182905260009081906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063d49031c090604401602060405180830381865afa158015611343573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113679190614c26565b905060007f00000000000000000000000000000000000000000000000000000000000000006012146113c4576113bf827f00000000000000000000000000000000000000000000000000000000000000006012612839565b6113c6565b815b905060017f0000000000000000000000000000000000000000000000000000000000000000146114fe576114f98161141f7f0000000000000000000000000000000000000000000000000000000000000000600a614df9565b604051635268657960e11b81527f00000000000000000000000000000000000000000000000000000000000000006004820152600160248201527f000000000000000000000000000000000000000000000000000000000000000060448201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a4d0caf290606401602060405180830381865afa1580156114d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114f49190614c26565b612896565b611500565b805b949350505050565b6115118861171f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031661eeee1461158057341561156257604051635e7e9adf60e11b815260040160405180910390fd5b4761156e33308a6117cb565b6115788147614bd9565b975050611584565b3496505b6115fa88888787878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8b01819004810282018101909252898152925089915088908190840183828082843760009201919091525061296392505050565b5050505050505050565b6000546001600160a01b0316331461162e5760405162461bcd60e51b8152600401610cb990614cca565b6001600160a01b0381166116935760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610cb9565b61169c8161217b565b50565b6000888860026116b0838383611d82565b6116bf8c8c8c8b8b8b8b612a55565b9c9b505050505050505050505050565b60006001600160e01b0319821663301cdc3960e21b148061170057506001600160e01b0319821663144b000160e11b145b8061084857506301ffc9a760e01b6001600160e01b0319831614610848565b604051636e49181f60e01b8152600481018290523060248201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636e49181f90604401602060405180830381865afa15801561178a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117ae9190614c09565b61169c57604051631b1d5a5960e31b815260040160405180910390fd5b6117d582826130ea565b505050565b60006001600160a01b0386166118035760405163a762251360e01b815260040160405180910390fd5b61180b61446c565b606060008060405180608001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020018e81526020017f000000000000000000000000000000000000000000000000000000000000000081526020017f000000000000000000000000000000000000000000000000000000000000000081525090507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632fa1b3918d838e7f00000000000000000000000000000000000000000000000000000000000000008f8d8d6040518863ffffffff1660e01b81526004016119149796959493929190614e31565b6000604051808303816000875af1158015611933573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261195b9190810190614f95565b995091955090935091508115611a9057604051632eec7b5560e11b8152600481018c90527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635dd8f6aa90602401602060405180830381865afa1580156119d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119f49190614bec565b604051638ae9c07b60e01b8152600481018d9052602481018490526001600160a01b038c8116604483015260c06064830152600060c48301528a15156084830152600160a48301529190911690638ae9c07b9060e4016020604051808303816000875af1158015611a69573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a8d9190614c26565b94505b88851015611ab157604051633dca309360e11b815260040160405180910390fd5b825115611d245760006040518061016001604052808e6001600160a01b031681526020018d81526020018660200151815260200183815260200160405180608001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602001600081526020017f000000000000000000000000000000000000000000000000000000000000000081526020017f000000000000000000000000000000000000000000000000000000000000000081525081526020018781526020018c6001600160a01b031681526020018a15158152602001898152602001604051806020016040528060008152508152602001888152509050600084519050611bec604051806060016040528060006001600160a01b0316815260200160008152602001606081525090565b60005b82811015611d1f57868181518110611c0957611c09614cff565b60209081029190910101519150602080830151608086015190910152604082015161012085015281516001600160a01b0390811690636b204943907f00000000000000000000000000000000000000000000000000000000000000001661eeee14611c75576000611c7b565b83602001515b866040518363ffffffff1660e01b8152600401611c9891906151b0565b6000604051808303818588803b158015611cb157600080fd5b505af1158015611cc5573d6000803e3d6000fd5b505050505081600001516001600160a01b03167f232bbbe420e7bac6f941dc82678daec2b4c712378d91e864b69aab6e26cdd42485846020015133604051611d0f939291906151c3565b60405180910390a2600101611bef565b505050505b50505087816000015182602001517f133161f1c9161488f777ab9a26aae91d47c0d9a3fafb398960f138db02c737978c8b8f888b8b33604051611d6d97969594939291906151f6565b60405180910390a45098975050505050505050565b336001600160a01b03841614801590611e2b575060405163c161c93f60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063c161c93f90611de8903390879087908790600401615256565b602060405180830381865afa158015611e05573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e299190614c09565b155b8015611ec8575060405163c161c93f60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063c161c93f90611e8590339087906000908790600401615256565b602060405180830381865afa158015611ea2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ec69190614c09565b155b156117d55760405163075fd2b160e01b815260040160405180910390fd5b60405163c664459760e01b8152600481018790526024810186905260448101859052600090819081906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063c664459790606401610140604051808303816000875af1158015611f63573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f87919061527f565b9150915085811015611fac5760405163b01493c160e01b815260040160405180910390fd5b6040516331a9108f60e11b8152600481018a90526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636352211e90602401602060405180830381865afa158015612014573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120389190614bec565b600254909150600090818115612058576120538d6000613203565b61205e565b633b9aca005b90506000806120958f89602001517f00000000000000000000000000000000000000000000000000000000000000008a8888613377565b92509050633b9aca0083146120a957908101905b816000036120b85760006120dc565b6120dc8f6120d38a61010001516001604f9190911c81161490565b84878a88613537565b9450801561211957633b9aca0083146120ff576120fa81858561233f565b612102565b60005b61210c9082614bd9565b985061211930878b6117cb565b505050508a846000015185602001517fc41a8d26c70cfcf1b9ea10f82482ac947b8be5bea2750bc729af844bbfde1e28858e88878c8f8f336040516121659897969594939291906152d7565b60405180910390a4505050509695505050505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b801580156121e25750336001600160a01b03851614155b801561227e575060405163c161c93f60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063c161c93f9061223b903390889088908890600401615256565b602060405180830381865afa158015612258573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061227c9190614c09565b155b801561231b575060405163c161c93f60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063c161c93f906122d890339088906000908890600401615256565b602060405180830381865afa1580156122f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123199190614c09565b155b156123395760405163075fd2b160e01b815260040160405180910390fd5b50505050565b6000806123518484633b9aca00612896565b61235b9085614bd9565b905061237085633b9aca006114f4818561532a565b61237a9086614bd9565b9150505b9392505050565b604051630862026560e41b8152600160048201526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660248301526000917f000000000000000000000000000000000000000000000000000000000000000090911690638620265090604401602060405180830381865afa158015612417573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061243b9190614bec565b9050806001600160a01b0316631ebc263f61eeee6001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03161461248e576000612490565b855b6001877f0000000000000000000000000000000000000000000000000000000000000000886000808a6040516020016124cb91815260200190565b6040516020818303038152906040526040518963ffffffff1660e01b81526004016124fc979695949392919061533d565b60206040518083038185885af193505050508015612537575060408051601f3d908101601f1916820190925261253491810190614c26565b60015b6125eb573d808015612565576040519150601f19603f3d011682016040523d82523d6000602084013e61256a565b606091505b506125a783306001600160a01b03851603612586576000612588565b835b306001600160a01b0386160361259f5760006125a1565b875b886136b4565b6001837f80a889d08f0d59eb962335b57fb1d5b29e86e3d23f15087b5541fddf15422bbe8784336040516125dd93929190615395565b60405180910390a350612339565b5050505050565b604051632538671560e01b8152600481018990526024810188905260448101879052600090819081906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690632538671590606401610140604051808303816000875af115801561266f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612693919061527f565b91509150878110156126b85760405163b01493c160e01b815260040160405180910390fd5b6002546040516331a9108f60e11b8152600481018d90526000919082906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690636352211e90602401602060405180830381865afa158015612726573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061274a9190614bec565b9050600082158061276a57503360009081526004602052604090205460ff165b61277e576127798f6001613203565b612784565b633b9aca005b9050633b9aca0081146127ba576127b58f6127ac8861010001516001604f9190911c81161490565b87868686613537565b6127bd565b60005b93508385039650866000146127d7576127d7308c896117cb565b505050508a826000015183602001517f2eeee47c6d8d31c3523c3aa07b4c3e3795db36be4c04546ef3e30a5102f568e18a8e86898d8d8d336040516128239897969594939291906153c6565b60405180910390a4505098975050505050505050565b600082820361284957508261237e565b828211156128775761285b8383614bd9565b61286690600a614df9565b6128709085615426565b905061237e565b6128818284614bd9565b61288c90600a614df9565b612870908561545b565b60008080600019858709858702925082811083820303915050806000036128d0578382816128c6576128c6615445565b049250505061237e565b8381106128fa57604051631dcf306360e21b81526004810182905260248101859052604401610cb9565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60008361297157600061297b565b61297b8686613731565b90506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663e7c8e3e3876129b7848961532a565b6040516001600160e01b031960e085901b16815260048101929092526024820152604401600060405180830381600087803b1580156129f557600080fd5b505af1158015612a09573d6000803e3d6000fd5b50505050857f9ecaf7fc3dfffd6867c175d6e684b1f1e3aef019398ba8db2c1ffab4a09db2538683868633604051612a4595949392919061547d565b60405180910390a2505050505050565b60006001600160a01b038416612a7e57604051637ba50db360e11b815260040160405180910390fd5b612a8661446c565b6000806000600254905060607f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a2df1f958e8e8e8c8c6040518663ffffffff1660e01b8152600401612ae69594939291906154c9565b6000604051808303816000875af1158015612b05573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612b2d9190810190615508565b6001600160a01b038d16600090815260046020526040902054909b5091985091965090915060ff1680612b7d5750612710612b6786613b85565b148015612b7d5750612710612b7b86613ba2565b145b80612b86575081155b612b9a57612b958c6002613203565b612ba0565b633b9aca005b925089861015612bc35760405163f896960b60e01b815260040160405180910390fd5b8a15612cd357604051632eec7b5560e11b8152600481018d90527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635dd8f6aa90602401602060405180830381865afa158015612c2e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c529190614bec565b604051631665bc0f60e01b81526001600160a01b038f81166004830152602482018f9052604482018e905260a06064830152600060a4830181905260848301529190911690631665bc0f9060c401600060405180830381600087803b158015612cba57600080fd5b505af1158015612cce573d6000803e3d6000fd5b505050505b8051156130135760006040518061014001604052808f6001600160a01b031681526020018e8152602001876020015181526020018d815260200160405180608001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020018a81526020017f000000000000000000000000000000000000000000000000000000000000000081526020017f0000000000000000000000000000000000000000000000000000000000000000815250815260200160405180608001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602001600081526020017f000000000000000000000000000000000000000000000000000000000000000081526020017f000000000000000000000000000000000000000000000000000000000000000081525081526020018b6001600160a01b031681526020018a8152602001604051806020016040528060008152508152602001898152509050612e89604051806060016040528060006001600160a01b0316815260200160008152602001606081525090565b8251600090815b8181101561300d57858181518110612eaa57612eaa614cff565b6020026020010151935086600014612ed057612ecb8460200151888a61233f565b612ed3565b60005b92508215612f02576020840151612eea908a61532a565b98508284602001818151612efe9190614bd9565b9052505b60208085015160a087015190910152604084015161010086015283516001600160a01b0390811690630bf46e59907f00000000000000000000000000000000000000000000000000000000000000001661eeee14612f61576000612f67565b85602001515b876040518363ffffffff1660e01b8152600401612f8491906156da565b6000604051808303818588803b158015612f9d57600080fd5b505af1158015612fb1573d6000803e3d6000fd5b505050505083600001516001600160a01b03167f6596068545b2541b0aff5579d91f991d0fe5957df8e2082483ef361953e1f9978686602001518633604051612ffd94939291906156ed565b60405180910390a2600101612e90565b50505050505b50841561306e576000633b9aca0083146130375761303286838561233f565b61303a565b60005b9050801561305b5761304c868561532a565b93506130588187614bd9565b95505b851561306c5761306c308a886117cb565b505b8260000361307d57600061308c565b61308c8b600085848c87613537565b5050505087816000015182602001517f2be10f2a0203c77d0fcaa9fd6484a8a1d6904de31cd820587f60c1c8c338c8148c898c888b8b336040516130d697969594939291906151f6565b60405180910390a450979650505050505050565b8047101561313a5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e63650000006044820152606401610cb9565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114613187576040519150601f19603f3d011682016040523d82523d6000602084013e61318c565b606091505b50509050806117d55760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d617920686176652072657665727465640000000000006064820152608401610cb9565b604051630862026560e41b8152600160048201526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116602483015260009182917f00000000000000000000000000000000000000000000000000000000000000001690638620265090604401602060405180830381865afa158015613295573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132b99190614bec565b6001600160a01b0316036132d25750633b9aca00610848565b6003546001600160a01b03161561336e5760035460405163192dd60960e01b81526001600160a01b039091169063192dd609906133159086908690600401615725565b602060405180830381865afa92505050801561334e575060408051601f3d908101601f1916820190925261334b91810190614c26565b60015b61335a57506000610848565b633b9aca00811161336c579050610848565b505b50600092915050565b6040516369e11cc560e01b81526004810187905260248101869052604481018590526000908190633b9aca009082907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906369e11cc590606401600060405180830381865afa1580156133f7573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261341f9190810190615757565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081018290529192505b82518110156135255782818151811061347657613476614cff565b6020026020010151915060006134918a846040015187612896565b905060006134a3848f8e858e8e613bbf565b905080158015906134b45750818114155b156134c6576134c3828861532a565b96505b81156134d257818b039a505b8360400151860395508b8d8f7f0d31ab573f6daa4b1edba8d31973b4ba9f98fbfecc47010c1533eeefd2a1225a8786863360405161351394939291906158b4565b60405180910390a4505060010161345b565b50879450505050965096945050505050565b600061354485858461233f565b9050851561365657600087815260016020818152604080842081516080810183528a815263ffffffff808b168286019081528982168386019081526001600160a01b03808d16606086019081528654808b018855968b5297909920935160029095029093019384555192909501805491519451909616600160401b02600160401b600160e01b03199486166401000000000267ffffffffffffffff199092169290951691909117179190911691909117909155518490869089907f77813be0661650ddc1a5193ff2837df4162b251cb432651e2c060c3fc39756be90613649908790899033909283526001600160a01b03918216602084015216604082015260600190565b60405180910390a46136aa565b613661818489612385565b604080516001600160a01b038516815233602082015260009183918a917fcf0c92a2c6d7c42f488326b0cb900104b99984b6b218db81cd29371364a35251910160405180910390a45b9695505050505050565b60405163e7c8e3e360e01b815260048101859052602481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063e7c8e3e390604401600060405180830381600087803b15801561371d57600080fd5b505af11580156115fa573d6000803e3d6000fd5b600082815260016020908152604080832080548251818502810185019093528083528493849084015b828210156137c757600084815260209081902060408051608081018252600286029092018054835260019081015463ffffffff8082168587015264010000000082041692840192909252600160401b9091046001600160a01b03166060830152908352909201910161375a565b50505060008681526001602052604081209293506137e692915061444b565b8051839060005b81811015613b3d57826000036138ac576000878152600160205260409020845185908390811061381f5761381f614cff565b60209081029190910181015182546001818101855560009485529383902082516002909202019081559181015191909201805460408401516060909401516001600160a01b0316600160401b02600160401b600160e01b031963ffffffff9586166401000000000267ffffffffffffffff1990931695909416949094171791909116919091179055613b35565b8381815181106138be576138be614cff565b6020026020010151600001518310613974578381815181106138e2576138e2614cff565b6020026020010151600001518303925083818151811061390457613904614cff565b60200260200101516020015163ffffffff166000148061394a5750633b9aca0084828151811061393657613936614cff565b60200260200101516040015163ffffffff16145b6139685761396384828151811061105c5761105c614cff565b61396b565b60005b85019450613b35565b600160008881526020019081526020016000206040518060800160405280858785815181106139a5576139a5614cff565b6020026020010151600001510381526020018684815181106139c9576139c9614cff565b60200260200101516020015163ffffffff1681526020018684815181106139f2576139f2614cff565b60200260200101516040015163ffffffff168152602001868481518110613a1b57613a1b614cff565b6020908102919091018101516060908101516001600160a01b0390811690935284546001818101875560009687529583902085516002909202019081559184015191909401805460408501519490950151909216600160401b02600160401b600160e01b031963ffffffff9485166401000000000267ffffffffffffffff19909616949092169390931793909317929092161790558351849082908110613ac457613ac4614cff565b60200260200101516020015163ffffffff1660001480613b0a5750633b9aca00848281518110613af657613af6614cff565b60200260200101516040015163ffffffff16145b613b2957613b248385838151811061107a5761107a614cff565b613b2c565b60005b85019450600092505b6001016137ed565b50604080518381523360208201528591879189917f59860d79d97c1fce2be7f987915c631471f4b08f671200463cc40a3380194ffb910160405180910390a450505092915050565b60006028826101000151901c61ffff166127106108489190614bd9565b60006038826101000151901c61ffff166127106108489190614bd9565b60c086015183906001600160a01b031615613e7f57633b9aca008214158015613c05575060c08701516001600160a01b031660009081526004602052604090205460ff16155b15613c1857613c1584848461233f565b90035b60006040518060c001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020018381526020017f000000000000000000000000000000000000000000000000000000000000000081526020018881526020018781526020018981525090506060613ca98960c00151634eba05fd60e11b61431d565b15613ddc578860c001516001600160a01b0316639d740bfa61eeee6001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614613d03576000613d05565b845b846040518363ffffffff1660e01b8152600401613d2291906158e9565b6000604051808303818588803b158015613d3b57600080fd5b505af193505050508015613d4d575060015b613dd7573d808015613d7b576040519150601f19603f3d011682016040523d82523d6000602084013e613d80565b606091505b50805115613d8e5780613dcf565b604051602001613dbf906020808252600d908201526c105b1b1bd8d85d194819985a5b609a1b604082015260600190565b6040516020818303038152906040525b915050613e1e565b613e1e565b604051602001613e0c906020808252600c908201526b12515490cc4d8d4819985a5b60a21b604082015260600190565b60405160208183030381529060405290505b805115613e7857613e35888a60c0015185896136b4565b60009250877f290b5df59e172593762964e4f8ed2b4a9192d3197bfd2be4bae123908f8007968a888433604051613e6f949392919061593d565b60405180910390a25b50506136aa565b6060870151156142da576060870151604051630862026560e41b81526000916001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691638620265091613f0f917f0000000000000000000000000000000000000000000000000000000000000000906004019182526001600160a01b0316602082015260400190565b602060405180830381865afa158015613f2c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f509190614bec565b90506001600160a01b038116613fb25760009150613f7187600080886136b4565b867f290b5df59e172593762964e4f8ed2b4a9192d3197bfd2be4bae123908f800796898733604051613fa593929190615980565b60405180910390a26142d4565b6001600160a01b0381163014801590613fcf5750633b9aca008314155b8015613ff457506001600160a01b03811660009081526004602052604090205460ff16155b156140095761400485858561233f565b820391505b87602001511561418657806001600160a01b0316630cf8e85861eeee6001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614614064576000614066565b835b8a60600151857f00000000000000000000000000000000000000000000000000000000000000008c6040516020016140a091815260200190565b6040516020818303038152906040526040518663ffffffff1660e01b81526004016140ce9493929190614c8f565b6000604051808303818588803b1580156140e757600080fd5b505af1935050505080156140f9575060015b614181573d808015614127576040519150601f19603f3d011682016040523d82523d6000602084013e61412c565b606091505b50614139888385896136b4565b60009250877f290b5df59e172593762964e4f8ed2b4a9192d3197bfd2be4bae123908f8007968a888433604051614173949392919061593d565b60405180910390a2506142d4565b6142d4565b806001600160a01b0316631ebc263f61eeee6001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316146141d75760006141d9565b835b60608b015160808c015186907f0000000000000000000000000000000000000000000000000000000000000000906001600160a01b031661421a5733614220565b8d608001515b60008f600001518f60405160200161423a91815260200190565b6040516020818303038152906040526040518963ffffffff1660e01b815260040161426b979695949392919061533d565b60206040518083038185885af1935050505080156142a6575060408051601f3d908101601f191682019092526142a391810190614c26565b60015b613e78573d808015614127576040519150601f19603f3d011682016040523d82523d6000602084013e61412c565b506136aa565b633b9aca0082146142f3576142f084848461233f565b90035b60808701516136aa9030906001600160a01b03166143115733614317565b88608001515b836117cb565b600061432883614339565b801561237e575061237e838361436c565b600061434c826301ffc9a760e01b61436c565b80156108485750614365826001600160e01b031961436c565b1592915050565b604080516001600160e01b0319831660248083019190915282518083039091018152604490910182526020810180516001600160e01b03166301ffc9a760e01b179052905160009190829081906001600160a01b03871690617530906143d39086906159dd565b6000604051808303818686fa925050503d806000811461440f576040519150601f19603f3d011682016040523d82523d6000602084013e614414565b606091505b509150915060208151101561442f5760009350505050610848565b8180156136aa5750808060200190518101906136aa9190614c09565b508054600082556002029060005260206000209081019061169c91906144c1565b6040518061012001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b03168152602001600081525090565b5b808211156144e857600081556001810180546001600160e01b03191690556002016144c2565b5090565b6000602082840312156144fe57600080fd5b81356001600160e01b03198116811461237e57600080fd5b6001600160a01b038116811461169c57600080fd5b60008083601f84011261453d57600080fd5b5081356001600160401b0381111561455457600080fd5b60208301915083602082850101111561456c57600080fd5b9250929050565b600080600080600080600060a0888a03121561458e57600080fd5b873596506020880135955060408801356145a781614516565b945060608801356001600160401b03808211156145c357600080fd5b6145cf8b838c0161452b565b909650945060808a01359150808211156145e857600080fd5b506145f58a828b0161452b565b989b979a50959850939692959293505050565b60006020828403121561461a57600080fd5b813561237e81614516565b801515811461169c57600080fd5b6000806000806000806000806000806101008b8d03121561465357600080fd5b8a35995060208b0135985060408b013561466c81614516565b975060608b013561467c81614516565b965060808b0135955060a08b013561469381614625565b945060c08b01356001600160401b03808211156146af57600080fd5b6146bb8e838f0161452b565b909650945060e08d01359150808211156146d457600080fd5b506146e18d828e0161452b565b915080935050809150509295989b9194979a5092959850565b6000806040838503121561470d57600080fd5b82359150602083013561471f81614516565b809150509250929050565b600080600080600080600060c0888a03121561474557600080fd5b873596506020880135955060408801359450606088013561476581614516565b93506080880135925060a08801356001600160401b0381111561478757600080fd5b6145f58a828b0161452b565b6000602082840312156147a557600080fd5b5035919050565b600080604083850312156147bf57600080fd5b82356147ca81614516565b9150602083013561471f81614625565b602080825282518282018190526000919060409081850190868401855b82811015614843578151805185528681015163ffffffff908116888701528682015116868601526060908101516001600160a01b031690850152608090930192908501906001016147f7565b5091979650505050505050565b634e487b7160e01b600052604160045260246000fd5b60405161012081016001600160401b038111828210171561488957614889614850565b60405290565b604051606081016001600160401b038111828210171561488957614889614850565b60405160e081016001600160401b038111828210171561488957614889614850565b604051601f8201601f191681016001600160401b03811182821017156148fb576148fb614850565b604052919050565b60006001600160401b0382111561491c5761491c614850565b50601f01601f191660200190565b600082601f83011261493b57600080fd5b813561494e61494982614903565b6148d3565b81815284602083860101111561496357600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060008060006101008a8c03121561499f57600080fd5b8935985060208a0135975060408a0135965060608a01356149bf81614516565b955060808a0135945060a08a01356149d681614516565b935060c08a01356001600160401b03808211156149f257600080fd5b6149fe8d838e0161492a565b945060e08c0135915080821115614a1457600080fd5b50614a218c828d0161452b565b915080935050809150509295985092959850929598565b60008060008060008060008060c0898b031215614a5457600080fd5b88359750602089013596506040890135614a6d81614516565b95506060890135614a7d81614625565b945060808901356001600160401b0380821115614a9957600080fd5b614aa58c838d0161452b565b909650945060a08b0135915080821115614abe57600080fd5b50614acb8b828c0161452b565b999c989b5096995094979396929594505050565b60008060408385031215614af257600080fd5b8235614afd81614516565b946020939093013593505050565b600080600080600080600080610100898b031215614b2857600080fd5b8835614b3381614516565b975060208901359650604089013595506060890135614b5181614516565b94506080890135935060a0890135614b6881614516565b925060c08901356001600160401b0380821115614b8457600080fd5b614b908c838d0161492a565b935060e08b0135915080821115614ba657600080fd5b50614bb38b828c0161492a565b9150509295985092959890939650565b634e487b7160e01b600052601160045260246000fd5b8181038181111561084857610848614bc3565b600060208284031215614bfe57600080fd5b815161237e81614516565b600060208284031215614c1b57600080fd5b815161237e81614625565b600060208284031215614c3857600080fd5b5051919050565b60005b83811015614c5a578181015183820152602001614c42565b50506000910152565b60008151808452614c7b816020860160208601614c3f565b601f01601f19169290920160200192915050565b84815283602082015260018060a01b038316604082015260a06060820152600060a082015260c0608082015260006136aa60c0830184614c63565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b634e487b7160e01b600052603260045260246000fd5b600181815b80851115614d50578160001904821115614d3657614d36614bc3565b80851615614d4357918102915b93841c9390800290614d1a565b509250929050565b600082614d6757506001610848565b81614d7457506000610848565b8160018114614d8a5760028114614d9457614db0565b6001915050610848565b60ff841115614da557614da5614bc3565b50506001821b610848565b5060208310610133831016604e8410600b8410161715614dd3575081810a610848565b614ddd8383614d15565b8060001904821115614df157614df1614bc3565b029392505050565b600061237e8383614d58565b80516001600160a01b031682526020808201519083015260408082015190830152606090810151910152565b6001600160a01b03888116825260009061014090614e52602085018b614e05565b8860a08501528760c085015280871660e08501525080610100840152614e7a81840186614c63565b9050828103610120840152614e8f8185614c63565b9a9950505050505050505050565b8051614ea881614516565b919050565b60006101208284031215614ec057600080fd5b614ec8614866565b9050815181526020820151602082015260408201516040820152606082015160608201526080820151608082015260a082015160a082015260c082015160c0820152614f1660e08301614e9d565b60e082015261010080830151818301525092915050565b60006001600160401b03821115614f4657614f46614850565b5060051b60200190565b600082601f830112614f6157600080fd5b8151614f6f61494982614903565b818152846020838601011115614f8457600080fd5b611500826020830160208701614c3f565b6000806000806101808587031215614fac57600080fd5b614fb68686614ead565b935061012085015192506101408501516001600160401b0380821115614fdb57600080fd5b818701915087601f830112614fef57600080fd5b8151614ffd61494982614f2d565b8082825260208201915060208360051b86010192508a83111561501f57600080fd5b602085015b838110156150a95780518581111561503b57600080fd5b86016060818e03601f1901121561505157600080fd5b61505961488f565b602082015161506781614516565b81526040820151602082015260608201518781111561508557600080fd5b6150948f602083860101614f50565b60408301525084525060209283019201615024565b506101608a015190965093505050808211156150c457600080fd5b506150d187828801614f50565b91505092959194509250565b80516001600160a01b031682526000610220602083015160208501526040830151604085015260608301516151156060860182614e05565b50608083015161512860e0860182614e05565b5060a083015161016085015260c08301516001600160a01b031661018085015260e083015115156101a08501526101008301516101c0850182905261516f82860182614c63565b9150506101208301518482036101e086015261518b8282614c63565b9150506101408301518482036102008601526151a78282614c63565b95945050505050565b60208152600061237e60208301846150dd565b6060815260006151d660608301866150dd565b6020830194909452506001600160a01b0391909116604090910152919050565b600060018060a01b03808a168352808916602084015287604084015286606084015260e0608084015261522c60e0840187614c63565b83810360a085015261523e8187614c63565b92505080841660c08401525098975050505050505050565b6001600160a01b0394851681529290931660208301526040820152606081019190915260800190565b600080610140838503121561529357600080fd5b61529d8484614ead565b915061012083015190509250929050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b600060018060a01b03808b16835289602084015288604084015287606084015286608084015260e060a084015261531260e0840186886152ae565b915080841660c0840152509998505050505050505050565b8082018082111561084857610848614bc3565b878152602081018790526001600160a01b038681166040830152851660608201526080810184905282151560a082015261010060c08201819052600090820181905261012060e08301819052614e8f81840185614c63565b8381526060602082015260006153ae6060830185614c63565b905060018060a01b0383166040830152949350505050565b600060018060a01b03808b16835289602084015288604084015287606084015260e060808401526153fa60e0840188614c63565b83810360a085015261540d8187896152ae565b92505080841660c0840152509998505050505050505050565b600081600019048311821515161561544057615440614bc3565b500290565b634e487b7160e01b600052601260045260246000fd5b60008261547857634e487b7160e01b600052601260045260246000fd5b500490565b85815284602082015260a06040820152600061549c60a0830186614c63565b82810360608401526154ae8186614c63565b91505060018060a01b03831660808301529695505050505050565b60018060a01b038616815284602082015283604082015260a0606082015260006154f660a0830185614c63565b8281036080840152610c838185614c63565b600080600080610180858703121561551f57600080fd5b6155298686614ead565b935061012085015192506101408501516001600160401b038082111561554e57600080fd5b818701915087601f83011261556257600080fd5b815161557061494982614f2d565b8082825260208201915060208360051b86010192508a83111561559257600080fd5b602085015b838110156150a9578051858111156155ae57600080fd5b86016060818e03601f190112156155c457600080fd5b6155cc61488f565b60208201516155da81614516565b8152604082015160208201526060820151878111156155f857600080fd5b6156078f602083860101614f50565b60408301525084525060209283019201615597565b80516001600160a01b031682526000610200602083015160208501526040830151604085015260608301516060850152608083015161565e6080860182614e05565b5060a083015161010061567381870183614e05565b60c08501516001600160a01b031661018087015260e08501516101a0870184905291506156a283870183614c63565b9250808501519150508482036101c08601526156be8282614c63565b9150506101208301518482036101e08601526151a78282614c63565b60208152600061237e602083018461561c565b608081526000615700608083018761561c565b60208301959095525060408101929092526001600160a01b0316606090910152919050565b828152604081016003831061574a57634e487b7160e01b600052602160045260246000fd5b8260208301529392505050565b6000602080838503121561576a57600080fd5b82516001600160401b0381111561578057600080fd5b8301601f8101851361579157600080fd5b805161579f61494982614f2d565b81815260e091820283018401918482019190888411156157be57600080fd5b938501935b838510156158545780858a0312156157db5760008081fd5b6157e36148b1565b85516157ee81614625565b8152858701516157fd81614625565b81880152604086810151908201526060808701519082015260808087015161582481614516565b9082015260a0868101519082015260c08087015161584181614516565b90820152835293840193918501916157c3565b50979650505050505050565b80511515825260208082015115159083015260408082015190830152606080820151908301526080808201516001600160a01b039081169184019190915260a0808301519084015260c09182015116910152565b61014081016158c38287615860565b60e08201949094526101008101929092526001600160a01b031661012090910152919050565b81516001600160a01b031681526020808301519082015260408083015190820152606080830151908201526080808301519082015260a08281015161018083019161593690840182615860565b5092915050565b600061014061594c8388615860565b8560e08401528061010084015261596581840186614c63565b91505060018060a01b03831661012083015295945050505050565b600061014061598f8387615860565b60e08301949094525061010081018390526012928101929092527115195c9b5a5b985b081b9bdd08199bdd5b9960721b6101608301526001600160a01b031661012082015261018001919050565b600082516159ef818460208701614c3f565b919091019291505056fea2646970667358221220558248dbc04ea10c612e57468002e5730c490a4a5abc710d603914a962691a5464736f6c63430008100033", + "devdoc": { + "kind": "dev", + "methods": { + "acceptsToken(address,uint256)": { + "params": { + "_projectId": "The project ID to check for token acceptance.", + "_token": "The token to check if this terminal accepts or not." + }, + "returns": { + "_0": "The flag." + } + }, + "addToBalanceOf(uint256,uint256,address,bool,string,bytes)": { + "params": { + "_amount": "The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.", + "_memo": "A memo to pass along to the emitted event.", + "_metadata": "Extra data to pass along to the emitted event.", + "_projectId": "The ID of the project to which the funds received belong.", + "_shouldRefundHeldFees": "A flag indicating if held fees should be refunded based on the amount being added.", + "_token": "The token being paid. This terminal ignores this property since it only manages one currency." + } + }, + "addToBalanceOf(uint256,uint256,address,string,bytes)": { + "params": { + "_amount": "The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.", + "_memo": "A memo to pass along to the emitted event.", + "_metadata": "Extra data to pass along to the emitted event.", + "_projectId": "The ID of the project to which the funds received belong.", + "_token": "The token being paid. This terminal ignores this property since it only manages one currency." + } + }, + "constructor": { + "params": { + "_baseWeightCurrency": "The currency to base token issuance on.", + "_directory": "A contract storing directories of terminals and controllers for each project.", + "_operatorStore": "A contract storing operator assignments.", + "_owner": "The address that will own this contract.", + "_prices": "A contract that exposes price feeds.", + "_projects": "A contract which mints ERC-721's that represent project ownership and transfers.", + "_splitsStore": "A contract that stores splits for each project.", + "_store": "A contract that stores the terminal's data." + } + }, + "currencyForToken(address)": { + "params": { + "_token": "The token to check for the currency of." + }, + "returns": { + "_0": "The currency index." + } + }, + "currentEthOverflowOf(uint256)": { + "details": "The current overflow is represented as a fixed point number with 18 decimals.", + "params": { + "_projectId": "The ID of the project to get overflow for." + }, + "returns": { + "_0": "The current amount of ETH overflow that project has in this terminal, as a fixed point number with 18 decimals." + } + }, + "decimalsForToken(address)": { + "params": { + "_token": "The token to check for the decimals of." + }, + "returns": { + "_0": "The number of decimals for the token." + } + }, + "distributePayoutsOf(uint256,uint256,uint256,address,uint256,bytes)": { + "details": "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.", + "params": { + "_amount": "The amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal.", + "_currency": "The expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency.", + "_metadata": "Bytes to send along to the emitted event, if provided.", + "_minReturnedTokens": "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.", + "_projectId": "The ID of the project having its payouts distributed.", + "_token": "The token being distributed. This terminal ignores this property since it only manages one token." + }, + "returns": { + "netLeftoverDistributionAmount": "The amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal." + } + }, + "heldFeesOf(uint256)": { + "params": { + "_projectId": "The ID of the project for which fees are being held." + }, + "returns": { + "_0": "An array of fees that are being held." + } + }, + "migrate(uint256,address)": { + "details": "Only a project's owner or a designated operator can migrate it.", + "params": { + "_projectId": "The ID of the project being migrated.", + "_to": "The terminal contract that will gain the project's funds." + }, + "returns": { + "balance": "The amount of funds that were migrated, as a fixed point number with the same amount of decimals as this terminal." + } + }, + "owner()": { + "details": "Returns the address of the current owner." + }, + "pay(uint256,uint256,address,address,uint256,bool,string,bytes)": { + "params": { + "_amount": "The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place.", + "_beneficiary": "The address to mint tokens for and pass along to the funding cycle's data source and delegate.", + "_memo": "A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.", + "_metadata": "Bytes to send along to the data source, delegate, and emitted event, if provided.", + "_minReturnedTokens": "The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal.", + "_preferClaimedTokens": "A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.", + "_projectId": "The ID of the project being paid.", + "_token": "The token being paid. This terminal ignores this property since it only manages one token." + }, + "returns": { + "_0": "The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals." + } + }, + "processFees(uint256)": { + "details": "Only a project owner, an operator, or the contract's owner can process held fees.", + "params": { + "_projectId": "The ID of the project whos held fees should be processed." + } + }, + "redeemTokensOf(address,uint256,uint256,address,uint256,address,string,bytes)": { + "details": "Only a token holder or a designated operator can redeem its tokens.", + "params": { + "_beneficiary": "The address to send the terminal tokens to.", + "_holder": "The account to redeem tokens for.", + "_memo": "A memo to pass along to the emitted event.", + "_metadata": "Bytes to send along to the data source, delegate, and emitted event, if provided.", + "_minReturnedTokens": "The minimum amount of terminal tokens expected in return, as a fixed point number with the same amount of decimals as the terminal.", + "_projectId": "The ID of the project to which the tokens being redeemed belong.", + "_token": "The token being reclaimed. This terminal ignores this property since it only manages one token.", + "_tokenCount": "The number of project tokens to redeem, as a fixed point number with 18 decimals." + }, + "returns": { + "reclaimAmount": "The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals." + } + }, + "renounceOwnership()": { + "details": "Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner." + }, + "setFee(uint256)": { + "details": "Only the owner of this contract can change the fee.", + "params": { + "_fee": "The new fee, out of MAX_FEE." + } + }, + "setFeeGauge(address)": { + "details": "Only the owner of this contract can change the fee gauge.", + "params": { + "_feeGauge": "The new fee gauge." + } + }, + "setFeelessAddress(address,bool)": { + "details": "Only the owner of this contract can set addresses as feeless.", + "params": { + "_address": "The address that can be paid towards while still bypassing fees.", + "_flag": "A flag indicating whether the terminal should be feeless or not." + } + }, + "supportsInterface(bytes4)": { + "details": "See {IERC165-supportsInterface}.", + "params": { + "_interfaceId": "The ID of the interface to check for adherance to." + }, + "returns": { + "_0": "A flag indicating if the provided interface ID is supported." + } + }, + "transferOwnership(address)": { + "details": "Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner." + }, + "useAllowanceOf(uint256,uint256,uint256,address,uint256,address,string,bytes)": { + "details": "Only a project's owner or a designated operator can use its allowance.Incurs the protocol fee.", + "params": { + "_amount": "The amount of terminal tokens to use from this project's current allowance, as a fixed point number with the same amount of decimals as this terminal.", + "_beneficiary": "The address to send the funds to.", + "_currency": "The expected currency of the amount being distributed. Must match the project's current funding cycle's overflow allowance currency.", + "_memo": "A memo to pass along to the emitted event.", + "_metadata": "Bytes to send along to the emitted event, if provided.", + "_minReturnedTokens": "The minimum number of tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with 18 decimals.", + "_projectId": "The ID of the project to use the allowance of.", + "_token": "The token being distributed. This terminal ignores this property since it only manages one token." + }, + "returns": { + "netDistributedAmount": "The amount of tokens that was distributed to the beneficiary, as a fixed point number with the same amount of decimals as the terminal." + } + } + }, + "version": 1 + }, + "userdoc": { + "errors": { + "PRBMath__MulDivOverflow(uint256,uint256)": [ + { + "notice": "Emitted when the result overflows uint256." + } + ] + }, + "kind": "user", + "methods": { + "acceptsToken(address,uint256)": { + "notice": "A flag indicating if this terminal accepts the specified token." + }, + "addToBalanceOf(uint256,uint256,address,bool,string,bytes)": { + "notice": "Receives funds belonging to the specified project." + }, + "addToBalanceOf(uint256,uint256,address,string,bytes)": { + "notice": "Receives funds belonging to the specified project." + }, + "baseWeightCurrency()": { + "notice": "The currency to base token issuance on." + }, + "currency()": { + "notice": "The currency to use when resolving price feeds for this terminal." + }, + "currencyForToken(address)": { + "notice": "The currency that should be used for the specified token." + }, + "currentEthOverflowOf(uint256)": { + "notice": "Gets the current overflowed amount in this terminal for a specified project, in terms of ETH." + }, + "decimals()": { + "notice": "The number of decimals the token fixed point amounts are expected to have." + }, + "decimalsForToken(address)": { + "notice": "The decimals that should be used in fixed number accounting for the specified token." + }, + "directory()": { + "notice": "The directory of terminals and controllers for projects." + }, + "distributePayoutsOf(uint256,uint256,uint256,address,uint256,bytes)": { + "notice": "Distributes payouts for a project with the distribution limit of its current funding cycle." + }, + "fee()": { + "notice": "The platform fee percent." + }, + "feeGauge()": { + "notice": "The data source that returns a discount to apply to a project's fee." + }, + "heldFeesOf(uint256)": { + "notice": "The fees that are currently being held to be processed later for each project." + }, + "isFeelessAddress(address)": { + "notice": "Addresses that can be paid towards from this terminal without incurring a fee." + }, + "migrate(uint256,address)": { + "notice": "Allows a project owner to migrate its funds and operations to a new terminal that accepts the same token type." + }, + "operatorStore()": { + "notice": "A contract storing operator assignments." + }, + "pay(uint256,uint256,address,address,uint256,bool,string,bytes)": { + "notice": "Contribute tokens to a project." + }, + "payoutSplitsGroup()": { + "notice": "The group that payout splits coming from this terminal are identified by." + }, + "prices()": { + "notice": "The contract that exposes price feeds." + }, + "processFees(uint256)": { + "notice": "Process any fees that are being held for the project." + }, + "projects()": { + "notice": "Mints ERC-721's that represent project ownership and transfers." + }, + "redeemTokensOf(address,uint256,uint256,address,uint256,address,string,bytes)": { + "notice": "Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source." + }, + "setFee(uint256)": { + "notice": "Allows the fee to be updated." + }, + "setFeeGauge(address)": { + "notice": "Allows the fee gauge to be updated." + }, + "setFeelessAddress(address,bool)": { + "notice": "Sets whether projects operating on this terminal can pay towards the specified address without incurring a fee." + }, + "splitsStore()": { + "notice": "The contract that stores splits for each project." + }, + "store()": { + "notice": "The contract that stores and manages the terminal's data." + }, + "supportsInterface(bytes4)": { + "notice": "Indicates if this contract adheres to the specified interface." + }, + "token()": { + "notice": "The token that this terminal accepts." + }, + "useAllowanceOf(uint256,uint256,uint256,address,uint256,address,string,bytes)": { + "notice": "Allows a project to send funds from its overflow up to the preconfigured allowance." + } + }, + "notice": "Manages all inflows and outflows of ETH funds into the protocol ecosystem.", + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 53, + "contract": "contracts/JBETHPaymentTerminal3_1_1.sol:JBETHPaymentTerminal3_1_1", + "label": "_owner", + "offset": 0, + "slot": "0", + "type": "t_address" + }, + { + "astId": 28823, + "contract": "contracts/JBETHPaymentTerminal3_1_1.sol:JBETHPaymentTerminal3_1_1", + "label": "_heldFeesOf", + "offset": 0, + "slot": "1", + "type": "t_mapping(t_uint256,t_array(t_struct(JBFee)36640_storage)dyn_storage)" + }, + { + "astId": 28860, + "contract": "contracts/JBETHPaymentTerminal3_1_1.sol:JBETHPaymentTerminal3_1_1", + "label": "fee", + "offset": 0, + "slot": "2", + "type": "t_uint256" + }, + { + "astId": 28864, + "contract": "contracts/JBETHPaymentTerminal3_1_1.sol:JBETHPaymentTerminal3_1_1", + "label": "feeGauge", + "offset": 0, + "slot": "3", + "type": "t_address" + }, + { + "astId": 28870, + "contract": "contracts/JBETHPaymentTerminal3_1_1.sol:JBETHPaymentTerminal3_1_1", + "label": "isFeelessAddress", + "offset": 0, + "slot": "4", + "type": "t_mapping(t_address,t_bool)" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_struct(JBFee)36640_storage)dyn_storage": { + "base": "t_struct(JBFee)36640_storage", + "encoding": "dynamic_array", + "label": "struct JBFee[]", + "numberOfBytes": "32" + }, + "t_bool": { + "encoding": "inplace", + "label": "bool", + "numberOfBytes": "1" + }, + "t_mapping(t_address,t_bool)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => bool)", + "numberOfBytes": "32", + "value": "t_bool" + }, + "t_mapping(t_uint256,t_array(t_struct(JBFee)36640_storage)dyn_storage)": { + "encoding": "mapping", + "key": "t_uint256", + "label": "mapping(uint256 => struct JBFee[])", + "numberOfBytes": "32", + "value": "t_array(t_struct(JBFee)36640_storage)dyn_storage" + }, + "t_struct(JBFee)36640_storage": { + "encoding": "inplace", + "label": "struct JBFee", + "members": [ + { + "astId": 36633, + "contract": "contracts/JBETHPaymentTerminal3_1_1.sol:JBETHPaymentTerminal3_1_1", + "label": "amount", + "offset": 0, + "slot": "0", + "type": "t_uint256" + }, + { + "astId": 36635, + "contract": "contracts/JBETHPaymentTerminal3_1_1.sol:JBETHPaymentTerminal3_1_1", + "label": "fee", + "offset": 0, + "slot": "1", + "type": "t_uint32" + }, + { + "astId": 36637, + "contract": "contracts/JBETHPaymentTerminal3_1_1.sol:JBETHPaymentTerminal3_1_1", + "label": "feeDiscount", + "offset": 4, + "slot": "1", + "type": "t_uint32" + }, + { + "astId": 36639, + "contract": "contracts/JBETHPaymentTerminal3_1_1.sol:JBETHPaymentTerminal3_1_1", + "label": "beneficiary", + "offset": 8, + "slot": "1", + "type": "t_address" + } + ], + "numberOfBytes": "64" + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint32": { + "encoding": "inplace", + "label": "uint32", + "numberOfBytes": "4" + } + } + } +} \ No newline at end of file diff --git a/deployments/goerli/JBSingleTokenPaymentTerminalStore3_1_1.json b/deployments/goerli/JBSingleTokenPaymentTerminalStore3_1_1.json new file mode 100644 index 000000000..d09906b2e --- /dev/null +++ b/deployments/goerli/JBSingleTokenPaymentTerminalStore3_1_1.json @@ -0,0 +1,1116 @@ +{ + "address": "0x5d8eC74256DB2326843714B852df3acE45144492", + "abi": [ + { + "inputs": [ + { + "internalType": "contract IJBDirectory", + "name": "_directory", + "type": "address" + }, + { + "internalType": "contract IJBFundingCycleStore", + "name": "_fundingCycleStore", + "type": "address" + }, + { + "internalType": "contract IJBPrices", + "name": "_prices", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "CURRENCY_MISMATCH", + "type": "error" + }, + { + "inputs": [], + "name": "DISTRIBUTION_AMOUNT_LIMIT_REACHED", + "type": "error" + }, + { + "inputs": [], + "name": "FUNDING_CYCLE_DISTRIBUTION_PAUSED", + "type": "error" + }, + { + "inputs": [], + "name": "FUNDING_CYCLE_PAYMENT_PAUSED", + "type": "error" + }, + { + "inputs": [], + "name": "FUNDING_CYCLE_REDEEM_PAUSED", + "type": "error" + }, + { + "inputs": [], + "name": "INADEQUATE_CONTROLLER_ALLOWANCE", + "type": "error" + }, + { + "inputs": [], + "name": "INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE", + "type": "error" + }, + { + "inputs": [], + "name": "INSUFFICIENT_TOKENS", + "type": "error" + }, + { + "inputs": [], + "name": "INVALID_AMOUNT_TO_SEND_DELEGATE", + "type": "error" + }, + { + "inputs": [], + "name": "INVALID_FUNDING_CYCLE", + "type": "error" + }, + { + "inputs": [], + "name": "PAYMENT_TERMINAL_MIGRATION_NOT_ALLOWED", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "prod1", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "denominator", + "type": "uint256" + } + ], + "name": "PRBMath__MulDivOverflow", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "contract IJBSingleTokenPaymentTerminal", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IJBSingleTokenPaymentTerminal", + "name": "_terminal", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + } + ], + "name": "currentOverflowOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_tokenCount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_totalSupply", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_overflow", + "type": "uint256" + } + ], + "name": "currentReclaimableOverflowOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IJBSingleTokenPaymentTerminal", + "name": "_terminal", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_tokenCount", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "_useTotalOverflow", + "type": "bool" + } + ], + "name": "currentReclaimableOverflowOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_decimals", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_currency", + "type": "uint256" + } + ], + "name": "currentTotalOverflowOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "directory", + "outputs": [ + { + "internalType": "contract IJBDirectory", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "fundingCycleStore", + "outputs": [ + { + "internalType": "contract IJBFundingCycleStore", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "prices", + "outputs": [ + { + "internalType": "contract IJBPrices", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "recordAddedBalanceFor", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_currency", + "type": "uint256" + } + ], + "name": "recordDistributionFor", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "number", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "configuration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "basedOn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "start", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "duration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "weight", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "discountRate", + "type": "uint256" + }, + { + "internalType": "contract IJBFundingCycleBallot", + "name": "ballot", + "type": "address" + }, + { + "internalType": "uint256", + "name": "metadata", + "type": "uint256" + } + ], + "internalType": "struct JBFundingCycle", + "name": "fundingCycle", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "distributedAmount", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + } + ], + "name": "recordMigration", + "outputs": [ + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_payer", + "type": "address" + }, + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "decimals", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "currency", + "type": "uint256" + } + ], + "internalType": "struct JBTokenAmount", + "name": "_amount", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_baseWeightCurrency", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_beneficiary", + "type": "address" + }, + { + "internalType": "string", + "name": "_memo", + "type": "string" + }, + { + "internalType": "bytes", + "name": "_metadata", + "type": "bytes" + } + ], + "name": "recordPaymentFrom", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "number", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "configuration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "basedOn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "start", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "duration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "weight", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "discountRate", + "type": "uint256" + }, + { + "internalType": "contract IJBFundingCycleBallot", + "name": "ballot", + "type": "address" + }, + { + "internalType": "uint256", + "name": "metadata", + "type": "uint256" + } + ], + "internalType": "struct JBFundingCycle", + "name": "fundingCycle", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "tokenCount", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "contract IJBPayDelegate3_1_1", + "name": "delegate", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "metadata", + "type": "bytes" + } + ], + "internalType": "struct JBPayDelegateAllocation3_1_1[]", + "name": "delegateAllocations", + "type": "tuple[]" + }, + { + "internalType": "string", + "name": "memo", + "type": "string" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_holder", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_tokenCount", + "type": "uint256" + }, + { + "internalType": "string", + "name": "_memo", + "type": "string" + }, + { + "internalType": "bytes", + "name": "_metadata", + "type": "bytes" + } + ], + "name": "recordRedemptionFor", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "number", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "configuration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "basedOn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "start", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "duration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "weight", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "discountRate", + "type": "uint256" + }, + { + "internalType": "contract IJBFundingCycleBallot", + "name": "ballot", + "type": "address" + }, + { + "internalType": "uint256", + "name": "metadata", + "type": "uint256" + } + ], + "internalType": "struct JBFundingCycle", + "name": "fundingCycle", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "reclaimAmount", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "contract IJBRedemptionDelegate3_1_1", + "name": "delegate", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "metadata", + "type": "bytes" + } + ], + "internalType": "struct JBRedemptionDelegateAllocation3_1_1[]", + "name": "delegateAllocations", + "type": "tuple[]" + }, + { + "internalType": "string", + "name": "memo", + "type": "string" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_currency", + "type": "uint256" + } + ], + "name": "recordUsedAllowanceOf", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "number", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "configuration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "basedOn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "start", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "duration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "weight", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "discountRate", + "type": "uint256" + }, + { + "internalType": "contract IJBFundingCycleBallot", + "name": "ballot", + "type": "address" + }, + { + "internalType": "uint256", + "name": "metadata", + "type": "uint256" + } + ], + "internalType": "struct JBFundingCycle", + "name": "fundingCycle", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "usedAmount", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IJBSingleTokenPaymentTerminal", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "usedDistributionLimitOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IJBSingleTokenPaymentTerminal", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "usedOverflowAllowanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "transactionHash": "0x860be79fbe0ecd8dab7958382c25dcddefc2b53c9790602425970ee4e6743dc1", + "receipt": { + "to": null, + "from": "0xE9bE6df23C7f9CaBa3005DA2fa2d8714d340D0aF", + "contractAddress": "0x5d8eC74256DB2326843714B852df3acE45144492", + "transactionIndex": 150, + "gasUsed": "2999374", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0xbbd5bc940581ee96c30eea613749439ae50e683da3f0046e0e0cbc158b8e325f", + "transactionHash": "0x860be79fbe0ecd8dab7958382c25dcddefc2b53c9790602425970ee4e6743dc1", + "logs": [], + "blockNumber": 9266638, + "cumulativeGasUsed": "27318841", + "status": 1, + "byzantium": true + }, + "args": [ + "0x8E05bcD2812E1449f0EC3aE24E2C395F533d9A99", + "0xB9Ee9d8203467f6EC0eAC81163d210bd1a7d3b55", + "0x9f0eC91d28fFc54874e9fF11A316Ba2537aCD72C" + ], + "numDeployments": 1, + "solcInputHash": "f58e5b1a8ab27311c5c442a686fda095", + "metadata": "{\"compiler\":{\"version\":\"0.8.16+commit.07a7930e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract IJBDirectory\",\"name\":\"_directory\",\"type\":\"address\"},{\"internalType\":\"contract IJBFundingCycleStore\",\"name\":\"_fundingCycleStore\",\"type\":\"address\"},{\"internalType\":\"contract IJBPrices\",\"name\":\"_prices\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"CURRENCY_MISMATCH\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DISTRIBUTION_AMOUNT_LIMIT_REACHED\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FUNDING_CYCLE_DISTRIBUTION_PAUSED\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FUNDING_CYCLE_PAYMENT_PAUSED\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FUNDING_CYCLE_REDEEM_PAUSED\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"INADEQUATE_CONTROLLER_ALLOWANCE\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"INSUFFICIENT_TOKENS\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"INVALID_AMOUNT_TO_SEND_DELEGATE\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"INVALID_FUNDING_CYCLE\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PAYMENT_TERMINAL_MIGRATION_NOT_ALLOWED\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"prod1\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"denominator\",\"type\":\"uint256\"}],\"name\":\"PRBMath__MulDivOverflow\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"contract IJBSingleTokenPaymentTerminal\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IJBSingleTokenPaymentTerminal\",\"name\":\"_terminal\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"}],\"name\":\"currentOverflowOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_tokenCount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_totalSupply\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_overflow\",\"type\":\"uint256\"}],\"name\":\"currentReclaimableOverflowOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IJBSingleTokenPaymentTerminal\",\"name\":\"_terminal\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_tokenCount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"_useTotalOverflow\",\"type\":\"bool\"}],\"name\":\"currentReclaimableOverflowOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_decimals\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_currency\",\"type\":\"uint256\"}],\"name\":\"currentTotalOverflowOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"directory\",\"outputs\":[{\"internalType\":\"contract IJBDirectory\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fundingCycleStore\",\"outputs\":[{\"internalType\":\"contract IJBFundingCycleStore\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"prices\",\"outputs\":[{\"internalType\":\"contract IJBPrices\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"recordAddedBalanceFor\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_currency\",\"type\":\"uint256\"}],\"name\":\"recordDistributionFor\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"number\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"configuration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"basedOn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"start\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"duration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"weight\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"discountRate\",\"type\":\"uint256\"},{\"internalType\":\"contract IJBFundingCycleBallot\",\"name\":\"ballot\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"metadata\",\"type\":\"uint256\"}],\"internalType\":\"struct JBFundingCycle\",\"name\":\"fundingCycle\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"distributedAmount\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"}],\"name\":\"recordMigration\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_payer\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"decimals\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"currency\",\"type\":\"uint256\"}],\"internalType\":\"struct JBTokenAmount\",\"name\":\"_amount\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_baseWeightCurrency\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_beneficiary\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"_memo\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"_metadata\",\"type\":\"bytes\"}],\"name\":\"recordPaymentFrom\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"number\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"configuration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"basedOn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"start\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"duration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"weight\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"discountRate\",\"type\":\"uint256\"},{\"internalType\":\"contract IJBFundingCycleBallot\",\"name\":\"ballot\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"metadata\",\"type\":\"uint256\"}],\"internalType\":\"struct JBFundingCycle\",\"name\":\"fundingCycle\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"tokenCount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"contract IJBPayDelegate3_1_1\",\"name\":\"delegate\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"metadata\",\"type\":\"bytes\"}],\"internalType\":\"struct JBPayDelegateAllocation3_1_1[]\",\"name\":\"delegateAllocations\",\"type\":\"tuple[]\"},{\"internalType\":\"string\",\"name\":\"memo\",\"type\":\"string\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_holder\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_tokenCount\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"_memo\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"_metadata\",\"type\":\"bytes\"}],\"name\":\"recordRedemptionFor\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"number\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"configuration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"basedOn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"start\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"duration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"weight\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"discountRate\",\"type\":\"uint256\"},{\"internalType\":\"contract IJBFundingCycleBallot\",\"name\":\"ballot\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"metadata\",\"type\":\"uint256\"}],\"internalType\":\"struct JBFundingCycle\",\"name\":\"fundingCycle\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"reclaimAmount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"contract IJBRedemptionDelegate3_1_1\",\"name\":\"delegate\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"metadata\",\"type\":\"bytes\"}],\"internalType\":\"struct JBRedemptionDelegateAllocation3_1_1[]\",\"name\":\"delegateAllocations\",\"type\":\"tuple[]\"},{\"internalType\":\"string\",\"name\":\"memo\",\"type\":\"string\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_currency\",\"type\":\"uint256\"}],\"name\":\"recordUsedAllowanceOf\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"number\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"configuration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"basedOn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"start\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"duration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"weight\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"discountRate\",\"type\":\"uint256\"},{\"internalType\":\"contract IJBFundingCycleBallot\",\"name\":\"ballot\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"metadata\",\"type\":\"uint256\"}],\"internalType\":\"struct JBFundingCycle\",\"name\":\"fundingCycle\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"usedAmount\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IJBSingleTokenPaymentTerminal\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"usedDistributionLimitOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IJBSingleTokenPaymentTerminal\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"usedOverflowAllowanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"This Store expects a project's controller to be an IJBController3_1.\",\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_directory\":\"A contract storing directories of terminals and controllers for each project.\",\"_fundingCycleStore\":\"A contract storing all funding cycle configurations.\",\"_prices\":\"A contract that exposes price feeds.\"}},\"currentOverflowOf(address,uint256)\":{\"details\":\"The current overflow is represented as a fixed point number with the same amount of decimals as the specified terminal.\",\"params\":{\"_projectId\":\"The ID of the project to get overflow for.\",\"_terminal\":\"The terminal for which the overflow is being calculated.\"},\"returns\":{\"_0\":\"The current amount of overflow that project has in the specified terminal.\"}},\"currentReclaimableOverflowOf(address,uint256,uint256,bool)\":{\"details\":\"If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.The current reclaimable overflow is returned in terms of the specified terminal's currency.The reclaimable overflow is represented as a fixed point number with the same amount of decimals as the specified terminal.\",\"params\":{\"_projectId\":\"The ID of the project to get the reclaimable overflow amount for.\",\"_terminal\":\"The terminal from which the reclaimable amount would come.\",\"_tokenCount\":\"The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\",\"_useTotalOverflow\":\"A flag indicating whether the overflow used in the calculation should be summed from all of the project's terminals. If false, overflow should be limited to the amount in the specified `_terminal`.\"},\"returns\":{\"_0\":\"The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_terminal`.\"}},\"currentReclaimableOverflowOf(uint256,uint256,uint256,uint256)\":{\"details\":\"If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\",\"params\":{\"_overflow\":\"The amount of overflow to make the calculation with, as a fixed point number.\",\"_projectId\":\"The ID of the project to get the reclaimable overflow amount for.\",\"_tokenCount\":\"The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\",\"_totalSupply\":\"The total number of tokens to make the calculation with, as a fixed point number with 18 decimals.\"},\"returns\":{\"_0\":\"The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_overflow`.\"}},\"currentTotalOverflowOf(uint256,uint256,uint256)\":{\"params\":{\"_currency\":\"The currency that the total overflow should be in terms of.\",\"_decimals\":\"The number of decimals that the fixed point overflow should include.\",\"_projectId\":\"The ID of the project to get total overflow for.\"},\"returns\":{\"_0\":\"The current total amount of overflow that project has across all terminals.\"}},\"recordAddedBalanceFor(uint256,uint256)\":{\"details\":\"The msg.sender must be an IJBSingleTokenPaymentTerminal.\",\"params\":{\"_amount\":\"The amount of terminal tokens added, as a fixed point number with the same amount of decimals as its relative terminal.\",\"_projectId\":\"The ID of the project to which the funds being added belong.\"}},\"recordDistributionFor(uint256,uint256,uint256)\":{\"details\":\"The msg.sender must be an IJBSingleTokenPaymentTerminal.\",\"params\":{\"_amount\":\"The amount to use from the distribution limit, as a fixed point number.\",\"_currency\":\"The currency of the `_amount`. This must match the project's current funding cycle's currency.\",\"_projectId\":\"The ID of the project that is having funds distributed.\"},\"returns\":{\"distributedAmount\":\"The amount of terminal tokens distributed, as a fixed point number with the same amount of decimals as its relative terminal.\",\"fundingCycle\":\"The funding cycle during which the distribution was made.\"}},\"recordMigration(uint256)\":{\"details\":\"The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount returned is in terms of the msg.senders tokens.\",\"params\":{\"_projectId\":\"The ID of the project being migrated.\"},\"returns\":{\"balance\":\"The project's migrated balance, as a fixed point number with the same amount of decimals as its relative terminal.\"}},\"recordPaymentFrom(address,(address,uint256,uint256,uint256),uint256,uint256,address,string,bytes)\":{\"details\":\"Mints the project's tokens according to values provided by a configured data source. If no data source is configured, mints tokens proportional to the amount of the contribution.The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.sender's tokens.\",\"params\":{\"_amount\":\"The amount of tokens being paid. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\",\"_baseWeightCurrency\":\"The currency to base token issuance on.\",\"_beneficiary\":\"The specified address that should be the beneficiary of anything that results from the payment.\",\"_memo\":\"A memo to pass along to the emitted event, and passed along to the funding cycle's data source.\",\"_metadata\":\"Bytes to send along to the data source, if one is provided.\",\"_payer\":\"The original address that sent the payment to the terminal.\",\"_projectId\":\"The ID of the project being paid.\"},\"returns\":{\"delegateAllocations\":\"The amount to send to delegates instead of adding to the local balance.\",\"fundingCycle\":\"The project's funding cycle during which payment was made.\",\"memo\":\"A memo that should be passed along to the emitted event.\",\"tokenCount\":\"The number of project tokens that were minted, as a fixed point number with 18 decimals.\"}},\"recordRedemptionFor(address,uint256,uint256,string,bytes)\":{\"details\":\"Redeems the project's tokens according to values provided by a configured data source. If no data source is configured, redeems tokens along a redemption bonding curve that is a function of the number of tokens being burned.The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.senders tokens.\",\"params\":{\"_holder\":\"The account that is having its tokens redeemed.\",\"_memo\":\"A memo to pass along to the emitted event.\",\"_metadata\":\"Bytes to send along to the data source, if one is provided.\",\"_projectId\":\"The ID of the project to which the tokens being redeemed belong.\",\"_tokenCount\":\"The number of project tokens to redeem, as a fixed point number with 18 decimals.\"},\"returns\":{\"delegateAllocations\":\"The amount to send to delegates instead of sending to the beneficiary.\",\"fundingCycle\":\"The funding cycle during which the redemption was made.\",\"memo\":\"A memo that should be passed along to the emitted event.\",\"reclaimAmount\":\"The amount of terminal tokens reclaimed, as a fixed point number with 18 decimals.\"}},\"recordUsedAllowanceOf(uint256,uint256,uint256)\":{\"details\":\"The msg.sender must be an IJBSingleTokenPaymentTerminal.\",\"params\":{\"_amount\":\"The amount to use from the allowance, as a fixed point number.\",\"_currency\":\"The currency of the `_amount`. Must match the currency of the overflow allowance.\",\"_projectId\":\"The ID of the project to use the allowance of.\"},\"returns\":{\"fundingCycle\":\"The funding cycle during which the overflow allowance is being used.\",\"usedAmount\":\"The amount of terminal tokens used, as a fixed point number with the same amount of decimals as its relative terminal.\"}}},\"stateVariables\":{\"balanceOf\":{\"custom:param\":\"_terminal The terminal to which the balance applies._projectId The ID of the project to get the balance of.\",\"details\":\"The balance is represented as a fixed point number with the same amount of decimals as its relative terminal.\"},\"usedDistributionLimitOf\":{\"custom:param\":\"_terminal The terminal to which the used distribution limit applies._projectId The ID of the project to get the used distribution limit of._fundingCycleNumber The number of the funding cycle during which the distribution limit was used.\",\"details\":\"Increases as projects use their preconfigured distribution limits.The used distribution limit is represented as a fixed point number with the same amount of decimals as its relative terminal.\"},\"usedOverflowAllowanceOf\":{\"custom:param\":\"_terminal The terminal to which the overflow allowance applies._projectId The ID of the project to get the used overflow allowance of._configuration The configuration of the during which the allowance was used.\",\"details\":\"Increases as projects use their allowance.The used allowance is represented as a fixed point number with the same amount of decimals as its relative terminal.\"}},\"version\":1},\"userdoc\":{\"errors\":{\"PRBMath__MulDivOverflow(uint256,uint256)\":[{\"notice\":\"Emitted when the result overflows uint256.\"}]},\"kind\":\"user\",\"methods\":{\"balanceOf(address,uint256)\":{\"notice\":\"The amount of tokens that each project has for each terminal, in terms of the terminal's token.\"},\"currentOverflowOf(address,uint256)\":{\"notice\":\"Gets the current overflowed amount in a terminal for a specified project.\"},\"currentReclaimableOverflowOf(address,uint256,uint256,bool)\":{\"notice\":\"The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the total token supply and overflow in the ecosystem.\"},\"currentReclaimableOverflowOf(uint256,uint256,uint256,uint256)\":{\"notice\":\"The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the specified total token supply and overflow amounts.\"},\"currentTotalOverflowOf(uint256,uint256,uint256)\":{\"notice\":\"Gets the current overflowed amount for a specified project across all terminals.\"},\"directory()\":{\"notice\":\"The directory of terminals and controllers for projects.\"},\"fundingCycleStore()\":{\"notice\":\"The contract storing all funding cycle configurations.\"},\"prices()\":{\"notice\":\"The contract that exposes price feeds.\"},\"recordAddedBalanceFor(uint256,uint256)\":{\"notice\":\"Records newly added funds for the project.\"},\"recordDistributionFor(uint256,uint256,uint256)\":{\"notice\":\"Records newly distributed funds for a project.\"},\"recordMigration(uint256)\":{\"notice\":\"Records the migration of funds from this store.\"},\"recordPaymentFrom(address,(address,uint256,uint256,uint256),uint256,uint256,address,string,bytes)\":{\"notice\":\"Records newly contributed tokens to a project.\"},\"recordRedemptionFor(address,uint256,uint256,string,bytes)\":{\"notice\":\"Records newly redeemed tokens of a project.\"},\"recordUsedAllowanceOf(uint256,uint256,uint256)\":{\"notice\":\"Records newly used allowance funds of a project.\"},\"usedDistributionLimitOf(address,uint256,uint256)\":{\"notice\":\"The amount of funds that a project has distributed from its limit during the current funding cycle for each terminal, in terms of the distribution limit's currency.\"},\"usedOverflowAllowanceOf(address,uint256,uint256)\":{\"notice\":\"The amount of funds that a project has used from its allowance during the current funding cycle configuration for each terminal, in terms of the overflow allowance's currency.\"}},\"notice\":\"Manages all bookkeeping for inflows and outflows of funds from any ISingleTokenPaymentTerminal.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/JBSingleTokenPaymentTerminalStore3_1_1.sol\":\"JBSingleTokenPaymentTerminalStore3_1_1\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/security/ReentrancyGuard.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Contract module that helps prevent reentrant calls to a function.\\n *\\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\\n * available, which can be applied to functions to make sure there are no nested\\n * (reentrant) calls to them.\\n *\\n * Note that because there is a single `nonReentrant` guard, functions marked as\\n * `nonReentrant` may not call one another. This can be worked around by making\\n * those functions `private`, and then adding `external` `nonReentrant` entry\\n * points to them.\\n *\\n * TIP: If you would like to learn more about reentrancy and alternative ways\\n * to protect against it, check out our blog post\\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\\n */\\nabstract contract ReentrancyGuard {\\n // Booleans are more expensive than uint256 or any type that takes up a full\\n // word because each write operation emits an extra SLOAD to first read the\\n // slot's contents, replace the bits taken up by the boolean, and then write\\n // back. This is the compiler's defense against contract upgrades and\\n // pointer aliasing, and it cannot be disabled.\\n\\n // The values being non-zero value makes deployment a bit more expensive,\\n // but in exchange the refund on every call to nonReentrant will be lower in\\n // amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to\\n // increase the likelihood of the full refund coming into effect.\\n uint256 private constant _NOT_ENTERED = 1;\\n uint256 private constant _ENTERED = 2;\\n\\n uint256 private _status;\\n\\n constructor() {\\n _status = _NOT_ENTERED;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a `nonReentrant` function from another `nonReentrant`\\n * function is not supported. It is possible to prevent this from happening\\n * by making the `nonReentrant` function external, and making it call a\\n * `private` function that does the actual work.\\n */\\n modifier nonReentrant() {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_status != _ENTERED, \\\"ReentrancyGuard: reentrant call\\\");\\n\\n // Any calls to nonReentrant after this point will fail\\n _status = _ENTERED;\\n\\n _;\\n\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _status = _NOT_ENTERED;\\n }\\n}\\n\",\"keccak256\":\"0x0e9621f60b2faabe65549f7ed0f24e8853a45c1b7990d47e8160e523683f3935\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC721/IERC721.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../../utils/introspection/IERC165.sol\\\";\\n\\n/**\\n * @dev Required interface of an ERC721 compliant contract.\\n */\\ninterface IERC721 is IERC165 {\\n /**\\n * @dev Emitted when `tokenId` token is transferred from `from` to `to`.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);\\n\\n /**\\n * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.\\n */\\n event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);\\n\\n /**\\n * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.\\n */\\n event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\\n\\n /**\\n * @dev Returns the number of tokens in ``owner``'s account.\\n */\\n function balanceOf(address owner) external view returns (uint256 balance);\\n\\n /**\\n * @dev Returns the owner of the `tokenId` token.\\n *\\n * Requirements:\\n *\\n * - `tokenId` must exist.\\n */\\n function ownerOf(uint256 tokenId) external view returns (address owner);\\n\\n /**\\n * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\\n * are aware of the ERC721 protocol to prevent tokens from being forever locked.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `tokenId` token must exist and be owned by `from`.\\n * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.\\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\\n *\\n * Emits a {Transfer} event.\\n */\\n function safeTransferFrom(\\n address from,\\n address to,\\n uint256 tokenId\\n ) external;\\n\\n /**\\n * @dev Transfers `tokenId` token from `from` to `to`.\\n *\\n * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `tokenId` token must be owned by `from`.\\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 tokenId\\n ) external;\\n\\n /**\\n * @dev Gives permission to `to` to transfer `tokenId` token to another account.\\n * The approval is cleared when the token is transferred.\\n *\\n * Only a single account can be approved at a time, so approving the zero address clears previous approvals.\\n *\\n * Requirements:\\n *\\n * - The caller must own the token or be an approved operator.\\n * - `tokenId` must exist.\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address to, uint256 tokenId) external;\\n\\n /**\\n * @dev Returns the account approved for `tokenId` token.\\n *\\n * Requirements:\\n *\\n * - `tokenId` must exist.\\n */\\n function getApproved(uint256 tokenId) external view returns (address operator);\\n\\n /**\\n * @dev Approve or remove `operator` as an operator for the caller.\\n * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.\\n *\\n * Requirements:\\n *\\n * - The `operator` cannot be the caller.\\n *\\n * Emits an {ApprovalForAll} event.\\n */\\n function setApprovalForAll(address operator, bool _approved) external;\\n\\n /**\\n * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.\\n *\\n * See {setApprovalForAll}\\n */\\n function isApprovedForAll(address owner, address operator) external view returns (bool);\\n\\n /**\\n * @dev Safely transfers `tokenId` token from `from` to `to`.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `tokenId` token must exist and be owned by `from`.\\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\\n *\\n * Emits a {Transfer} event.\\n */\\n function safeTransferFrom(\\n address from,\\n address to,\\n uint256 tokenId,\\n bytes calldata data\\n ) external;\\n}\\n\",\"keccak256\":\"0x516a22876c1fab47f49b1bc22b4614491cd05338af8bd2e7b382da090a079990\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/IERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC165 standard, as defined in the\\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\\n *\\n * Implementers can declare support of contract interfaces, which can then be\\n * queried by others ({ERC165Checker}).\\n *\\n * For an implementation, see {ERC165}.\\n */\\ninterface IERC165 {\\n /**\\n * @dev Returns true if this contract implements the interface defined by\\n * `interfaceId`. See the corresponding\\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\\n * to learn more about how these ids are created.\\n *\\n * This function call must use less than 30 000 gas.\\n */\\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\\n}\\n\",\"keccak256\":\"0x447a5f3ddc18419d41ff92b3773fb86471b1db25773e07f877f548918a185bf1\",\"license\":\"MIT\"},\"@paulrberg/contracts/math/PRBMath.sol\":{\"content\":\"// SPDX-License-Identifier: Unlicense\\npragma solidity >=0.8.4;\\n\\nimport \\\"prb-math/contracts/PRBMath.sol\\\";\\n\",\"keccak256\":\"0x42821345981bc0434a90ba2268a2f5278dfe9e38166981d72fc7f3b776a29495\",\"license\":\"Unlicense\"},\"contracts/JBSingleTokenPaymentTerminalStore3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.16;\\n\\nimport {ReentrancyGuard} from '@openzeppelin/contracts/security/ReentrancyGuard.sol';\\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\\nimport {JBBallotState} from './enums/JBBallotState.sol';\\nimport {IJBController3_1} from './interfaces/IJBController3_1.sol';\\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\\nimport {IJBFundingCycleDataSource3_1_1} from './interfaces/IJBFundingCycleDataSource3_1_1.sol';\\nimport {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol';\\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\\nimport {IJBSingleTokenPaymentTerminal} from './interfaces/IJBSingleTokenPaymentTerminal.sol';\\nimport {IJBSingleTokenPaymentTerminalStore3_1_1} from './interfaces/IJBSingleTokenPaymentTerminalStore3_1_1.sol';\\nimport {JBConstants} from './libraries/JBConstants.sol';\\nimport {JBCurrencies} from './libraries/JBCurrencies.sol';\\nimport {JBFixedPointNumber} from './libraries/JBFixedPointNumber.sol';\\nimport {JBFundingCycleMetadataResolver} from './libraries/JBFundingCycleMetadataResolver.sol';\\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\\nimport {JBPayDelegateAllocation3_1_1} from './structs/JBPayDelegateAllocation3_1_1.sol';\\nimport {JBPayParamsData} from './structs/JBPayParamsData.sol';\\nimport {JBRedeemParamsData} from './structs/JBRedeemParamsData.sol';\\nimport {JBRedemptionDelegateAllocation3_1_1} from './structs/JBRedemptionDelegateAllocation3_1_1.sol';\\nimport {JBTokenAmount} from './structs/JBTokenAmount.sol';\\n\\n/// @notice Manages all bookkeeping for inflows and outflows of funds from any ISingleTokenPaymentTerminal.\\n/// @dev This Store expects a project's controller to be an IJBController3_1.\\ncontract JBSingleTokenPaymentTerminalStore3_1_1 is\\n ReentrancyGuard,\\n IJBSingleTokenPaymentTerminalStore3_1_1\\n{\\n // A library that parses the packed funding cycle metadata into a friendlier format.\\n using JBFundingCycleMetadataResolver for JBFundingCycle;\\n\\n //*********************************************************************//\\n // --------------------------- custom errors ------------------------- //\\n //*********************************************************************//\\n error INVALID_AMOUNT_TO_SEND_DELEGATE();\\n error CURRENCY_MISMATCH();\\n error DISTRIBUTION_AMOUNT_LIMIT_REACHED();\\n error FUNDING_CYCLE_PAYMENT_PAUSED();\\n error FUNDING_CYCLE_DISTRIBUTION_PAUSED();\\n error FUNDING_CYCLE_REDEEM_PAUSED();\\n error INADEQUATE_CONTROLLER_ALLOWANCE();\\n error INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\\n error INSUFFICIENT_TOKENS();\\n error INVALID_FUNDING_CYCLE();\\n error PAYMENT_TERMINAL_MIGRATION_NOT_ALLOWED();\\n\\n //*********************************************************************//\\n // -------------------------- private constants ---------------------- //\\n //*********************************************************************//\\n\\n /// @notice Ensures a maximum number of decimal points of persisted fidelity on mulDiv operations of fixed point numbers.\\n uint256 private constant _MAX_FIXED_POINT_FIDELITY = 18;\\n\\n //*********************************************************************//\\n // ---------------- public immutable stored properties --------------- //\\n //*********************************************************************//\\n\\n /// @notice The directory of terminals and controllers for projects.\\n IJBDirectory public immutable override directory;\\n\\n /// @notice The contract storing all funding cycle configurations.\\n IJBFundingCycleStore public immutable override fundingCycleStore;\\n\\n /// @notice The contract that exposes price feeds.\\n IJBPrices public immutable override prices;\\n\\n //*********************************************************************//\\n // --------------------- public stored properties -------------------- //\\n //*********************************************************************//\\n\\n /// @notice The amount of tokens that each project has for each terminal, in terms of the terminal's token.\\n /// @dev The balance is represented as a fixed point number with the same amount of decimals as its relative terminal.\\n /// @custom:param _terminal The terminal to which the balance applies.\\n /// @custom:param _projectId The ID of the project to get the balance of.\\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => uint256)) public override balanceOf;\\n\\n /// @notice The amount of funds that a project has distributed from its limit during the current funding cycle for each terminal, in terms of the distribution limit's currency.\\n /// @dev Increases as projects use their preconfigured distribution limits.\\n /// @dev The used distribution limit is represented as a fixed point number with the same amount of decimals as its relative terminal.\\n /// @custom:param _terminal The terminal to which the used distribution limit applies.\\n /// @custom:param _projectId The ID of the project to get the used distribution limit of.\\n /// @custom:param _fundingCycleNumber The number of the funding cycle during which the distribution limit was used.\\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => mapping(uint256 => uint256)))\\n public\\n override usedDistributionLimitOf;\\n\\n /// @notice The amount of funds that a project has used from its allowance during the current funding cycle configuration for each terminal, in terms of the overflow allowance's currency.\\n /// @dev Increases as projects use their allowance.\\n /// @dev The used allowance is represented as a fixed point number with the same amount of decimals as its relative terminal.\\n /// @custom:param _terminal The terminal to which the overflow allowance applies.\\n /// @custom:param _projectId The ID of the project to get the used overflow allowance of.\\n /// @custom:param _configuration The configuration of the during which the allowance was used.\\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => mapping(uint256 => uint256)))\\n public\\n override usedOverflowAllowanceOf;\\n\\n //*********************************************************************//\\n // ------------------------- external views -------------------------- //\\n //*********************************************************************//\\n\\n /// @notice Gets the current overflowed amount in a terminal for a specified project.\\n /// @dev The current overflow is represented as a fixed point number with the same amount of decimals as the specified terminal.\\n /// @param _terminal The terminal for which the overflow is being calculated.\\n /// @param _projectId The ID of the project to get overflow for.\\n /// @return The current amount of overflow that project has in the specified terminal.\\n function currentOverflowOf(\\n IJBSingleTokenPaymentTerminal _terminal,\\n uint256 _projectId\\n ) external view override returns (uint256) {\\n // Return the overflow during the project's current funding cycle.\\n return\\n _overflowDuring(\\n _terminal,\\n _projectId,\\n fundingCycleStore.currentOf(_projectId),\\n _terminal.currency()\\n );\\n }\\n\\n /// @notice Gets the current overflowed amount for a specified project across all terminals.\\n /// @param _projectId The ID of the project to get total overflow for.\\n /// @param _decimals The number of decimals that the fixed point overflow should include.\\n /// @param _currency The currency that the total overflow should be in terms of.\\n /// @return The current total amount of overflow that project has across all terminals.\\n function currentTotalOverflowOf(\\n uint256 _projectId,\\n uint256 _decimals,\\n uint256 _currency\\n ) external view override returns (uint256) {\\n return _currentTotalOverflowOf(_projectId, _decimals, _currency);\\n }\\n\\n /// @notice The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the total token supply and overflow in the ecosystem.\\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\\n /// @dev The current reclaimable overflow is returned in terms of the specified terminal's currency.\\n /// @dev The reclaimable overflow is represented as a fixed point number with the same amount of decimals as the specified terminal.\\n /// @param _terminal The terminal from which the reclaimable amount would come.\\n /// @param _projectId The ID of the project to get the reclaimable overflow amount for.\\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\\n /// @param _useTotalOverflow A flag indicating whether the overflow used in the calculation should be summed from all of the project's terminals. If false, overflow should be limited to the amount in the specified `_terminal`.\\n /// @return The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_terminal`.\\n function currentReclaimableOverflowOf(\\n IJBSingleTokenPaymentTerminal _terminal,\\n uint256 _projectId,\\n uint256 _tokenCount,\\n bool _useTotalOverflow\\n ) external view override returns (uint256) {\\n // Get a reference to the project's current funding cycle.\\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\\n\\n // Get the amount of current overflow.\\n // Use the project's total overflow across all of its terminals if the flag species specifies so. Otherwise, use the overflow local to the specified terminal.\\n uint256 _currentOverflow = _useTotalOverflow\\n ? _currentTotalOverflowOf(_projectId, _terminal.decimals(), _terminal.currency())\\n : _overflowDuring(_terminal, _projectId, _fundingCycle, _terminal.currency());\\n\\n // If there's no overflow, there's no reclaimable overflow.\\n if (_currentOverflow == 0) return 0;\\n\\n // Get the number of outstanding tokens the project has.\\n uint256 _totalSupply = IJBController3_1(directory.controllerOf(_projectId))\\n .totalOutstandingTokensOf(_projectId);\\n\\n // Can't redeem more tokens that is in the supply.\\n if (_tokenCount > _totalSupply) return 0;\\n\\n // Return the reclaimable overflow amount.\\n return\\n _reclaimableOverflowDuring(\\n _projectId,\\n _fundingCycle,\\n _tokenCount,\\n _totalSupply,\\n _currentOverflow\\n );\\n }\\n\\n /// @notice The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the specified total token supply and overflow amounts.\\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\\n /// @param _projectId The ID of the project to get the reclaimable overflow amount for.\\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\\n /// @param _totalSupply The total number of tokens to make the calculation with, as a fixed point number with 18 decimals.\\n /// @param _overflow The amount of overflow to make the calculation with, as a fixed point number.\\n /// @return The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_overflow`.\\n function currentReclaimableOverflowOf(\\n uint256 _projectId,\\n uint256 _tokenCount,\\n uint256 _totalSupply,\\n uint256 _overflow\\n ) external view override returns (uint256) {\\n // If there's no overflow, there's no reclaimable overflow.\\n if (_overflow == 0) return 0;\\n\\n // Can't redeem more tokens that is in the supply.\\n if (_tokenCount > _totalSupply) return 0;\\n\\n // Get a reference to the project's current funding cycle.\\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\\n\\n // Return the reclaimable overflow amount.\\n return\\n _reclaimableOverflowDuring(_projectId, _fundingCycle, _tokenCount, _totalSupply, _overflow);\\n }\\n\\n //*********************************************************************//\\n // -------------------------- constructor ---------------------------- //\\n //*********************************************************************//\\n\\n /// @param _directory A contract storing directories of terminals and controllers for each project.\\n /// @param _fundingCycleStore A contract storing all funding cycle configurations.\\n /// @param _prices A contract that exposes price feeds.\\n constructor(IJBDirectory _directory, IJBFundingCycleStore _fundingCycleStore, IJBPrices _prices) {\\n directory = _directory;\\n fundingCycleStore = _fundingCycleStore;\\n prices = _prices;\\n }\\n\\n //*********************************************************************//\\n // ---------------------- external transactions ---------------------- //\\n //*********************************************************************//\\n\\n /// @notice Records newly contributed tokens to a project.\\n /// @dev Mints the project's tokens according to values provided by a configured data source. If no data source is configured, mints tokens proportional to the amount of the contribution.\\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.sender's tokens.\\n /// @param _payer The original address that sent the payment to the terminal.\\n /// @param _amount The amount of tokens being paid. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\\n /// @param _projectId The ID of the project being paid.\\n /// @param _baseWeightCurrency The currency to base token issuance on.\\n /// @param _beneficiary The specified address that should be the beneficiary of anything that results from the payment.\\n /// @param _memo A memo to pass along to the emitted event, and passed along to the funding cycle's data source.\\n /// @param _metadata Bytes to send along to the data source, if one is provided.\\n /// @return fundingCycle The project's funding cycle during which payment was made.\\n /// @return tokenCount The number of project tokens that were minted, as a fixed point number with 18 decimals.\\n /// @return delegateAllocations The amount to send to delegates instead of adding to the local balance.\\n /// @return memo A memo that should be passed along to the emitted event.\\n function recordPaymentFrom(\\n address _payer,\\n JBTokenAmount calldata _amount,\\n uint256 _projectId,\\n uint256 _baseWeightCurrency,\\n address _beneficiary,\\n string calldata _memo,\\n bytes memory _metadata\\n )\\n external\\n override\\n nonReentrant\\n returns (\\n JBFundingCycle memory fundingCycle,\\n uint256 tokenCount,\\n JBPayDelegateAllocation3_1_1[] memory delegateAllocations,\\n string memory memo\\n )\\n {\\n // Get a reference to the current funding cycle for the project.\\n fundingCycle = fundingCycleStore.currentOf(_projectId);\\n\\n // The project must have a funding cycle configured.\\n if (fundingCycle.number == 0) revert INVALID_FUNDING_CYCLE();\\n\\n // Must not be paused.\\n if (fundingCycle.payPaused()) revert FUNDING_CYCLE_PAYMENT_PAUSED();\\n\\n // The weight according to which new token supply is to be minted, as a fixed point number with 18 decimals.\\n uint256 _weight;\\n\\n // If the funding cycle has configured a data source, use it to derive a weight and memo.\\n if (fundingCycle.useDataSourceForPay() && fundingCycle.dataSource() != address(0)) {\\n // Create the params that'll be sent to the data source.\\n JBPayParamsData memory _data = JBPayParamsData(\\n IJBSingleTokenPaymentTerminal(msg.sender),\\n _payer,\\n _amount,\\n _projectId,\\n fundingCycle.configuration,\\n _beneficiary,\\n fundingCycle.weight,\\n fundingCycle.reservedRate(),\\n _memo,\\n _metadata\\n );\\n (_weight, memo, delegateAllocations) = IJBFundingCycleDataSource3_1_1(\\n fundingCycle.dataSource()\\n ).payParams(_data);\\n }\\n // Otherwise use the funding cycle's weight\\n else {\\n _weight = fundingCycle.weight;\\n memo = _memo;\\n }\\n\\n // Scoped section prevents stack too deep. `_balanceDiff` only used within scope.\\n {\\n // Keep a reference to the amount that should be added to the project's balance.\\n uint256 _balanceDiff = _amount.value;\\n\\n // Validate all delegated amounts. This needs to be done before returning the delegate allocations to ensure valid delegated amounts.\\n if (delegateAllocations.length != 0) {\\n for (uint256 _i; _i < delegateAllocations.length; ) {\\n // Get a reference to the amount to be delegated.\\n uint256 _delegatedAmount = delegateAllocations[_i].amount;\\n\\n // Validate if non-zero.\\n if (_delegatedAmount != 0) {\\n // Can't delegate more than was paid.\\n if (_delegatedAmount > _balanceDiff) revert INVALID_AMOUNT_TO_SEND_DELEGATE();\\n\\n // Decrement the total amount being added to the balance.\\n _balanceDiff = _balanceDiff - _delegatedAmount;\\n }\\n\\n unchecked {\\n ++_i;\\n }\\n }\\n }\\n\\n // If there's no amount being recorded, there's nothing left to do.\\n if (_amount.value == 0) return (fundingCycle, 0, delegateAllocations, memo);\\n\\n // Add the correct balance difference to the token balance of the project.\\n if (_balanceDiff != 0)\\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] +\\n _balanceDiff;\\n }\\n\\n // If there's no weight, token count must be 0 so there's nothing left to do.\\n if (_weight == 0) return (fundingCycle, 0, delegateAllocations, memo);\\n\\n // Get a reference to the number of decimals in the amount. (prevents stack too deep).\\n uint256 _decimals = _amount.decimals;\\n\\n // If the terminal should base its weight on a different currency from the terminal's currency, determine the factor.\\n // The weight is always a fixed point mumber with 18 decimals. To ensure this, the ratio should use the same number of decimals as the `_amount`.\\n uint256 _weightRatio = _amount.currency == _baseWeightCurrency\\n ? 10 ** _decimals\\n : prices.priceFor(_amount.currency, _baseWeightCurrency, _decimals);\\n\\n // Find the number of tokens to mint, as a fixed point number with as many decimals as `weight` has.\\n tokenCount = PRBMath.mulDiv(_amount.value, _weight, _weightRatio);\\n }\\n\\n /// @notice Records newly redeemed tokens of a project.\\n /// @dev Redeems the project's tokens according to values provided by a configured data source. If no data source is configured, redeems tokens along a redemption bonding curve that is a function of the number of tokens being burned.\\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.senders tokens.\\n /// @param _holder The account that is having its tokens redeemed.\\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\\n /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals.\\n /// @param _memo A memo to pass along to the emitted event.\\n /// @param _metadata Bytes to send along to the data source, if one is provided.\\n /// @return fundingCycle The funding cycle during which the redemption was made.\\n /// @return reclaimAmount The amount of terminal tokens reclaimed, as a fixed point number with 18 decimals.\\n /// @return delegateAllocations The amount to send to delegates instead of sending to the beneficiary.\\n /// @return memo A memo that should be passed along to the emitted event.\\n function recordRedemptionFor(\\n address _holder,\\n uint256 _projectId,\\n uint256 _tokenCount,\\n string memory _memo,\\n bytes memory _metadata\\n )\\n external\\n override\\n nonReentrant\\n returns (\\n JBFundingCycle memory fundingCycle,\\n uint256 reclaimAmount,\\n JBRedemptionDelegateAllocation3_1_1[] memory delegateAllocations,\\n string memory memo\\n )\\n {\\n // Get a reference to the project's current funding cycle.\\n fundingCycle = fundingCycleStore.currentOf(_projectId);\\n\\n // The current funding cycle must not be paused.\\n if (fundingCycle.redeemPaused()) revert FUNDING_CYCLE_REDEEM_PAUSED();\\n\\n // Scoped section prevents stack too deep. `_reclaimedTokenAmount`, `_currentOverflow`, and `_totalSupply` only used within scope.\\n {\\n // Get a reference to the reclaimed token amount struct, the current overflow, and the total token supply.\\n JBTokenAmount memory _reclaimedTokenAmount;\\n uint256 _currentOverflow;\\n uint256 _totalSupply;\\n\\n // Another scoped section prevents stack too deep. `_token`, `_decimals`, and `_currency` only used within scope.\\n {\\n // Get a reference to the terminal's tokens.\\n address _token = IJBSingleTokenPaymentTerminal(msg.sender).token();\\n\\n // Get a reference to the terminal's decimals.\\n uint256 _decimals = IJBSingleTokenPaymentTerminal(msg.sender).decimals();\\n\\n // Get areference to the terminal's currency.\\n uint256 _currency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\\n\\n // Get the amount of current overflow.\\n // Use the local overflow if the funding cycle specifies that it should be used. Otherwise, use the project's total overflow across all of its terminals.\\n _currentOverflow = fundingCycle.useTotalOverflowForRedemptions()\\n ? _currentTotalOverflowOf(_projectId, _decimals, _currency)\\n : _overflowDuring(\\n IJBSingleTokenPaymentTerminal(msg.sender),\\n _projectId,\\n fundingCycle,\\n _currency\\n );\\n\\n // Get the number of outstanding tokens the project has.\\n _totalSupply = IJBController3_1(directory.controllerOf(_projectId))\\n .totalOutstandingTokensOf(_projectId);\\n\\n // Can't redeem more tokens that is in the supply.\\n if (_tokenCount > _totalSupply) revert INSUFFICIENT_TOKENS();\\n\\n if (_currentOverflow != 0)\\n // Calculate reclaim amount using the current overflow amount.\\n reclaimAmount = _reclaimableOverflowDuring(\\n _projectId,\\n fundingCycle,\\n _tokenCount,\\n _totalSupply,\\n _currentOverflow\\n );\\n\\n _reclaimedTokenAmount = JBTokenAmount(_token, reclaimAmount, _decimals, _currency);\\n }\\n\\n // If the funding cycle has configured a data source, use it to derive a claim amount and memo.\\n if (fundingCycle.useDataSourceForRedeem() && fundingCycle.dataSource() != address(0)) {\\n // Yet another scoped section prevents stack too deep. `_state` only used within scope.\\n {\\n // Get a reference to the ballot state.\\n JBBallotState _state = fundingCycleStore.currentBallotStateOf(_projectId);\\n\\n // Create the params that'll be sent to the data source.\\n JBRedeemParamsData memory _data = JBRedeemParamsData(\\n IJBSingleTokenPaymentTerminal(msg.sender),\\n _holder,\\n _projectId,\\n fundingCycle.configuration,\\n _tokenCount,\\n _totalSupply,\\n _currentOverflow,\\n _reclaimedTokenAmount,\\n fundingCycle.useTotalOverflowForRedemptions(),\\n _state == JBBallotState.Active\\n ? fundingCycle.ballotRedemptionRate()\\n : fundingCycle.redemptionRate(),\\n _memo,\\n _metadata\\n );\\n (reclaimAmount, memo, delegateAllocations) = IJBFundingCycleDataSource3_1_1(\\n fundingCycle.dataSource()\\n ).redeemParams(_data);\\n }\\n } else {\\n memo = _memo;\\n }\\n }\\n\\n // Keep a reference to the amount that should be subtracted from the project's balance.\\n uint256 _balanceDiff = reclaimAmount;\\n\\n if (delegateAllocations.length != 0) {\\n // Validate all delegated amounts.\\n for (uint256 _i; _i < delegateAllocations.length; ) {\\n // Get a reference to the amount to be delegated.\\n uint256 _delegatedAmount = delegateAllocations[_i].amount;\\n\\n // Validate if non-zero.\\n if (_delegatedAmount != 0)\\n // Increment the total amount being subtracted from the balance.\\n _balanceDiff = _balanceDiff + _delegatedAmount;\\n\\n unchecked {\\n ++_i;\\n }\\n }\\n }\\n\\n // The amount being reclaimed must be within the project's balance.\\n if (_balanceDiff > balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId])\\n revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\\n\\n // Remove the reclaimed funds from the project's balance.\\n if (_balanceDiff != 0) {\\n unchecked {\\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\\n _balanceDiff;\\n }\\n }\\n }\\n\\n /// @notice Records newly distributed funds for a project.\\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\\n /// @param _projectId The ID of the project that is having funds distributed.\\n /// @param _amount The amount to use from the distribution limit, as a fixed point number.\\n /// @param _currency The currency of the `_amount`. This must match the project's current funding cycle's currency.\\n /// @return fundingCycle The funding cycle during which the distribution was made.\\n /// @return distributedAmount The amount of terminal tokens distributed, as a fixed point number with the same amount of decimals as its relative terminal.\\n function recordDistributionFor(\\n uint256 _projectId,\\n uint256 _amount,\\n uint256 _currency\\n )\\n external\\n override\\n nonReentrant\\n returns (JBFundingCycle memory fundingCycle, uint256 distributedAmount)\\n {\\n // Get a reference to the project's current funding cycle.\\n fundingCycle = fundingCycleStore.currentOf(_projectId);\\n\\n // The funding cycle must not be configured to have distributions paused.\\n if (fundingCycle.distributionsPaused()) revert FUNDING_CYCLE_DISTRIBUTION_PAUSED();\\n\\n // The new total amount that has been distributed during this funding cycle.\\n uint256 _newUsedDistributionLimitOf = usedDistributionLimitOf[\\n IJBSingleTokenPaymentTerminal(msg.sender)\\n ][_projectId][fundingCycle.number] + _amount;\\n\\n // Amount must be within what is still distributable.\\n (uint256 _distributionLimitOf, uint256 _distributionLimitCurrencyOf) = IJBController3_1(\\n directory.controllerOf(_projectId)\\n ).fundAccessConstraintsStore().distributionLimitOf(\\n _projectId,\\n fundingCycle.configuration,\\n IJBSingleTokenPaymentTerminal(msg.sender),\\n IJBSingleTokenPaymentTerminal(msg.sender).token()\\n );\\n\\n // Make sure the new used amount is within the distribution limit.\\n if (_newUsedDistributionLimitOf > _distributionLimitOf || _distributionLimitOf == 0)\\n revert DISTRIBUTION_AMOUNT_LIMIT_REACHED();\\n\\n // Make sure the currencies match.\\n if (_currency != _distributionLimitCurrencyOf) revert CURRENCY_MISMATCH();\\n\\n // Get a reference to the terminal's currency.\\n uint256 _balanceCurrency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\\n\\n // Convert the amount to the balance's currency.\\n distributedAmount = (_currency == _balanceCurrency)\\n ? _amount\\n : PRBMath.mulDiv(\\n _amount,\\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\\n prices.priceFor(_currency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\\n );\\n\\n // The amount being distributed must be available.\\n if (distributedAmount > balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId])\\n revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\\n\\n // Store the new amount.\\n usedDistributionLimitOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId][\\n fundingCycle.number\\n ] = _newUsedDistributionLimitOf;\\n\\n // Removed the distributed funds from the project's token balance.\\n unchecked {\\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\\n distributedAmount;\\n }\\n }\\n\\n /// @notice Records newly used allowance funds of a project.\\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\\n /// @param _projectId The ID of the project to use the allowance of.\\n /// @param _amount The amount to use from the allowance, as a fixed point number.\\n /// @param _currency The currency of the `_amount`. Must match the currency of the overflow allowance.\\n /// @return fundingCycle The funding cycle during which the overflow allowance is being used.\\n /// @return usedAmount The amount of terminal tokens used, as a fixed point number with the same amount of decimals as its relative terminal.\\n function recordUsedAllowanceOf(\\n uint256 _projectId,\\n uint256 _amount,\\n uint256 _currency\\n )\\n external\\n override\\n nonReentrant\\n returns (JBFundingCycle memory fundingCycle, uint256 usedAmount)\\n {\\n // Get a reference to the project's current funding cycle.\\n fundingCycle = fundingCycleStore.currentOf(_projectId);\\n\\n // Get a reference to the new used overflow allowance for this funding cycle configuration.\\n uint256 _newUsedOverflowAllowanceOf = usedOverflowAllowanceOf[\\n IJBSingleTokenPaymentTerminal(msg.sender)\\n ][_projectId][fundingCycle.configuration] + _amount;\\n\\n // There must be sufficient allowance available.\\n (uint256 _overflowAllowanceOf, uint256 _overflowAllowanceCurrency) = IJBController3_1(\\n directory.controllerOf(_projectId)\\n ).fundAccessConstraintsStore().overflowAllowanceOf(\\n _projectId,\\n fundingCycle.configuration,\\n IJBSingleTokenPaymentTerminal(msg.sender),\\n IJBSingleTokenPaymentTerminal(msg.sender).token()\\n );\\n\\n // Make sure the new used amount is within the allowance.\\n if (_newUsedOverflowAllowanceOf > _overflowAllowanceOf || _overflowAllowanceOf == 0)\\n revert INADEQUATE_CONTROLLER_ALLOWANCE();\\n\\n // Make sure the currencies match.\\n if (_currency != _overflowAllowanceCurrency) revert CURRENCY_MISMATCH();\\n\\n // Get a reference to the terminal's currency.\\n uint256 _balanceCurrency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\\n\\n // Convert the amount to this store's terminal's token.\\n usedAmount = (_currency == _balanceCurrency)\\n ? _amount\\n : PRBMath.mulDiv(\\n _amount,\\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\\n prices.priceFor(_currency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\\n );\\n\\n // The amount being distributed must be available in the overflow.\\n if (\\n usedAmount >\\n _overflowDuring(\\n IJBSingleTokenPaymentTerminal(msg.sender),\\n _projectId,\\n fundingCycle,\\n _balanceCurrency\\n )\\n ) revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\\n\\n // Store the incremented value.\\n usedOverflowAllowanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId][\\n fundingCycle.configuration\\n ] = _newUsedOverflowAllowanceOf;\\n\\n // Update the project's balance.\\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\\n usedAmount;\\n }\\n\\n /// @notice Records newly added funds for the project.\\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\\n /// @param _projectId The ID of the project to which the funds being added belong.\\n /// @param _amount The amount of terminal tokens added, as a fixed point number with the same amount of decimals as its relative terminal.\\n function recordAddedBalanceFor(uint256 _projectId, uint256 _amount) external override {\\n // Increment the balance.\\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] +\\n _amount;\\n }\\n\\n /// @notice Records the migration of funds from this store.\\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount returned is in terms of the msg.senders tokens.\\n /// @param _projectId The ID of the project being migrated.\\n /// @return balance The project's migrated balance, as a fixed point number with the same amount of decimals as its relative terminal.\\n function recordMigration(\\n uint256 _projectId\\n ) external override nonReentrant returns (uint256 balance) {\\n // Get a reference to the project's current funding cycle.\\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\\n\\n // Migration must be allowed.\\n if (!_fundingCycle.terminalMigrationAllowed()) revert PAYMENT_TERMINAL_MIGRATION_NOT_ALLOWED();\\n\\n // Return the current balance.\\n balance = balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId];\\n\\n // Set the balance to 0.\\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] = 0;\\n }\\n\\n //*********************************************************************//\\n // --------------------- private helper functions -------------------- //\\n //*********************************************************************//\\n\\n /// @notice The amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens when measured from the specified.\\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\\n /// @param _projectId The ID of the project to get the reclaimable overflow amount for.\\n /// @param _fundingCycle The funding cycle during which reclaimable overflow is being calculated.\\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\\n /// @param _totalSupply The total supply of tokens to make the calculation with, as a fixed point number with 18 decimals.\\n /// @param _overflow The amount of overflow to make the calculation with.\\n /// @return The amount of overflowed tokens that can be reclaimed.\\n function _reclaimableOverflowDuring(\\n uint256 _projectId,\\n JBFundingCycle memory _fundingCycle,\\n uint256 _tokenCount,\\n uint256 _totalSupply,\\n uint256 _overflow\\n ) private view returns (uint256) {\\n // If the amount being redeemed is the total supply, return the rest of the overflow.\\n if (_tokenCount == _totalSupply) return _overflow;\\n\\n // Use the ballot redemption rate if the queued cycle is pending approval according to the previous funding cycle's ballot.\\n uint256 _redemptionRate = fundingCycleStore.currentBallotStateOf(_projectId) ==\\n JBBallotState.Active\\n ? _fundingCycle.ballotRedemptionRate()\\n : _fundingCycle.redemptionRate();\\n\\n // If the redemption rate is 0, nothing is claimable.\\n if (_redemptionRate == 0) return 0;\\n\\n // Get a reference to the linear proportion.\\n uint256 _base = PRBMath.mulDiv(_overflow, _tokenCount, _totalSupply);\\n\\n // These conditions are all part of the same curve. Edge conditions are separated because fewer operation are necessary.\\n if (_redemptionRate == JBConstants.MAX_REDEMPTION_RATE) return _base;\\n\\n return\\n PRBMath.mulDiv(\\n _base,\\n _redemptionRate +\\n PRBMath.mulDiv(\\n _tokenCount,\\n JBConstants.MAX_REDEMPTION_RATE - _redemptionRate,\\n _totalSupply\\n ),\\n JBConstants.MAX_REDEMPTION_RATE\\n );\\n }\\n\\n /// @notice Gets the amount that is overflowing when measured from the specified funding cycle.\\n /// @dev This amount changes as the value of the balance changes in relation to the currency being used to measure the distribution limit.\\n /// @param _terminal The terminal for which the overflow is being calculated.\\n /// @param _projectId The ID of the project to get overflow for.\\n /// @param _fundingCycle The ID of the funding cycle to base the overflow on.\\n /// @param _balanceCurrency The currency that the stored balance is expected to be in terms of.\\n /// @return overflow The overflow of funds, as a fixed point number with 18 decimals.\\n function _overflowDuring(\\n IJBSingleTokenPaymentTerminal _terminal,\\n uint256 _projectId,\\n JBFundingCycle memory _fundingCycle,\\n uint256 _balanceCurrency\\n ) private view returns (uint256) {\\n // Get the current balance of the project.\\n uint256 _balanceOf = balanceOf[_terminal][_projectId];\\n\\n // If there's no balance, there's no overflow.\\n if (_balanceOf == 0) return 0;\\n\\n // Get a reference to the distribution limit during the funding cycle.\\n (uint256 _distributionLimit, uint256 _distributionLimitCurrency) = IJBController3_1(\\n directory.controllerOf(_projectId)\\n ).fundAccessConstraintsStore().distributionLimitOf(\\n _projectId,\\n _fundingCycle.configuration,\\n _terminal,\\n _terminal.token()\\n );\\n\\n // Get a reference to the amount still distributable during the funding cycle.\\n uint256 _distributionLimitRemaining = _distributionLimit -\\n usedDistributionLimitOf[_terminal][_projectId][_fundingCycle.number];\\n\\n // Convert the _distributionRemaining to be in terms of the provided currency.\\n if (_distributionLimitRemaining != 0 && _distributionLimitCurrency != _balanceCurrency)\\n _distributionLimitRemaining = PRBMath.mulDiv(\\n _distributionLimitRemaining,\\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\\n prices.priceFor(_distributionLimitCurrency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\\n );\\n\\n // Overflow is the balance of this project minus the amount that can still be distributed.\\n unchecked {\\n return\\n _balanceOf > _distributionLimitRemaining ? _balanceOf - _distributionLimitRemaining : 0;\\n }\\n }\\n\\n /// @notice Gets the amount that is currently overflowing across all of a project's terminals.\\n /// @dev This amount changes as the value of the balances changes in relation to the currency being used to measure the project's distribution limits.\\n /// @param _projectId The ID of the project to get the total overflow for.\\n /// @param _decimals The number of decimals that the fixed point overflow should include.\\n /// @param _currency The currency that the overflow should be in terms of.\\n /// @return overflow The total overflow of a project's funds.\\n function _currentTotalOverflowOf(\\n uint256 _projectId,\\n uint256 _decimals,\\n uint256 _currency\\n ) private view returns (uint256) {\\n // Get a reference to the project's terminals.\\n IJBPaymentTerminal[] memory _terminals = directory.terminalsOf(_projectId);\\n\\n // Keep a reference to the ETH overflow across all terminals, as a fixed point number with 18 decimals.\\n uint256 _ethOverflow;\\n\\n // Add the current ETH overflow for each terminal.\\n for (uint256 _i; _i < _terminals.length; ) {\\n _ethOverflow = _ethOverflow + _terminals[_i].currentEthOverflowOf(_projectId);\\n unchecked {\\n ++_i;\\n }\\n }\\n\\n // Convert the ETH overflow to the specified currency if needed, maintaining a fixed point number with 18 decimals.\\n uint256 _totalOverflow18Decimal = _currency == JBCurrencies.ETH\\n ? _ethOverflow\\n : PRBMath.mulDiv(_ethOverflow, 10 ** 18, prices.priceFor(JBCurrencies.ETH, _currency, 18));\\n\\n // Adjust the decimals of the fixed point number if needed to match the target decimals.\\n return\\n (_decimals == 18)\\n ? _totalOverflow18Decimal\\n : JBFixedPointNumber.adjustDecimals(_totalOverflow18Decimal, 18, _decimals);\\n }\\n}\\n\",\"keccak256\":\"0xb0cde3ddcf06733537717094bb426d8817812ade5f5f594da1b3cc54cbfe9263\",\"license\":\"MIT\"},\"contracts/enums/JBBallotState.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nenum JBBallotState {\\n Active,\\n Approved,\\n Failed\\n}\\n\",\"keccak256\":\"0x891fcac63470398b3a11239da7feba6b07d640809fcefd2404303b823d7378f8\",\"license\":\"MIT\"},\"contracts/interfaces/IJBController3_0_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IJBController3_0_1 {\\n function reservedTokenBalanceOf(uint256 projectId) external view returns (uint256);\\n\\n function totalOutstandingTokensOf(uint256 projectId) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0xf64926bf7ab5850ea9b7ec27d92a021f02344a3fadb0396af80966ad08b3dd2b\",\"license\":\"MIT\"},\"contracts/interfaces/IJBController3_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\\nimport {JBBallotState} from './../enums/JBBallotState.sol';\\nimport {JBFundAccessConstraints} from './../structs/JBFundAccessConstraints.sol';\\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\\nimport {JBFundingCycleData} from './../structs/JBFundingCycleData.sol';\\nimport {JBFundingCycleMetadata} from './../structs/JBFundingCycleMetadata.sol';\\nimport {JBGroupedSplits} from './../structs/JBGroupedSplits.sol';\\nimport {JBProjectMetadata} from './../structs/JBProjectMetadata.sol';\\nimport {JBSplit} from './../structs/JBSplit.sol';\\nimport {IJBController3_0_1} from './IJBController3_0_1.sol';\\nimport {IJBDirectory} from './IJBDirectory.sol';\\nimport {IJBFundAccessConstraintsStore} from './IJBFundAccessConstraintsStore.sol';\\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\\nimport {IJBMigratable} from './IJBMigratable.sol';\\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\\nimport {IJBProjects} from './IJBProjects.sol';\\nimport {IJBSplitsStore} from './IJBSplitsStore.sol';\\nimport {IJBTokenStore} from './IJBTokenStore.sol';\\n\\ninterface IJBController3_1 is IJBController3_0_1, IERC165 {\\n event LaunchProject(uint256 configuration, uint256 projectId, string memo, address caller);\\n\\n event LaunchFundingCycles(uint256 configuration, uint256 projectId, string memo, address caller);\\n\\n event ReconfigureFundingCycles(\\n uint256 configuration,\\n uint256 projectId,\\n string memo,\\n address caller\\n );\\n\\n event DistributeReservedTokens(\\n uint256 indexed fundingCycleConfiguration,\\n uint256 indexed fundingCycleNumber,\\n uint256 indexed projectId,\\n address beneficiary,\\n uint256 tokenCount,\\n uint256 beneficiaryTokenCount,\\n string memo,\\n address caller\\n );\\n\\n event DistributeToReservedTokenSplit(\\n uint256 indexed projectId,\\n uint256 indexed domain,\\n uint256 indexed group,\\n JBSplit split,\\n uint256 tokenCount,\\n address caller\\n );\\n\\n event MintTokens(\\n address indexed beneficiary,\\n uint256 indexed projectId,\\n uint256 tokenCount,\\n uint256 beneficiaryTokenCount,\\n string memo,\\n uint256 reservedRate,\\n address caller\\n );\\n\\n event BurnTokens(\\n address indexed holder,\\n uint256 indexed projectId,\\n uint256 tokenCount,\\n string memo,\\n address caller\\n );\\n\\n event Migrate(uint256 indexed projectId, IJBMigratable to, address caller);\\n\\n event PrepMigration(uint256 indexed projectId, address from, address caller);\\n\\n function projects() external view returns (IJBProjects);\\n\\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\\n\\n function tokenStore() external view returns (IJBTokenStore);\\n\\n function splitsStore() external view returns (IJBSplitsStore);\\n\\n function fundAccessConstraintsStore() external view returns (IJBFundAccessConstraintsStore);\\n\\n function directory() external view returns (IJBDirectory);\\n\\n function reservedTokenBalanceOf(uint256 projectId) external view returns (uint256);\\n\\n function totalOutstandingTokensOf(uint256 projectId) external view returns (uint256);\\n\\n function getFundingCycleOf(\\n uint256 projectId,\\n uint256 configuration\\n )\\n external\\n view\\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata);\\n\\n function latestConfiguredFundingCycleOf(\\n uint256 projectId\\n )\\n external\\n view\\n returns (JBFundingCycle memory, JBFundingCycleMetadata memory metadata, JBBallotState);\\n\\n function currentFundingCycleOf(\\n uint256 projectId\\n )\\n external\\n view\\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata);\\n\\n function queuedFundingCycleOf(\\n uint256 projectId\\n )\\n external\\n view\\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata);\\n\\n function launchProjectFor(\\n address owner,\\n JBProjectMetadata calldata projectMetadata,\\n JBFundingCycleData calldata data,\\n JBFundingCycleMetadata calldata metadata,\\n uint256 mustStartAtOrAfter,\\n JBGroupedSplits[] memory groupedSplits,\\n JBFundAccessConstraints[] memory fundAccessConstraints,\\n IJBPaymentTerminal[] memory terminals,\\n string calldata memo\\n ) external returns (uint256 projectId);\\n\\n function launchFundingCyclesFor(\\n uint256 projectId,\\n JBFundingCycleData calldata data,\\n JBFundingCycleMetadata calldata metadata,\\n uint256 mustStartAtOrAfter,\\n JBGroupedSplits[] memory groupedSplits,\\n JBFundAccessConstraints[] memory fundAccessConstraints,\\n IJBPaymentTerminal[] memory terminals,\\n string calldata memo\\n ) external returns (uint256 configuration);\\n\\n function reconfigureFundingCyclesOf(\\n uint256 projectId,\\n JBFundingCycleData calldata data,\\n JBFundingCycleMetadata calldata metadata,\\n uint256 mustStartAtOrAfter,\\n JBGroupedSplits[] memory groupedSplits,\\n JBFundAccessConstraints[] memory fundAccessConstraints,\\n string calldata memo\\n ) external returns (uint256);\\n\\n function mintTokensOf(\\n uint256 projectId,\\n uint256 tokenCount,\\n address beneficiary,\\n string calldata memo,\\n bool preferClaimedTokens,\\n bool useReservedRate\\n ) external returns (uint256 beneficiaryTokenCount);\\n\\n function burnTokensOf(\\n address holder,\\n uint256 projectId,\\n uint256 tokenCount,\\n string calldata memo,\\n bool preferClaimedTokens\\n ) external;\\n\\n function distributeReservedTokensOf(\\n uint256 projectId,\\n string memory memo\\n ) external returns (uint256);\\n\\n function migrate(uint256 projectId, IJBMigratable to) external;\\n}\\n\",\"keccak256\":\"0xe09f3d0d670a40e5d66d3fddc8a63f51b8ccb24175ffbb703ba95496deb85bdb\",\"license\":\"MIT\"},\"contracts/interfaces/IJBDirectory.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\\nimport {IJBProjects} from './IJBProjects.sol';\\n\\ninterface IJBDirectory {\\n event SetController(uint256 indexed projectId, address indexed controller, address caller);\\n\\n event AddTerminal(uint256 indexed projectId, IJBPaymentTerminal indexed terminal, address caller);\\n\\n event SetTerminals(uint256 indexed projectId, IJBPaymentTerminal[] terminals, address caller);\\n\\n event SetPrimaryTerminal(\\n uint256 indexed projectId,\\n address indexed token,\\n IJBPaymentTerminal indexed terminal,\\n address caller\\n );\\n\\n event SetIsAllowedToSetFirstController(address indexed addr, bool indexed flag, address caller);\\n\\n function projects() external view returns (IJBProjects);\\n\\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\\n\\n function controllerOf(uint256 projectId) external view returns (address);\\n\\n function isAllowedToSetFirstController(address account) external view returns (bool);\\n\\n function terminalsOf(uint256 projectId) external view returns (IJBPaymentTerminal[] memory);\\n\\n function isTerminalOf(\\n uint256 projectId,\\n IJBPaymentTerminal terminal\\n ) external view returns (bool);\\n\\n function primaryTerminalOf(\\n uint256 projectId,\\n address token\\n ) external view returns (IJBPaymentTerminal);\\n\\n function setControllerOf(uint256 projectId, address controller) external;\\n\\n function setTerminalsOf(uint256 projectId, IJBPaymentTerminal[] calldata terminals) external;\\n\\n function setPrimaryTerminalOf(\\n uint256 projectId,\\n address token,\\n IJBPaymentTerminal terminal\\n ) external;\\n\\n function setIsAllowedToSetFirstController(address account, bool flag) external;\\n}\\n\",\"keccak256\":\"0x490d5fe691ee7d9c9179fa19964de279882176513d92f3efc0aa98dc34799d1c\",\"license\":\"MIT\"},\"contracts/interfaces/IJBFundAccessConstraintsStore.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\\nimport {JBFundAccessConstraints} from './../structs/JBFundAccessConstraints.sol';\\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\\n\\ninterface IJBFundAccessConstraintsStore is IERC165 {\\n event SetFundAccessConstraints(\\n uint256 indexed fundingCycleConfiguration,\\n uint256 indexed projectId,\\n JBFundAccessConstraints constraints,\\n address caller\\n );\\n\\n function distributionLimitOf(\\n uint256 projectId,\\n uint256 configuration,\\n IJBPaymentTerminal terminal,\\n address token\\n ) external view returns (uint256 distributionLimit, uint256 distributionLimitCurrency);\\n\\n function overflowAllowanceOf(\\n uint256 projectId,\\n uint256 configuration,\\n IJBPaymentTerminal terminal,\\n address token\\n ) external view returns (uint256 overflowAllowance, uint256 overflowAllowanceCurrency);\\n\\n function setFor(\\n uint256 projectId,\\n uint256 configuration,\\n JBFundAccessConstraints[] memory fundAccessConstaints\\n ) external;\\n}\\n\",\"keccak256\":\"0x82e3daec501e6f4d27ad7b9ab67f449e3cd4ef83a75062cd8b6fbffc17ae634d\",\"license\":\"MIT\"},\"contracts/interfaces/IJBFundingCycleBallot.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\\nimport {JBBallotState} from './../enums/JBBallotState.sol';\\n\\ninterface IJBFundingCycleBallot is IERC165 {\\n function duration() external view returns (uint256);\\n\\n function stateOf(\\n uint256 projectId,\\n uint256 configuration,\\n uint256 start\\n ) external view returns (JBBallotState);\\n}\\n\",\"keccak256\":\"0x729b4a700618f890e434d31ef9252e1cce9d0473fe7f8f070872df5b348bed23\",\"license\":\"MIT\"},\"contracts/interfaces/IJBFundingCycleDataSource3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\\nimport {JBPayDelegateAllocation3_1_1} from './../structs/JBPayDelegateAllocation3_1_1.sol';\\nimport {JBPayParamsData} from './../structs/JBPayParamsData.sol';\\nimport {JBRedeemParamsData} from './../structs/JBRedeemParamsData.sol';\\nimport {JBRedemptionDelegateAllocation3_1_1} from './../structs/JBRedemptionDelegateAllocation3_1_1.sol';\\n\\n/// @title Datasource\\n/// @notice The datasource is called by JBPayoutRedemptionPaymentTerminals on pay and redemption, and provide an extra layer of logic to use a custom weight, a custom memo and/or a pay/redeem delegate\\ninterface IJBFundingCycleDataSource3_1_1 is IERC165 {\\n /// @notice The datasource implementation for JBPaymentTerminal.pay(..)\\n /// @param data the data passed to the data source in terminal.pay(..), as a JBPayParamsData struct:\\n /// @return weight the weight to use to override the funding cycle weight\\n /// @return memo the memo to override the pay(..) memo\\n /// @return delegateAllocations The amount to send to delegates instead of adding to the local balance.\\n function payParams(\\n JBPayParamsData calldata data\\n )\\n external\\n returns (\\n uint256 weight,\\n string memory memo,\\n JBPayDelegateAllocation3_1_1[] memory delegateAllocations\\n );\\n\\n /// @notice The datasource implementation for JBPaymentTerminal.redeemTokensOf(..)\\n /// @param data the data passed to the data source in terminal.redeemTokensOf(..), as a JBRedeemParamsData struct:\\n /// @return reclaimAmount The amount to claim, overriding the terminal logic.\\n /// @return memo The memo to override the redeemTokensOf(..) memo.\\n /// @return delegateAllocations The amount to send to delegates instead of adding to the beneficiary.\\n function redeemParams(\\n JBRedeemParamsData calldata data\\n )\\n external\\n returns (\\n uint256 reclaimAmount,\\n string memory memo,\\n JBRedemptionDelegateAllocation3_1_1[] memory delegateAllocations\\n );\\n}\\n\",\"keccak256\":\"0x7315c10ae1fc6c401704ac3dec2a4c3e60ab4ac3ae051bea581d7db2ded38f34\",\"license\":\"MIT\"},\"contracts/interfaces/IJBFundingCycleStore.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBBallotState} from './../enums/JBBallotState.sol';\\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\\nimport {JBFundingCycleData} from './../structs/JBFundingCycleData.sol';\\n\\ninterface IJBFundingCycleStore {\\n event Configure(\\n uint256 indexed configuration,\\n uint256 indexed projectId,\\n JBFundingCycleData data,\\n uint256 metadata,\\n uint256 mustStartAtOrAfter,\\n address caller\\n );\\n\\n event Init(uint256 indexed configuration, uint256 indexed projectId, uint256 indexed basedOn);\\n\\n function latestConfigurationOf(uint256 projectId) external view returns (uint256);\\n\\n function get(\\n uint256 projectId,\\n uint256 configuration\\n ) external view returns (JBFundingCycle memory);\\n\\n function latestConfiguredOf(\\n uint256 projectId\\n ) external view returns (JBFundingCycle memory fundingCycle, JBBallotState ballotState);\\n\\n function queuedOf(uint256 projectId) external view returns (JBFundingCycle memory fundingCycle);\\n\\n function currentOf(uint256 projectId) external view returns (JBFundingCycle memory fundingCycle);\\n\\n function currentBallotStateOf(uint256 projectId) external view returns (JBBallotState);\\n\\n function configureFor(\\n uint256 projectId,\\n JBFundingCycleData calldata data,\\n uint256 metadata,\\n uint256 mustStartAtOrAfter\\n ) external returns (JBFundingCycle memory fundingCycle);\\n}\\n\",\"keccak256\":\"0x524350f6c6fcb45eaf927f4e6d13cd2f5029c2b858233bb9a338fe411ce34dab\",\"license\":\"MIT\"},\"contracts/interfaces/IJBMigratable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IJBMigratable {\\n function prepForMigrationOf(uint256 projectId, address from) external;\\n}\\n\",\"keccak256\":\"0xdee578477bbb7a66e9a1735e45a7795e95cfd374d85f55b61b3302476844c418\",\"license\":\"MIT\"},\"contracts/interfaces/IJBPayDelegate3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\\nimport {JBDidPayData3_1_1} from './../structs/JBDidPayData3_1_1.sol';\\n\\n/// @title Pay delegate\\n/// @notice Delegate called after JBTerminal.pay(..) logic completion (if passed by the funding cycle datasource)\\ninterface IJBPayDelegate3_1_1 is IERC165 {\\n /// @notice This function is called by JBPaymentTerminal.pay(..), after the execution of its logic\\n /// @dev Critical business logic should be protected by an appropriate access control\\n /// @param data the data passed by the terminal, as a JBDidPayData3_1_1 struct:\\n function didPay(JBDidPayData3_1_1 calldata data) external payable;\\n}\\n\",\"keccak256\":\"0x9448d24cd9c559b44c468c6a76d850f6eaadf31446db903092a2f32503a67294\",\"license\":\"MIT\"},\"contracts/interfaces/IJBPaymentTerminal.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\\n\\ninterface IJBPaymentTerminal is IERC165 {\\n function acceptsToken(address token, uint256 projectId) external view returns (bool);\\n\\n function currencyForToken(address token) external view returns (uint256);\\n\\n function decimalsForToken(address token) external view returns (uint256);\\n\\n // Return value must be a fixed point number with 18 decimals.\\n function currentEthOverflowOf(uint256 projectId) external view returns (uint256);\\n\\n function pay(\\n uint256 projectId,\\n uint256 amount,\\n address token,\\n address beneficiary,\\n uint256 minReturnedTokens,\\n bool preferClaimedTokens,\\n string calldata memo,\\n bytes calldata metadata\\n ) external payable returns (uint256 beneficiaryTokenCount);\\n\\n function addToBalanceOf(\\n uint256 projectId,\\n uint256 amount,\\n address token,\\n string calldata memo,\\n bytes calldata metadata\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x273bc1fa373fac08e5635fce7d38fd92e9fabba353568b3f7a5be54c01fe4d27\",\"license\":\"MIT\"},\"contracts/interfaces/IJBPriceFeed.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IJBPriceFeed {\\n function currentPrice(uint256 targetDecimals) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0x9328b2b52bc112641f3a6167c8cf242831a52c85016ce1310626bdc3489bded7\",\"license\":\"MIT\"},\"contracts/interfaces/IJBPrices.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBPriceFeed} from './IJBPriceFeed.sol';\\n\\ninterface IJBPrices {\\n event AddFeed(uint256 indexed currency, uint256 indexed base, IJBPriceFeed feed);\\n\\n function feedFor(uint256 currency, uint256 base) external view returns (IJBPriceFeed);\\n\\n function priceFor(\\n uint256 currency,\\n uint256 base,\\n uint256 decimals\\n ) external view returns (uint256);\\n\\n function addFeedFor(uint256 currency, uint256 base, IJBPriceFeed priceFeed) external;\\n}\\n\",\"keccak256\":\"0xc1623499fa541b15891e27a59288e03360ce78c7933d28bf575b48b68ce4981c\",\"license\":\"MIT\"},\"contracts/interfaces/IJBProjects.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC721} from '@openzeppelin/contracts/token/ERC721/IERC721.sol';\\nimport {JBProjectMetadata} from './../structs/JBProjectMetadata.sol';\\nimport {IJBTokenUriResolver} from './IJBTokenUriResolver.sol';\\n\\ninterface IJBProjects is IERC721 {\\n event Create(\\n uint256 indexed projectId,\\n address indexed owner,\\n JBProjectMetadata metadata,\\n address caller\\n );\\n\\n event SetMetadata(uint256 indexed projectId, JBProjectMetadata metadata, address caller);\\n\\n event SetTokenUriResolver(IJBTokenUriResolver indexed resolver, address caller);\\n\\n function count() external view returns (uint256);\\n\\n function metadataContentOf(\\n uint256 projectId,\\n uint256 domain\\n ) external view returns (string memory);\\n\\n function tokenUriResolver() external view returns (IJBTokenUriResolver);\\n\\n function createFor(\\n address owner,\\n JBProjectMetadata calldata metadata\\n ) external returns (uint256 projectId);\\n\\n function setMetadataOf(uint256 projectId, JBProjectMetadata calldata metadata) external;\\n\\n function setTokenUriResolver(IJBTokenUriResolver newResolver) external;\\n}\\n\",\"keccak256\":\"0x00235f20975e6a9465ac921076c85125a3834e29893f93f93e287a89f9e6b915\",\"license\":\"MIT\"},\"contracts/interfaces/IJBRedemptionDelegate3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\\nimport {JBDidRedeemData3_1_1} from './../structs/JBDidRedeemData3_1_1.sol';\\n\\n/// @title Redemption delegate\\n/// @notice Delegate called after JBTerminal.redeemTokensOf(..) logic completion (if passed by the funding cycle datasource)\\ninterface IJBRedemptionDelegate3_1_1 is IERC165 {\\n /// @notice This function is called by JBPaymentTerminal.redeemTokensOf(..), after the execution of its logic\\n /// @dev Critical business logic should be protected by an appropriate access control\\n /// @param data the data passed by the terminal, as a JBDidRedeemData struct:\\n function didRedeem(JBDidRedeemData3_1_1 calldata data) external payable;\\n}\\n\",\"keccak256\":\"0x6034773b78e98902625563bd176a97267e729cb5205d25b06e8a2262b131c0d8\",\"license\":\"MIT\"},\"contracts/interfaces/IJBSingleTokenPaymentTerminal.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\\n\\ninterface IJBSingleTokenPaymentTerminal is IJBPaymentTerminal {\\n function token() external view returns (address);\\n\\n function currency() external view returns (uint256);\\n\\n function decimals() external view returns (uint256);\\n}\\n\",\"keccak256\":\"0x8e00670c66dea368dc523615425c2a79fcee10ec3c3355bf94feb82638172b3f\",\"license\":\"MIT\"},\"contracts/interfaces/IJBSingleTokenPaymentTerminalStore3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\\nimport {JBPayDelegateAllocation3_1_1} from './../structs/JBPayDelegateAllocation3_1_1.sol';\\nimport {JBRedemptionDelegateAllocation3_1_1} from './../structs/JBRedemptionDelegateAllocation3_1_1.sol';\\nimport {JBTokenAmount} from './../structs/JBTokenAmount.sol';\\nimport {IJBDirectory} from './IJBDirectory.sol';\\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\\nimport {IJBPrices} from './IJBPrices.sol';\\nimport {IJBSingleTokenPaymentTerminal} from './IJBSingleTokenPaymentTerminal.sol';\\n\\ninterface IJBSingleTokenPaymentTerminalStore3_1_1 {\\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\\n\\n function directory() external view returns (IJBDirectory);\\n\\n function prices() external view returns (IJBPrices);\\n\\n function balanceOf(\\n IJBSingleTokenPaymentTerminal terminal,\\n uint256 projectId\\n ) external view returns (uint256);\\n\\n function usedDistributionLimitOf(\\n IJBSingleTokenPaymentTerminal terminal,\\n uint256 projectId,\\n uint256 fundingCycleNumber\\n ) external view returns (uint256);\\n\\n function usedOverflowAllowanceOf(\\n IJBSingleTokenPaymentTerminal terminal,\\n uint256 projectId,\\n uint256 fundingCycleConfiguration\\n ) external view returns (uint256);\\n\\n function currentOverflowOf(\\n IJBSingleTokenPaymentTerminal terminal,\\n uint256 projectId\\n ) external view returns (uint256);\\n\\n function currentTotalOverflowOf(\\n uint256 projectId,\\n uint256 decimals,\\n uint256 currency\\n ) external view returns (uint256);\\n\\n function currentReclaimableOverflowOf(\\n IJBSingleTokenPaymentTerminal terminal,\\n uint256 projectId,\\n uint256 tokenCount,\\n bool useTotalOverflow\\n ) external view returns (uint256);\\n\\n function currentReclaimableOverflowOf(\\n uint256 projectId,\\n uint256 tokenCount,\\n uint256 totalSupply,\\n uint256 overflow\\n ) external view returns (uint256);\\n\\n function recordPaymentFrom(\\n address payer,\\n JBTokenAmount memory amount,\\n uint256 projectId,\\n uint256 baseWeightCurrency,\\n address beneficiary,\\n string calldata inputMemo,\\n bytes calldata metadata\\n )\\n external\\n returns (\\n JBFundingCycle memory fundingCycle,\\n uint256 tokenCount,\\n JBPayDelegateAllocation3_1_1[] memory delegateAllocations,\\n string memory outputMemo\\n );\\n\\n function recordRedemptionFor(\\n address holder,\\n uint256 projectId,\\n uint256 tokenCount,\\n string calldata inputMemo,\\n bytes calldata metadata\\n )\\n external\\n returns (\\n JBFundingCycle memory fundingCycle,\\n uint256 reclaimAmount,\\n JBRedemptionDelegateAllocation3_1_1[] memory delegateAllocations,\\n string memory outputMemo\\n );\\n\\n function recordDistributionFor(\\n uint256 projectId,\\n uint256 amount,\\n uint256 currency\\n ) external returns (JBFundingCycle memory fundingCycle, uint256 distributedAmount);\\n\\n function recordUsedAllowanceOf(\\n uint256 projectId,\\n uint256 amount,\\n uint256 currency\\n ) external returns (JBFundingCycle memory fundingCycle, uint256 withdrawnAmount);\\n\\n function recordAddedBalanceFor(uint256 projectId, uint256 amount) external;\\n\\n function recordMigration(uint256 projectId) external returns (uint256 balance);\\n}\\n\",\"keccak256\":\"0xf009c9fb787cda2a18805b9a9e2105c7f1309ade1eac3af229816cfd27ba1d64\",\"license\":\"MIT\"},\"contracts/interfaces/IJBSplitAllocator.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\\nimport {JBSplitAllocationData} from '../structs/JBSplitAllocationData.sol';\\n\\n/// @title Split allocator\\n/// @notice Provide a way to process a single split with extra logic\\n/// @dev The contract address should be set as an allocator in the adequate split\\ninterface IJBSplitAllocator is IERC165 {\\n /// @notice This function is called by JBPaymentTerminal.distributePayoutOf(..), during the processing of the split including it\\n /// @dev Critical business logic should be protected by an appropriate access control. The token and/or eth are optimistically transfered to the allocator for its logic.\\n /// @param data the data passed by the terminal, as a JBSplitAllocationData struct:\\n function allocate(JBSplitAllocationData calldata data) external payable;\\n}\\n\",\"keccak256\":\"0x1643b444409d91858eb86f67abf3d757d2deb3ccd7265eb8e68d6ffdac083de6\",\"license\":\"MIT\"},\"contracts/interfaces/IJBSplitsStore.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBGroupedSplits} from './../structs/JBGroupedSplits.sol';\\nimport {JBSplit} from './../structs/JBSplit.sol';\\nimport {IJBDirectory} from './IJBDirectory.sol';\\nimport {IJBProjects} from './IJBProjects.sol';\\n\\ninterface IJBSplitsStore {\\n event SetSplit(\\n uint256 indexed projectId,\\n uint256 indexed domain,\\n uint256 indexed group,\\n JBSplit split,\\n address caller\\n );\\n\\n function projects() external view returns (IJBProjects);\\n\\n function directory() external view returns (IJBDirectory);\\n\\n function splitsOf(\\n uint256 projectId,\\n uint256 domain,\\n uint256 group\\n ) external view returns (JBSplit[] memory);\\n\\n function set(uint256 projectId, uint256 domain, JBGroupedSplits[] memory groupedSplits) external;\\n}\\n\",\"keccak256\":\"0x3ce0eb12f10282481a3bf86e62b368bcff254081088cfabb20353d60cfadbc7a\",\"license\":\"MIT\"},\"contracts/interfaces/IJBToken.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IJBToken {\\n function projectId() external view returns (uint256);\\n\\n function decimals() external view returns (uint8);\\n\\n function totalSupply(uint256 projectId) external view returns (uint256);\\n\\n function balanceOf(address account, uint256 projectId) external view returns (uint256);\\n\\n function mint(uint256 projectId, address account, uint256 amount) external;\\n\\n function burn(uint256 projectId, address account, uint256 amount) external;\\n\\n function approve(uint256, address spender, uint256 amount) external;\\n\\n function transfer(uint256 projectId, address to, uint256 amount) external;\\n\\n function transferFrom(uint256 projectId, address from, address to, uint256 amount) external;\\n}\\n\",\"keccak256\":\"0xeefe58d140e4e13f255d5c7c5cdf5ba66dd00835f04015c446ff224f8ad14c34\",\"license\":\"MIT\"},\"contracts/interfaces/IJBTokenStore.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\\nimport {IJBProjects} from './IJBProjects.sol';\\nimport {IJBToken} from './IJBToken.sol';\\n\\ninterface IJBTokenStore {\\n event Issue(\\n uint256 indexed projectId,\\n IJBToken indexed token,\\n string name,\\n string symbol,\\n address caller\\n );\\n\\n event Mint(\\n address indexed holder,\\n uint256 indexed projectId,\\n uint256 amount,\\n bool tokensWereClaimed,\\n bool preferClaimedTokens,\\n address caller\\n );\\n\\n event Burn(\\n address indexed holder,\\n uint256 indexed projectId,\\n uint256 amount,\\n uint256 initialUnclaimedBalance,\\n uint256 initialClaimedBalance,\\n bool preferClaimedTokens,\\n address caller\\n );\\n\\n event Claim(\\n address indexed holder,\\n uint256 indexed projectId,\\n uint256 initialUnclaimedBalance,\\n uint256 amount,\\n address caller\\n );\\n\\n event Set(uint256 indexed projectId, IJBToken indexed newToken, address caller);\\n\\n event Transfer(\\n address indexed holder,\\n uint256 indexed projectId,\\n address indexed recipient,\\n uint256 amount,\\n address caller\\n );\\n\\n function tokenOf(uint256 projectId) external view returns (IJBToken);\\n\\n function projects() external view returns (IJBProjects);\\n\\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\\n\\n function unclaimedBalanceOf(address holder, uint256 projectId) external view returns (uint256);\\n\\n function unclaimedTotalSupplyOf(uint256 projectId) external view returns (uint256);\\n\\n function totalSupplyOf(uint256 projectId) external view returns (uint256);\\n\\n function balanceOf(address holder, uint256 projectId) external view returns (uint256 result);\\n\\n function issueFor(\\n uint256 projectId,\\n string calldata name,\\n string calldata symbol\\n ) external returns (IJBToken token);\\n\\n function setFor(uint256 projectId, IJBToken token) external;\\n\\n function burnFrom(\\n address holder,\\n uint256 projectId,\\n uint256 amount,\\n bool preferClaimedTokens\\n ) external;\\n\\n function mintFor(\\n address holder,\\n uint256 projectId,\\n uint256 amount,\\n bool preferClaimedTokens\\n ) external;\\n\\n function claimFor(address holder, uint256 projectId, uint256 amount) external;\\n\\n function transferFrom(\\n address holder,\\n uint256 projectId,\\n address recipient,\\n uint256 amount\\n ) external;\\n}\\n\",\"keccak256\":\"0x4db7bb4fe824dc9bfbc997ea3e07f42be8900bcad4e0b991e726c23c2de84ba4\",\"license\":\"MIT\"},\"contracts/interfaces/IJBTokenUriResolver.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IJBTokenUriResolver {\\n function getUri(uint256 projectId) external view returns (string memory tokenUri);\\n}\\n\",\"keccak256\":\"0xc7c9537184a1a36bc30874e5ac29b0fbccf45a99d40806837cfe30d6d9a1c84a\",\"license\":\"MIT\"},\"contracts/libraries/JBConstants.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/// @notice Global constants used across Juicebox contracts.\\nlibrary JBConstants {\\n uint256 public constant MAX_RESERVED_RATE = 10_000;\\n uint256 public constant MAX_REDEMPTION_RATE = 10_000;\\n uint256 public constant MAX_DISCOUNT_RATE = 1_000_000_000;\\n uint256 public constant SPLITS_TOTAL_PERCENT = 1_000_000_000;\\n uint256 public constant MAX_FEE = 1_000_000_000;\\n uint256 public constant MAX_FEE_DISCOUNT = 1_000_000_000;\\n}\\n\",\"keccak256\":\"0x7f2741e86062c5019f51d7e1a7b192ec1880d7e15a9a1589362ae7424de3003b\",\"license\":\"MIT\"},\"contracts/libraries/JBCurrencies.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nlibrary JBCurrencies {\\n uint256 public constant ETH = 1;\\n uint256 public constant USD = 2;\\n}\\n\",\"keccak256\":\"0x7e417ff25c173608ee4fe6d9fc3dcd5e1458c78c889af12bac47b1189a436076\",\"license\":\"MIT\"},\"contracts/libraries/JBFixedPointNumber.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.16;\\n\\nlibrary JBFixedPointNumber {\\n function adjustDecimals(\\n uint256 _value,\\n uint256 _decimals,\\n uint256 _targetDecimals\\n ) internal pure returns (uint256) {\\n // If decimals need adjusting, multiply or divide the price by the decimal adjuster to get the normalized result.\\n if (_targetDecimals == _decimals) return _value;\\n else if (_targetDecimals > _decimals) return _value * 10**(_targetDecimals - _decimals);\\n else return _value / 10**(_decimals - _targetDecimals);\\n }\\n}\\n\",\"keccak256\":\"0x18efac48269f3a3bd7e9a1c770776f950e0afa86769e6f8b128002c3b8c6742c\",\"license\":\"MIT\"},\"contracts/libraries/JBFundingCycleMetadataResolver.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.16;\\n\\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\\nimport {JBFundingCycleMetadata} from './../structs/JBFundingCycleMetadata.sol';\\nimport {JBGlobalFundingCycleMetadata} from './../structs/JBGlobalFundingCycleMetadata.sol';\\nimport {JBConstants} from './JBConstants.sol';\\nimport {JBGlobalFundingCycleMetadataResolver} from './JBGlobalFundingCycleMetadataResolver.sol';\\n\\nlibrary JBFundingCycleMetadataResolver {\\n function global(JBFundingCycle memory _fundingCycle)\\n internal\\n pure\\n returns (JBGlobalFundingCycleMetadata memory)\\n {\\n return JBGlobalFundingCycleMetadataResolver.expandMetadata(uint8(_fundingCycle.metadata >> 8));\\n }\\n\\n function reservedRate(JBFundingCycle memory _fundingCycle) internal pure returns (uint256) {\\n return uint256(uint16(_fundingCycle.metadata >> 24));\\n }\\n\\n function redemptionRate(JBFundingCycle memory _fundingCycle) internal pure returns (uint256) {\\n // Redemption rate is a number 0-10000. It's inverse was stored so the most common case of 100% results in no storage needs.\\n return JBConstants.MAX_REDEMPTION_RATE - uint256(uint16(_fundingCycle.metadata >> 40));\\n }\\n\\n function ballotRedemptionRate(JBFundingCycle memory _fundingCycle)\\n internal\\n pure\\n returns (uint256)\\n {\\n // Redemption rate is a number 0-10000. It's inverse was stored so the most common case of 100% results in no storage needs.\\n return JBConstants.MAX_REDEMPTION_RATE - uint256(uint16(_fundingCycle.metadata >> 56));\\n }\\n\\n function payPaused(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\\n return ((_fundingCycle.metadata >> 72) & 1) == 1;\\n }\\n\\n function distributionsPaused(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\\n return ((_fundingCycle.metadata >> 73) & 1) == 1;\\n }\\n\\n function redeemPaused(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\\n return ((_fundingCycle.metadata >> 74) & 1) == 1;\\n }\\n\\n function burnPaused(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\\n return ((_fundingCycle.metadata >> 75) & 1) == 1;\\n }\\n\\n function mintingAllowed(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\\n return ((_fundingCycle.metadata >> 76) & 1) == 1;\\n }\\n\\n function terminalMigrationAllowed(JBFundingCycle memory _fundingCycle)\\n internal\\n pure\\n returns (bool)\\n {\\n return ((_fundingCycle.metadata >> 77) & 1) == 1;\\n }\\n\\n function controllerMigrationAllowed(JBFundingCycle memory _fundingCycle)\\n internal\\n pure\\n returns (bool)\\n {\\n return ((_fundingCycle.metadata >> 78) & 1) == 1;\\n }\\n\\n function shouldHoldFees(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\\n return ((_fundingCycle.metadata >> 79) & 1) == 1;\\n }\\n\\n function preferClaimedTokenOverride(JBFundingCycle memory _fundingCycle)\\n internal\\n pure\\n returns (bool)\\n {\\n return ((_fundingCycle.metadata >> 80) & 1) == 1;\\n }\\n\\n function useTotalOverflowForRedemptions(JBFundingCycle memory _fundingCycle)\\n internal\\n pure\\n returns (bool)\\n {\\n return ((_fundingCycle.metadata >> 81) & 1) == 1;\\n }\\n\\n function useDataSourceForPay(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\\n return (_fundingCycle.metadata >> 82) & 1 == 1;\\n }\\n\\n function useDataSourceForRedeem(JBFundingCycle memory _fundingCycle)\\n internal\\n pure\\n returns (bool)\\n {\\n return (_fundingCycle.metadata >> 83) & 1 == 1;\\n }\\n\\n function dataSource(JBFundingCycle memory _fundingCycle) internal pure returns (address) {\\n return address(uint160(_fundingCycle.metadata >> 84));\\n }\\n\\n function metadata(JBFundingCycle memory _fundingCycle) internal pure returns (uint256) {\\n return uint256(uint8(_fundingCycle.metadata >> 244));\\n }\\n\\n /// @notice Pack the funding cycle metadata.\\n /// @param _metadata The metadata to validate and pack.\\n /// @return packed The packed uint256 of all metadata params. The first 8 bits specify the version. \\n function packFundingCycleMetadata(JBFundingCycleMetadata memory _metadata)\\n internal\\n pure\\n returns (uint256 packed)\\n {\\n // version 1 in the bits 0-7 (8 bits).\\n packed = 1;\\n // global metadta in bits 8-23 (16 bits).\\n packed |=\\n JBGlobalFundingCycleMetadataResolver.packFundingCycleGlobalMetadata(_metadata.global) <<\\n 8;\\n // reserved rate in bits 24-39 (16 bits).\\n packed |= _metadata.reservedRate << 24;\\n // redemption rate in bits 40-55 (16 bits).\\n // redemption rate is a number 0-10000. Store the reverse so the most common case of 100% results in no storage needs.\\n packed |= (JBConstants.MAX_REDEMPTION_RATE - _metadata.redemptionRate) << 40;\\n // ballot redemption rate rate in bits 56-71 (16 bits).\\n // ballot redemption rate is a number 0-10000. Store the reverse so the most common case of 100% results in no storage needs.\\n packed |= (JBConstants.MAX_REDEMPTION_RATE - _metadata.ballotRedemptionRate) << 56;\\n // pause pay in bit 72.\\n if (_metadata.pausePay) packed |= 1 << 72;\\n // pause tap in bit 73.\\n if (_metadata.pauseDistributions) packed |= 1 << 73;\\n // pause redeem in bit 74.\\n if (_metadata.pauseRedeem) packed |= 1 << 74;\\n // pause burn in bit 75.\\n if (_metadata.pauseBurn) packed |= 1 << 75;\\n // allow minting in bit 76.\\n if (_metadata.allowMinting) packed |= 1 << 76;\\n // allow terminal migration in bit 77.\\n if (_metadata.allowTerminalMigration) packed |= 1 << 77;\\n // allow controller migration in bit 78.\\n if (_metadata.allowControllerMigration) packed |= 1 << 78;\\n // hold fees in bit 79.\\n if (_metadata.holdFees) packed |= 1 << 79;\\n // prefer claimed token override in bit 80.\\n if (_metadata.preferClaimedTokenOverride) packed |= 1 << 80;\\n // useTotalOverflowForRedemptions in bit 81.\\n if (_metadata.useTotalOverflowForRedemptions) packed |= 1 << 81;\\n // use pay data source in bit 82.\\n if (_metadata.useDataSourceForPay) packed |= 1 << 82;\\n // use redeem data source in bit 83.\\n if (_metadata.useDataSourceForRedeem) packed |= 1 << 83;\\n // data source address in bits 84-243.\\n packed |= uint256(uint160(address(_metadata.dataSource))) << 84;\\n // metadata in bits 244-252 (8 bits).\\n packed |= _metadata.metadata << 244;\\n }\\n\\n /// @notice Expand the funding cycle metadata.\\n /// @param _fundingCycle The funding cycle having its metadata expanded.\\n /// @return metadata The metadata object. \\n function expandMetadata(JBFundingCycle memory _fundingCycle)\\n internal\\n pure\\n returns (JBFundingCycleMetadata memory)\\n {\\n return\\n JBFundingCycleMetadata(\\n global(_fundingCycle),\\n reservedRate(_fundingCycle),\\n redemptionRate(_fundingCycle),\\n ballotRedemptionRate(_fundingCycle),\\n payPaused(_fundingCycle),\\n distributionsPaused(_fundingCycle),\\n redeemPaused(_fundingCycle),\\n burnPaused(_fundingCycle),\\n mintingAllowed(_fundingCycle),\\n terminalMigrationAllowed(_fundingCycle),\\n controllerMigrationAllowed(_fundingCycle),\\n shouldHoldFees(_fundingCycle),\\n preferClaimedTokenOverride(_fundingCycle),\\n useTotalOverflowForRedemptions(_fundingCycle),\\n useDataSourceForPay(_fundingCycle),\\n useDataSourceForRedeem(_fundingCycle),\\n dataSource(_fundingCycle),\\n metadata(_fundingCycle)\\n );\\n }\\n}\\n\",\"keccak256\":\"0xedb0b93d5578ca5a21ab55f65274e441513bce982b04ffc76f26e627abfbbe0c\",\"license\":\"MIT\"},\"contracts/libraries/JBGlobalFundingCycleMetadataResolver.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.16;\\n\\nimport {JBFundingCycleMetadata} from './../structs/JBFundingCycleMetadata.sol';\\nimport {JBGlobalFundingCycleMetadata} from './../structs/JBGlobalFundingCycleMetadata.sol';\\n\\nlibrary JBGlobalFundingCycleMetadataResolver {\\n function setTerminalsAllowed(uint8 _data) internal pure returns (bool) {\\n return (_data & 1) == 1;\\n }\\n\\n function setControllerAllowed(uint8 _data) internal pure returns (bool) {\\n return ((_data >> 1) & 1) == 1;\\n }\\n\\n function transfersPaused(uint8 _data) internal pure returns (bool) {\\n return ((_data >> 2) & 1) == 1;\\n }\\n\\n /// @notice Pack the global funding cycle metadata.\\n /// @param _metadata The metadata to validate and pack.\\n /// @return packed The packed uint256 of all global metadata params. The first 8 bits specify the version.\\n function packFundingCycleGlobalMetadata(\\n JBGlobalFundingCycleMetadata memory _metadata\\n ) internal pure returns (uint256 packed) {\\n // allow set terminals in bit 0.\\n if (_metadata.allowSetTerminals) packed |= 1;\\n // allow set controller in bit 1.\\n if (_metadata.allowSetController) packed |= 1 << 1;\\n // pause transfers in bit 2.\\n if (_metadata.pauseTransfers) packed |= 1 << 2;\\n }\\n\\n /// @notice Expand the global funding cycle metadata.\\n /// @param _packedMetadata The packed metadata to expand.\\n /// @return metadata The global metadata object.\\n function expandMetadata(\\n uint8 _packedMetadata\\n ) internal pure returns (JBGlobalFundingCycleMetadata memory metadata) {\\n return\\n JBGlobalFundingCycleMetadata(\\n setTerminalsAllowed(_packedMetadata),\\n setControllerAllowed(_packedMetadata),\\n transfersPaused(_packedMetadata)\\n );\\n }\\n}\\n\",\"keccak256\":\"0x8a016001787db05e3bbd442db7eaa3f49f1d3a3210d2b5c6e52254a241f3b161\",\"license\":\"MIT\"},\"contracts/structs/JBDidPayData3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBTokenAmount} from './JBTokenAmount.sol';\\n\\n/// @custom:member payer The address from which the payment originated.\\n/// @custom:member projectId The ID of the project for which the payment was made.\\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the payment is being made.\\n/// @custom:member amount The amount of the payment. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\\n/// @custom:member forwardedAmount The amount of the payment that is being sent to the delegate. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\\n/// @custom:member projectTokenCount The number of project tokens minted for the beneficiary.\\n/// @custom:member beneficiary The address to which the tokens were minted.\\n/// @custom:member preferClaimedTokens A flag indicating whether the request prefered to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract.\\n/// @custom:member memo The memo that is being emitted alongside the payment.\\n/// @custom:member dataSourceMetadata Extra data to send to the delegate sent by the data source.\\n/// @custom:member payerMetadata Extra data to send to the delegate sent by the payer.\\nstruct JBDidPayData3_1_1 {\\n address payer;\\n uint256 projectId;\\n uint256 currentFundingCycleConfiguration;\\n JBTokenAmount amount;\\n JBTokenAmount forwardedAmount;\\n uint256 projectTokenCount;\\n address beneficiary;\\n bool preferClaimedTokens;\\n string memo;\\n bytes dataSourceMetadata;\\n bytes payerMetadata;\\n}\\n\",\"keccak256\":\"0x2e659555149ff14c045b749b1d1a3156b8296ab08375ac2abec92afc43bf3acf\",\"license\":\"MIT\"},\"contracts/structs/JBDidRedeemData3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBTokenAmount} from './JBTokenAmount.sol';\\n\\n/// @custom:member holder The holder of the tokens being redeemed.\\n/// @custom:member projectId The ID of the project with which the redeemed tokens are associated.\\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the redemption is being made.\\n/// @custom:member projectTokenCount The number of project tokens being redeemed.\\n/// @custom:member reclaimedAmount The amount reclaimed from the treasury. Includes the token being reclaimed, the value, the number of decimals included, and the currency of the amount.\\n/// @custom:member forwardedAmount The amount of the payment that is being sent to the delegate. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\\n/// @custom:member beneficiary The address to which the reclaimed amount will be sent.\\n/// @custom:member memo The memo that is being emitted alongside the redemption.\\n/// @custom:member dataSourceMetadata Extra data to send to the delegate sent by the data source.\\n/// @custom:member redeemerMetadata Extra data to send to the delegate sent by the redeemer.\\nstruct JBDidRedeemData3_1_1 {\\n address holder;\\n uint256 projectId;\\n uint256 currentFundingCycleConfiguration;\\n uint256 projectTokenCount;\\n JBTokenAmount reclaimedAmount;\\n JBTokenAmount forwardedAmount;\\n address payable beneficiary;\\n string memo;\\n bytes dataSourceMetadata;\\n bytes redeemerMetadata;\\n}\\n\",\"keccak256\":\"0x23848d41aa179d16e9b7033befd3a855d43f6a009e24030c2ba1bb5b06cb3924\",\"license\":\"MIT\"},\"contracts/structs/JBFundAccessConstraints.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\\n\\n/// @custom:member terminal The terminal within which the distribution limit and the overflow allowance applies.\\n/// @custom:member token The token for which the fund access constraints apply.\\n/// @custom:member distributionLimit The amount of the distribution limit, as a fixed point number with the same number of decimals as the terminal within which the limit applies.\\n/// @custom:member distributionLimitCurrency The currency of the distribution limit.\\n/// @custom:member overflowAllowance The amount of the allowance, as a fixed point number with the same number of decimals as the terminal within which the allowance applies.\\n/// @custom:member overflowAllowanceCurrency The currency of the overflow allowance.\\nstruct JBFundAccessConstraints {\\n IJBPaymentTerminal terminal;\\n address token;\\n uint256 distributionLimit;\\n uint256 distributionLimitCurrency;\\n uint256 overflowAllowance;\\n uint256 overflowAllowanceCurrency;\\n}\\n\",\"keccak256\":\"0xbef975eb73e58c00eaaa7abbd449db545056b049907bb2034aefcdde10bcf11f\",\"license\":\"MIT\"},\"contracts/structs/JBFundingCycle.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBFundingCycleBallot} from './../interfaces/IJBFundingCycleBallot.sol';\\n\\n/// @custom:member number The funding cycle number for the cycle's project. Each funding cycle has a number that is an increment of the cycle that directly preceded it. Each project's first funding cycle has a number of 1.\\n/// @custom:member configuration The timestamp when the parameters for this funding cycle were configured. This value will stay the same for subsequent funding cycles that roll over from an originally configured cycle.\\n/// @custom:member basedOn The `configuration` of the funding cycle that was active when this cycle was created.\\n/// @custom:member start The timestamp marking the moment from which the funding cycle is considered active. It is a unix timestamp measured in seconds.\\n/// @custom:member duration The number of seconds the funding cycle lasts for, after which a new funding cycle will start. A duration of 0 means that the funding cycle will stay active until the project owner explicitly issues a reconfiguration, at which point a new funding cycle will immediately start with the updated properties. If the duration is greater than 0, a project owner cannot make changes to a funding cycle's parameters while it is active \\u2013 any proposed changes will apply to the subsequent cycle. If no changes are proposed, a funding cycle rolls over to another one with the same properties but new `start` timestamp and a discounted `weight`.\\n/// @custom:member weight A fixed point number with 18 decimals that contracts can use to base arbitrary calculations on. For example, payment terminals can use this to determine how many tokens should be minted when a payment is received.\\n/// @custom:member discountRate A percent by how much the `weight` of the subsequent funding cycle should be reduced, if the project owner hasn't configured the subsequent funding cycle with an explicit `weight`. If it's 0, each funding cycle will have equal weight. If the number is 90%, the next funding cycle will have a 10% smaller weight. This weight is out of `JBConstants.MAX_DISCOUNT_RATE`.\\n/// @custom:member ballot An address of a contract that says whether a proposed reconfiguration should be accepted or rejected. It can be used to create rules around how a project owner can change funding cycle parameters over time.\\n/// @custom:member metadata Extra data that can be associated with a funding cycle.\\nstruct JBFundingCycle {\\n uint256 number;\\n uint256 configuration;\\n uint256 basedOn;\\n uint256 start;\\n uint256 duration;\\n uint256 weight;\\n uint256 discountRate;\\n IJBFundingCycleBallot ballot;\\n uint256 metadata;\\n}\\n\",\"keccak256\":\"0x01d2ee9ae017694097985a08a36421b6801d96badd16e38c6085f3a5ac796ed1\",\"license\":\"MIT\"},\"contracts/structs/JBFundingCycleData.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBFundingCycleBallot} from './../interfaces/IJBFundingCycleBallot.sol';\\n\\n/// @custom:member duration The number of seconds the funding cycle lasts for, after which a new funding cycle will start. A duration of 0 means that the funding cycle will stay active until the project owner explicitly issues a reconfiguration, at which point a new funding cycle will immediately start with the updated properties. If the duration is greater than 0, a project owner cannot make changes to a funding cycle's parameters while it is active \\u2013 any proposed changes will apply to the subsequent cycle. If no changes are proposed, a funding cycle rolls over to another one with the same properties but new `start` timestamp and a discounted `weight`.\\n/// @custom:member weight A fixed point number with 18 decimals that contracts can use to base arbitrary calculations on. For example, payment terminals can use this to determine how many tokens should be minted when a payment is received.\\n/// @custom:member discountRate A percent by how much the `weight` of the subsequent funding cycle should be reduced, if the project owner hasn't configured the subsequent funding cycle with an explicit `weight`. If it's 0, each funding cycle will have equal weight. If the number is 90%, the next funding cycle will have a 10% smaller weight. This weight is out of `JBConstants.MAX_DISCOUNT_RATE`.\\n/// @custom:member ballot An address of a contract that says whether a proposed reconfiguration should be accepted or rejected. It can be used to create rules around how a project owner can change funding cycle parameters over time.\\nstruct JBFundingCycleData {\\n uint256 duration;\\n uint256 weight;\\n uint256 discountRate;\\n IJBFundingCycleBallot ballot;\\n}\\n\",\"keccak256\":\"0x3cd9257969fdd54bee497b01be2c623e33c941306662002b3b88fa0ab8a27db5\",\"license\":\"MIT\"},\"contracts/structs/JBFundingCycleMetadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBGlobalFundingCycleMetadata} from './JBGlobalFundingCycleMetadata.sol';\\n\\n/// @custom:member global Data used globally in non-migratable ecosystem contracts.\\n/// @custom:member reservedRate The reserved rate of the funding cycle. This number is a percentage calculated out of `JBConstants.MAX_RESERVED_RATE`.\\n/// @custom:member redemptionRate The redemption rate of the funding cycle. This number is a percentage calculated out of `JBConstants.MAX_REDEMPTION_RATE`.\\n/// @custom:member ballotRedemptionRate The redemption rate to use during an active ballot of the funding cycle. This number is a percentage calculated out of `JBConstants.MAX_REDEMPTION_RATE`.\\n/// @custom:member pausePay A flag indicating if the pay functionality should be paused during the funding cycle.\\n/// @custom:member pauseDistributions A flag indicating if the distribute functionality should be paused during the funding cycle.\\n/// @custom:member pauseRedeem A flag indicating if the redeem functionality should be paused during the funding cycle.\\n/// @custom:member pauseBurn A flag indicating if the burn functionality should be paused during the funding cycle.\\n/// @custom:member allowMinting A flag indicating if minting tokens should be allowed during this funding cycle.\\n/// @custom:member allowTerminalMigration A flag indicating if migrating terminals should be allowed during this funding cycle.\\n/// @custom:member allowControllerMigration A flag indicating if migrating controllers should be allowed during this funding cycle.\\n/// @custom:member holdFees A flag indicating if fees should be held during this funding cycle.\\n/// @custom:member preferClaimedTokenOverride A flag indicating if claimed tokens should always be prefered to unclaimed tokens when minting.\\n/// @custom:member useTotalOverflowForRedemptions A flag indicating if redemptions should use the project's balance held in all terminals instead of the project's local terminal balance from which the redemption is being fulfilled.\\n/// @custom:member useDataSourceForPay A flag indicating if the data source should be used for pay transactions during this funding cycle.\\n/// @custom:member useDataSourceForRedeem A flag indicating if the data source should be used for redeem transactions during this funding cycle.\\n/// @custom:member dataSource The data source to use during this funding cycle.\\n/// @custom:member metadata Metadata of the metadata, up to uint8 in size.\\nstruct JBFundingCycleMetadata {\\n JBGlobalFundingCycleMetadata global;\\n uint256 reservedRate;\\n uint256 redemptionRate;\\n uint256 ballotRedemptionRate;\\n bool pausePay;\\n bool pauseDistributions;\\n bool pauseRedeem;\\n bool pauseBurn;\\n bool allowMinting;\\n bool allowTerminalMigration;\\n bool allowControllerMigration;\\n bool holdFees;\\n bool preferClaimedTokenOverride;\\n bool useTotalOverflowForRedemptions;\\n bool useDataSourceForPay;\\n bool useDataSourceForRedeem;\\n address dataSource;\\n uint256 metadata;\\n}\\n\",\"keccak256\":\"0x477bbd36c94da3f56fac6c8c60b2e2e3c5b8fc557a880b5359980bc556ccd300\",\"license\":\"MIT\"},\"contracts/structs/JBGlobalFundingCycleMetadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/// @custom:member allowSetTerminals A flag indicating if setting terminals should be allowed during this funding cycle.\\n/// @custom:member allowSetController A flag indicating if setting a new controller should be allowed during this funding cycle.\\n/// @custom:member pauseTransfers A flag indicating if the project token transfer functionality should be paused during the funding cycle.\\nstruct JBGlobalFundingCycleMetadata {\\n bool allowSetTerminals;\\n bool allowSetController;\\n bool pauseTransfers;\\n}\\n\",\"keccak256\":\"0x5f95bce22550c69bb7b1ee17279d51415ae8bae10c5b759c8b88f0b0aba854ed\",\"license\":\"MIT\"},\"contracts/structs/JBGroupedSplits.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBSplit} from './JBSplit.sol';\\n\\n/// @custom:member group The group indentifier.\\n/// @custom:member splits The splits to associate with the group.\\nstruct JBGroupedSplits {\\n uint256 group;\\n JBSplit[] splits;\\n}\\n\",\"keccak256\":\"0x71fcdbff5cd055cee8d06b73568c44cedda8f5a2351e7d8ce9dd71d8a1f914a8\",\"license\":\"MIT\"},\"contracts/structs/JBPayDelegateAllocation3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBPayDelegate3_1_1} from '../interfaces/IJBPayDelegate3_1_1.sol';\\n\\n/// @custom:member delegate A delegate contract to use for subsequent calls.\\n/// @custom:member amount The amount to send to the delegate.\\n/// @custom:member metadata Metadata to pass the delegate.\\nstruct JBPayDelegateAllocation3_1_1 {\\n IJBPayDelegate3_1_1 delegate;\\n uint256 amount;\\n bytes metadata;\\n}\\n\",\"keccak256\":\"0x8d87206a7015af9ec9e5fc059e39bfcea44aa007f8812213c6fd489d0a9c2e17\",\"license\":\"MIT\"},\"contracts/structs/JBPayParamsData.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\\nimport {JBTokenAmount} from './JBTokenAmount.sol';\\n\\n/// @custom:member terminal The terminal that is facilitating the payment.\\n/// @custom:member payer The address from which the payment originated.\\n/// @custom:member amount The amount of the payment. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\\n/// @custom:member projectId The ID of the project being paid.\\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the payment is being made.\\n/// @custom:member beneficiary The specified address that should be the beneficiary of anything that results from the payment.\\n/// @custom:member weight The weight of the funding cycle during which the payment is being made.\\n/// @custom:member reservedRate The reserved rate of the funding cycle during which the payment is being made.\\n/// @custom:member memo The memo that was sent alongside the payment.\\n/// @custom:member metadata Extra data provided by the payer.\\nstruct JBPayParamsData {\\n IJBPaymentTerminal terminal;\\n address payer;\\n JBTokenAmount amount;\\n uint256 projectId;\\n uint256 currentFundingCycleConfiguration;\\n address beneficiary;\\n uint256 weight;\\n uint256 reservedRate;\\n string memo;\\n bytes metadata;\\n}\\n\",\"keccak256\":\"0xc7909dfe6de88faca33a47a588559c80e14d3d1256f2c17e13f5ea6e23ce8732\",\"license\":\"MIT\"},\"contracts/structs/JBProjectMetadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/// @custom:member content The metadata content.\\n/// @custom:member domain The domain within which the metadata applies.\\nstruct JBProjectMetadata {\\n string content;\\n uint256 domain;\\n}\\n\",\"keccak256\":\"0x9545ea42927f3451c9d901a2f7ab7c1aeef3242e5ed2b75521a90225a5a0f891\",\"license\":\"MIT\"},\"contracts/structs/JBRedeemParamsData.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\\nimport {JBTokenAmount} from './JBTokenAmount.sol';\\n\\n/// @custom:member terminal The terminal that is facilitating the redemption.\\n/// @custom:member holder The holder of the tokens being redeemed.\\n/// @custom:member projectId The ID of the project whos tokens are being redeemed.\\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the redemption is being made.\\n/// @custom:member tokenCount The proposed number of tokens being redeemed, as a fixed point number with 18 decimals.\\n/// @custom:member totalSupply The total supply of tokens used in the calculation, as a fixed point number with 18 decimals.\\n/// @custom:member overflow The amount of overflow used in the reclaim amount calculation.\\n/// @custom:member reclaimAmount The amount that should be reclaimed by the redeemer using the protocol's standard bonding curve redemption formula. Includes the token being reclaimed, the reclaim value, the number of decimals included, and the currency of the reclaim amount.\\n/// @custom:member useTotalOverflow If overflow across all of a project's terminals is being used when making redemptions.\\n/// @custom:member redemptionRate The redemption rate of the funding cycle during which the redemption is being made.\\n/// @custom:member memo The proposed memo that is being emitted alongside the redemption.\\n/// @custom:member metadata Extra data provided by the redeemer.\\nstruct JBRedeemParamsData {\\n IJBPaymentTerminal terminal;\\n address holder;\\n uint256 projectId;\\n uint256 currentFundingCycleConfiguration;\\n uint256 tokenCount;\\n uint256 totalSupply;\\n uint256 overflow;\\n JBTokenAmount reclaimAmount;\\n bool useTotalOverflow;\\n uint256 redemptionRate;\\n string memo;\\n bytes metadata;\\n}\\n\",\"keccak256\":\"0x2eada17b425e75bfeffa786dc5b5ef13407b798cc1822597dd0d3389e67e9229\",\"license\":\"MIT\"},\"contracts/structs/JBRedemptionDelegateAllocation3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBRedemptionDelegate3_1_1} from '../interfaces/IJBRedemptionDelegate3_1_1.sol';\\n\\n/// @custom:member delegate A delegate contract to use for subsequent calls.\\n/// @custom:member amount The amount to send to the delegate.\\n/// @custom:member metadata Metadata to pass the delegate.\\nstruct JBRedemptionDelegateAllocation3_1_1 {\\n IJBRedemptionDelegate3_1_1 delegate;\\n uint256 amount;\\n bytes metadata;\\n}\\n\",\"keccak256\":\"0x16d2b586f4591b0d18324f233b4d4a13c6dc687b5f2c5becadbedbbdc373cdc4\",\"license\":\"MIT\"},\"contracts/structs/JBSplit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBSplitAllocator} from './../interfaces/IJBSplitAllocator.sol';\\n\\n/// @custom:member preferClaimed A flag that only has effect if a projectId is also specified, and the project has a token contract attached. If so, this flag indicates if the tokens that result from making a payment to the project should be delivered claimed into the beneficiary's wallet, or unclaimed to save gas.\\n/// @custom:member preferAddToBalance A flag indicating if a distribution to a project should prefer triggering it's addToBalance function instead of its pay function.\\n/// @custom:member percent The percent of the whole group that this split occupies. This number is out of `JBConstants.SPLITS_TOTAL_PERCENT`.\\n/// @custom:member projectId The ID of a project. If an allocator is not set but a projectId is set, funds will be sent to the protocol treasury belonging to the project who's ID is specified. Resulting tokens will be routed to the beneficiary with the claimed token preference respected.\\n/// @custom:member beneficiary An address. The role the of the beneficary depends on whether or not projectId is specified, and whether or not an allocator is specified. If allocator is set, the beneficiary will be forwarded to the allocator for it to use. If allocator is not set but projectId is set, the beneficiary is the address to which the project's tokens will be sent that result from a payment to it. If neither allocator or projectId are set, the beneficiary is where the funds from the split will be sent.\\n/// @custom:member lockedUntil Specifies if the split should be unchangeable until the specified time, with the exception of extending the locked period.\\n/// @custom:member allocator If an allocator is specified, funds will be sent to the allocator contract along with all properties of this split.\\nstruct JBSplit {\\n bool preferClaimed;\\n bool preferAddToBalance;\\n uint256 percent;\\n uint256 projectId;\\n address payable beneficiary;\\n uint256 lockedUntil;\\n IJBSplitAllocator allocator;\\n}\\n\",\"keccak256\":\"0x7bf3f79f95cf6211dcdcf5af68ddc963f2304379ea50a5feaf27c645879fe3fe\",\"license\":\"MIT\"},\"contracts/structs/JBSplitAllocationData.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBSplit} from './JBSplit.sol';\\n\\n/// @custom:member token The token being sent to the split allocator.\\n/// @custom:member amount The amount being sent to the split allocator, as a fixed point number.\\n/// @custom:member decimals The number of decimals in the amount.\\n/// @custom:member projectId The project to which the split belongs.\\n/// @custom:member group The group to which the split belongs.\\n/// @custom:member split The split that caused the allocation.\\nstruct JBSplitAllocationData {\\n address token;\\n uint256 amount;\\n uint256 decimals;\\n uint256 projectId;\\n uint256 group;\\n JBSplit split;\\n}\\n\",\"keccak256\":\"0x85dcbcad02f315a1a3cc44140ffc77fdfbcafed7089eab55ffb66f1bebc2b40b\",\"license\":\"MIT\"},\"contracts/structs/JBTokenAmount.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/// @custom:member token The token the payment was made in.\\n/// @custom:member value The amount of tokens that was paid, as a fixed point number.\\n/// @custom:member decimals The number of decimals included in the value fixed point number.\\n/// @custom:member currency The expected currency of the value.\\nstruct JBTokenAmount {\\n address token;\\n uint256 value;\\n uint256 decimals;\\n uint256 currency;\\n}\\n\",\"keccak256\":\"0x9317f1f47aef544de592a48a4b20fa3d54586d988c8bb7420b40076920ea200d\",\"license\":\"MIT\"},\"prb-math/contracts/PRBMath.sol\":{\"content\":\"// SPDX-License-Identifier: Unlicense\\npragma solidity >=0.8.4;\\n\\n/// @notice Emitted when the result overflows uint256.\\nerror PRBMath__MulDivFixedPointOverflow(uint256 prod1);\\n\\n/// @notice Emitted when the result overflows uint256.\\nerror PRBMath__MulDivOverflow(uint256 prod1, uint256 denominator);\\n\\n/// @notice Emitted when one of the inputs is type(int256).min.\\nerror PRBMath__MulDivSignedInputTooSmall();\\n\\n/// @notice Emitted when the intermediary absolute result overflows int256.\\nerror PRBMath__MulDivSignedOverflow(uint256 rAbs);\\n\\n/// @notice Emitted when the input is MIN_SD59x18.\\nerror PRBMathSD59x18__AbsInputTooSmall();\\n\\n/// @notice Emitted when ceiling a number overflows SD59x18.\\nerror PRBMathSD59x18__CeilOverflow(int256 x);\\n\\n/// @notice Emitted when one of the inputs is MIN_SD59x18.\\nerror PRBMathSD59x18__DivInputTooSmall();\\n\\n/// @notice Emitted when one of the intermediary unsigned results overflows SD59x18.\\nerror PRBMathSD59x18__DivOverflow(uint256 rAbs);\\n\\n/// @notice Emitted when the input is greater than 133.084258667509499441.\\nerror PRBMathSD59x18__ExpInputTooBig(int256 x);\\n\\n/// @notice Emitted when the input is greater than 192.\\nerror PRBMathSD59x18__Exp2InputTooBig(int256 x);\\n\\n/// @notice Emitted when flooring a number underflows SD59x18.\\nerror PRBMathSD59x18__FloorUnderflow(int256 x);\\n\\n/// @notice Emitted when converting a basic integer to the fixed-point format overflows SD59x18.\\nerror PRBMathSD59x18__FromIntOverflow(int256 x);\\n\\n/// @notice Emitted when converting a basic integer to the fixed-point format underflows SD59x18.\\nerror PRBMathSD59x18__FromIntUnderflow(int256 x);\\n\\n/// @notice Emitted when the product of the inputs is negative.\\nerror PRBMathSD59x18__GmNegativeProduct(int256 x, int256 y);\\n\\n/// @notice Emitted when multiplying the inputs overflows SD59x18.\\nerror PRBMathSD59x18__GmOverflow(int256 x, int256 y);\\n\\n/// @notice Emitted when the input is less than or equal to zero.\\nerror PRBMathSD59x18__LogInputTooSmall(int256 x);\\n\\n/// @notice Emitted when one of the inputs is MIN_SD59x18.\\nerror PRBMathSD59x18__MulInputTooSmall();\\n\\n/// @notice Emitted when the intermediary absolute result overflows SD59x18.\\nerror PRBMathSD59x18__MulOverflow(uint256 rAbs);\\n\\n/// @notice Emitted when the intermediary absolute result overflows SD59x18.\\nerror PRBMathSD59x18__PowuOverflow(uint256 rAbs);\\n\\n/// @notice Emitted when the input is negative.\\nerror PRBMathSD59x18__SqrtNegativeInput(int256 x);\\n\\n/// @notice Emitted when the calculating the square root overflows SD59x18.\\nerror PRBMathSD59x18__SqrtOverflow(int256 x);\\n\\n/// @notice Emitted when addition overflows UD60x18.\\nerror PRBMathUD60x18__AddOverflow(uint256 x, uint256 y);\\n\\n/// @notice Emitted when ceiling a number overflows UD60x18.\\nerror PRBMathUD60x18__CeilOverflow(uint256 x);\\n\\n/// @notice Emitted when the input is greater than 133.084258667509499441.\\nerror PRBMathUD60x18__ExpInputTooBig(uint256 x);\\n\\n/// @notice Emitted when the input is greater than 192.\\nerror PRBMathUD60x18__Exp2InputTooBig(uint256 x);\\n\\n/// @notice Emitted when converting a basic integer to the fixed-point format format overflows UD60x18.\\nerror PRBMathUD60x18__FromUintOverflow(uint256 x);\\n\\n/// @notice Emitted when multiplying the inputs overflows UD60x18.\\nerror PRBMathUD60x18__GmOverflow(uint256 x, uint256 y);\\n\\n/// @notice Emitted when the input is less than 1.\\nerror PRBMathUD60x18__LogInputTooSmall(uint256 x);\\n\\n/// @notice Emitted when the calculating the square root overflows UD60x18.\\nerror PRBMathUD60x18__SqrtOverflow(uint256 x);\\n\\n/// @notice Emitted when subtraction underflows UD60x18.\\nerror PRBMathUD60x18__SubUnderflow(uint256 x, uint256 y);\\n\\n/// @dev Common mathematical functions used in both PRBMathSD59x18 and PRBMathUD60x18. Note that this shared library\\n/// does not always assume the signed 59.18-decimal fixed-point or the unsigned 60.18-decimal fixed-point\\n/// representation. When it does not, it is explicitly mentioned in the NatSpec documentation.\\nlibrary PRBMath {\\n /// STRUCTS ///\\n\\n struct SD59x18 {\\n int256 value;\\n }\\n\\n struct UD60x18 {\\n uint256 value;\\n }\\n\\n /// STORAGE ///\\n\\n /// @dev How many trailing decimals can be represented.\\n uint256 internal constant SCALE = 1e18;\\n\\n /// @dev Largest power of two divisor of SCALE.\\n uint256 internal constant SCALE_LPOTD = 262144;\\n\\n /// @dev SCALE inverted mod 2^256.\\n uint256 internal constant SCALE_INVERSE =\\n 78156646155174841979727994598816262306175212592076161876661_508869554232690281;\\n\\n /// FUNCTIONS ///\\n\\n /// @notice Calculates the binary exponent of x using the binary fraction method.\\n /// @dev Has to use 192.64-bit fixed-point numbers.\\n /// See https://ethereum.stackexchange.com/a/96594/24693.\\n /// @param x The exponent as an unsigned 192.64-bit fixed-point number.\\n /// @return result The result as an unsigned 60.18-decimal fixed-point number.\\n function exp2(uint256 x) internal pure returns (uint256 result) {\\n unchecked {\\n // Start from 0.5 in the 192.64-bit fixed-point format.\\n result = 0x800000000000000000000000000000000000000000000000;\\n\\n // Multiply the result by root(2, 2^-i) when the bit at position i is 1. None of the intermediary results overflows\\n // because the initial result is 2^191 and all magic factors are less than 2^65.\\n if (x & 0x8000000000000000 > 0) {\\n result = (result * 0x16A09E667F3BCC909) >> 64;\\n }\\n if (x & 0x4000000000000000 > 0) {\\n result = (result * 0x1306FE0A31B7152DF) >> 64;\\n }\\n if (x & 0x2000000000000000 > 0) {\\n result = (result * 0x1172B83C7D517ADCE) >> 64;\\n }\\n if (x & 0x1000000000000000 > 0) {\\n result = (result * 0x10B5586CF9890F62A) >> 64;\\n }\\n if (x & 0x800000000000000 > 0) {\\n result = (result * 0x1059B0D31585743AE) >> 64;\\n }\\n if (x & 0x400000000000000 > 0) {\\n result = (result * 0x102C9A3E778060EE7) >> 64;\\n }\\n if (x & 0x200000000000000 > 0) {\\n result = (result * 0x10163DA9FB33356D8) >> 64;\\n }\\n if (x & 0x100000000000000 > 0) {\\n result = (result * 0x100B1AFA5ABCBED61) >> 64;\\n }\\n if (x & 0x80000000000000 > 0) {\\n result = (result * 0x10058C86DA1C09EA2) >> 64;\\n }\\n if (x & 0x40000000000000 > 0) {\\n result = (result * 0x1002C605E2E8CEC50) >> 64;\\n }\\n if (x & 0x20000000000000 > 0) {\\n result = (result * 0x100162F3904051FA1) >> 64;\\n }\\n if (x & 0x10000000000000 > 0) {\\n result = (result * 0x1000B175EFFDC76BA) >> 64;\\n }\\n if (x & 0x8000000000000 > 0) {\\n result = (result * 0x100058BA01FB9F96D) >> 64;\\n }\\n if (x & 0x4000000000000 > 0) {\\n result = (result * 0x10002C5CC37DA9492) >> 64;\\n }\\n if (x & 0x2000000000000 > 0) {\\n result = (result * 0x1000162E525EE0547) >> 64;\\n }\\n if (x & 0x1000000000000 > 0) {\\n result = (result * 0x10000B17255775C04) >> 64;\\n }\\n if (x & 0x800000000000 > 0) {\\n result = (result * 0x1000058B91B5BC9AE) >> 64;\\n }\\n if (x & 0x400000000000 > 0) {\\n result = (result * 0x100002C5C89D5EC6D) >> 64;\\n }\\n if (x & 0x200000000000 > 0) {\\n result = (result * 0x10000162E43F4F831) >> 64;\\n }\\n if (x & 0x100000000000 > 0) {\\n result = (result * 0x100000B1721BCFC9A) >> 64;\\n }\\n if (x & 0x80000000000 > 0) {\\n result = (result * 0x10000058B90CF1E6E) >> 64;\\n }\\n if (x & 0x40000000000 > 0) {\\n result = (result * 0x1000002C5C863B73F) >> 64;\\n }\\n if (x & 0x20000000000 > 0) {\\n result = (result * 0x100000162E430E5A2) >> 64;\\n }\\n if (x & 0x10000000000 > 0) {\\n result = (result * 0x1000000B172183551) >> 64;\\n }\\n if (x & 0x8000000000 > 0) {\\n result = (result * 0x100000058B90C0B49) >> 64;\\n }\\n if (x & 0x4000000000 > 0) {\\n result = (result * 0x10000002C5C8601CC) >> 64;\\n }\\n if (x & 0x2000000000 > 0) {\\n result = (result * 0x1000000162E42FFF0) >> 64;\\n }\\n if (x & 0x1000000000 > 0) {\\n result = (result * 0x10000000B17217FBB) >> 64;\\n }\\n if (x & 0x800000000 > 0) {\\n result = (result * 0x1000000058B90BFCE) >> 64;\\n }\\n if (x & 0x400000000 > 0) {\\n result = (result * 0x100000002C5C85FE3) >> 64;\\n }\\n if (x & 0x200000000 > 0) {\\n result = (result * 0x10000000162E42FF1) >> 64;\\n }\\n if (x & 0x100000000 > 0) {\\n result = (result * 0x100000000B17217F8) >> 64;\\n }\\n if (x & 0x80000000 > 0) {\\n result = (result * 0x10000000058B90BFC) >> 64;\\n }\\n if (x & 0x40000000 > 0) {\\n result = (result * 0x1000000002C5C85FE) >> 64;\\n }\\n if (x & 0x20000000 > 0) {\\n result = (result * 0x100000000162E42FF) >> 64;\\n }\\n if (x & 0x10000000 > 0) {\\n result = (result * 0x1000000000B17217F) >> 64;\\n }\\n if (x & 0x8000000 > 0) {\\n result = (result * 0x100000000058B90C0) >> 64;\\n }\\n if (x & 0x4000000 > 0) {\\n result = (result * 0x10000000002C5C860) >> 64;\\n }\\n if (x & 0x2000000 > 0) {\\n result = (result * 0x1000000000162E430) >> 64;\\n }\\n if (x & 0x1000000 > 0) {\\n result = (result * 0x10000000000B17218) >> 64;\\n }\\n if (x & 0x800000 > 0) {\\n result = (result * 0x1000000000058B90C) >> 64;\\n }\\n if (x & 0x400000 > 0) {\\n result = (result * 0x100000000002C5C86) >> 64;\\n }\\n if (x & 0x200000 > 0) {\\n result = (result * 0x10000000000162E43) >> 64;\\n }\\n if (x & 0x100000 > 0) {\\n result = (result * 0x100000000000B1721) >> 64;\\n }\\n if (x & 0x80000 > 0) {\\n result = (result * 0x10000000000058B91) >> 64;\\n }\\n if (x & 0x40000 > 0) {\\n result = (result * 0x1000000000002C5C8) >> 64;\\n }\\n if (x & 0x20000 > 0) {\\n result = (result * 0x100000000000162E4) >> 64;\\n }\\n if (x & 0x10000 > 0) {\\n result = (result * 0x1000000000000B172) >> 64;\\n }\\n if (x & 0x8000 > 0) {\\n result = (result * 0x100000000000058B9) >> 64;\\n }\\n if (x & 0x4000 > 0) {\\n result = (result * 0x10000000000002C5D) >> 64;\\n }\\n if (x & 0x2000 > 0) {\\n result = (result * 0x1000000000000162E) >> 64;\\n }\\n if (x & 0x1000 > 0) {\\n result = (result * 0x10000000000000B17) >> 64;\\n }\\n if (x & 0x800 > 0) {\\n result = (result * 0x1000000000000058C) >> 64;\\n }\\n if (x & 0x400 > 0) {\\n result = (result * 0x100000000000002C6) >> 64;\\n }\\n if (x & 0x200 > 0) {\\n result = (result * 0x10000000000000163) >> 64;\\n }\\n if (x & 0x100 > 0) {\\n result = (result * 0x100000000000000B1) >> 64;\\n }\\n if (x & 0x80 > 0) {\\n result = (result * 0x10000000000000059) >> 64;\\n }\\n if (x & 0x40 > 0) {\\n result = (result * 0x1000000000000002C) >> 64;\\n }\\n if (x & 0x20 > 0) {\\n result = (result * 0x10000000000000016) >> 64;\\n }\\n if (x & 0x10 > 0) {\\n result = (result * 0x1000000000000000B) >> 64;\\n }\\n if (x & 0x8 > 0) {\\n result = (result * 0x10000000000000006) >> 64;\\n }\\n if (x & 0x4 > 0) {\\n result = (result * 0x10000000000000003) >> 64;\\n }\\n if (x & 0x2 > 0) {\\n result = (result * 0x10000000000000001) >> 64;\\n }\\n if (x & 0x1 > 0) {\\n result = (result * 0x10000000000000001) >> 64;\\n }\\n\\n // We're doing two things at the same time:\\n //\\n // 1. Multiply the result by 2^n + 1, where \\\"2^n\\\" is the integer part and the one is added to account for\\n // the fact that we initially set the result to 0.5. This is accomplished by subtracting from 191\\n // rather than 192.\\n // 2. Convert the result to the unsigned 60.18-decimal fixed-point format.\\n //\\n // This works because 2^(191-ip) = 2^ip / 2^191, where \\\"ip\\\" is the integer part \\\"2^n\\\".\\n result *= SCALE;\\n result >>= (191 - (x >> 64));\\n }\\n }\\n\\n /// @notice Finds the zero-based index of the first one in the binary representation of x.\\n /// @dev See the note on msb in the \\\"Find First Set\\\" Wikipedia article https://en.wikipedia.org/wiki/Find_first_set\\n /// @param x The uint256 number for which to find the index of the most significant bit.\\n /// @return msb The index of the most significant bit as an uint256.\\n function mostSignificantBit(uint256 x) internal pure returns (uint256 msb) {\\n if (x >= 2**128) {\\n x >>= 128;\\n msb += 128;\\n }\\n if (x >= 2**64) {\\n x >>= 64;\\n msb += 64;\\n }\\n if (x >= 2**32) {\\n x >>= 32;\\n msb += 32;\\n }\\n if (x >= 2**16) {\\n x >>= 16;\\n msb += 16;\\n }\\n if (x >= 2**8) {\\n x >>= 8;\\n msb += 8;\\n }\\n if (x >= 2**4) {\\n x >>= 4;\\n msb += 4;\\n }\\n if (x >= 2**2) {\\n x >>= 2;\\n msb += 2;\\n }\\n if (x >= 2**1) {\\n // No need to shift x any more.\\n msb += 1;\\n }\\n }\\n\\n /// @notice Calculates floor(x*y\\u00f7denominator) with full precision.\\n ///\\n /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv.\\n ///\\n /// Requirements:\\n /// - The denominator cannot be zero.\\n /// - The result must fit within uint256.\\n ///\\n /// Caveats:\\n /// - This function does not work with fixed-point numbers.\\n ///\\n /// @param x The multiplicand as an uint256.\\n /// @param y The multiplier as an uint256.\\n /// @param denominator The divisor as an uint256.\\n /// @return result The result as an uint256.\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator\\n ) internal pure returns (uint256 result) {\\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\\n // variables such that product = prod1 * 2^256 + prod0.\\n uint256 prod0; // Least significant 256 bits of the product\\n uint256 prod1; // Most significant 256 bits of the product\\n assembly {\\n let mm := mulmod(x, y, not(0))\\n prod0 := mul(x, y)\\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\\n }\\n\\n // Handle non-overflow cases, 256 by 256 division.\\n if (prod1 == 0) {\\n unchecked {\\n result = prod0 / denominator;\\n }\\n return result;\\n }\\n\\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\\n if (prod1 >= denominator) {\\n revert PRBMath__MulDivOverflow(prod1, denominator);\\n }\\n\\n ///////////////////////////////////////////////\\n // 512 by 256 division.\\n ///////////////////////////////////////////////\\n\\n // Make division exact by subtracting the remainder from [prod1 prod0].\\n uint256 remainder;\\n assembly {\\n // Compute remainder using mulmod.\\n remainder := mulmod(x, y, denominator)\\n\\n // Subtract 256 bit number from 512 bit number.\\n prod1 := sub(prod1, gt(remainder, prod0))\\n prod0 := sub(prod0, remainder)\\n }\\n\\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\\n // See https://cs.stackexchange.com/q/138556/92363.\\n unchecked {\\n // Does not overflow because the denominator cannot be zero at this stage in the function.\\n uint256 lpotdod = denominator & (~denominator + 1);\\n assembly {\\n // Divide denominator by lpotdod.\\n denominator := div(denominator, lpotdod)\\n\\n // Divide [prod1 prod0] by lpotdod.\\n prod0 := div(prod0, lpotdod)\\n\\n // Flip lpotdod such that it is 2^256 / lpotdod. If lpotdod is zero, then it becomes one.\\n lpotdod := add(div(sub(0, lpotdod), lpotdod), 1)\\n }\\n\\n // Shift in bits from prod1 into prod0.\\n prod0 |= prod1 * lpotdod;\\n\\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\\n // four bits. That is, denominator * inv = 1 mod 2^4.\\n uint256 inverse = (3 * denominator) ^ 2;\\n\\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\\n // in modular arithmetic, doubling the correct bits in each step.\\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\\n\\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\\n // is no longer required.\\n result = prod0 * inverse;\\n return result;\\n }\\n }\\n\\n /// @notice Calculates floor(x*y\\u00f71e18) with full precision.\\n ///\\n /// @dev Variant of \\\"mulDiv\\\" with constant folding, i.e. in which the denominator is always 1e18. Before returning the\\n /// final result, we add 1 if (x * y) % SCALE >= HALF_SCALE. Without this, 6.6e-19 would be truncated to 0 instead of\\n /// being rounded to 1e-18. See \\\"Listing 6\\\" and text above it at https://accu.org/index.php/journals/1717.\\n ///\\n /// Requirements:\\n /// - The result must fit within uint256.\\n ///\\n /// Caveats:\\n /// - The body is purposely left uncommented; see the NatSpec comments in \\\"PRBMath.mulDiv\\\" to understand how this works.\\n /// - It is assumed that the result can never be type(uint256).max when x and y solve the following two equations:\\n /// 1. x * y = type(uint256).max * SCALE\\n /// 2. (x * y) % SCALE >= SCALE / 2\\n ///\\n /// @param x The multiplicand as an unsigned 60.18-decimal fixed-point number.\\n /// @param y The multiplier as an unsigned 60.18-decimal fixed-point number.\\n /// @return result The result as an unsigned 60.18-decimal fixed-point number.\\n function mulDivFixedPoint(uint256 x, uint256 y) internal pure returns (uint256 result) {\\n uint256 prod0;\\n uint256 prod1;\\n assembly {\\n let mm := mulmod(x, y, not(0))\\n prod0 := mul(x, y)\\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\\n }\\n\\n if (prod1 >= SCALE) {\\n revert PRBMath__MulDivFixedPointOverflow(prod1);\\n }\\n\\n uint256 remainder;\\n uint256 roundUpUnit;\\n assembly {\\n remainder := mulmod(x, y, SCALE)\\n roundUpUnit := gt(remainder, 499999999999999999)\\n }\\n\\n if (prod1 == 0) {\\n unchecked {\\n result = (prod0 / SCALE) + roundUpUnit;\\n return result;\\n }\\n }\\n\\n assembly {\\n result := add(\\n mul(\\n or(\\n div(sub(prod0, remainder), SCALE_LPOTD),\\n mul(sub(prod1, gt(remainder, prod0)), add(div(sub(0, SCALE_LPOTD), SCALE_LPOTD), 1))\\n ),\\n SCALE_INVERSE\\n ),\\n roundUpUnit\\n )\\n }\\n }\\n\\n /// @notice Calculates floor(x*y\\u00f7denominator) with full precision.\\n ///\\n /// @dev An extension of \\\"mulDiv\\\" for signed numbers. Works by computing the signs and the absolute values separately.\\n ///\\n /// Requirements:\\n /// - None of the inputs can be type(int256).min.\\n /// - The result must fit within int256.\\n ///\\n /// @param x The multiplicand as an int256.\\n /// @param y The multiplier as an int256.\\n /// @param denominator The divisor as an int256.\\n /// @return result The result as an int256.\\n function mulDivSigned(\\n int256 x,\\n int256 y,\\n int256 denominator\\n ) internal pure returns (int256 result) {\\n if (x == type(int256).min || y == type(int256).min || denominator == type(int256).min) {\\n revert PRBMath__MulDivSignedInputTooSmall();\\n }\\n\\n // Get hold of the absolute values of x, y and the denominator.\\n uint256 ax;\\n uint256 ay;\\n uint256 ad;\\n unchecked {\\n ax = x < 0 ? uint256(-x) : uint256(x);\\n ay = y < 0 ? uint256(-y) : uint256(y);\\n ad = denominator < 0 ? uint256(-denominator) : uint256(denominator);\\n }\\n\\n // Compute the absolute value of (x*y)\\u00f7denominator. The result must fit within int256.\\n uint256 rAbs = mulDiv(ax, ay, ad);\\n if (rAbs > uint256(type(int256).max)) {\\n revert PRBMath__MulDivSignedOverflow(rAbs);\\n }\\n\\n // Get the signs of x, y and the denominator.\\n uint256 sx;\\n uint256 sy;\\n uint256 sd;\\n assembly {\\n sx := sgt(x, sub(0, 1))\\n sy := sgt(y, sub(0, 1))\\n sd := sgt(denominator, sub(0, 1))\\n }\\n\\n // XOR over sx, sy and sd. This is checking whether there are one or three negative signs in the inputs.\\n // If yes, the result should be negative.\\n result = sx ^ sy ^ sd == 0 ? -int256(rAbs) : int256(rAbs);\\n }\\n\\n /// @notice Calculates the square root of x, rounding down.\\n /// @dev Uses the Babylonian method https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method.\\n ///\\n /// Caveats:\\n /// - This function does not work with fixed-point numbers.\\n ///\\n /// @param x The uint256 number for which to calculate the square root.\\n /// @return result The result as an uint256.\\n function sqrt(uint256 x) internal pure returns (uint256 result) {\\n if (x == 0) {\\n return 0;\\n }\\n\\n // Set the initial guess to the closest power of two that is higher than x.\\n uint256 xAux = uint256(x);\\n result = 1;\\n if (xAux >= 0x100000000000000000000000000000000) {\\n xAux >>= 128;\\n result <<= 64;\\n }\\n if (xAux >= 0x10000000000000000) {\\n xAux >>= 64;\\n result <<= 32;\\n }\\n if (xAux >= 0x100000000) {\\n xAux >>= 32;\\n result <<= 16;\\n }\\n if (xAux >= 0x10000) {\\n xAux >>= 16;\\n result <<= 8;\\n }\\n if (xAux >= 0x100) {\\n xAux >>= 8;\\n result <<= 4;\\n }\\n if (xAux >= 0x10) {\\n xAux >>= 4;\\n result <<= 2;\\n }\\n if (xAux >= 0x8) {\\n result <<= 1;\\n }\\n\\n // The operations can never overflow because the result is max 2^127 when it enters this block.\\n unchecked {\\n result = (result + x / result) >> 1;\\n result = (result + x / result) >> 1;\\n result = (result + x / result) >> 1;\\n result = (result + x / result) >> 1;\\n result = (result + x / result) >> 1;\\n result = (result + x / result) >> 1;\\n result = (result + x / result) >> 1; // Seven iterations should be enough\\n uint256 roundedDownResult = x / result;\\n return result >= roundedDownResult ? roundedDownResult : result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x62cbabae4910e168e99b9c2c3e3b5c9c7ad5e7abd961dcc63b7ea3d83d8ea87e\",\"license\":\"Unlicense\"}},\"version\":1}", + "bytecode": "0x60e06040523480156200001157600080fd5b506040516200366a3803806200366a833981016040819052620000349162000070565b60016000556001600160a01b0392831660805290821660a0521660c052620000c4565b6001600160a01b03811681146200006d57600080fd5b50565b6000806000606084860312156200008657600080fd5b8351620000938162000057565b6020850151909350620000a68162000057565b6040850151909250620000b98162000057565b809150509250925092565b60805160a05160c0516134ea6200018060003960008181610273015281816106d201528181610c1c0152818161214c015261232901526000818161018b0152818161036f0152818161083f01528181610d0601528181610e1c0152818161120d015281816114d7015281816115a0015281816118d901528181611cdf01526123b00152600081816102390152818161041f0152818161105c01528181611782015281816119b201528181611f2201526121c801526134ea6000f3fe608060405234801561001057600080fd5b50600436106100ff5760003560e01c8063c294b2f411610097578063d49031c011610066578063d49031c014610295578063d4c3a8d2146102a8578063e7c8e3e3146102d9578063e8ba563a146102ee57600080fd5b8063c294b2f414610221578063c41c2f2414610234578063c66445971461025b578063d3419bf31461026e57600080fd5b80636bb6a5ad116100d35780636bb6a5ad146101c5578063a2df1f95146101d8578063a57c7f59146101fb578063b753d7e91461020e57600080fd5b8062fdd58e1461010457806325386715146101425780632fa1b39114610163578063557e715514610186575b600080fd5b61012f6101123660046125c3565b600160209081526000928352604080842090915290825290205481565b6040519081526020015b60405180910390f35b6101556101503660046125ef565b61031f565b60405161013992919061267a565b6101766101713660046127fa565b6107f5565b604051610139949392919061290b565b6101ad7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610139565b61012f6101d33660046129bd565b610cc5565b6101eb6101e63660046129d6565b610dd2565b6040516101399493929190612a77565b61012f610209366004612b12565b61149c565b61012f61021c3660046125ef565b611566565b61012f61022f366004612b44565b61157d565b6101ad7f000000000000000000000000000000000000000000000000000000000000000081565b6101556102693660046125ef565b611892565b6101ad7f000000000000000000000000000000000000000000000000000000000000000081565b61012f6102a33660046125c3565b611cd6565b61012f6102b6366004612b93565b600360209081526000938452604080852082529284528284209052825290205481565b6102ec6102e7366004612bc8565b611db4565b005b61012f6102fc366004612b93565b600260209081526000938452604080852082529284528284209052825290205481565b610327612556565b60006002600054036103545760405162461bcd60e51b815260040161034b90612bea565b60405180910390fd5b60026000556040516321d1336160e11b8152600481018690527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906343a266c29060240161012060405180830381865afa1580156103bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103e39190612c31565b336000908152600360209081526040808320898452825280832082850151845290915281205491935090610418908690612cc7565b90506000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635dd8f6aa896040518263ffffffff1660e01b815260040161046b91815260200190565b602060405180830381865afa158015610488573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104ac9190612cda565b6001600160a01b031663a29a68146040518163ffffffff1660e01b8152600401602060405180830381865afa1580156104e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061050d9190612cda565b6001600160a01b0316637a81b56289876020015133336001600160a01b031663fc0c546a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610560573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105849190612cda565b6040518563ffffffff1660e01b81526004016105a39493929190612cf7565b6040805180830381865afa1580156105bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105e39190612d1e565b91509150818311806105f3575081155b1561061157604051635b76558960e11b815260040160405180910390fd5b8086146106315760405163e56ea4e760e01b815260040160405180910390fd5b6000336001600160a01b031663e5a6b10f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610671573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106959190612d42565b90508087146107505761074b886106ae6012600a612e3f565b604051635268657960e11b8152600481018b905260248101859052601260448201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a4d0caf2906064015b602060405180830381865afa158015610722573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107469190612d42565b611dfd565b610752565b875b9450610760338a8884611eca565b851115610780576040516317e53f6760e11b815260040160405180910390fd5b3360008181526003602090815260408083208d845282528083208a83015184528252808320889055928252600181528282208c8352905220546107c4908690612e4b565b3360009081526001602081815260408084209d84529c90529a81209190915598909855509296919550909350505050565b6107fd612556565b60006060806002600054036108245760405162461bcd60e51b815260040161034b90612bea565b60026000556040516321d1336160e11b8152600481018b90527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906343a266c29060240161012060405180830381865afa15801561088f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108b39190612c31565b80519094506000036108d85760405163174b338d60e11b815260040160405180910390fd5b61010084015160481c6001908116036109045760405163a3bb913360e01b815260040160405180910390fd5b61010084015160009060521c600190811614801561093a5750600061092e86610100015160541c90565b6001600160a01b031614155b15610a8c576000604051806101400160405280336001600160a01b031681526020018f6001600160a01b031681526020018e80360381019061097c9190612e5e565b815260208082018f905288015160408201526001600160a01b038c16606082015260a080890151608083015261010089015191019060181c61ffff1681526020018a8a8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050908252506020018890529050610a0d86610100015160541c90565b6001600160a01b031663d46cf171826040518263ffffffff1660e01b8152600401610a389190612ecd565b6000604051808303816000875af1158015610a57573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610a7f9190810190613038565b955093509150610acd9050565b8460a00151905087878080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509294505050505b825160208d01359015610b495760005b8451811015610b47576000858281518110610afa57610afa613169565b602002602001015160200151905080600014610b3e5782811115610b31576040516336a8da9360e11b815260040160405180910390fd5b610b3b8184612e4b565b92505b50600101610add565b505b8c60200135600003610b61575060009350610cae9050565b8015610bc8573360009081526001602090815260408083208f8452909152902054610b8d908290612cc7565b60016000336001600160a01b03166001600160a01b0316815260200190815260200160002060008e8152602001908152602001600020819055505b5080600003610bdb575060009250610cae565b60408c0135600060608e01358c14610c8c57604051635268657960e11b815260608f01356004820152602481018d9052604481018390526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063a4d0caf290606401602060405180830381865afa158015610c63573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c879190612d42565b610c97565b610c9782600a612e3f565b9050610ca88e602001358483611dfd565b95505050505b600160008190555098509850985098945050505050565b6000600260005403610ce95760405162461bcd60e51b815260040161034b90612bea565b600260009081556040516321d1336160e11b8152600481018490527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906343a266c29060240161012060405180830381865afa158015610d56573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d7a9190612c31565b610100810151909150604d1c600190811614610da9576040516373e4f05f60e11b815260040160405180910390fd5b505033600090815260016020818152604080842094845293905291812080549082905591905590565b610dda612556565b6000606080600260005403610e015760405162461bcd60e51b815260040161034b90612bea565b60026000556040516321d1336160e11b8152600481018990527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906343a266c29060240161012060405180830381865afa158015610e6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e909190612c31565b610100810151909450604a1c600190811603610ebf5760405163a97cf58f60e01b815260040160405180910390fd5b610ef3604051806080016040528060006001600160a01b031681526020016000815260200160008152602001600081525090565b6000806000336001600160a01b031663fc0c546a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f5a9190612cda565b90506000336001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f9c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fc09190612d42565b90506000336001600160a01b031663e5a6b10f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611002573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110269190612d42565b6101008b015190915060511c60019081161461104d57611048338f8c84611eca565b611058565b6110588e83836121a5565b94507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635dd8f6aa8f6040518263ffffffff1660e01b81526004016110a891815260200190565b602060405180830381865afa1580156110c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110e99190612cda565b6001600160a01b031663c18f2d318f6040518263ffffffff1660e01b815260040161111691815260200190565b602060405180830381865afa158015611133573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111579190612d42565b9350838d111561117957604051625c579160e91b815260040160405180910390fd5b841561118f5761118c8e8b8f8789612387565b98505b604080516080810182526001600160a01b03949094168452602084018a9052830191909152606082015261010088015190935060531c60019081161480156111ef575060006111e388610100015160541c90565b6001600160a01b031614155b156113c657604051633157d5c760e21b8152600481018c90526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063c55f571c90602401602060405180830381865afa15801561125c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611280919061317f565b90506000604051806101800160405280336001600160a01b031681526020018f6001600160a01b031681526020018e81526020018a6020015181526020018d81526020018481526020018581526020018681526020016112ed8b6101000151600160519190911c81161490565b151581526020016000846002811115611308576113086131a0565b1461131b576113168b6124bf565b611324565b6113248b6124dc565b81526020018c81526020018b815250905061134489610100015160541c90565b6001600160a01b031663a51cfd18826040518263ffffffff1660e01b815260040161136f91906131b6565b6000604051808303816000875af115801561138e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526113b691908101906132ae565b91995090975095506113ca915050565b8893505b50508251849150156114245760005b83518110156114225760008482815181106113f6576113f6613169565b602002602001015160200151905080600014611419576114168184612cc7565b92505b506001016113d9565b505b3360009081526001602090815260408083208c845290915290205481111561145f576040516317e53f6760e11b815260040160405180910390fd5b8015611487573360009081526001602090815260408083208c84529091529020805482900390555b50600160008190555095509550955095915050565b6000816000036114ae5750600061155e565b828411156114be5750600061155e565b6040516321d1336160e11b8152600481018690526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906343a266c29060240161012060405180830381865afa158015611527573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061154b9190612c31565b905061155a8682878787612387565b9150505b949350505050565b60006115738484846121a5565b90505b9392505050565b6040516321d1336160e11b81526004810184905260009081906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906343a266c29060240161012060405180830381865afa1580156115e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061160c9190612c31565b9050600083611687576116828787848a6001600160a01b031663e5a6b10f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611659573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061167d9190612d42565b611eca565b611754565b61175486886001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156116c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116ed9190612d42565b896001600160a01b031663e5a6b10f6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561172b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061174f9190612d42565b6121a5565b9050806000036117695760009250505061155e565b604051632eec7b5560e11b8152600481018790526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635dd8f6aa90602401602060405180830381865afa1580156117d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117f59190612cda565b6001600160a01b031663c18f2d31886040518263ffffffff1660e01b815260040161182291815260200190565b602060405180830381865afa15801561183f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118639190612d42565b905080861115611879576000935050505061155e565b6118868784888486612387565b98975050505050505050565b61189a612556565b60006002600054036118be5760405162461bcd60e51b815260040161034b90612bea565b60026000556040516321d1336160e11b8152600481018690527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906343a266c29060240161012060405180830381865afa158015611929573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061194d9190612c31565b61010081015190925060491c60019081160361197c5760405163861e9dcd60e01b815260040160405180910390fd5b3360009081526002602090815260408083208884528252808320855184529091528120546119ab908690612cc7565b90506000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635dd8f6aa896040518263ffffffff1660e01b81526004016119fe91815260200190565b602060405180830381865afa158015611a1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a3f9190612cda565b6001600160a01b031663a29a68146040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aa09190612cda565b6001600160a01b031663e8db213089876020015133336001600160a01b031663fc0c546a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611af3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b179190612cda565b6040518563ffffffff1660e01b8152600401611b369493929190612cf7565b6040805180830381865afa158015611b52573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b769190612d1e565b9150915081831180611b86575081155b15611ba457604051630236b92b60e21b815260040160405180910390fd5b808614611bc45760405163e56ea4e760e01b815260040160405180910390fd5b6000336001600160a01b031663e5a6b10f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611c04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c289190612d42565b9050808714611c4657611c41886106ae6012600a612e3f565b611c48565b875b3360009081526001602090815260408083208d8452909152902054909550851115611c86576040516317e53f6760e11b815260040160405180910390fd5b50503360008181526002602090815260408083208b845282528083208851845282528083209590955591815260018083528482209982529890915291822080548490039055509490945593915050565b6000611dab83837f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166343a266c2866040518263ffffffff1660e01b8152600401611d2b91815260200190565b61012060405180830381865afa158015611d49573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d6d9190612c31565b866001600160a01b031663e5a6b10f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611659573d6000803e3d6000fd5b90505b92915050565b336000908152600160209081526040808320858452909152902054611dda908290612cc7565b336000908152600160209081526040808320958352949052929092209190915550565b6000808060001985870985870292508281108382030391505080600003611e3757838281611e2d57611e2d6133ce565b0492505050611576565b838110611e6157604051631dcf306360e21b8152600481018290526024810185905260440161034b565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b6001600160a01b0384166000908152600160209081526040808320868452909152812054808203611eff57600091505061155e565b604051632eec7b5560e11b81526004810186905260009081906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690635dd8f6aa90602401602060405180830381865afa158015611f69573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f8d9190612cda565b6001600160a01b031663a29a68146040518163ffffffff1660e01b8152600401602060405180830381865afa158015611fca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fee9190612cda565b6001600160a01b031663e8db21308888602001518b8c6001600160a01b031663fc0c546a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612041573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120659190612cda565b6040518563ffffffff1660e01b81526004016120849493929190612cf7565b6040805180830381865afa1580156120a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120c49190612d1e565b6001600160a01b038a1660009081526002602090815260408083208c845282528083208b518452909152812054929450909250906121029084612e4b565b905080158015906121135750858214155b1561218657612183816121286012600a612e3f565b604051635268657960e11b815260048101869052602481018a9052601260448201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a4d0caf290606401610705565b90505b808411612194576000612198565b8084035b9998505050505050505050565b60405163d175415360e01b81526004810184905260009081906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063d175415390602401600060405180830381865afa15801561220f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261223791908101906133e4565b90506000805b82518110156122e25782818151811061225857612258613169565b60200260200101516001600160a01b031663a32e1e96886040518263ffffffff1660e01b815260040161228d91815260200190565b602060405180830381865afa1580156122aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122ce9190612d42565b6122d89083612cc7565b915060010161223d565b5060006001851461235d57604051635268657960e11b8152600160048201526024810186905260126044820152612358908390670de0b6b3a7640000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063a4d0caf290606401610705565b61235f565b815b90508560121461237a57612375816012886124f9565b61237c565b805b979650505050505050565b60008284036123975750806124b6565b600080604051633157d5c760e21b8152600481018990527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063c55f571c90602401602060405180830381865afa1580156123ff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612423919061317f565b6002811115612434576124346131a0565b1461244757612442866124bf565b612450565b612450866124dc565b9050806000036124645760009150506124b6565b6000612471848787611dfd565b905061271082036124855791506124b69050565b6124b18161249f8861249986612710612e4b565b89611dfd565b6124a99085612cc7565b612710611dfd565b925050505b95945050505050565b60006028826101000151901c61ffff16612710611dae9190612e4b565b60006038826101000151901c61ffff16612710611dae9190612e4b565b6000828203612509575082611576565b828211156125375761251b8383612e4b565b61252690600a612e3f565b6125309085613473565b9050611576565b6125418284612e4b565b61254c90600a612e3f565b6125309085613492565b6040518061012001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b03168152602001600081525090565b6001600160a01b03811681146125c057600080fd5b50565b600080604083850312156125d657600080fd5b82356125e1816125ab565b946020939093013593505050565b60008060006060848603121561260457600080fd5b505081359360208301359350604090920135919050565b805182526020808201519083015260408082015190830152606080820151908301526080808201519083015260a0808201519083015260c0808201519083015260e0808201516001600160a01b03169083015261010090810151910152565b6101408101612689828561261b565b826101208301529392505050565b60008083601f8401126126a957600080fd5b50813567ffffffffffffffff8111156126c157600080fd5b6020830191508360208285010111156126d957600080fd5b9250929050565b634e487b7160e01b600052604160045260246000fd5b604051610120810167ffffffffffffffff8111828210171561271a5761271a6126e0565b60405290565b6040516060810167ffffffffffffffff8111828210171561271a5761271a6126e0565b604051601f8201601f1916810167ffffffffffffffff8111828210171561276c5761276c6126e0565b604052919050565b600067ffffffffffffffff82111561278e5761278e6126e0565b50601f01601f191660200190565b60006127af6127aa84612774565b612743565b90508281528383830111156127c357600080fd5b828260208301376000602084830101529392505050565b600082601f8301126127eb57600080fd5b611dab8383356020850161279c565b600080600080600080600080888a0361014081121561281857600080fd5b8935612823816125ab565b98506080601f198201121561283757600080fd5b5060208901965060a0890135955060c0890135945060e089013561285a816125ab565b935061010089013567ffffffffffffffff8082111561287857600080fd5b6128848c838d01612697565b90955093506101208b013591508082111561289e57600080fd5b506128ab8b828c016127da565b9150509295985092959890939650565b60005b838110156128d65781810151838201526020016128be565b50506000910152565b600081518084526128f78160208601602086016128bb565b601f01601f19169290920160200192915050565b600061018080830161291d848961261b565b61012084018790526101408401919091528451908190526101a080840191600581901b850190910190602080880160005b838110156129a65787850361019f19018652815180516001600160a01b031686528381015184870152604090810151606091870182905290612992818801836128df565b97850197965050509082019060010161294e565b505050508381036101608501526124b181866128df565b6000602082840312156129cf57600080fd5b5035919050565b600080600080600060a086880312156129ee57600080fd5b85356129f9816125ab565b94506020860135935060408601359250606086013567ffffffffffffffff80821115612a2457600080fd5b818801915088601f830112612a3857600080fd5b612a478983356020850161279c565b93506080880135915080821115612a5d57600080fd5b50612a6a888289016127da565b9150509295509295909350565b6000610180808301612a89848961261b565b61012084018790526101408401919091528451908190526101a080840191600581901b850190910190602080880160005b838110156129a65787850361019f19018652815180516001600160a01b031686528381015184870152604090810151606091870182905290612afe818801836128df565b978501979650505090820190600101612aba565b60008060008060808587031215612b2857600080fd5b5050823594602084013594506040840135936060013592509050565b60008060008060808587031215612b5a57600080fd5b8435612b65816125ab565b9350602085013592506040850135915060608501358015158114612b8857600080fd5b939692955090935050565b600080600060608486031215612ba857600080fd5b8335612bb3816125ab565b95602085013595506040909401359392505050565b60008060408385031215612bdb57600080fd5b50508035926020909101359150565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b8051612c2c816125ab565b919050565b60006101208284031215612c4457600080fd5b612c4c6126f6565b825181526020830151602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c0820152612c9860e08401612c21565b60e0820152610100928301519281019290925250919050565b634e487b7160e01b600052601160045260246000fd5b80820180821115611dae57611dae612cb1565b600060208284031215612cec57600080fd5b8151611576816125ab565b93845260208401929092526001600160a01b03908116604084015216606082015260800190565b60008060408385031215612d3157600080fd5b505080516020909101519092909150565b600060208284031215612d5457600080fd5b5051919050565b600181815b80851115612d96578160001904821115612d7c57612d7c612cb1565b80851615612d8957918102915b93841c9390800290612d60565b509250929050565b600082612dad57506001611dae565b81612dba57506000611dae565b8160018114612dd05760028114612dda57612df6565b6001915050611dae565b60ff841115612deb57612deb612cb1565b50506001821b611dae565b5060208310610133831016604e8410600b8410161715612e19575081810a611dae565b612e238383612d5b565b8060001904821115612e3757612e37612cb1565b029392505050565b6000611dab8383612d9e565b81810381811115611dae57611dae612cb1565b600060808284031215612e7057600080fd5b6040516080810181811067ffffffffffffffff82111715612e9357612e936126e0565b6040528235612ea1816125ab565b808252506020830135602082015260408301356040820152606083013560608201528091505092915050565b60208152612ee76020820183516001600160a01b03169052565b60006020830151612f0360408401826001600160a01b03169052565b506040830151612f3d606084018280516001600160a01b031682526020808201519083015260408082015190830152606090810151910152565b50606083015160e08301526080830151610100818185015260a08501519150610120612f73818601846001600160a01b03169052565b60c086015161014086015260e08601516101608601528186015192506101a0915081610180860152612fa96101c08601846128df565b90860151858203601f190183870152909250612fc583826128df565b9695505050505050565b600082601f830112612fe057600080fd5b8151612fee6127aa82612774565b81815284602083860101111561300357600080fd5b61155e8260208301602087016128bb565b600067ffffffffffffffff82111561302e5761302e6126e0565b5060051b60200190565b60008060006060848603121561304d57600080fd5b8351925060208085015167ffffffffffffffff8082111561306d57600080fd5b61307988838901612fcf565b9450604087015191508082111561308f57600080fd5b818701915087601f8301126130a357600080fd5b81516130b16127aa82613014565b81815260059190911b8301840190848101908a8311156130d057600080fd5b8585015b83811015613158578051858111156130ec5760008081fd5b86016060818e03601f190112156131035760008081fd5b61310b612720565b88820151613118816125ab565b81526040820151898201526060820151878111156131365760008081fd5b6131448f8b83860101612fcf565b6040830152508452509186019186016130d4565b508096505050505050509250925092565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561319157600080fd5b81516003811061157657600080fd5b634e487b7160e01b600052602160045260246000fd5b602081526131d06020820183516001600160a01b03169052565b600060208301516131ec60408401826001600160a01b03169052565b506040830151606083015260608301516080830152608083015160a083015260a083015160c083015260c083015160e083015260e083015161010061325a8185018380516001600160a01b031682526020808201519083015260408082015190830152606090810151910152565b8401511515610180840152506101208301516101a08301526101408301516101e06101c084018190526132916102008501836128df565b9150610160850151601f198584030182860152612fc583826128df565b6000806000606084860312156132c357600080fd5b8351925060208085015167ffffffffffffffff808211156132e357600080fd5b6132ef88838901612fcf565b9450604087015191508082111561330557600080fd5b818701915087601f83011261331957600080fd5b81516133276127aa82613014565b81815260059190911b8301840190848101908a83111561334657600080fd5b8585015b83811015613158578051858111156133625760008081fd5b86016060818e03601f190112156133795760008081fd5b613381612720565b8882015161338e816125ab565b81526040820151898201526060820151878111156133ac5760008081fd5b6133ba8f8b83860101612fcf565b60408301525084525091860191860161334a565b634e487b7160e01b600052601260045260246000fd5b600060208083850312156133f757600080fd5b825167ffffffffffffffff81111561340e57600080fd5b8301601f8101851361341f57600080fd5b805161342d6127aa82613014565b81815260059190911b8201830190838101908783111561344c57600080fd5b928401925b8284101561237c578351613464816125ab565b82529284019290840190613451565b600081600019048311821515161561348d5761348d612cb1565b500290565b6000826134af57634e487b7160e01b600052601260045260246000fd5b50049056fea26469706673582212207c0b0d6ef21a30936e47f919249183a609014eddc061713ac513cccd6177f36164736f6c63430008100033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100ff5760003560e01c8063c294b2f411610097578063d49031c011610066578063d49031c014610295578063d4c3a8d2146102a8578063e7c8e3e3146102d9578063e8ba563a146102ee57600080fd5b8063c294b2f414610221578063c41c2f2414610234578063c66445971461025b578063d3419bf31461026e57600080fd5b80636bb6a5ad116100d35780636bb6a5ad146101c5578063a2df1f95146101d8578063a57c7f59146101fb578063b753d7e91461020e57600080fd5b8062fdd58e1461010457806325386715146101425780632fa1b39114610163578063557e715514610186575b600080fd5b61012f6101123660046125c3565b600160209081526000928352604080842090915290825290205481565b6040519081526020015b60405180910390f35b6101556101503660046125ef565b61031f565b60405161013992919061267a565b6101766101713660046127fa565b6107f5565b604051610139949392919061290b565b6101ad7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610139565b61012f6101d33660046129bd565b610cc5565b6101eb6101e63660046129d6565b610dd2565b6040516101399493929190612a77565b61012f610209366004612b12565b61149c565b61012f61021c3660046125ef565b611566565b61012f61022f366004612b44565b61157d565b6101ad7f000000000000000000000000000000000000000000000000000000000000000081565b6101556102693660046125ef565b611892565b6101ad7f000000000000000000000000000000000000000000000000000000000000000081565b61012f6102a33660046125c3565b611cd6565b61012f6102b6366004612b93565b600360209081526000938452604080852082529284528284209052825290205481565b6102ec6102e7366004612bc8565b611db4565b005b61012f6102fc366004612b93565b600260209081526000938452604080852082529284528284209052825290205481565b610327612556565b60006002600054036103545760405162461bcd60e51b815260040161034b90612bea565b60405180910390fd5b60026000556040516321d1336160e11b8152600481018690527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906343a266c29060240161012060405180830381865afa1580156103bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103e39190612c31565b336000908152600360209081526040808320898452825280832082850151845290915281205491935090610418908690612cc7565b90506000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635dd8f6aa896040518263ffffffff1660e01b815260040161046b91815260200190565b602060405180830381865afa158015610488573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104ac9190612cda565b6001600160a01b031663a29a68146040518163ffffffff1660e01b8152600401602060405180830381865afa1580156104e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061050d9190612cda565b6001600160a01b0316637a81b56289876020015133336001600160a01b031663fc0c546a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610560573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105849190612cda565b6040518563ffffffff1660e01b81526004016105a39493929190612cf7565b6040805180830381865afa1580156105bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105e39190612d1e565b91509150818311806105f3575081155b1561061157604051635b76558960e11b815260040160405180910390fd5b8086146106315760405163e56ea4e760e01b815260040160405180910390fd5b6000336001600160a01b031663e5a6b10f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610671573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106959190612d42565b90508087146107505761074b886106ae6012600a612e3f565b604051635268657960e11b8152600481018b905260248101859052601260448201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a4d0caf2906064015b602060405180830381865afa158015610722573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107469190612d42565b611dfd565b610752565b875b9450610760338a8884611eca565b851115610780576040516317e53f6760e11b815260040160405180910390fd5b3360008181526003602090815260408083208d845282528083208a83015184528252808320889055928252600181528282208c8352905220546107c4908690612e4b565b3360009081526001602081815260408084209d84529c90529a81209190915598909855509296919550909350505050565b6107fd612556565b60006060806002600054036108245760405162461bcd60e51b815260040161034b90612bea565b60026000556040516321d1336160e11b8152600481018b90527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906343a266c29060240161012060405180830381865afa15801561088f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108b39190612c31565b80519094506000036108d85760405163174b338d60e11b815260040160405180910390fd5b61010084015160481c6001908116036109045760405163a3bb913360e01b815260040160405180910390fd5b61010084015160009060521c600190811614801561093a5750600061092e86610100015160541c90565b6001600160a01b031614155b15610a8c576000604051806101400160405280336001600160a01b031681526020018f6001600160a01b031681526020018e80360381019061097c9190612e5e565b815260208082018f905288015160408201526001600160a01b038c16606082015260a080890151608083015261010089015191019060181c61ffff1681526020018a8a8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050908252506020018890529050610a0d86610100015160541c90565b6001600160a01b031663d46cf171826040518263ffffffff1660e01b8152600401610a389190612ecd565b6000604051808303816000875af1158015610a57573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610a7f9190810190613038565b955093509150610acd9050565b8460a00151905087878080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509294505050505b825160208d01359015610b495760005b8451811015610b47576000858281518110610afa57610afa613169565b602002602001015160200151905080600014610b3e5782811115610b31576040516336a8da9360e11b815260040160405180910390fd5b610b3b8184612e4b565b92505b50600101610add565b505b8c60200135600003610b61575060009350610cae9050565b8015610bc8573360009081526001602090815260408083208f8452909152902054610b8d908290612cc7565b60016000336001600160a01b03166001600160a01b0316815260200190815260200160002060008e8152602001908152602001600020819055505b5080600003610bdb575060009250610cae565b60408c0135600060608e01358c14610c8c57604051635268657960e11b815260608f01356004820152602481018d9052604481018390526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063a4d0caf290606401602060405180830381865afa158015610c63573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c879190612d42565b610c97565b610c9782600a612e3f565b9050610ca88e602001358483611dfd565b95505050505b600160008190555098509850985098945050505050565b6000600260005403610ce95760405162461bcd60e51b815260040161034b90612bea565b600260009081556040516321d1336160e11b8152600481018490527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906343a266c29060240161012060405180830381865afa158015610d56573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d7a9190612c31565b610100810151909150604d1c600190811614610da9576040516373e4f05f60e11b815260040160405180910390fd5b505033600090815260016020818152604080842094845293905291812080549082905591905590565b610dda612556565b6000606080600260005403610e015760405162461bcd60e51b815260040161034b90612bea565b60026000556040516321d1336160e11b8152600481018990527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906343a266c29060240161012060405180830381865afa158015610e6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e909190612c31565b610100810151909450604a1c600190811603610ebf5760405163a97cf58f60e01b815260040160405180910390fd5b610ef3604051806080016040528060006001600160a01b031681526020016000815260200160008152602001600081525090565b6000806000336001600160a01b031663fc0c546a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f5a9190612cda565b90506000336001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f9c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fc09190612d42565b90506000336001600160a01b031663e5a6b10f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611002573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110269190612d42565b6101008b015190915060511c60019081161461104d57611048338f8c84611eca565b611058565b6110588e83836121a5565b94507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635dd8f6aa8f6040518263ffffffff1660e01b81526004016110a891815260200190565b602060405180830381865afa1580156110c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110e99190612cda565b6001600160a01b031663c18f2d318f6040518263ffffffff1660e01b815260040161111691815260200190565b602060405180830381865afa158015611133573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111579190612d42565b9350838d111561117957604051625c579160e91b815260040160405180910390fd5b841561118f5761118c8e8b8f8789612387565b98505b604080516080810182526001600160a01b03949094168452602084018a9052830191909152606082015261010088015190935060531c60019081161480156111ef575060006111e388610100015160541c90565b6001600160a01b031614155b156113c657604051633157d5c760e21b8152600481018c90526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063c55f571c90602401602060405180830381865afa15801561125c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611280919061317f565b90506000604051806101800160405280336001600160a01b031681526020018f6001600160a01b031681526020018e81526020018a6020015181526020018d81526020018481526020018581526020018681526020016112ed8b6101000151600160519190911c81161490565b151581526020016000846002811115611308576113086131a0565b1461131b576113168b6124bf565b611324565b6113248b6124dc565b81526020018c81526020018b815250905061134489610100015160541c90565b6001600160a01b031663a51cfd18826040518263ffffffff1660e01b815260040161136f91906131b6565b6000604051808303816000875af115801561138e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526113b691908101906132ae565b91995090975095506113ca915050565b8893505b50508251849150156114245760005b83518110156114225760008482815181106113f6576113f6613169565b602002602001015160200151905080600014611419576114168184612cc7565b92505b506001016113d9565b505b3360009081526001602090815260408083208c845290915290205481111561145f576040516317e53f6760e11b815260040160405180910390fd5b8015611487573360009081526001602090815260408083208c84529091529020805482900390555b50600160008190555095509550955095915050565b6000816000036114ae5750600061155e565b828411156114be5750600061155e565b6040516321d1336160e11b8152600481018690526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906343a266c29060240161012060405180830381865afa158015611527573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061154b9190612c31565b905061155a8682878787612387565b9150505b949350505050565b60006115738484846121a5565b90505b9392505050565b6040516321d1336160e11b81526004810184905260009081906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906343a266c29060240161012060405180830381865afa1580156115e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061160c9190612c31565b9050600083611687576116828787848a6001600160a01b031663e5a6b10f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611659573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061167d9190612d42565b611eca565b611754565b61175486886001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156116c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116ed9190612d42565b896001600160a01b031663e5a6b10f6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561172b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061174f9190612d42565b6121a5565b9050806000036117695760009250505061155e565b604051632eec7b5560e11b8152600481018790526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635dd8f6aa90602401602060405180830381865afa1580156117d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117f59190612cda565b6001600160a01b031663c18f2d31886040518263ffffffff1660e01b815260040161182291815260200190565b602060405180830381865afa15801561183f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118639190612d42565b905080861115611879576000935050505061155e565b6118868784888486612387565b98975050505050505050565b61189a612556565b60006002600054036118be5760405162461bcd60e51b815260040161034b90612bea565b60026000556040516321d1336160e11b8152600481018690527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906343a266c29060240161012060405180830381865afa158015611929573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061194d9190612c31565b61010081015190925060491c60019081160361197c5760405163861e9dcd60e01b815260040160405180910390fd5b3360009081526002602090815260408083208884528252808320855184529091528120546119ab908690612cc7565b90506000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635dd8f6aa896040518263ffffffff1660e01b81526004016119fe91815260200190565b602060405180830381865afa158015611a1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a3f9190612cda565b6001600160a01b031663a29a68146040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aa09190612cda565b6001600160a01b031663e8db213089876020015133336001600160a01b031663fc0c546a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611af3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b179190612cda565b6040518563ffffffff1660e01b8152600401611b369493929190612cf7565b6040805180830381865afa158015611b52573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b769190612d1e565b9150915081831180611b86575081155b15611ba457604051630236b92b60e21b815260040160405180910390fd5b808614611bc45760405163e56ea4e760e01b815260040160405180910390fd5b6000336001600160a01b031663e5a6b10f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611c04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c289190612d42565b9050808714611c4657611c41886106ae6012600a612e3f565b611c48565b875b3360009081526001602090815260408083208d8452909152902054909550851115611c86576040516317e53f6760e11b815260040160405180910390fd5b50503360008181526002602090815260408083208b845282528083208851845282528083209590955591815260018083528482209982529890915291822080548490039055509490945593915050565b6000611dab83837f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166343a266c2866040518263ffffffff1660e01b8152600401611d2b91815260200190565b61012060405180830381865afa158015611d49573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d6d9190612c31565b866001600160a01b031663e5a6b10f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611659573d6000803e3d6000fd5b90505b92915050565b336000908152600160209081526040808320858452909152902054611dda908290612cc7565b336000908152600160209081526040808320958352949052929092209190915550565b6000808060001985870985870292508281108382030391505080600003611e3757838281611e2d57611e2d6133ce565b0492505050611576565b838110611e6157604051631dcf306360e21b8152600481018290526024810185905260440161034b565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b6001600160a01b0384166000908152600160209081526040808320868452909152812054808203611eff57600091505061155e565b604051632eec7b5560e11b81526004810186905260009081906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690635dd8f6aa90602401602060405180830381865afa158015611f69573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f8d9190612cda565b6001600160a01b031663a29a68146040518163ffffffff1660e01b8152600401602060405180830381865afa158015611fca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fee9190612cda565b6001600160a01b031663e8db21308888602001518b8c6001600160a01b031663fc0c546a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612041573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120659190612cda565b6040518563ffffffff1660e01b81526004016120849493929190612cf7565b6040805180830381865afa1580156120a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120c49190612d1e565b6001600160a01b038a1660009081526002602090815260408083208c845282528083208b518452909152812054929450909250906121029084612e4b565b905080158015906121135750858214155b1561218657612183816121286012600a612e3f565b604051635268657960e11b815260048101869052602481018a9052601260448201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a4d0caf290606401610705565b90505b808411612194576000612198565b8084035b9998505050505050505050565b60405163d175415360e01b81526004810184905260009081906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063d175415390602401600060405180830381865afa15801561220f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261223791908101906133e4565b90506000805b82518110156122e25782818151811061225857612258613169565b60200260200101516001600160a01b031663a32e1e96886040518263ffffffff1660e01b815260040161228d91815260200190565b602060405180830381865afa1580156122aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122ce9190612d42565b6122d89083612cc7565b915060010161223d565b5060006001851461235d57604051635268657960e11b8152600160048201526024810186905260126044820152612358908390670de0b6b3a7640000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063a4d0caf290606401610705565b61235f565b815b90508560121461237a57612375816012886124f9565b61237c565b805b979650505050505050565b60008284036123975750806124b6565b600080604051633157d5c760e21b8152600481018990527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063c55f571c90602401602060405180830381865afa1580156123ff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612423919061317f565b6002811115612434576124346131a0565b1461244757612442866124bf565b612450565b612450866124dc565b9050806000036124645760009150506124b6565b6000612471848787611dfd565b905061271082036124855791506124b69050565b6124b18161249f8861249986612710612e4b565b89611dfd565b6124a99085612cc7565b612710611dfd565b925050505b95945050505050565b60006028826101000151901c61ffff16612710611dae9190612e4b565b60006038826101000151901c61ffff16612710611dae9190612e4b565b6000828203612509575082611576565b828211156125375761251b8383612e4b565b61252690600a612e3f565b6125309085613473565b9050611576565b6125418284612e4b565b61254c90600a612e3f565b6125309085613492565b6040518061012001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b03168152602001600081525090565b6001600160a01b03811681146125c057600080fd5b50565b600080604083850312156125d657600080fd5b82356125e1816125ab565b946020939093013593505050565b60008060006060848603121561260457600080fd5b505081359360208301359350604090920135919050565b805182526020808201519083015260408082015190830152606080820151908301526080808201519083015260a0808201519083015260c0808201519083015260e0808201516001600160a01b03169083015261010090810151910152565b6101408101612689828561261b565b826101208301529392505050565b60008083601f8401126126a957600080fd5b50813567ffffffffffffffff8111156126c157600080fd5b6020830191508360208285010111156126d957600080fd5b9250929050565b634e487b7160e01b600052604160045260246000fd5b604051610120810167ffffffffffffffff8111828210171561271a5761271a6126e0565b60405290565b6040516060810167ffffffffffffffff8111828210171561271a5761271a6126e0565b604051601f8201601f1916810167ffffffffffffffff8111828210171561276c5761276c6126e0565b604052919050565b600067ffffffffffffffff82111561278e5761278e6126e0565b50601f01601f191660200190565b60006127af6127aa84612774565b612743565b90508281528383830111156127c357600080fd5b828260208301376000602084830101529392505050565b600082601f8301126127eb57600080fd5b611dab8383356020850161279c565b600080600080600080600080888a0361014081121561281857600080fd5b8935612823816125ab565b98506080601f198201121561283757600080fd5b5060208901965060a0890135955060c0890135945060e089013561285a816125ab565b935061010089013567ffffffffffffffff8082111561287857600080fd5b6128848c838d01612697565b90955093506101208b013591508082111561289e57600080fd5b506128ab8b828c016127da565b9150509295985092959890939650565b60005b838110156128d65781810151838201526020016128be565b50506000910152565b600081518084526128f78160208601602086016128bb565b601f01601f19169290920160200192915050565b600061018080830161291d848961261b565b61012084018790526101408401919091528451908190526101a080840191600581901b850190910190602080880160005b838110156129a65787850361019f19018652815180516001600160a01b031686528381015184870152604090810151606091870182905290612992818801836128df565b97850197965050509082019060010161294e565b505050508381036101608501526124b181866128df565b6000602082840312156129cf57600080fd5b5035919050565b600080600080600060a086880312156129ee57600080fd5b85356129f9816125ab565b94506020860135935060408601359250606086013567ffffffffffffffff80821115612a2457600080fd5b818801915088601f830112612a3857600080fd5b612a478983356020850161279c565b93506080880135915080821115612a5d57600080fd5b50612a6a888289016127da565b9150509295509295909350565b6000610180808301612a89848961261b565b61012084018790526101408401919091528451908190526101a080840191600581901b850190910190602080880160005b838110156129a65787850361019f19018652815180516001600160a01b031686528381015184870152604090810151606091870182905290612afe818801836128df565b978501979650505090820190600101612aba565b60008060008060808587031215612b2857600080fd5b5050823594602084013594506040840135936060013592509050565b60008060008060808587031215612b5a57600080fd5b8435612b65816125ab565b9350602085013592506040850135915060608501358015158114612b8857600080fd5b939692955090935050565b600080600060608486031215612ba857600080fd5b8335612bb3816125ab565b95602085013595506040909401359392505050565b60008060408385031215612bdb57600080fd5b50508035926020909101359150565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b8051612c2c816125ab565b919050565b60006101208284031215612c4457600080fd5b612c4c6126f6565b825181526020830151602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c0820152612c9860e08401612c21565b60e0820152610100928301519281019290925250919050565b634e487b7160e01b600052601160045260246000fd5b80820180821115611dae57611dae612cb1565b600060208284031215612cec57600080fd5b8151611576816125ab565b93845260208401929092526001600160a01b03908116604084015216606082015260800190565b60008060408385031215612d3157600080fd5b505080516020909101519092909150565b600060208284031215612d5457600080fd5b5051919050565b600181815b80851115612d96578160001904821115612d7c57612d7c612cb1565b80851615612d8957918102915b93841c9390800290612d60565b509250929050565b600082612dad57506001611dae565b81612dba57506000611dae565b8160018114612dd05760028114612dda57612df6565b6001915050611dae565b60ff841115612deb57612deb612cb1565b50506001821b611dae565b5060208310610133831016604e8410600b8410161715612e19575081810a611dae565b612e238383612d5b565b8060001904821115612e3757612e37612cb1565b029392505050565b6000611dab8383612d9e565b81810381811115611dae57611dae612cb1565b600060808284031215612e7057600080fd5b6040516080810181811067ffffffffffffffff82111715612e9357612e936126e0565b6040528235612ea1816125ab565b808252506020830135602082015260408301356040820152606083013560608201528091505092915050565b60208152612ee76020820183516001600160a01b03169052565b60006020830151612f0360408401826001600160a01b03169052565b506040830151612f3d606084018280516001600160a01b031682526020808201519083015260408082015190830152606090810151910152565b50606083015160e08301526080830151610100818185015260a08501519150610120612f73818601846001600160a01b03169052565b60c086015161014086015260e08601516101608601528186015192506101a0915081610180860152612fa96101c08601846128df565b90860151858203601f190183870152909250612fc583826128df565b9695505050505050565b600082601f830112612fe057600080fd5b8151612fee6127aa82612774565b81815284602083860101111561300357600080fd5b61155e8260208301602087016128bb565b600067ffffffffffffffff82111561302e5761302e6126e0565b5060051b60200190565b60008060006060848603121561304d57600080fd5b8351925060208085015167ffffffffffffffff8082111561306d57600080fd5b61307988838901612fcf565b9450604087015191508082111561308f57600080fd5b818701915087601f8301126130a357600080fd5b81516130b16127aa82613014565b81815260059190911b8301840190848101908a8311156130d057600080fd5b8585015b83811015613158578051858111156130ec5760008081fd5b86016060818e03601f190112156131035760008081fd5b61310b612720565b88820151613118816125ab565b81526040820151898201526060820151878111156131365760008081fd5b6131448f8b83860101612fcf565b6040830152508452509186019186016130d4565b508096505050505050509250925092565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561319157600080fd5b81516003811061157657600080fd5b634e487b7160e01b600052602160045260246000fd5b602081526131d06020820183516001600160a01b03169052565b600060208301516131ec60408401826001600160a01b03169052565b506040830151606083015260608301516080830152608083015160a083015260a083015160c083015260c083015160e083015260e083015161010061325a8185018380516001600160a01b031682526020808201519083015260408082015190830152606090810151910152565b8401511515610180840152506101208301516101a08301526101408301516101e06101c084018190526132916102008501836128df565b9150610160850151601f198584030182860152612fc583826128df565b6000806000606084860312156132c357600080fd5b8351925060208085015167ffffffffffffffff808211156132e357600080fd5b6132ef88838901612fcf565b9450604087015191508082111561330557600080fd5b818701915087601f83011261331957600080fd5b81516133276127aa82613014565b81815260059190911b8301840190848101908a83111561334657600080fd5b8585015b83811015613158578051858111156133625760008081fd5b86016060818e03601f190112156133795760008081fd5b613381612720565b8882015161338e816125ab565b81526040820151898201526060820151878111156133ac5760008081fd5b6133ba8f8b83860101612fcf565b60408301525084525091860191860161334a565b634e487b7160e01b600052601260045260246000fd5b600060208083850312156133f757600080fd5b825167ffffffffffffffff81111561340e57600080fd5b8301601f8101851361341f57600080fd5b805161342d6127aa82613014565b81815260059190911b8201830190838101908783111561344c57600080fd5b928401925b8284101561237c578351613464816125ab565b82529284019290840190613451565b600081600019048311821515161561348d5761348d612cb1565b500290565b6000826134af57634e487b7160e01b600052601260045260246000fd5b50049056fea26469706673582212207c0b0d6ef21a30936e47f919249183a609014eddc061713ac513cccd6177f36164736f6c63430008100033", + "devdoc": { + "details": "This Store expects a project's controller to be an IJBController3_1.", + "kind": "dev", + "methods": { + "constructor": { + "params": { + "_directory": "A contract storing directories of terminals and controllers for each project.", + "_fundingCycleStore": "A contract storing all funding cycle configurations.", + "_prices": "A contract that exposes price feeds." + } + }, + "currentOverflowOf(address,uint256)": { + "details": "The current overflow is represented as a fixed point number with the same amount of decimals as the specified terminal.", + "params": { + "_projectId": "The ID of the project to get overflow for.", + "_terminal": "The terminal for which the overflow is being calculated." + }, + "returns": { + "_0": "The current amount of overflow that project has in the specified terminal." + } + }, + "currentReclaimableOverflowOf(address,uint256,uint256,bool)": { + "details": "If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.The current reclaimable overflow is returned in terms of the specified terminal's currency.The reclaimable overflow is represented as a fixed point number with the same amount of decimals as the specified terminal.", + "params": { + "_projectId": "The ID of the project to get the reclaimable overflow amount for.", + "_terminal": "The terminal from which the reclaimable amount would come.", + "_tokenCount": "The number of tokens to make the calculation with, as a fixed point number with 18 decimals.", + "_useTotalOverflow": "A flag indicating whether the overflow used in the calculation should be summed from all of the project's terminals. If false, overflow should be limited to the amount in the specified `_terminal`." + }, + "returns": { + "_0": "The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_terminal`." + } + }, + "currentReclaimableOverflowOf(uint256,uint256,uint256,uint256)": { + "details": "If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.", + "params": { + "_overflow": "The amount of overflow to make the calculation with, as a fixed point number.", + "_projectId": "The ID of the project to get the reclaimable overflow amount for.", + "_tokenCount": "The number of tokens to make the calculation with, as a fixed point number with 18 decimals.", + "_totalSupply": "The total number of tokens to make the calculation with, as a fixed point number with 18 decimals." + }, + "returns": { + "_0": "The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_overflow`." + } + }, + "currentTotalOverflowOf(uint256,uint256,uint256)": { + "params": { + "_currency": "The currency that the total overflow should be in terms of.", + "_decimals": "The number of decimals that the fixed point overflow should include.", + "_projectId": "The ID of the project to get total overflow for." + }, + "returns": { + "_0": "The current total amount of overflow that project has across all terminals." + } + }, + "recordAddedBalanceFor(uint256,uint256)": { + "details": "The msg.sender must be an IJBSingleTokenPaymentTerminal.", + "params": { + "_amount": "The amount of terminal tokens added, as a fixed point number with the same amount of decimals as its relative terminal.", + "_projectId": "The ID of the project to which the funds being added belong." + } + }, + "recordDistributionFor(uint256,uint256,uint256)": { + "details": "The msg.sender must be an IJBSingleTokenPaymentTerminal.", + "params": { + "_amount": "The amount to use from the distribution limit, as a fixed point number.", + "_currency": "The currency of the `_amount`. This must match the project's current funding cycle's currency.", + "_projectId": "The ID of the project that is having funds distributed." + }, + "returns": { + "distributedAmount": "The amount of terminal tokens distributed, as a fixed point number with the same amount of decimals as its relative terminal.", + "fundingCycle": "The funding cycle during which the distribution was made." + } + }, + "recordMigration(uint256)": { + "details": "The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount returned is in terms of the msg.senders tokens.", + "params": { + "_projectId": "The ID of the project being migrated." + }, + "returns": { + "balance": "The project's migrated balance, as a fixed point number with the same amount of decimals as its relative terminal." + } + }, + "recordPaymentFrom(address,(address,uint256,uint256,uint256),uint256,uint256,address,string,bytes)": { + "details": "Mints the project's tokens according to values provided by a configured data source. If no data source is configured, mints tokens proportional to the amount of the contribution.The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.sender's tokens.", + "params": { + "_amount": "The amount of tokens being paid. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.", + "_baseWeightCurrency": "The currency to base token issuance on.", + "_beneficiary": "The specified address that should be the beneficiary of anything that results from the payment.", + "_memo": "A memo to pass along to the emitted event, and passed along to the funding cycle's data source.", + "_metadata": "Bytes to send along to the data source, if one is provided.", + "_payer": "The original address that sent the payment to the terminal.", + "_projectId": "The ID of the project being paid." + }, + "returns": { + "delegateAllocations": "The amount to send to delegates instead of adding to the local balance.", + "fundingCycle": "The project's funding cycle during which payment was made.", + "memo": "A memo that should be passed along to the emitted event.", + "tokenCount": "The number of project tokens that were minted, as a fixed point number with 18 decimals." + } + }, + "recordRedemptionFor(address,uint256,uint256,string,bytes)": { + "details": "Redeems the project's tokens according to values provided by a configured data source. If no data source is configured, redeems tokens along a redemption bonding curve that is a function of the number of tokens being burned.The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.senders tokens.", + "params": { + "_holder": "The account that is having its tokens redeemed.", + "_memo": "A memo to pass along to the emitted event.", + "_metadata": "Bytes to send along to the data source, if one is provided.", + "_projectId": "The ID of the project to which the tokens being redeemed belong.", + "_tokenCount": "The number of project tokens to redeem, as a fixed point number with 18 decimals." + }, + "returns": { + "delegateAllocations": "The amount to send to delegates instead of sending to the beneficiary.", + "fundingCycle": "The funding cycle during which the redemption was made.", + "memo": "A memo that should be passed along to the emitted event.", + "reclaimAmount": "The amount of terminal tokens reclaimed, as a fixed point number with 18 decimals." + } + }, + "recordUsedAllowanceOf(uint256,uint256,uint256)": { + "details": "The msg.sender must be an IJBSingleTokenPaymentTerminal.", + "params": { + "_amount": "The amount to use from the allowance, as a fixed point number.", + "_currency": "The currency of the `_amount`. Must match the currency of the overflow allowance.", + "_projectId": "The ID of the project to use the allowance of." + }, + "returns": { + "fundingCycle": "The funding cycle during which the overflow allowance is being used.", + "usedAmount": "The amount of terminal tokens used, as a fixed point number with the same amount of decimals as its relative terminal." + } + } + }, + "stateVariables": { + "balanceOf": { + "custom:param": "_terminal The terminal to which the balance applies._projectId The ID of the project to get the balance of.", + "details": "The balance is represented as a fixed point number with the same amount of decimals as its relative terminal." + }, + "usedDistributionLimitOf": { + "custom:param": "_terminal The terminal to which the used distribution limit applies._projectId The ID of the project to get the used distribution limit of._fundingCycleNumber The number of the funding cycle during which the distribution limit was used.", + "details": "Increases as projects use their preconfigured distribution limits.The used distribution limit is represented as a fixed point number with the same amount of decimals as its relative terminal." + }, + "usedOverflowAllowanceOf": { + "custom:param": "_terminal The terminal to which the overflow allowance applies._projectId The ID of the project to get the used overflow allowance of._configuration The configuration of the during which the allowance was used.", + "details": "Increases as projects use their allowance.The used allowance is represented as a fixed point number with the same amount of decimals as its relative terminal." + } + }, + "version": 1 + }, + "userdoc": { + "errors": { + "PRBMath__MulDivOverflow(uint256,uint256)": [ + { + "notice": "Emitted when the result overflows uint256." + } + ] + }, + "kind": "user", + "methods": { + "balanceOf(address,uint256)": { + "notice": "The amount of tokens that each project has for each terminal, in terms of the terminal's token." + }, + "currentOverflowOf(address,uint256)": { + "notice": "Gets the current overflowed amount in a terminal for a specified project." + }, + "currentReclaimableOverflowOf(address,uint256,uint256,bool)": { + "notice": "The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the total token supply and overflow in the ecosystem." + }, + "currentReclaimableOverflowOf(uint256,uint256,uint256,uint256)": { + "notice": "The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the specified total token supply and overflow amounts." + }, + "currentTotalOverflowOf(uint256,uint256,uint256)": { + "notice": "Gets the current overflowed amount for a specified project across all terminals." + }, + "directory()": { + "notice": "The directory of terminals and controllers for projects." + }, + "fundingCycleStore()": { + "notice": "The contract storing all funding cycle configurations." + }, + "prices()": { + "notice": "The contract that exposes price feeds." + }, + "recordAddedBalanceFor(uint256,uint256)": { + "notice": "Records newly added funds for the project." + }, + "recordDistributionFor(uint256,uint256,uint256)": { + "notice": "Records newly distributed funds for a project." + }, + "recordMigration(uint256)": { + "notice": "Records the migration of funds from this store." + }, + "recordPaymentFrom(address,(address,uint256,uint256,uint256),uint256,uint256,address,string,bytes)": { + "notice": "Records newly contributed tokens to a project." + }, + "recordRedemptionFor(address,uint256,uint256,string,bytes)": { + "notice": "Records newly redeemed tokens of a project." + }, + "recordUsedAllowanceOf(uint256,uint256,uint256)": { + "notice": "Records newly used allowance funds of a project." + }, + "usedDistributionLimitOf(address,uint256,uint256)": { + "notice": "The amount of funds that a project has distributed from its limit during the current funding cycle for each terminal, in terms of the distribution limit's currency." + }, + "usedOverflowAllowanceOf(address,uint256,uint256)": { + "notice": "The amount of funds that a project has used from its allowance during the current funding cycle configuration for each terminal, in terms of the overflow allowance's currency." + } + }, + "notice": "Manages all bookkeeping for inflows and outflows of funds from any ISingleTokenPaymentTerminal.", + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 773, + "contract": "contracts/JBSingleTokenPaymentTerminalStore3_1_1.sol:JBSingleTokenPaymentTerminalStore3_1_1", + "label": "_status", + "offset": 0, + "slot": "0", + "type": "t_uint256" + }, + { + "astId": 19905, + "contract": "contracts/JBSingleTokenPaymentTerminalStore3_1_1.sol:JBSingleTokenPaymentTerminalStore3_1_1", + "label": "balanceOf", + "offset": 0, + "slot": "1", + "type": "t_mapping(t_contract(IJBSingleTokenPaymentTerminal)34671,t_mapping(t_uint256,t_uint256))" + }, + { + "astId": 19916, + "contract": "contracts/JBSingleTokenPaymentTerminalStore3_1_1.sol:JBSingleTokenPaymentTerminalStore3_1_1", + "label": "usedDistributionLimitOf", + "offset": 0, + "slot": "2", + "type": "t_mapping(t_contract(IJBSingleTokenPaymentTerminal)34671,t_mapping(t_uint256,t_mapping(t_uint256,t_uint256)))" + }, + { + "astId": 19927, + "contract": "contracts/JBSingleTokenPaymentTerminalStore3_1_1.sol:JBSingleTokenPaymentTerminalStore3_1_1", + "label": "usedOverflowAllowanceOf", + "offset": 0, + "slot": "3", + "type": "t_mapping(t_contract(IJBSingleTokenPaymentTerminal)34671,t_mapping(t_uint256,t_mapping(t_uint256,t_uint256)))" + } + ], + "types": { + "t_contract(IJBSingleTokenPaymentTerminal)34671": { + "encoding": "inplace", + "label": "contract IJBSingleTokenPaymentTerminal", + "numberOfBytes": "20" + }, + "t_mapping(t_contract(IJBSingleTokenPaymentTerminal)34671,t_mapping(t_uint256,t_mapping(t_uint256,t_uint256)))": { + "encoding": "mapping", + "key": "t_contract(IJBSingleTokenPaymentTerminal)34671", + "label": "mapping(contract IJBSingleTokenPaymentTerminal => mapping(uint256 => mapping(uint256 => uint256)))", + "numberOfBytes": "32", + "value": "t_mapping(t_uint256,t_mapping(t_uint256,t_uint256))" + }, + "t_mapping(t_contract(IJBSingleTokenPaymentTerminal)34671,t_mapping(t_uint256,t_uint256))": { + "encoding": "mapping", + "key": "t_contract(IJBSingleTokenPaymentTerminal)34671", + "label": "mapping(contract IJBSingleTokenPaymentTerminal => mapping(uint256 => uint256))", + "numberOfBytes": "32", + "value": "t_mapping(t_uint256,t_uint256)" + }, + "t_mapping(t_uint256,t_mapping(t_uint256,t_uint256))": { + "encoding": "mapping", + "key": "t_uint256", + "label": "mapping(uint256 => mapping(uint256 => uint256))", + "numberOfBytes": "32", + "value": "t_mapping(t_uint256,t_uint256)" + }, + "t_mapping(t_uint256,t_uint256)": { + "encoding": "mapping", + "key": "t_uint256", + "label": "mapping(uint256 => uint256)", + "numberOfBytes": "32", + "value": "t_uint256" + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + } + } + } +} \ No newline at end of file diff --git a/deployments/goerli/solcInputs/11cb1f66a0f8213d7bf83deb0ae9d2f7.json b/deployments/goerli/solcInputs/11cb1f66a0f8213d7bf83deb0ae9d2f7.json new file mode 100644 index 000000000..45acfbc43 --- /dev/null +++ b/deployments/goerli/solcInputs/11cb1f66a0f8213d7bf83deb0ae9d2f7.json @@ -0,0 +1,461 @@ +{ + "language": "Solidity", + "sources": { + "contracts/abstract/JBControllerUtility.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {IJBControllerUtility} from './../interfaces/IJBControllerUtility.sol';\nimport {IJBDirectory} from './../interfaces/IJBDirectory.sol';\n\n/// @notice Provides tools for contracts with functionality that can only be accessed by a project's controller.\nabstract contract JBControllerUtility is IJBControllerUtility {\n //*********************************************************************//\n // --------------------------- custom errors -------------------------- //\n //*********************************************************************//\n error CONTROLLER_UNAUTHORIZED();\n\n //*********************************************************************//\n // ---------------------------- modifiers ---------------------------- //\n //*********************************************************************//\n\n /// @notice Only allows the controller of the specified project to proceed.\n /// @param _projectId The ID of the project.\n modifier onlyController(uint256 _projectId) {\n if (address(directory.controllerOf(_projectId)) != msg.sender) revert CONTROLLER_UNAUTHORIZED();\n _;\n }\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n constructor(IJBDirectory _directory) {\n directory = _directory;\n }\n}\n" + }, + "contracts/interfaces/IJBControllerUtility.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBDirectory} from './IJBDirectory.sol';\n\ninterface IJBControllerUtility {\n function directory() external view returns (IJBDirectory);\n}\n" + }, + "contracts/interfaces/IJBDirectory.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\nimport {IJBProjects} from './IJBProjects.sol';\n\ninterface IJBDirectory {\n event SetController(uint256 indexed projectId, address indexed controller, address caller);\n\n event AddTerminal(uint256 indexed projectId, IJBPaymentTerminal indexed terminal, address caller);\n\n event SetTerminals(uint256 indexed projectId, IJBPaymentTerminal[] terminals, address caller);\n\n event SetPrimaryTerminal(\n uint256 indexed projectId,\n address indexed token,\n IJBPaymentTerminal indexed terminal,\n address caller\n );\n\n event SetIsAllowedToSetFirstController(address indexed addr, bool indexed flag, address caller);\n\n function projects() external view returns (IJBProjects);\n\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\n\n function controllerOf(uint256 projectId) external view returns (address);\n\n function isAllowedToSetFirstController(address account) external view returns (bool);\n\n function terminalsOf(uint256 projectId) external view returns (IJBPaymentTerminal[] memory);\n\n function isTerminalOf(\n uint256 projectId,\n IJBPaymentTerminal terminal\n ) external view returns (bool);\n\n function primaryTerminalOf(\n uint256 projectId,\n address token\n ) external view returns (IJBPaymentTerminal);\n\n function setControllerOf(uint256 projectId, address controller) external;\n\n function setTerminalsOf(uint256 projectId, IJBPaymentTerminal[] calldata terminals) external;\n\n function setPrimaryTerminalOf(\n uint256 projectId,\n address token,\n IJBPaymentTerminal terminal\n ) external;\n\n function setIsAllowedToSetFirstController(address account, bool flag) external;\n}\n" + }, + "contracts/interfaces/IJBFundingCycleStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBBallotState} from './../enums/JBBallotState.sol';\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\nimport {JBFundingCycleData} from './../structs/JBFundingCycleData.sol';\n\ninterface IJBFundingCycleStore {\n event Configure(\n uint256 indexed configuration,\n uint256 indexed projectId,\n JBFundingCycleData data,\n uint256 metadata,\n uint256 mustStartAtOrAfter,\n address caller\n );\n\n event Init(uint256 indexed configuration, uint256 indexed projectId, uint256 indexed basedOn);\n\n function latestConfigurationOf(uint256 projectId) external view returns (uint256);\n\n function get(\n uint256 projectId,\n uint256 configuration\n ) external view returns (JBFundingCycle memory);\n\n function latestConfiguredOf(\n uint256 projectId\n ) external view returns (JBFundingCycle memory fundingCycle, JBBallotState ballotState);\n\n function queuedOf(uint256 projectId) external view returns (JBFundingCycle memory fundingCycle);\n\n function currentOf(uint256 projectId) external view returns (JBFundingCycle memory fundingCycle);\n\n function currentBallotStateOf(uint256 projectId) external view returns (JBBallotState);\n\n function configureFor(\n uint256 projectId,\n JBFundingCycleData calldata data,\n uint256 metadata,\n uint256 mustStartAtOrAfter\n ) external returns (JBFundingCycle memory fundingCycle);\n}\n" + }, + "contracts/interfaces/IJBPaymentTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\n\ninterface IJBPaymentTerminal is IERC165 {\n function acceptsToken(address token, uint256 projectId) external view returns (bool);\n\n function currencyForToken(address token) external view returns (uint256);\n\n function decimalsForToken(address token) external view returns (uint256);\n\n // Return value must be a fixed point number with 18 decimals.\n function currentEthOverflowOf(uint256 projectId) external view returns (uint256);\n\n function pay(\n uint256 projectId,\n uint256 amount,\n address token,\n address beneficiary,\n uint256 minReturnedTokens,\n bool preferClaimedTokens,\n string calldata memo,\n bytes calldata metadata\n ) external payable returns (uint256 beneficiaryTokenCount);\n\n function addToBalanceOf(\n uint256 projectId,\n uint256 amount,\n address token,\n string calldata memo,\n bytes calldata metadata\n ) external payable;\n}\n" + }, + "contracts/interfaces/IJBProjects.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC721} from '@openzeppelin/contracts/token/ERC721/IERC721.sol';\nimport {JBProjectMetadata} from './../structs/JBProjectMetadata.sol';\nimport {IJBTokenUriResolver} from './IJBTokenUriResolver.sol';\n\ninterface IJBProjects is IERC721 {\n event Create(\n uint256 indexed projectId,\n address indexed owner,\n JBProjectMetadata metadata,\n address caller\n );\n\n event SetMetadata(uint256 indexed projectId, JBProjectMetadata metadata, address caller);\n\n event SetTokenUriResolver(IJBTokenUriResolver indexed resolver, address caller);\n\n function count() external view returns (uint256);\n\n function metadataContentOf(\n uint256 projectId,\n uint256 domain\n ) external view returns (string memory);\n\n function tokenUriResolver() external view returns (IJBTokenUriResolver);\n\n function createFor(\n address owner,\n JBProjectMetadata calldata metadata\n ) external returns (uint256 projectId);\n\n function setMetadataOf(uint256 projectId, JBProjectMetadata calldata metadata) external;\n\n function setTokenUriResolver(IJBTokenUriResolver newResolver) external;\n}\n" + }, + "contracts/enums/JBBallotState.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nenum JBBallotState {\n Active,\n Approved,\n Failed\n}\n" + }, + "contracts/structs/JBFundingCycle.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBFundingCycleBallot} from './../interfaces/IJBFundingCycleBallot.sol';\n\n/// @custom:member number The funding cycle number for the cycle's project. Each funding cycle has a number that is an increment of the cycle that directly preceded it. Each project's first funding cycle has a number of 1.\n/// @custom:member configuration The timestamp when the parameters for this funding cycle were configured. This value will stay the same for subsequent funding cycles that roll over from an originally configured cycle.\n/// @custom:member basedOn The `configuration` of the funding cycle that was active when this cycle was created.\n/// @custom:member start The timestamp marking the moment from which the funding cycle is considered active. It is a unix timestamp measured in seconds.\n/// @custom:member duration The number of seconds the funding cycle lasts for, after which a new funding cycle will start. A duration of 0 means that the funding cycle will stay active until the project owner explicitly issues a reconfiguration, at which point a new funding cycle will immediately start with the updated properties. If the duration is greater than 0, a project owner cannot make changes to a funding cycle's parameters while it is active – any proposed changes will apply to the subsequent cycle. If no changes are proposed, a funding cycle rolls over to another one with the same properties but new `start` timestamp and a discounted `weight`.\n/// @custom:member weight A fixed point number with 18 decimals that contracts can use to base arbitrary calculations on. For example, payment terminals can use this to determine how many tokens should be minted when a payment is received.\n/// @custom:member discountRate A percent by how much the `weight` of the subsequent funding cycle should be reduced, if the project owner hasn't configured the subsequent funding cycle with an explicit `weight`. If it's 0, each funding cycle will have equal weight. If the number is 90%, the next funding cycle will have a 10% smaller weight. This weight is out of `JBConstants.MAX_DISCOUNT_RATE`.\n/// @custom:member ballot An address of a contract that says whether a proposed reconfiguration should be accepted or rejected. It can be used to create rules around how a project owner can change funding cycle parameters over time.\n/// @custom:member metadata Extra data that can be associated with a funding cycle.\nstruct JBFundingCycle {\n uint256 number;\n uint256 configuration;\n uint256 basedOn;\n uint256 start;\n uint256 duration;\n uint256 weight;\n uint256 discountRate;\n IJBFundingCycleBallot ballot;\n uint256 metadata;\n}\n" + }, + "contracts/structs/JBFundingCycleData.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBFundingCycleBallot} from './../interfaces/IJBFundingCycleBallot.sol';\n\n/// @custom:member duration The number of seconds the funding cycle lasts for, after which a new funding cycle will start. A duration of 0 means that the funding cycle will stay active until the project owner explicitly issues a reconfiguration, at which point a new funding cycle will immediately start with the updated properties. If the duration is greater than 0, a project owner cannot make changes to a funding cycle's parameters while it is active – any proposed changes will apply to the subsequent cycle. If no changes are proposed, a funding cycle rolls over to another one with the same properties but new `start` timestamp and a discounted `weight`.\n/// @custom:member weight A fixed point number with 18 decimals that contracts can use to base arbitrary calculations on. For example, payment terminals can use this to determine how many tokens should be minted when a payment is received.\n/// @custom:member discountRate A percent by how much the `weight` of the subsequent funding cycle should be reduced, if the project owner hasn't configured the subsequent funding cycle with an explicit `weight`. If it's 0, each funding cycle will have equal weight. If the number is 90%, the next funding cycle will have a 10% smaller weight. This weight is out of `JBConstants.MAX_DISCOUNT_RATE`.\n/// @custom:member ballot An address of a contract that says whether a proposed reconfiguration should be accepted or rejected. It can be used to create rules around how a project owner can change funding cycle parameters over time.\nstruct JBFundingCycleData {\n uint256 duration;\n uint256 weight;\n uint256 discountRate;\n IJBFundingCycleBallot ballot;\n}\n" + }, + "contracts/interfaces/IJBFundingCycleBallot.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBBallotState} from './../enums/JBBallotState.sol';\n\ninterface IJBFundingCycleBallot is IERC165 {\n function duration() external view returns (uint256);\n\n function stateOf(\n uint256 projectId,\n uint256 configuration,\n uint256 start\n ) external view returns (JBBallotState);\n}\n" + }, + "@openzeppelin/contracts/utils/introspection/IERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n" + }, + "@openzeppelin/contracts/token/ERC721/IERC721.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../../utils/introspection/IERC165.sol\";\n\n/**\n * @dev Required interface of an ERC721 compliant contract.\n */\ninterface IERC721 is IERC165 {\n /**\n * @dev Emitted when `tokenId` token is transferred from `from` to `to`.\n */\n event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);\n\n /**\n * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.\n */\n event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);\n\n /**\n * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.\n */\n event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n /**\n * @dev Returns the number of tokens in ``owner``'s account.\n */\n function balanceOf(address owner) external view returns (uint256 balance);\n\n /**\n * @dev Returns the owner of the `tokenId` token.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n */\n function ownerOf(uint256 tokenId) external view returns (address owner);\n\n /**\n * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\n * are aware of the ERC721 protocol to prevent tokens from being forever locked.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must exist and be owned by `from`.\n * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId\n ) external;\n\n /**\n * @dev Transfers `tokenId` token from `from` to `to`.\n *\n * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must be owned by `from`.\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 tokenId\n ) external;\n\n /**\n * @dev Gives permission to `to` to transfer `tokenId` token to another account.\n * The approval is cleared when the token is transferred.\n *\n * Only a single account can be approved at a time, so approving the zero address clears previous approvals.\n *\n * Requirements:\n *\n * - The caller must own the token or be an approved operator.\n * - `tokenId` must exist.\n *\n * Emits an {Approval} event.\n */\n function approve(address to, uint256 tokenId) external;\n\n /**\n * @dev Returns the account approved for `tokenId` token.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n */\n function getApproved(uint256 tokenId) external view returns (address operator);\n\n /**\n * @dev Approve or remove `operator` as an operator for the caller.\n * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.\n *\n * Requirements:\n *\n * - The `operator` cannot be the caller.\n *\n * Emits an {ApprovalForAll} event.\n */\n function setApprovalForAll(address operator, bool _approved) external;\n\n /**\n * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.\n *\n * See {setApprovalForAll}\n */\n function isApprovedForAll(address owner, address operator) external view returns (bool);\n\n /**\n * @dev Safely transfers `tokenId` token from `from` to `to`.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must exist and be owned by `from`.\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId,\n bytes calldata data\n ) external;\n}\n" + }, + "contracts/structs/JBProjectMetadata.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @custom:member content The metadata content.\n/// @custom:member domain The domain within which the metadata applies.\nstruct JBProjectMetadata {\n string content;\n uint256 domain;\n}\n" + }, + "contracts/interfaces/IJBTokenUriResolver.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBTokenUriResolver {\n function getUri(uint256 projectId) external view returns (string memory tokenUri);\n}\n" + }, + "contracts/JBTokenStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {JBControllerUtility} from './abstract/JBControllerUtility.sol';\nimport {JBOperatable} from './abstract/JBOperatable.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {IJBToken} from './interfaces/IJBToken.sol';\nimport {IJBTokenStore} from './interfaces/IJBTokenStore.sol';\nimport {JBFundingCycleMetadataResolver} from './libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBOperations} from './libraries/JBOperations.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\nimport {JBToken} from './JBToken.sol';\n\n/// @notice Manage token minting, burning, and account balances.\n/// @dev Token balances can be either represented internally or claimed as ERC-20s into wallets. This contract manages these two representations and allows claiming.\n/// @dev The total supply of a project's tokens and the balance of each account are calculated in this contract.\n/// @dev Each project can bring their own token if they prefer, and swap between tokens at any time.\ncontract JBTokenStore is JBControllerUtility, JBOperatable, IJBTokenStore {\n // A library that parses the packed funding cycle metadata into a friendlier format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error ALREADY_SET();\n error EMPTY_NAME();\n error EMPTY_SYMBOL();\n error EMPTY_TOKEN();\n error INSUFFICIENT_FUNDS();\n error INSUFFICIENT_UNCLAIMED_TOKENS();\n error PROJECT_ALREADY_HAS_TOKEN();\n error RECIPIENT_ZERO_ADDRESS();\n error TOKEN_NOT_FOUND();\n error TOKENS_MUST_HAVE_18_DECIMALS();\n error TRANSFERS_PAUSED();\n error OVERFLOW_ALERT();\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice Mints ERC-721's that represent project ownership and transfers. \n IJBProjects public immutable override projects;\n\n /// @notice The contract storing all funding cycle configurations. \n IJBFundingCycleStore public immutable override fundingCycleStore;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice Each project's attached token contract.\n /// @custom:param _projectId The ID of the project to which the token belongs. \n mapping(uint256 => IJBToken) public override tokenOf;\n\n /// @notice The total supply of unclaimed tokens for each project.\n /// @custom:param _projectId The ID of the project to which the token belongs. \n mapping(uint256 => uint256) public override unclaimedTotalSupplyOf;\n\n /// @notice Each holder's balance of unclaimed tokens for each project.\n /// @custom:param _holder The holder of balance.\n /// @custom:param _projectId The ID of the project to which the token belongs.\n mapping(address => mapping(uint256 => uint256)) public override unclaimedBalanceOf;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice The total balance of tokens a holder has for a specified project, including claimed and unclaimed tokens.\n /// @param _holder The token holder to get a balance for.\n /// @param _projectId The project to get the `_holder`s balance of.\n /// @return balance The project token balance of the `_holder \n function balanceOf(address _holder, uint256 _projectId)\n external\n view\n override\n returns (uint256 balance)\n {\n // Get a reference to the holder's unclaimed balance for the project.\n balance = unclaimedBalanceOf[_holder][_projectId];\n\n // Get a reference to the project's current token.\n IJBToken _token = tokenOf[_projectId];\n\n // If the project has a current token, add the holder's balance to the total.\n if (_token != IJBToken(address(0))) balance = balance + _token.balanceOf(_holder, _projectId);\n }\n\n //*********************************************************************//\n // --------------------------- public views -------------------------- //\n //*********************************************************************//\n\n /// @notice The total supply of tokens for each project, including claimed and unclaimed tokens.\n /// @param _projectId The ID of the project to get the total token supply of.\n /// @return totalSupply The total supply of the project's tokens.\n function totalSupplyOf(uint256 _projectId) public view override returns (uint256 totalSupply) {\n // Get a reference to the total supply of the project's unclaimed tokens.\n totalSupply = unclaimedTotalSupplyOf[_projectId];\n\n // Get a reference to the project's current token.\n IJBToken _token = tokenOf[_projectId];\n\n // If the project has a current token, add its total supply to the total.\n if (_token != IJBToken(address(0))) totalSupply = totalSupply + _token.totalSupply(_projectId);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _fundingCycleStore A contract storing all funding cycle configurations.\n constructor(\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBFundingCycleStore _fundingCycleStore\n ) JBOperatable(_operatorStore) JBControllerUtility(_directory) {\n projects = _projects;\n fundingCycleStore = _fundingCycleStore;\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Issues a project's ERC-20 tokens that'll be used when claiming tokens.\n /// @dev Deploys a project's ERC-20 token contract.\n /// @dev Only a project's owner or operator can issue its token.\n /// @param _projectId The ID of the project being issued tokens.\n /// @param _name The ERC-20's name.\n /// @param _symbol The ERC-20's symbol.\n /// @return token The token that was issued.\n function issueFor(\n uint256 _projectId,\n string calldata _name,\n string calldata _symbol\n )\n external\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.ISSUE)\n returns (IJBToken token)\n {\n // There must be a name.\n if (bytes(_name).length == 0) revert EMPTY_NAME();\n\n // There must be a symbol.\n if (bytes(_symbol).length == 0) revert EMPTY_SYMBOL();\n \n // The project shouldn't already have a token.\n if (tokenOf[_projectId] != IJBToken(address(0))) revert PROJECT_ALREADY_HAS_TOKEN();\n\n // Deploy the token contract.\n token = new JBToken(_name, _symbol, _projectId);\n\n // Store the token contract.\n tokenOf[_projectId] = token;\n\n emit Issue(_projectId, token, _name, _symbol, msg.sender);\n }\n\n /// @notice Set a project's token if not already set.\n /// @dev Only a project's owner or operator can set its token.\n /// @param _projectId The ID of the project to which the set token belongs.\n /// @param _token The new token. \n function setFor(uint256 _projectId, IJBToken _token)\n external\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.SET_TOKEN)\n {\n // Can't set to the zero address.\n if (_token == IJBToken(address(0))) revert EMPTY_TOKEN();\n\n // Can't set token if already set.\n if (tokenOf[_projectId] != IJBToken(address(0))) revert ALREADY_SET();\n\n // Can't change to a token that doesn't use 18 decimals.\n if (_token.decimals() != 18) revert TOKENS_MUST_HAVE_18_DECIMALS();\n\n // Store the new token.\n tokenOf[_projectId] = _token;\n\n emit Set(_projectId, _token, msg.sender);\n }\n\n /// @notice Mint new project tokens.\n /// @dev Only a project's current controller can mint its tokens.\n /// @param _holder The address receiving the new tokens.\n /// @param _projectId The ID of the project to which the tokens belong.\n /// @param _amount The amount of tokens to mint.\n /// @param _preferClaimedTokens A flag indicating whether there's a preference for minted tokens to be claimed automatically into the `_holder`s wallet if the project currently has a token contract attached.\n function mintFor(\n address _holder,\n uint256 _projectId,\n uint256 _amount,\n bool _preferClaimedTokens\n ) external override onlyController(_projectId) {\n // Get a reference to the project's current token.\n IJBToken _token = tokenOf[_projectId];\n\n // Save a reference to whether there exists a token and the caller prefers these claimed tokens.\n bool _shouldClaimTokens = _preferClaimedTokens && _token != IJBToken(address(0));\n\n if (_shouldClaimTokens)\n // If tokens should be claimed, mint tokens into the holder's wallet.\n _token.mint(_projectId, _holder, _amount);\n else {\n // Otherwise, add the tokens to the unclaimed balance and total supply.\n unclaimedBalanceOf[_holder][_projectId] = unclaimedBalanceOf[_holder][_projectId] + _amount;\n unclaimedTotalSupplyOf[_projectId] = unclaimedTotalSupplyOf[_projectId] + _amount;\n }\n\n // The total supply can't exceed the maximum value storable in a uint224.\n if (totalSupplyOf(_projectId) > type(uint224).max) revert OVERFLOW_ALERT();\n\n emit Mint(_holder, _projectId, _amount, _shouldClaimTokens, _preferClaimedTokens, msg.sender);\n }\n\n /// @notice Burns a project's tokens.\n /// @dev Only a project's current controller can burn its tokens.\n /// @param _holder The address that owns the tokens being burned.\n /// @param _projectId The ID of the project to which the burned tokens belong.\n /// @param _amount The amount of tokens to burn.\n /// @param _preferClaimedTokens A flag indicating whether there's a preference for tokens to burned from the `_holder`s wallet if the project currently has a token contract attached.\n function burnFrom(\n address _holder,\n uint256 _projectId,\n uint256 _amount,\n bool _preferClaimedTokens\n ) external override onlyController(_projectId) {\n // Get a reference to the project's current token.\n IJBToken _token = tokenOf[_projectId];\n\n // Get a reference to the amount of unclaimed project tokens the holder has.\n uint256 _unclaimedBalance = unclaimedBalanceOf[_holder][_projectId];\n\n // Get a reference to the amount of the project's current token the holder has in their wallet.\n uint256 _claimedBalance = _token == IJBToken(address(0))\n ? 0\n : _token.balanceOf(_holder, _projectId);\n\n // There must be adequate tokens to burn across the holder's claimed and unclaimed balance.\n if (_amount > _claimedBalance + _unclaimedBalance) revert INSUFFICIENT_FUNDS();\n\n // The amount of tokens to burn.\n uint256 _claimedTokensToBurn;\n\n // Get a reference to how many claimed tokens should be burned\n if (_claimedBalance != 0)\n if (_preferClaimedTokens)\n // If prefer converted, burn the claimed tokens before the unclaimed.\n _claimedTokensToBurn = _claimedBalance < _amount ? _claimedBalance : _amount;\n // Otherwise, burn unclaimed tokens before claimed tokens.\n else {\n unchecked {\n _claimedTokensToBurn = _unclaimedBalance < _amount ? _amount - _unclaimedBalance : 0;\n }\n }\n\n // The amount of unclaimed tokens to burn.\n uint256 _unclaimedTokensToBurn;\n unchecked {\n _unclaimedTokensToBurn = _amount - _claimedTokensToBurn;\n }\n\n // Subtract the tokens from the unclaimed balance and total supply.\n if (_unclaimedTokensToBurn > 0) {\n // Reduce the holders balance and the total supply.\n unclaimedBalanceOf[_holder][_projectId] =\n unclaimedBalanceOf[_holder][_projectId] -\n _unclaimedTokensToBurn;\n unclaimedTotalSupplyOf[_projectId] =\n unclaimedTotalSupplyOf[_projectId] -\n _unclaimedTokensToBurn;\n }\n\n // Burn the claimed tokens.\n if (_claimedTokensToBurn > 0) _token.burn(_projectId, _holder, _claimedTokensToBurn);\n\n emit Burn(\n _holder,\n _projectId,\n _amount,\n _unclaimedBalance,\n _claimedBalance,\n _preferClaimedTokens,\n msg.sender\n );\n }\n\n /// @notice Claims internally accounted for tokens into a holder's wallet.\n /// @dev Only a token holder or an operator specified by the token holder can claim its unclaimed tokens.\n /// @param _holder The owner of the tokens being claimed.\n /// @param _projectId The ID of the project whose tokens are being claimed.\n /// @param _amount The amount of tokens to claim.\n function claimFor(\n address _holder,\n uint256 _projectId,\n uint256 _amount\n ) external override requirePermission(_holder, _projectId, JBOperations.CLAIM) {\n // Get a reference to the project's current token.\n IJBToken _token = tokenOf[_projectId];\n\n // The project must have a token contract attached.\n if (_token == IJBToken(address(0))) revert TOKEN_NOT_FOUND();\n\n // Get a reference to the amount of unclaimed project tokens the holder has.\n uint256 _unclaimedBalance = unclaimedBalanceOf[_holder][_projectId];\n\n // There must be enough unclaimed tokens to claim.\n if (_unclaimedBalance < _amount) revert INSUFFICIENT_UNCLAIMED_TOKENS();\n\n unchecked {\n // Subtract the claim amount from the holder's unclaimed project token balance.\n unclaimedBalanceOf[_holder][_projectId] = _unclaimedBalance - _amount;\n\n // Subtract the claim amount from the project's unclaimed total supply.\n unclaimedTotalSupplyOf[_projectId] = unclaimedTotalSupplyOf[_projectId] - _amount;\n }\n\n // Mint the equivalent amount of the project's token for the holder.\n _token.mint(_projectId, _holder, _amount);\n\n emit Claim(_holder, _projectId, _unclaimedBalance, _amount, msg.sender);\n }\n\n /// @notice Allows a holder to transfer unclaimed tokens to another account.\n /// @dev Only a token holder or an operator can transfer its unclaimed tokens.\n /// @param _holder The address to transfer tokens from.\n /// @param _projectId The ID of the project whose tokens are being transferred.\n /// @param _recipient The recipient of the tokens.\n /// @param _amount The amount of tokens to transfer.\n function transferFrom(\n address _holder,\n uint256 _projectId,\n address _recipient,\n uint256 _amount\n ) external override requirePermission(_holder, _projectId, JBOperations.TRANSFER) {\n // Get a reference to the current funding cycle for the project.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Must not be paused.\n if (_fundingCycle.global().pauseTransfers) revert TRANSFERS_PAUSED();\n\n // Can't transfer to the zero address.\n if (_recipient == address(0)) revert RECIPIENT_ZERO_ADDRESS();\n\n // Get a reference to the holder's unclaimed project token balance.\n uint256 _unclaimedBalance = unclaimedBalanceOf[_holder][_projectId];\n\n // The holder must have enough unclaimed tokens to transfer.\n if (_amount > _unclaimedBalance) revert INSUFFICIENT_UNCLAIMED_TOKENS();\n\n // Subtract from the holder's unclaimed token balance.\n unchecked {\n unclaimedBalanceOf[_holder][_projectId] = _unclaimedBalance - _amount;\n }\n\n // Add the unclaimed project tokens to the recipient's balance.\n unclaimedBalanceOf[_recipient][_projectId] =\n unclaimedBalanceOf[_recipient][_projectId] +\n _amount;\n\n emit Transfer(_holder, _projectId, _recipient, _amount, msg.sender);\n }\n}\n" + }, + "contracts/abstract/JBOperatable.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {IJBOperatable} from './../interfaces/IJBOperatable.sol';\nimport {IJBOperatorStore} from './../interfaces/IJBOperatorStore.sol';\n\n/// @notice Modifiers to allow access to functions based on the message sender's operator status.\nabstract contract JBOperatable is IJBOperatable {\n //*********************************************************************//\n // --------------------------- custom errors -------------------------- //\n //*********************************************************************//\n error UNAUTHORIZED();\n\n //*********************************************************************//\n // ---------------------------- modifiers ---------------------------- //\n //*********************************************************************//\n\n /// @notice Only allows the speficied account or an operator of the account to proceed.\n /// @param _account The account to check for.\n /// @param _domain The domain namespace to look for an operator within.\n /// @param _permissionIndex The index of the permission to check for.\n modifier requirePermission(\n address _account,\n uint256 _domain,\n uint256 _permissionIndex\n ) {\n _requirePermission(_account, _domain, _permissionIndex);\n _;\n }\n\n /// @notice Only allows the speficied account, an operator of the account to proceed, or a truthy override flag.\n /// @param _account The account to check for.\n /// @param _domain The domain namespace to look for an operator within.\n /// @param _permissionIndex The index of the permission to check for.\n /// @param _override A condition to force allowance for.\n modifier requirePermissionAllowingOverride(\n address _account,\n uint256 _domain,\n uint256 _permissionIndex,\n bool _override\n ) {\n _requirePermissionAllowingOverride(_account, _domain, _permissionIndex, _override);\n _;\n }\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice A contract storing operator assignments.\n IJBOperatorStore public immutable override operatorStore;\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _operatorStore A contract storing operator assignments.\n constructor(IJBOperatorStore _operatorStore) {\n operatorStore = _operatorStore;\n }\n\n //*********************************************************************//\n // -------------------------- internal views ------------------------- //\n //*********************************************************************//\n\n /// @notice Require the message sender is either the account or has the specified permission.\n /// @param _account The account to allow.\n /// @param _domain The domain namespace within which the permission index will be checked.\n /// @param _permissionIndex The permission index that an operator must have within the specified domain to be allowed.\n function _requirePermission(\n address _account,\n uint256 _domain,\n uint256 _permissionIndex\n ) internal view {\n if (\n msg.sender != _account &&\n !operatorStore.hasPermission(msg.sender, _account, _domain, _permissionIndex) &&\n !operatorStore.hasPermission(msg.sender, _account, 0, _permissionIndex)\n ) revert UNAUTHORIZED();\n }\n\n /// @notice Require the message sender is either the account, has the specified permission, or the override condition is true.\n /// @param _account The account to allow.\n /// @param _domain The domain namespace within which the permission index will be checked.\n /// @param _domain The permission index that an operator must have within the specified domain to be allowed.\n /// @param _override The override condition to allow.\n function _requirePermissionAllowingOverride(\n address _account,\n uint256 _domain,\n uint256 _permissionIndex,\n bool _override\n ) internal view {\n if (\n !_override &&\n msg.sender != _account &&\n !operatorStore.hasPermission(msg.sender, _account, _domain, _permissionIndex) &&\n !operatorStore.hasPermission(msg.sender, _account, 0, _permissionIndex)\n ) revert UNAUTHORIZED();\n }\n}\n" + }, + "contracts/interfaces/IJBOperatorStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBOperatorData} from './../structs/JBOperatorData.sol';\n\ninterface IJBOperatorStore {\n event SetOperator(\n address indexed operator,\n address indexed account,\n uint256 indexed domain,\n uint256[] permissionIndexes,\n uint256 packed\n );\n\n function permissionsOf(\n address operator,\n address account,\n uint256 domain\n ) external view returns (uint256);\n\n function hasPermission(\n address operator,\n address account,\n uint256 domain,\n uint256 permissionIndex\n ) external view returns (bool);\n\n function hasPermissions(\n address operator,\n address account,\n uint256 domain,\n uint256[] calldata permissionIndexes\n ) external view returns (bool);\n\n function setOperator(JBOperatorData calldata operatorData) external;\n\n function setOperators(JBOperatorData[] calldata operatorData) external;\n}\n" + }, + "contracts/interfaces/IJBToken.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBToken {\n function projectId() external view returns (uint256);\n\n function decimals() external view returns (uint8);\n\n function totalSupply(uint256 projectId) external view returns (uint256);\n\n function balanceOf(address account, uint256 projectId) external view returns (uint256);\n\n function mint(uint256 projectId, address account, uint256 amount) external;\n\n function burn(uint256 projectId, address account, uint256 amount) external;\n\n function approve(uint256, address spender, uint256 amount) external;\n\n function transfer(uint256 projectId, address to, uint256 amount) external;\n\n function transferFrom(uint256 projectId, address from, address to, uint256 amount) external;\n}\n" + }, + "contracts/interfaces/IJBTokenStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\nimport {IJBProjects} from './IJBProjects.sol';\nimport {IJBToken} from './IJBToken.sol';\n\ninterface IJBTokenStore {\n event Issue(\n uint256 indexed projectId,\n IJBToken indexed token,\n string name,\n string symbol,\n address caller\n );\n\n event Mint(\n address indexed holder,\n uint256 indexed projectId,\n uint256 amount,\n bool tokensWereClaimed,\n bool preferClaimedTokens,\n address caller\n );\n\n event Burn(\n address indexed holder,\n uint256 indexed projectId,\n uint256 amount,\n uint256 initialUnclaimedBalance,\n uint256 initialClaimedBalance,\n bool preferClaimedTokens,\n address caller\n );\n\n event Claim(\n address indexed holder,\n uint256 indexed projectId,\n uint256 initialUnclaimedBalance,\n uint256 amount,\n address caller\n );\n\n event Set(uint256 indexed projectId, IJBToken indexed newToken, address caller);\n\n event Transfer(\n address indexed holder,\n uint256 indexed projectId,\n address indexed recipient,\n uint256 amount,\n address caller\n );\n\n function tokenOf(uint256 projectId) external view returns (IJBToken);\n\n function projects() external view returns (IJBProjects);\n\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\n\n function unclaimedBalanceOf(address holder, uint256 projectId) external view returns (uint256);\n\n function unclaimedTotalSupplyOf(uint256 projectId) external view returns (uint256);\n\n function totalSupplyOf(uint256 projectId) external view returns (uint256);\n\n function balanceOf(address holder, uint256 projectId) external view returns (uint256 result);\n\n function issueFor(\n uint256 projectId,\n string calldata name,\n string calldata symbol\n ) external returns (IJBToken token);\n\n function setFor(uint256 projectId, IJBToken token) external;\n\n function burnFrom(\n address holder,\n uint256 projectId,\n uint256 amount,\n bool preferClaimedTokens\n ) external;\n\n function mintFor(\n address holder,\n uint256 projectId,\n uint256 amount,\n bool preferClaimedTokens\n ) external;\n\n function claimFor(address holder, uint256 projectId, uint256 amount) external;\n\n function transferFrom(\n address holder,\n uint256 projectId,\n address recipient,\n uint256 amount\n ) external;\n}\n" + }, + "contracts/libraries/JBFundingCycleMetadataResolver.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\nimport {JBFundingCycleMetadata} from './../structs/JBFundingCycleMetadata.sol';\nimport {JBGlobalFundingCycleMetadata} from './../structs/JBGlobalFundingCycleMetadata.sol';\nimport {JBConstants} from './JBConstants.sol';\nimport {JBGlobalFundingCycleMetadataResolver} from './JBGlobalFundingCycleMetadataResolver.sol';\n\nlibrary JBFundingCycleMetadataResolver {\n function global(JBFundingCycle memory _fundingCycle)\n internal\n pure\n returns (JBGlobalFundingCycleMetadata memory)\n {\n return JBGlobalFundingCycleMetadataResolver.expandMetadata(uint8(_fundingCycle.metadata >> 8));\n }\n\n function reservedRate(JBFundingCycle memory _fundingCycle) internal pure returns (uint256) {\n return uint256(uint16(_fundingCycle.metadata >> 24));\n }\n\n function redemptionRate(JBFundingCycle memory _fundingCycle) internal pure returns (uint256) {\n // Redemption rate is a number 0-10000. It's inverse was stored so the most common case of 100% results in no storage needs.\n return JBConstants.MAX_REDEMPTION_RATE - uint256(uint16(_fundingCycle.metadata >> 40));\n }\n\n function ballotRedemptionRate(JBFundingCycle memory _fundingCycle)\n internal\n pure\n returns (uint256)\n {\n // Redemption rate is a number 0-10000. It's inverse was stored so the most common case of 100% results in no storage needs.\n return JBConstants.MAX_REDEMPTION_RATE - uint256(uint16(_fundingCycle.metadata >> 56));\n }\n\n function payPaused(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\n return ((_fundingCycle.metadata >> 72) & 1) == 1;\n }\n\n function distributionsPaused(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\n return ((_fundingCycle.metadata >> 73) & 1) == 1;\n }\n\n function redeemPaused(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\n return ((_fundingCycle.metadata >> 74) & 1) == 1;\n }\n\n function burnPaused(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\n return ((_fundingCycle.metadata >> 75) & 1) == 1;\n }\n\n function mintingAllowed(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\n return ((_fundingCycle.metadata >> 76) & 1) == 1;\n }\n\n function terminalMigrationAllowed(JBFundingCycle memory _fundingCycle)\n internal\n pure\n returns (bool)\n {\n return ((_fundingCycle.metadata >> 77) & 1) == 1;\n }\n\n function controllerMigrationAllowed(JBFundingCycle memory _fundingCycle)\n internal\n pure\n returns (bool)\n {\n return ((_fundingCycle.metadata >> 78) & 1) == 1;\n }\n\n function shouldHoldFees(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\n return ((_fundingCycle.metadata >> 79) & 1) == 1;\n }\n\n function preferClaimedTokenOverride(JBFundingCycle memory _fundingCycle)\n internal\n pure\n returns (bool)\n {\n return ((_fundingCycle.metadata >> 80) & 1) == 1;\n }\n\n function useTotalOverflowForRedemptions(JBFundingCycle memory _fundingCycle)\n internal\n pure\n returns (bool)\n {\n return ((_fundingCycle.metadata >> 81) & 1) == 1;\n }\n\n function useDataSourceForPay(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\n return (_fundingCycle.metadata >> 82) & 1 == 1;\n }\n\n function useDataSourceForRedeem(JBFundingCycle memory _fundingCycle)\n internal\n pure\n returns (bool)\n {\n return (_fundingCycle.metadata >> 83) & 1 == 1;\n }\n\n function dataSource(JBFundingCycle memory _fundingCycle) internal pure returns (address) {\n return address(uint160(_fundingCycle.metadata >> 84));\n }\n\n function metadata(JBFundingCycle memory _fundingCycle) internal pure returns (uint256) {\n return uint256(uint8(_fundingCycle.metadata >> 244));\n }\n\n /// @notice Pack the funding cycle metadata.\n /// @param _metadata The metadata to validate and pack.\n /// @return packed The packed uint256 of all metadata params. The first 8 bits specify the version. \n function packFundingCycleMetadata(JBFundingCycleMetadata memory _metadata)\n internal\n pure\n returns (uint256 packed)\n {\n // version 1 in the bits 0-7 (8 bits).\n packed = 1;\n // global metadta in bits 8-23 (16 bits).\n packed |=\n JBGlobalFundingCycleMetadataResolver.packFundingCycleGlobalMetadata(_metadata.global) <<\n 8;\n // reserved rate in bits 24-39 (16 bits).\n packed |= _metadata.reservedRate << 24;\n // redemption rate in bits 40-55 (16 bits).\n // redemption rate is a number 0-10000. Store the reverse so the most common case of 100% results in no storage needs.\n packed |= (JBConstants.MAX_REDEMPTION_RATE - _metadata.redemptionRate) << 40;\n // ballot redemption rate rate in bits 56-71 (16 bits).\n // ballot redemption rate is a number 0-10000. Store the reverse so the most common case of 100% results in no storage needs.\n packed |= (JBConstants.MAX_REDEMPTION_RATE - _metadata.ballotRedemptionRate) << 56;\n // pause pay in bit 72.\n if (_metadata.pausePay) packed |= 1 << 72;\n // pause tap in bit 73.\n if (_metadata.pauseDistributions) packed |= 1 << 73;\n // pause redeem in bit 74.\n if (_metadata.pauseRedeem) packed |= 1 << 74;\n // pause burn in bit 75.\n if (_metadata.pauseBurn) packed |= 1 << 75;\n // allow minting in bit 76.\n if (_metadata.allowMinting) packed |= 1 << 76;\n // allow terminal migration in bit 77.\n if (_metadata.allowTerminalMigration) packed |= 1 << 77;\n // allow controller migration in bit 78.\n if (_metadata.allowControllerMigration) packed |= 1 << 78;\n // hold fees in bit 79.\n if (_metadata.holdFees) packed |= 1 << 79;\n // prefer claimed token override in bit 80.\n if (_metadata.preferClaimedTokenOverride) packed |= 1 << 80;\n // useTotalOverflowForRedemptions in bit 81.\n if (_metadata.useTotalOverflowForRedemptions) packed |= 1 << 81;\n // use pay data source in bit 82.\n if (_metadata.useDataSourceForPay) packed |= 1 << 82;\n // use redeem data source in bit 83.\n if (_metadata.useDataSourceForRedeem) packed |= 1 << 83;\n // data source address in bits 84-243.\n packed |= uint256(uint160(address(_metadata.dataSource))) << 84;\n // metadata in bits 244-252 (8 bits).\n packed |= _metadata.metadata << 244;\n }\n\n /// @notice Expand the funding cycle metadata.\n /// @param _fundingCycle The funding cycle having its metadata expanded.\n /// @return metadata The metadata object. \n function expandMetadata(JBFundingCycle memory _fundingCycle)\n internal\n pure\n returns (JBFundingCycleMetadata memory)\n {\n return\n JBFundingCycleMetadata(\n global(_fundingCycle),\n reservedRate(_fundingCycle),\n redemptionRate(_fundingCycle),\n ballotRedemptionRate(_fundingCycle),\n payPaused(_fundingCycle),\n distributionsPaused(_fundingCycle),\n redeemPaused(_fundingCycle),\n burnPaused(_fundingCycle),\n mintingAllowed(_fundingCycle),\n terminalMigrationAllowed(_fundingCycle),\n controllerMigrationAllowed(_fundingCycle),\n shouldHoldFees(_fundingCycle),\n preferClaimedTokenOverride(_fundingCycle),\n useTotalOverflowForRedemptions(_fundingCycle),\n useDataSourceForPay(_fundingCycle),\n useDataSourceForRedeem(_fundingCycle),\n dataSource(_fundingCycle),\n metadata(_fundingCycle)\n );\n }\n}\n" + }, + "contracts/libraries/JBOperations.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nlibrary JBOperations {\n uint256 public constant RECONFIGURE = 1;\n uint256 public constant REDEEM = 2;\n uint256 public constant MIGRATE_CONTROLLER = 3;\n uint256 public constant MIGRATE_TERMINAL = 4;\n uint256 public constant PROCESS_FEES = 5;\n uint256 public constant SET_METADATA = 6;\n uint256 public constant ISSUE = 7;\n uint256 public constant SET_TOKEN = 8;\n uint256 public constant MINT = 9;\n uint256 public constant BURN = 10;\n uint256 public constant CLAIM = 11;\n uint256 public constant TRANSFER = 12;\n uint256 public constant REQUIRE_CLAIM = 13; // unused in v3\n uint256 public constant SET_CONTROLLER = 14;\n uint256 public constant SET_TERMINALS = 15;\n uint256 public constant SET_PRIMARY_TERMINAL = 16;\n uint256 public constant USE_ALLOWANCE = 17;\n uint256 public constant SET_SPLITS = 18;\n}\n" + }, + "contracts/JBToken.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';\nimport {ERC20Votes, ERC20, ERC20Permit} from '@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.sol';\nimport {IJBToken} from './interfaces/IJBToken.sol';\n\n/// @notice An ERC-20 token that can be used by a project in the `JBTokenStore`.\ncontract JBToken is ERC20Votes, Ownable, IJBToken {\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error BAD_PROJECT();\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The ID of the project that this token should be exclusively used for. Send 0 to support any project.\n uint256 public immutable override projectId;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice The total supply of this ERC20.\n /// @param _projectId the ID of the project to which the token belongs. This is ignored.\n /// @return The total supply of this ERC20, as a fixed point number.\n function totalSupply(uint256 _projectId) external view override returns (uint256) {\n _projectId; // Prevents unused var compiler and natspec complaints.\n\n return super.totalSupply();\n }\n\n /// @notice An account's balance of this ERC20.\n /// @param _account The account to get a balance of.\n /// @param _projectId is the ID of the project to which the token belongs. This is ignored.\n /// @return The balance of the `_account` of this ERC20, as a fixed point number with 18 decimals.\n function balanceOf(\n address _account,\n uint256 _projectId\n ) external view override returns (uint256) {\n _account; // Prevents unused var compiler and natspec complaints.\n _projectId; // Prevents unused var compiler and natspec complaints.\n\n return super.balanceOf(_account);\n }\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice The number of decimals included in the fixed point accounting of this token.\n /// @return The number of decimals.\n function decimals() public view override(ERC20, IJBToken) returns (uint8) {\n return super.decimals();\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _name The name of the token.\n /// @param _symbol The symbol that the token should be represented by.\n /// @param _projectId The ID of the project that this token should be exclusively used for. Send 0 to support any project.\n constructor(\n string memory _name,\n string memory _symbol,\n uint256 _projectId\n ) ERC20(_name, _symbol) ERC20Permit(_name) {\n projectId = _projectId;\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Mints more of the token.\n /// @dev Only the owner of this contract cant mint more of it.\n /// @param _projectId The ID of the project to which the token belongs.\n /// @param _account The account to mint the tokens for.\n /// @param _amount The amount of tokens to mint, as a fixed point number with 18 decimals.\n function mint(uint256 _projectId, address _account, uint256 _amount) external override onlyOwner {\n // Can't mint for a wrong project.\n if (projectId != 0 && _projectId != projectId) revert BAD_PROJECT();\n\n return _mint(_account, _amount);\n }\n\n /// @notice Burn some outstanding tokens.\n /// @dev Only the owner of this contract cant burn some of its supply.\n /// @param _projectId The ID of the project to which the token belongs.\n /// @param _account The account to burn tokens from.\n /// @param _amount The amount of tokens to burn, as a fixed point number with 18 decimals.\n function burn(uint256 _projectId, address _account, uint256 _amount) external override onlyOwner {\n // Can't burn for a wrong project.\n if (projectId != 0 && _projectId != projectId) revert BAD_PROJECT();\n\n return _burn(_account, _amount);\n }\n\n /// @notice Approves an account to spend tokens on the `msg.sender`s behalf.\n /// @param _projectId the ID of the project to which the token belongs.\n /// @param _spender The address that will be spending tokens on the `msg.sender`s behalf.\n /// @param _amount The amount the `_spender` is allowed to spend.\n function approve(uint256 _projectId, address _spender, uint256 _amount) external override {\n // Can't approve for a wrong project.\n if (projectId != 0 && _projectId != projectId) revert BAD_PROJECT();\n\n approve(_spender, _amount);\n }\n\n /// @notice Transfer tokens to an account.\n /// @param _projectId The ID of the project to which the token belongs.\n /// @param _to The destination address.\n /// @param _amount The amount of the transfer, as a fixed point number with 18 decimals.\n function transfer(uint256 _projectId, address _to, uint256 _amount) external override {\n // Can't transfer for a wrong project.\n if (projectId != 0 && _projectId != projectId) revert BAD_PROJECT();\n\n transfer(_to, _amount);\n }\n\n /// @notice Transfer tokens between accounts.\n /// @param _projectId The ID of the project to which the token belongs.\n /// @param _from The originating address.\n /// @param _to The destination address.\n /// @param _amount The amount of the transfer, as a fixed point number with 18 decimals.\n function transferFrom(\n uint256 _projectId,\n address _from,\n address _to,\n uint256 _amount\n ) external override {\n // Can't transfer for a wrong project.\n if (projectId != 0 && _projectId != projectId) revert BAD_PROJECT();\n\n transferFrom(_from, _to, _amount);\n }\n}\n" + }, + "contracts/interfaces/IJBOperatable.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBOperatorStore} from './IJBOperatorStore.sol';\n\ninterface IJBOperatable {\n function operatorStore() external view returns (IJBOperatorStore);\n}\n" + }, + "contracts/structs/JBOperatorData.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @custom:member operator The address of the operator.\n/// @custom:member domain The domain within which the operator is being given permissions. A domain of 0 is a wildcard domain, which gives an operator access to all domains.\n/// @custom:member permissionIndexes The indexes of the permissions the operator is being given.\nstruct JBOperatorData {\n address operator;\n uint256 domain;\n uint256[] permissionIndexes;\n}\n" + }, + "contracts/structs/JBFundingCycleMetadata.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBGlobalFundingCycleMetadata} from './JBGlobalFundingCycleMetadata.sol';\n\n/// @custom:member global Data used globally in non-migratable ecosystem contracts.\n/// @custom:member reservedRate The reserved rate of the funding cycle. This number is a percentage calculated out of `JBConstants.MAX_RESERVED_RATE`.\n/// @custom:member redemptionRate The redemption rate of the funding cycle. This number is a percentage calculated out of `JBConstants.MAX_REDEMPTION_RATE`.\n/// @custom:member ballotRedemptionRate The redemption rate to use during an active ballot of the funding cycle. This number is a percentage calculated out of `JBConstants.MAX_REDEMPTION_RATE`.\n/// @custom:member pausePay A flag indicating if the pay functionality should be paused during the funding cycle.\n/// @custom:member pauseDistributions A flag indicating if the distribute functionality should be paused during the funding cycle.\n/// @custom:member pauseRedeem A flag indicating if the redeem functionality should be paused during the funding cycle.\n/// @custom:member pauseBurn A flag indicating if the burn functionality should be paused during the funding cycle.\n/// @custom:member allowMinting A flag indicating if minting tokens should be allowed during this funding cycle.\n/// @custom:member allowTerminalMigration A flag indicating if migrating terminals should be allowed during this funding cycle.\n/// @custom:member allowControllerMigration A flag indicating if migrating controllers should be allowed during this funding cycle.\n/// @custom:member holdFees A flag indicating if fees should be held during this funding cycle.\n/// @custom:member preferClaimedTokenOverride A flag indicating if claimed tokens should always be prefered to unclaimed tokens when minting.\n/// @custom:member useTotalOverflowForRedemptions A flag indicating if redemptions should use the project's balance held in all terminals instead of the project's local terminal balance from which the redemption is being fulfilled.\n/// @custom:member useDataSourceForPay A flag indicating if the data source should be used for pay transactions during this funding cycle.\n/// @custom:member useDataSourceForRedeem A flag indicating if the data source should be used for redeem transactions during this funding cycle.\n/// @custom:member dataSource The data source to use during this funding cycle.\n/// @custom:member metadata Metadata of the metadata, up to uint8 in size.\nstruct JBFundingCycleMetadata {\n JBGlobalFundingCycleMetadata global;\n uint256 reservedRate;\n uint256 redemptionRate;\n uint256 ballotRedemptionRate;\n bool pausePay;\n bool pauseDistributions;\n bool pauseRedeem;\n bool pauseBurn;\n bool allowMinting;\n bool allowTerminalMigration;\n bool allowControllerMigration;\n bool holdFees;\n bool preferClaimedTokenOverride;\n bool useTotalOverflowForRedemptions;\n bool useDataSourceForPay;\n bool useDataSourceForRedeem;\n address dataSource;\n uint256 metadata;\n}\n" + }, + "contracts/structs/JBGlobalFundingCycleMetadata.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @custom:member allowSetTerminals A flag indicating if setting terminals should be allowed during this funding cycle.\n/// @custom:member allowSetController A flag indicating if setting a new controller should be allowed during this funding cycle.\n/// @custom:member pauseTransfers A flag indicating if the project token transfer functionality should be paused during the funding cycle.\nstruct JBGlobalFundingCycleMetadata {\n bool allowSetTerminals;\n bool allowSetController;\n bool pauseTransfers;\n}\n" + }, + "contracts/libraries/JBConstants.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @notice Global constants used across Juicebox contracts.\nlibrary JBConstants {\n uint256 public constant MAX_RESERVED_RATE = 10_000;\n uint256 public constant MAX_REDEMPTION_RATE = 10_000;\n uint256 public constant MAX_DISCOUNT_RATE = 1_000_000_000;\n uint256 public constant SPLITS_TOTAL_PERCENT = 1_000_000_000;\n uint256 public constant MAX_FEE = 1_000_000_000;\n uint256 public constant MAX_FEE_DISCOUNT = 1_000_000_000;\n}\n" + }, + "contracts/libraries/JBGlobalFundingCycleMetadataResolver.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {JBFundingCycleMetadata} from './../structs/JBFundingCycleMetadata.sol';\nimport {JBGlobalFundingCycleMetadata} from './../structs/JBGlobalFundingCycleMetadata.sol';\n\nlibrary JBGlobalFundingCycleMetadataResolver {\n function setTerminalsAllowed(uint8 _data) internal pure returns (bool) {\n return (_data & 1) == 1;\n }\n\n function setControllerAllowed(uint8 _data) internal pure returns (bool) {\n return ((_data >> 1) & 1) == 1;\n }\n\n function transfersPaused(uint8 _data) internal pure returns (bool) {\n return ((_data >> 2) & 1) == 1;\n }\n\n /// @notice Pack the global funding cycle metadata.\n /// @param _metadata The metadata to validate and pack.\n /// @return packed The packed uint256 of all global metadata params. The first 8 bits specify the version.\n function packFundingCycleGlobalMetadata(\n JBGlobalFundingCycleMetadata memory _metadata\n ) internal pure returns (uint256 packed) {\n // allow set terminals in bit 0.\n if (_metadata.allowSetTerminals) packed |= 1;\n // allow set controller in bit 1.\n if (_metadata.allowSetController) packed |= 1 << 1;\n // pause transfers in bit 2.\n if (_metadata.pauseTransfers) packed |= 1 << 2;\n }\n\n /// @notice Expand the global funding cycle metadata.\n /// @param _packedMetadata The packed metadata to expand.\n /// @return metadata The global metadata object.\n function expandMetadata(\n uint8 _packedMetadata\n ) internal pure returns (JBGlobalFundingCycleMetadata memory metadata) {\n return\n JBGlobalFundingCycleMetadata(\n setTerminalsAllowed(_packedMetadata),\n setControllerAllowed(_packedMetadata),\n transfersPaused(_packedMetadata)\n );\n }\n}\n" + }, + "@openzeppelin/contracts/access/Ownable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n _;\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (token/ERC20/extensions/ERC20Votes.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./draft-ERC20Permit.sol\";\nimport \"../../../utils/math/Math.sol\";\nimport \"../../../governance/utils/IVotes.sol\";\nimport \"../../../utils/math/SafeCast.sol\";\nimport \"../../../utils/cryptography/ECDSA.sol\";\n\n/**\n * @dev Extension of ERC20 to support Compound-like voting and delegation. This version is more generic than Compound's,\n * and supports token supply up to 2^224^ - 1, while COMP is limited to 2^96^ - 1.\n *\n * NOTE: If exact COMP compatibility is required, use the {ERC20VotesComp} variant of this module.\n *\n * This extension keeps a history (checkpoints) of each account's vote power. Vote power can be delegated either\n * by calling the {delegate} function directly, or by providing a signature to be used with {delegateBySig}. Voting\n * power can be queried through the public accessors {getVotes} and {getPastVotes}.\n *\n * By default, token balance does not account for voting power. This makes transfers cheaper. The downside is that it\n * requires users to delegate to themselves in order to activate checkpoints and have their voting power tracked.\n *\n * _Available since v4.2._\n */\nabstract contract ERC20Votes is IVotes, ERC20Permit {\n struct Checkpoint {\n uint32 fromBlock;\n uint224 votes;\n }\n\n bytes32 private constant _DELEGATION_TYPEHASH =\n keccak256(\"Delegation(address delegatee,uint256 nonce,uint256 expiry)\");\n\n mapping(address => address) private _delegates;\n mapping(address => Checkpoint[]) private _checkpoints;\n Checkpoint[] private _totalSupplyCheckpoints;\n\n /**\n * @dev Get the `pos`-th checkpoint for `account`.\n */\n function checkpoints(address account, uint32 pos) public view virtual returns (Checkpoint memory) {\n return _checkpoints[account][pos];\n }\n\n /**\n * @dev Get number of checkpoints for `account`.\n */\n function numCheckpoints(address account) public view virtual returns (uint32) {\n return SafeCast.toUint32(_checkpoints[account].length);\n }\n\n /**\n * @dev Get the address `account` is currently delegating to.\n */\n function delegates(address account) public view virtual override returns (address) {\n return _delegates[account];\n }\n\n /**\n * @dev Gets the current votes balance for `account`\n */\n function getVotes(address account) public view virtual override returns (uint256) {\n uint256 pos = _checkpoints[account].length;\n return pos == 0 ? 0 : _checkpoints[account][pos - 1].votes;\n }\n\n /**\n * @dev Retrieve the number of votes for `account` at the end of `blockNumber`.\n *\n * Requirements:\n *\n * - `blockNumber` must have been already mined\n */\n function getPastVotes(address account, uint256 blockNumber) public view virtual override returns (uint256) {\n require(blockNumber < block.number, \"ERC20Votes: block not yet mined\");\n return _checkpointsLookup(_checkpoints[account], blockNumber);\n }\n\n /**\n * @dev Retrieve the `totalSupply` at the end of `blockNumber`. Note, this value is the sum of all balances.\n * It is but NOT the sum of all the delegated votes!\n *\n * Requirements:\n *\n * - `blockNumber` must have been already mined\n */\n function getPastTotalSupply(uint256 blockNumber) public view virtual override returns (uint256) {\n require(blockNumber < block.number, \"ERC20Votes: block not yet mined\");\n return _checkpointsLookup(_totalSupplyCheckpoints, blockNumber);\n }\n\n /**\n * @dev Lookup a value in a list of (sorted) checkpoints.\n */\n function _checkpointsLookup(Checkpoint[] storage ckpts, uint256 blockNumber) private view returns (uint256) {\n // We run a binary search to look for the earliest checkpoint taken after `blockNumber`.\n //\n // During the loop, the index of the wanted checkpoint remains in the range [low-1, high).\n // With each iteration, either `low` or `high` is moved towards the middle of the range to maintain the invariant.\n // - If the middle checkpoint is after `blockNumber`, we look in [low, mid)\n // - If the middle checkpoint is before or equal to `blockNumber`, we look in [mid+1, high)\n // Once we reach a single value (when low == high), we've found the right checkpoint at the index high-1, if not\n // out of bounds (in which case we're looking too far in the past and the result is 0).\n // Note that if the latest checkpoint available is exactly for `blockNumber`, we end up with an index that is\n // past the end of the array, so we technically don't find a checkpoint after `blockNumber`, but it works out\n // the same.\n uint256 high = ckpts.length;\n uint256 low = 0;\n while (low < high) {\n uint256 mid = Math.average(low, high);\n if (ckpts[mid].fromBlock > blockNumber) {\n high = mid;\n } else {\n low = mid + 1;\n }\n }\n\n return high == 0 ? 0 : ckpts[high - 1].votes;\n }\n\n /**\n * @dev Delegate votes from the sender to `delegatee`.\n */\n function delegate(address delegatee) public virtual override {\n _delegate(_msgSender(), delegatee);\n }\n\n /**\n * @dev Delegates votes from signer to `delegatee`\n */\n function delegateBySig(\n address delegatee,\n uint256 nonce,\n uint256 expiry,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) public virtual override {\n require(block.timestamp <= expiry, \"ERC20Votes: signature expired\");\n address signer = ECDSA.recover(\n _hashTypedDataV4(keccak256(abi.encode(_DELEGATION_TYPEHASH, delegatee, nonce, expiry))),\n v,\n r,\n s\n );\n require(nonce == _useNonce(signer), \"ERC20Votes: invalid nonce\");\n _delegate(signer, delegatee);\n }\n\n /**\n * @dev Maximum token supply. Defaults to `type(uint224).max` (2^224^ - 1).\n */\n function _maxSupply() internal view virtual returns (uint224) {\n return type(uint224).max;\n }\n\n /**\n * @dev Snapshots the totalSupply after it has been increased.\n */\n function _mint(address account, uint256 amount) internal virtual override {\n super._mint(account, amount);\n require(totalSupply() <= _maxSupply(), \"ERC20Votes: total supply risks overflowing votes\");\n\n _writeCheckpoint(_totalSupplyCheckpoints, _add, amount);\n }\n\n /**\n * @dev Snapshots the totalSupply after it has been decreased.\n */\n function _burn(address account, uint256 amount) internal virtual override {\n super._burn(account, amount);\n\n _writeCheckpoint(_totalSupplyCheckpoints, _subtract, amount);\n }\n\n /**\n * @dev Move voting power when tokens are transferred.\n *\n * Emits a {DelegateVotesChanged} event.\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual override {\n super._afterTokenTransfer(from, to, amount);\n\n _moveVotingPower(delegates(from), delegates(to), amount);\n }\n\n /**\n * @dev Change delegation for `delegator` to `delegatee`.\n *\n * Emits events {DelegateChanged} and {DelegateVotesChanged}.\n */\n function _delegate(address delegator, address delegatee) internal virtual {\n address currentDelegate = delegates(delegator);\n uint256 delegatorBalance = balanceOf(delegator);\n _delegates[delegator] = delegatee;\n\n emit DelegateChanged(delegator, currentDelegate, delegatee);\n\n _moveVotingPower(currentDelegate, delegatee, delegatorBalance);\n }\n\n function _moveVotingPower(\n address src,\n address dst,\n uint256 amount\n ) private {\n if (src != dst && amount > 0) {\n if (src != address(0)) {\n (uint256 oldWeight, uint256 newWeight) = _writeCheckpoint(_checkpoints[src], _subtract, amount);\n emit DelegateVotesChanged(src, oldWeight, newWeight);\n }\n\n if (dst != address(0)) {\n (uint256 oldWeight, uint256 newWeight) = _writeCheckpoint(_checkpoints[dst], _add, amount);\n emit DelegateVotesChanged(dst, oldWeight, newWeight);\n }\n }\n }\n\n function _writeCheckpoint(\n Checkpoint[] storage ckpts,\n function(uint256, uint256) view returns (uint256) op,\n uint256 delta\n ) private returns (uint256 oldWeight, uint256 newWeight) {\n uint256 pos = ckpts.length;\n oldWeight = pos == 0 ? 0 : ckpts[pos - 1].votes;\n newWeight = op(oldWeight, delta);\n\n if (pos > 0 && ckpts[pos - 1].fromBlock == block.number) {\n ckpts[pos - 1].votes = SafeCast.toUint224(newWeight);\n } else {\n ckpts.push(Checkpoint({fromBlock: SafeCast.toUint32(block.number), votes: SafeCast.toUint224(newWeight)}));\n }\n }\n\n function _add(uint256 a, uint256 b) private pure returns (uint256) {\n return a + b;\n }\n\n function _subtract(uint256 a, uint256 b) private pure returns (uint256) {\n return a - b;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Context.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-ERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./draft-IERC20Permit.sol\";\nimport \"../ERC20.sol\";\nimport \"../../../utils/cryptography/draft-EIP712.sol\";\nimport \"../../../utils/cryptography/ECDSA.sol\";\nimport \"../../../utils/Counters.sol\";\n\n/**\n * @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * _Available since v3.4._\n */\nabstract contract ERC20Permit is ERC20, IERC20Permit, EIP712 {\n using Counters for Counters.Counter;\n\n mapping(address => Counters.Counter) private _nonces;\n\n // solhint-disable-next-line var-name-mixedcase\n bytes32 private immutable _PERMIT_TYPEHASH =\n keccak256(\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\");\n\n /**\n * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `\"1\"`.\n *\n * It's a good idea to use the same `name` that is defined as the ERC20 token name.\n */\n constructor(string memory name) EIP712(name, \"1\") {}\n\n /**\n * @dev See {IERC20Permit-permit}.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) public virtual override {\n require(block.timestamp <= deadline, \"ERC20Permit: expired deadline\");\n\n bytes32 structHash = keccak256(abi.encode(_PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline));\n\n bytes32 hash = _hashTypedDataV4(structHash);\n\n address signer = ECDSA.recover(hash, v, r, s);\n require(signer == owner, \"ERC20Permit: invalid signature\");\n\n _approve(owner, spender, value);\n }\n\n /**\n * @dev See {IERC20Permit-nonces}.\n */\n function nonces(address owner) public view virtual override returns (uint256) {\n return _nonces[owner].current();\n }\n\n /**\n * @dev See {IERC20Permit-DOMAIN_SEPARATOR}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view override returns (bytes32) {\n return _domainSeparatorV4();\n }\n\n /**\n * @dev \"Consume a nonce\": return the current value and increment.\n *\n * _Available since v4.1._\n */\n function _useNonce(address owner) internal virtual returns (uint256 current) {\n Counters.Counter storage nonce = _nonces[owner];\n current = nonce.current();\n nonce.increment();\n }\n}\n" + }, + "@openzeppelin/contracts/utils/math/Math.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n /**\n * @dev Returns the largest of two numbers.\n */\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\n return a >= b ? a : b;\n }\n\n /**\n * @dev Returns the smallest of two numbers.\n */\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\n return a < b ? a : b;\n }\n\n /**\n * @dev Returns the average of two numbers. The result is rounded towards\n * zero.\n */\n function average(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b) / 2 can overflow.\n return (a & b) + (a ^ b) / 2;\n }\n\n /**\n * @dev Returns the ceiling of the division of two numbers.\n *\n * This differs from standard division with `/` in that it rounds up instead\n * of rounding down.\n */\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b - 1) / b can overflow on addition, so we distribute.\n return a / b + (a % b == 0 ? 0 : 1);\n }\n\n /**\n * @dev Returns the absolute unsigned value of a signed value.\n */\n function abs(int256 n) internal pure returns (uint256) {\n unchecked {\n // must be unchecked in order to support `n = type(int256).min`\n return uint256(n >= 0 ? n : -n);\n }\n }\n}\n" + }, + "@openzeppelin/contracts/governance/utils/IVotes.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (governance/utils/IVotes.sol)\npragma solidity ^0.8.0;\n\n/**\n * @dev Common interface for {ERC20Votes}, {ERC721Votes}, and other {Votes}-enabled contracts.\n *\n * _Available since v4.5._\n */\ninterface IVotes {\n /**\n * @dev Emitted when an account changes their delegate.\n */\n event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);\n\n /**\n * @dev Emitted when a token transfer or delegate change results in changes to a delegate's number of votes.\n */\n event DelegateVotesChanged(address indexed delegate, uint256 previousBalance, uint256 newBalance);\n\n /**\n * @dev Returns the current amount of votes that `account` has.\n */\n function getVotes(address account) external view returns (uint256);\n\n /**\n * @dev Returns the amount of votes that `account` had at the end of a past block (`blockNumber`).\n */\n function getPastVotes(address account, uint256 blockNumber) external view returns (uint256);\n\n /**\n * @dev Returns the total supply of votes available at the end of a past block (`blockNumber`).\n *\n * NOTE: This value is the sum of all available votes, which is not necessarily the sum of all delegated votes.\n * Votes that have not been delegated are still part of total supply, even though they would not participate in a\n * vote.\n */\n function getPastTotalSupply(uint256 blockNumber) external view returns (uint256);\n\n /**\n * @dev Returns the delegate that `account` has chosen.\n */\n function delegates(address account) external view returns (address);\n\n /**\n * @dev Delegates votes from the sender to `delegatee`.\n */\n function delegate(address delegatee) external;\n\n /**\n * @dev Delegates votes from signer to `delegatee`.\n */\n function delegateBySig(\n address delegatee,\n uint256 nonce,\n uint256 expiry,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n}\n" + }, + "@openzeppelin/contracts/utils/math/SafeCast.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeCast.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow\n * checks.\n *\n * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can\n * easily result in undesired exploitation or bugs, since developers usually\n * assume that overflows raise errors. `SafeCast` restores this intuition by\n * reverting the transaction when such an operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n *\n * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing\n * all math on `uint256` and `int256` and then downcasting.\n */\nlibrary SafeCast {\n /**\n * @dev Returns the downcasted uint224 from uint256, reverting on\n * overflow (when the input is greater than largest uint224).\n *\n * Counterpart to Solidity's `uint224` operator.\n *\n * Requirements:\n *\n * - input must fit into 224 bits\n */\n function toUint224(uint256 value) internal pure returns (uint224) {\n require(value <= type(uint224).max, \"SafeCast: value doesn't fit in 224 bits\");\n return uint224(value);\n }\n\n /**\n * @dev Returns the downcasted uint128 from uint256, reverting on\n * overflow (when the input is greater than largest uint128).\n *\n * Counterpart to Solidity's `uint128` operator.\n *\n * Requirements:\n *\n * - input must fit into 128 bits\n */\n function toUint128(uint256 value) internal pure returns (uint128) {\n require(value <= type(uint128).max, \"SafeCast: value doesn't fit in 128 bits\");\n return uint128(value);\n }\n\n /**\n * @dev Returns the downcasted uint96 from uint256, reverting on\n * overflow (when the input is greater than largest uint96).\n *\n * Counterpart to Solidity's `uint96` operator.\n *\n * Requirements:\n *\n * - input must fit into 96 bits\n */\n function toUint96(uint256 value) internal pure returns (uint96) {\n require(value <= type(uint96).max, \"SafeCast: value doesn't fit in 96 bits\");\n return uint96(value);\n }\n\n /**\n * @dev Returns the downcasted uint64 from uint256, reverting on\n * overflow (when the input is greater than largest uint64).\n *\n * Counterpart to Solidity's `uint64` operator.\n *\n * Requirements:\n *\n * - input must fit into 64 bits\n */\n function toUint64(uint256 value) internal pure returns (uint64) {\n require(value <= type(uint64).max, \"SafeCast: value doesn't fit in 64 bits\");\n return uint64(value);\n }\n\n /**\n * @dev Returns the downcasted uint32 from uint256, reverting on\n * overflow (when the input is greater than largest uint32).\n *\n * Counterpart to Solidity's `uint32` operator.\n *\n * Requirements:\n *\n * - input must fit into 32 bits\n */\n function toUint32(uint256 value) internal pure returns (uint32) {\n require(value <= type(uint32).max, \"SafeCast: value doesn't fit in 32 bits\");\n return uint32(value);\n }\n\n /**\n * @dev Returns the downcasted uint16 from uint256, reverting on\n * overflow (when the input is greater than largest uint16).\n *\n * Counterpart to Solidity's `uint16` operator.\n *\n * Requirements:\n *\n * - input must fit into 16 bits\n */\n function toUint16(uint256 value) internal pure returns (uint16) {\n require(value <= type(uint16).max, \"SafeCast: value doesn't fit in 16 bits\");\n return uint16(value);\n }\n\n /**\n * @dev Returns the downcasted uint8 from uint256, reverting on\n * overflow (when the input is greater than largest uint8).\n *\n * Counterpart to Solidity's `uint8` operator.\n *\n * Requirements:\n *\n * - input must fit into 8 bits.\n */\n function toUint8(uint256 value) internal pure returns (uint8) {\n require(value <= type(uint8).max, \"SafeCast: value doesn't fit in 8 bits\");\n return uint8(value);\n }\n\n /**\n * @dev Converts a signed int256 into an unsigned uint256.\n *\n * Requirements:\n *\n * - input must be greater than or equal to 0.\n */\n function toUint256(int256 value) internal pure returns (uint256) {\n require(value >= 0, \"SafeCast: value must be positive\");\n return uint256(value);\n }\n\n /**\n * @dev Returns the downcasted int128 from int256, reverting on\n * overflow (when the input is less than smallest int128 or\n * greater than largest int128).\n *\n * Counterpart to Solidity's `int128` operator.\n *\n * Requirements:\n *\n * - input must fit into 128 bits\n *\n * _Available since v3.1._\n */\n function toInt128(int256 value) internal pure returns (int128) {\n require(value >= type(int128).min && value <= type(int128).max, \"SafeCast: value doesn't fit in 128 bits\");\n return int128(value);\n }\n\n /**\n * @dev Returns the downcasted int64 from int256, reverting on\n * overflow (when the input is less than smallest int64 or\n * greater than largest int64).\n *\n * Counterpart to Solidity's `int64` operator.\n *\n * Requirements:\n *\n * - input must fit into 64 bits\n *\n * _Available since v3.1._\n */\n function toInt64(int256 value) internal pure returns (int64) {\n require(value >= type(int64).min && value <= type(int64).max, \"SafeCast: value doesn't fit in 64 bits\");\n return int64(value);\n }\n\n /**\n * @dev Returns the downcasted int32 from int256, reverting on\n * overflow (when the input is less than smallest int32 or\n * greater than largest int32).\n *\n * Counterpart to Solidity's `int32` operator.\n *\n * Requirements:\n *\n * - input must fit into 32 bits\n *\n * _Available since v3.1._\n */\n function toInt32(int256 value) internal pure returns (int32) {\n require(value >= type(int32).min && value <= type(int32).max, \"SafeCast: value doesn't fit in 32 bits\");\n return int32(value);\n }\n\n /**\n * @dev Returns the downcasted int16 from int256, reverting on\n * overflow (when the input is less than smallest int16 or\n * greater than largest int16).\n *\n * Counterpart to Solidity's `int16` operator.\n *\n * Requirements:\n *\n * - input must fit into 16 bits\n *\n * _Available since v3.1._\n */\n function toInt16(int256 value) internal pure returns (int16) {\n require(value >= type(int16).min && value <= type(int16).max, \"SafeCast: value doesn't fit in 16 bits\");\n return int16(value);\n }\n\n /**\n * @dev Returns the downcasted int8 from int256, reverting on\n * overflow (when the input is less than smallest int8 or\n * greater than largest int8).\n *\n * Counterpart to Solidity's `int8` operator.\n *\n * Requirements:\n *\n * - input must fit into 8 bits.\n *\n * _Available since v3.1._\n */\n function toInt8(int256 value) internal pure returns (int8) {\n require(value >= type(int8).min && value <= type(int8).max, \"SafeCast: value doesn't fit in 8 bits\");\n return int8(value);\n }\n\n /**\n * @dev Converts an unsigned uint256 into a signed int256.\n *\n * Requirements:\n *\n * - input must be less than or equal to maxInt256.\n */\n function toInt256(uint256 value) internal pure returns (int256) {\n // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive\n require(value <= uint256(type(int256).max), \"SafeCast: value doesn't fit in an int256\");\n return int256(value);\n }\n}\n" + }, + "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n // Check the signature length\n // - case 65: r,s,v signature (standard)\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else if (signature.length == 64) {\n bytes32 r;\n bytes32 vs;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n vs := mload(add(signature, 0x40))\n }\n return tryRecover(hash, r, vs);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/ERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `recipient` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address recipient, uint256 amount) public virtual override returns (bool) {\n _transfer(_msgSender(), recipient, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n _approve(_msgSender(), spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `sender` and `recipient` cannot be the zero address.\n * - `sender` must have a balance of at least `amount`.\n * - the caller must have allowance for ``sender``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) public virtual override returns (bool) {\n uint256 currentAllowance = _allowances[sender][_msgSender()];\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: transfer amount exceeds allowance\");\n unchecked {\n _approve(sender, _msgSender(), currentAllowance - amount);\n }\n }\n\n _transfer(sender, recipient, amount);\n\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n _approve(_msgSender(), spender, _allowances[_msgSender()][spender] + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n uint256 currentAllowance = _allowances[_msgSender()][spender];\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(_msgSender(), spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `sender` cannot be the zero address.\n * - `recipient` cannot be the zero address.\n * - `sender` must have a balance of at least `amount`.\n */\n function _transfer(\n address sender,\n address recipient,\n uint256 amount\n ) internal virtual {\n require(sender != address(0), \"ERC20: transfer from the zero address\");\n require(recipient != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(sender, recipient, amount);\n\n uint256 senderBalance = _balances[sender];\n require(senderBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[sender] = senderBalance - amount;\n }\n _balances[recipient] += amount;\n\n emit Transfer(sender, recipient, amount);\n\n _afterTokenTransfer(sender, recipient, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" + }, + "@openzeppelin/contracts/utils/cryptography/draft-EIP712.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/cryptography/draft-EIP712.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./ECDSA.sol\";\n\n/**\n * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.\n *\n * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,\n * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding\n * they need in their contracts using a combination of `abi.encode` and `keccak256`.\n *\n * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding\n * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA\n * ({_hashTypedDataV4}).\n *\n * The implementation of the domain separator was designed to be as efficient as possible while still properly updating\n * the chain id to protect against replay attacks on an eventual fork of the chain.\n *\n * NOTE: This contract implements the version of the encoding known as \"v4\", as implemented by the JSON RPC method\n * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].\n *\n * _Available since v3.4._\n */\nabstract contract EIP712 {\n /* solhint-disable var-name-mixedcase */\n // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to\n // invalidate the cached domain separator if the chain id changes.\n bytes32 private immutable _CACHED_DOMAIN_SEPARATOR;\n uint256 private immutable _CACHED_CHAIN_ID;\n address private immutable _CACHED_THIS;\n\n bytes32 private immutable _HASHED_NAME;\n bytes32 private immutable _HASHED_VERSION;\n bytes32 private immutable _TYPE_HASH;\n\n /* solhint-enable var-name-mixedcase */\n\n /**\n * @dev Initializes the domain separator and parameter caches.\n *\n * The meaning of `name` and `version` is specified in\n * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:\n *\n * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.\n * - `version`: the current major version of the signing domain.\n *\n * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart\n * contract upgrade].\n */\n constructor(string memory name, string memory version) {\n bytes32 hashedName = keccak256(bytes(name));\n bytes32 hashedVersion = keccak256(bytes(version));\n bytes32 typeHash = keccak256(\n \"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\"\n );\n _HASHED_NAME = hashedName;\n _HASHED_VERSION = hashedVersion;\n _CACHED_CHAIN_ID = block.chainid;\n _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion);\n _CACHED_THIS = address(this);\n _TYPE_HASH = typeHash;\n }\n\n /**\n * @dev Returns the domain separator for the current chain.\n */\n function _domainSeparatorV4() internal view returns (bytes32) {\n if (address(this) == _CACHED_THIS && block.chainid == _CACHED_CHAIN_ID) {\n return _CACHED_DOMAIN_SEPARATOR;\n } else {\n return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION);\n }\n }\n\n function _buildDomainSeparator(\n bytes32 typeHash,\n bytes32 nameHash,\n bytes32 versionHash\n ) private view returns (bytes32) {\n return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this)));\n }\n\n /**\n * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this\n * function returns the hash of the fully encoded EIP712 message for this domain.\n *\n * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:\n *\n * ```solidity\n * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(\n * keccak256(\"Mail(address to,string contents)\"),\n * mailTo,\n * keccak256(bytes(mailContents))\n * )));\n * address signer = ECDSA.recover(digest, signature);\n * ```\n */\n function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {\n return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Counters.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Counters.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @title Counters\n * @author Matt Condon (@shrugs)\n * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number\n * of elements in a mapping, issuing ERC721 ids, or counting request ids.\n *\n * Include with `using Counters for Counters.Counter;`\n */\nlibrary Counters {\n struct Counter {\n // This variable should never be directly accessed by users of the library: interactions must be restricted to\n // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add\n // this feature: see https://github.com/ethereum/solidity/issues/4637\n uint256 _value; // default: 0\n }\n\n function current(Counter storage counter) internal view returns (uint256) {\n return counter._value;\n }\n\n function increment(Counter storage counter) internal {\n unchecked {\n counter._value += 1;\n }\n }\n\n function decrement(Counter storage counter) internal {\n uint256 value = counter._value;\n require(value > 0, \"Counter: decrement overflow\");\n unchecked {\n counter._value = value - 1;\n }\n }\n\n function reset(Counter storage counter) internal {\n counter._value = 0;\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/IERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address recipient, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) external returns (bool);\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" + }, + "@openzeppelin/contracts/utils/Strings.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n}\n" + }, + "contracts/JBController3_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {ERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {JBOperatable} from './abstract/JBOperatable.sol';\nimport {JBBallotState} from './enums/JBBallotState.sol';\nimport {IJBController3_0_1} from './interfaces/IJBController3_0_1.sol';\nimport {IJBController3_1} from './interfaces/IJBController3_1.sol';\nimport {IJBController} from './interfaces/IJBController.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBFundAccessConstraintsStore} from './interfaces/IJBFundAccessConstraintsStore.sol';\nimport {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol';\nimport {IJBMigratable} from './interfaces/IJBMigratable.sol';\nimport {IJBOperatable} from './interfaces/IJBOperatable.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {IJBSplitAllocator} from './interfaces/IJBSplitAllocator.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {IJBTokenStore} from './interfaces/IJBTokenStore.sol';\nimport {JBConstants} from './libraries/JBConstants.sol';\nimport {JBFundingCycleMetadataResolver} from './libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBOperations} from './libraries/JBOperations.sol';\nimport {JBSplitsGroups} from './libraries/JBSplitsGroups.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\nimport {JBSplitAllocationData} from './structs/JBSplitAllocationData.sol';\nimport {JBFundAccessConstraints} from './structs/JBFundAccessConstraints.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\nimport {JBFundingCycleData} from './structs/JBFundingCycleData.sol';\nimport {JBFundingCycleMetadata} from './structs/JBFundingCycleMetadata.sol';\nimport {JBGroupedSplits} from './structs/JBGroupedSplits.sol';\nimport {JBProjectMetadata} from './structs/JBProjectMetadata.sol';\nimport {JBSplit} from './structs/JBSplit.sol';\n\n/// @notice Stitches together funding cycles and project tokens, making sure all activity is accounted for and correct.\n/// @dev This Controller has the same functionality as JBController3_0_1, except it is not backwards compatible with the original IJBController view methods.\ncontract JBController3_1 is JBOperatable, ERC165, IJBController3_1, IJBMigratable {\n // A library that parses the packed funding cycle metadata into a more friendly format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n\n error BURN_PAUSED_AND_SENDER_NOT_VALID_TERMINAL_DELEGATE();\n error FUNDING_CYCLE_ALREADY_LAUNCHED();\n error INVALID_BALLOT_REDEMPTION_RATE();\n error INVALID_REDEMPTION_RATE();\n error INVALID_RESERVED_RATE();\n error MIGRATION_NOT_ALLOWED();\n error MINT_NOT_ALLOWED_AND_NOT_TERMINAL_DELEGATE();\n error NO_BURNABLE_TOKENS();\n error NOT_CURRENT_CONTROLLER();\n error ZERO_TOKENS_TO_MINT();\n\n //*********************************************************************//\n // --------------------- internal stored properties ------------------ //\n //*********************************************************************//\n\n /// @notice Data regarding the distribution limit of a project during a configuration.\n /// @dev bits 0-231: The amount of token that a project can distribute per funding cycle.\n /// @dev bits 232-255: The currency of amount that a project can distribute.\n /// @custom:param _projectId The ID of the project to get the packed distribution limit data of.\n /// @custom:param _configuration The configuration during which the packed distribution limit data applies.\n /// @custom:param _terminal The terminal from which distributions are being limited.\n /// @custom:param _token The token for which distributions are being limited.\n mapping(uint256 => mapping(uint256 => mapping(IJBPaymentTerminal => mapping(address => uint256))))\n internal _packedDistributionLimitDataOf;\n\n /// @notice Data regarding the overflow allowance of a project during a configuration.\n /// @dev bits 0-231: The amount of overflow that a project is allowed to tap into on-demand throughout the configuration.\n /// @dev bits 232-255: The currency of the amount of overflow that a project is allowed to tap.\n /// @custom:param _projectId The ID of the project to get the packed overflow allowance data of.\n /// @custom:param _configuration The configuration during which the packed overflow allowance data applies.\n /// @custom:param _terminal The terminal managing the overflow.\n /// @custom:param _token The token for which overflow is being allowed.\n mapping(uint256 => mapping(uint256 => mapping(IJBPaymentTerminal => mapping(address => uint256))))\n internal _packedOverflowAllowanceDataOf;\n\n //*********************************************************************//\n // --------------- public immutable stored properties ---------------- //\n //*********************************************************************//\n\n /// @notice Mints ERC-721's that represent project ownership.\n IJBProjects public immutable override projects;\n\n /// @notice The contract storing all funding cycle configurations.\n IJBFundingCycleStore public immutable override fundingCycleStore;\n\n /// @notice The contract that manages token minting and burning.\n IJBTokenStore public immutable override tokenStore;\n\n /// @notice The contract that stores splits for each project.\n IJBSplitsStore public immutable override splitsStore;\n\n /// @notice A contract that stores fund access constraints for each project.\n IJBFundAccessConstraintsStore public immutable override fundAccessConstraintsStore;\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The current undistributed reserved token balance of.\n mapping(uint256 => uint256) public override reservedTokenBalanceOf;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice A project's funding cycle for the specified configuration along with its metadata.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The funding cycle.\n /// @return metadata The funding cycle's metadata.\n function getFundingCycleOf(\n uint256 _projectId,\n uint256 _configuration\n )\n external\n view\n override\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata)\n {\n fundingCycle = fundingCycleStore.get(_projectId, _configuration);\n metadata = fundingCycle.expandMetadata();\n }\n\n /// @notice A project's latest configured funding cycle along with its metadata and the ballot state of the configuration.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The latest configured funding cycle.\n /// @return metadata The latest configured funding cycle's metadata.\n /// @return ballotState The state of the configuration.\n function latestConfiguredFundingCycleOf(\n uint256 _projectId\n )\n external\n view\n override\n returns (\n JBFundingCycle memory fundingCycle,\n JBFundingCycleMetadata memory metadata,\n JBBallotState ballotState\n )\n {\n (fundingCycle, ballotState) = fundingCycleStore.latestConfiguredOf(_projectId);\n metadata = fundingCycle.expandMetadata();\n }\n\n /// @notice A project's current funding cycle along with its metadata.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The current funding cycle.\n /// @return metadata The current funding cycle's metadata.\n function currentFundingCycleOf(\n uint256 _projectId\n )\n external\n view\n override\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata)\n {\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n metadata = fundingCycle.expandMetadata();\n }\n\n /// @notice A project's queued funding cycle along with its metadata.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The queued funding cycle.\n /// @return metadata The queued funding cycle's metadata.\n function queuedFundingCycleOf(\n uint256 _projectId\n )\n external\n view\n override\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata)\n {\n fundingCycle = fundingCycleStore.queuedOf(_projectId);\n metadata = fundingCycle.expandMetadata();\n }\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice Gets the current total amount of outstanding tokens for a project.\n /// @param _projectId The ID of the project to get total outstanding tokens of.\n /// @return The current total amount of outstanding tokens for the project.\n function totalOutstandingTokensOf(uint256 _projectId) public view override returns (uint256) {\n // Add the reserved tokens to the total supply.\n return tokenStore.totalSupplyOf(_projectId) + reservedTokenBalanceOf[_projectId];\n }\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if the provided interface ID is supported.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(ERC165, IERC165) returns (bool) {\n return\n _interfaceId == type(IJBController3_1).interfaceId ||\n _interfaceId == type(IJBController3_0_1).interfaceId ||\n _interfaceId == type(IJBMigratable).interfaceId ||\n _interfaceId == type(IJBOperatable).interfaceId ||\n super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // ---------------------------- constructor -------------------------- //\n //*********************************************************************//\n\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _fundingCycleStore A contract storing all funding cycle configurations.\n /// @param _tokenStore A contract that manages token minting and burning.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _fundAccessConstraintsStore A contract that stores fund access constraints for each project.\n constructor(\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBFundingCycleStore _fundingCycleStore,\n IJBTokenStore _tokenStore,\n IJBSplitsStore _splitsStore,\n IJBFundAccessConstraintsStore _fundAccessConstraintsStore\n ) JBOperatable(_operatorStore) {\n projects = _projects;\n directory = _directory;\n fundingCycleStore = _fundingCycleStore;\n tokenStore = _tokenStore;\n splitsStore = _splitsStore;\n fundAccessConstraintsStore = _fundAccessConstraintsStore;\n }\n\n //*********************************************************************//\n // --------------------- external transactions ----------------------- //\n //*********************************************************************//\n\n /// @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.\n /// @dev Each operation within this transaction can be done in sequence separately.\n /// @dev Anyone can deploy a project on an owner's behalf.\n /// @param _owner The address to set as the owner of the project. The project ERC-721 will be owned by this address.\n /// @param _projectMetadata Metadata to associate with the project within a particular domain. This can be updated any time by the owner of the project.\n /// @param _data Data that defines the project's first funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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`.\n /// @param _terminals Payment terminals to add for the project.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return projectId The ID of the project.\n function launchProjectFor(\n address _owner,\n JBProjectMetadata calldata _projectMetadata,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] calldata _groupedSplits,\n JBFundAccessConstraints[] calldata _fundAccessConstraints,\n IJBPaymentTerminal[] memory _terminals,\n string memory _memo\n ) external virtual override returns (uint256 projectId) {\n // Keep a reference to the directory.\n IJBDirectory _directory = directory;\n\n // Mint the project into the wallet of the owner.\n projectId = projects.createFor(_owner, _projectMetadata);\n\n // Set this contract as the project's controller in the directory.\n _directory.setControllerOf(projectId, address(this));\n\n // Configure the first funding cycle.\n uint256 _configuration = _configure(\n projectId,\n _data,\n _metadata,\n _mustStartAtOrAfter,\n _groupedSplits,\n _fundAccessConstraints\n );\n\n // Add the provided terminals to the list of terminals.\n if (_terminals.length > 0) _directory.setTerminalsOf(projectId, _terminals);\n\n emit LaunchProject(_configuration, projectId, _memo, msg.sender);\n }\n\n /// @notice Creates a funding cycle for an already existing project ERC-721.\n /// @dev Each operation within this transaction can be done in sequence separately.\n /// @dev Only a project owner or operator can launch its funding cycles.\n /// @param _projectId The ID of the project to launch funding cycles for.\n /// @param _data Data that defines the project's first funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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`.\n /// @param _terminals Payment terminals to add for the project.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return configuration The configuration of the funding cycle that was successfully created.\n function launchFundingCyclesFor(\n uint256 _projectId,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] calldata _groupedSplits,\n JBFundAccessConstraints[] memory _fundAccessConstraints,\n IJBPaymentTerminal[] memory _terminals,\n string memory _memo\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.RECONFIGURE)\n returns (uint256 configuration)\n {\n // If there is a previous configuration, reconfigureFundingCyclesOf should be called instead\n if (fundingCycleStore.latestConfigurationOf(_projectId) > 0)\n revert FUNDING_CYCLE_ALREADY_LAUNCHED();\n\n // Set this contract as the project's controller in the directory.\n directory.setControllerOf(_projectId, address(this));\n\n // Configure the first funding cycle.\n configuration = _configure(\n _projectId,\n _data,\n _metadata,\n _mustStartAtOrAfter,\n _groupedSplits,\n _fundAccessConstraints\n );\n\n // Add the provided terminals to the list of terminals.\n if (_terminals.length > 0) directory.setTerminalsOf(_projectId, _terminals);\n\n emit LaunchFundingCycles(configuration, _projectId, _memo, msg.sender);\n }\n\n /// @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.\n /// @dev Only a project's owner or a designated operator can configure its funding cycles.\n /// @param _projectId The ID of the project whose funding cycles are being reconfigured.\n /// @param _data Data that defines the funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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`.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return configuration The configuration of the funding cycle that was successfully reconfigured.\n function reconfigureFundingCyclesOf(\n uint256 _projectId,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] calldata _groupedSplits,\n JBFundAccessConstraints[] calldata _fundAccessConstraints,\n string calldata _memo\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.RECONFIGURE)\n returns (uint256 configuration)\n {\n // Configure the next funding cycle.\n configuration = _configure(\n _projectId,\n _data,\n _metadata,\n _mustStartAtOrAfter,\n _groupedSplits,\n _fundAccessConstraints\n );\n\n emit ReconfigureFundingCycles(configuration, _projectId, _memo, msg.sender);\n }\n\n /// @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.\n /// @dev Only a project's owner, a designated operator, one of its terminals, or the current data source can mint its tokens.\n /// @param _projectId The ID of the project to which the tokens being minted belong.\n /// @param _tokenCount The amount of tokens to mint in total, counting however many should be reserved.\n /// @param _beneficiary The account that the tokens are being minted for.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _preferClaimedTokens A flag indicating whether a project's attached token contract should be minted if they have been issued.\n /// @param _useReservedRate Whether to use the current funding cycle's reserved rate in the mint calculation.\n /// @return beneficiaryTokenCount The amount of tokens minted for the beneficiary.\n function mintTokensOf(\n uint256 _projectId,\n uint256 _tokenCount,\n address _beneficiary,\n string calldata _memo,\n bool _preferClaimedTokens,\n bool _useReservedRate\n ) external virtual override returns (uint256 beneficiaryTokenCount) {\n // There should be tokens to mint.\n if (_tokenCount == 0) revert ZERO_TOKENS_TO_MINT();\n\n // Define variables that will be needed outside scoped section below.\n // Keep a reference to the reserved rate to use\n uint256 _reservedRate;\n\n // Scoped section prevents stack too deep. `_fundingCycle` only used within scope.\n {\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Minting limited to: project owner, authorized callers, project terminal and current funding cycle data source\n _requirePermissionAllowingOverride(\n projects.ownerOf(_projectId),\n _projectId,\n JBOperations.MINT,\n directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender)) ||\n msg.sender == address(_fundingCycle.dataSource())\n );\n\n // If the message sender is not a terminal or a datasource, the current funding cycle must allow minting.\n if (\n !_fundingCycle.mintingAllowed() &&\n !directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender)) &&\n msg.sender != address(_fundingCycle.dataSource())\n ) revert MINT_NOT_ALLOWED_AND_NOT_TERMINAL_DELEGATE();\n\n // Determine the reserved rate to use.\n _reservedRate = _useReservedRate ? _fundingCycle.reservedRate() : 0;\n\n // Override the claimed token preference with the funding cycle value.\n _preferClaimedTokens = _preferClaimedTokens == true\n ? _preferClaimedTokens\n : _fundingCycle.preferClaimedTokenOverride();\n }\n\n if (_reservedRate != JBConstants.MAX_RESERVED_RATE) {\n // The unreserved token count that will be minted for the beneficiary.\n beneficiaryTokenCount = PRBMath.mulDiv(\n _tokenCount,\n JBConstants.MAX_RESERVED_RATE - _reservedRate,\n JBConstants.MAX_RESERVED_RATE\n );\n\n // Mint the tokens.\n tokenStore.mintFor(_beneficiary, _projectId, beneficiaryTokenCount, _preferClaimedTokens);\n }\n\n // Add reserved tokens if needed\n if (_reservedRate > 0)\n reservedTokenBalanceOf[_projectId] += _tokenCount - beneficiaryTokenCount;\n\n emit MintTokens(\n _beneficiary,\n _projectId,\n _tokenCount,\n beneficiaryTokenCount,\n _memo,\n _reservedRate,\n msg.sender\n );\n }\n\n /// @notice Burns a token holder's supply.\n /// @dev Only a token's holder, a designated operator, or a project's terminal can burn it.\n /// @param _holder The account that is having its tokens burned.\n /// @param _projectId The ID of the project to which the tokens being burned belong.\n /// @param _tokenCount The number of tokens to burn.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _preferClaimedTokens A flag indicating whether a project's attached token contract should be burned first if they have been issued.\n function burnTokensOf(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n string calldata _memo,\n bool _preferClaimedTokens\n )\n external\n virtual\n override\n requirePermissionAllowingOverride(\n _holder,\n _projectId,\n JBOperations.BURN,\n directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender))\n )\n {\n // There should be tokens to burn\n if (_tokenCount == 0) revert NO_BURNABLE_TOKENS();\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // If the message sender is a terminal, the current funding cycle must not be paused.\n if (\n _fundingCycle.burnPaused() &&\n !directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender))\n ) revert BURN_PAUSED_AND_SENDER_NOT_VALID_TERMINAL_DELEGATE();\n\n // Burn the tokens.\n tokenStore.burnFrom(_holder, _projectId, _tokenCount, _preferClaimedTokens);\n\n emit BurnTokens(_holder, _projectId, _tokenCount, _memo, msg.sender);\n }\n\n /// @notice Distributes all outstanding reserved tokens for a project.\n /// @param _projectId The ID of the project to which the reserved tokens belong.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return The amount of minted reserved tokens.\n function distributeReservedTokensOf(\n uint256 _projectId,\n string calldata _memo\n ) external virtual override returns (uint256) {\n return _distributeReservedTokensOf(_projectId, _memo);\n }\n\n /// @notice Allows other controllers to signal to this one that a migration is expected for the specified project.\n /// @dev This controller should not yet be the project's controller.\n /// @param _projectId The ID of the project that will be migrated to this controller.\n /// @param _from The controller being migrated from.\n function prepForMigrationOf(uint256 _projectId, address _from) external virtual override {\n _projectId; // Prevents unused var compiler and natspec complaints.\n _from; // Prevents unused var compiler and natspec complaints.\n }\n\n /// @notice Allows a project to migrate from this controller to another.\n /// @dev Only a project's owner or a designated operator can migrate it.\n /// @param _projectId The ID of the project that will be migrated from this controller.\n /// @param _to The controller to which the project is migrating.\n function migrate(\n uint256 _projectId,\n IJBMigratable _to\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.MIGRATE_CONTROLLER)\n {\n // Keep a reference to the directory.\n IJBDirectory _directory = directory;\n\n // This controller must be the project's current controller.\n if (_directory.controllerOf(_projectId) != address(this)) revert NOT_CURRENT_CONTROLLER();\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Migration must be allowed.\n if (!_fundingCycle.controllerMigrationAllowed()) revert MIGRATION_NOT_ALLOWED();\n\n // All reserved tokens must be minted before migrating.\n if (reservedTokenBalanceOf[_projectId] != 0) _distributeReservedTokensOf(_projectId, '');\n\n // Make sure the new controller is prepped for the migration.\n _to.prepForMigrationOf(_projectId, address(this));\n\n // Set the new controller.\n _directory.setControllerOf(_projectId, address(_to));\n\n emit Migrate(_projectId, _to, msg.sender);\n }\n\n //*********************************************************************//\n // ------------------------ internal functions ----------------------- //\n //*********************************************************************//\n\n /// @notice Distributes all outstanding reserved tokens for a project.\n /// @param _projectId The ID of the project to which the reserved tokens belong.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return tokenCount The amount of minted reserved tokens.\n function _distributeReservedTokensOf(\n uint256 _projectId,\n string memory _memo\n ) internal returns (uint256 tokenCount) {\n // Keep a reference to the token store.\n IJBTokenStore _tokenStore = tokenStore;\n\n // Get the current funding cycle to read the reserved rate from.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Get a reference to the number of tokens that need to be minted.\n tokenCount = reservedTokenBalanceOf[_projectId];\n\n // Reset the reserved token balance\n reservedTokenBalanceOf[_projectId] = 0;\n\n // Get a reference to the project owner.\n address _owner = projects.ownerOf(_projectId);\n\n // Distribute tokens to splits and get a reference to the leftover amount to mint after all splits have gotten their share.\n uint256 _leftoverTokenCount = tokenCount == 0\n ? 0\n : _distributeToReservedTokenSplitsOf(\n _projectId,\n _fundingCycle.configuration,\n JBSplitsGroups.RESERVED_TOKENS,\n tokenCount\n );\n\n // Mint any leftover tokens to the project owner.\n if (_leftoverTokenCount > 0)\n _tokenStore.mintFor(_owner, _projectId, _leftoverTokenCount, false);\n\n emit DistributeReservedTokens(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _owner,\n tokenCount,\n _leftoverTokenCount,\n _memo,\n msg.sender\n );\n }\n\n /// @notice Distribute tokens to the splits according to the specified funding cycle configuration.\n /// @param _projectId The ID of the project for which reserved token splits are being distributed.\n /// @param _domain The domain of the splits to distribute the reserved tokens between.\n /// @param _group The group of the splits to distribute the reserved tokens between.\n /// @param _amount The total amount of tokens to mint.\n /// @return leftoverAmount If the splits percents dont add up to 100%, the leftover amount is returned.\n function _distributeToReservedTokenSplitsOf(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group,\n uint256 _amount\n ) internal returns (uint256 leftoverAmount) {\n // Keep a reference to the token store.\n IJBTokenStore _tokenStore = tokenStore;\n\n // Set the leftover amount to the initial amount.\n leftoverAmount = _amount;\n\n // Get a reference to the project's reserved token splits.\n JBSplit[] memory _splits = splitsStore.splitsOf(_projectId, _domain, _group);\n\n //Transfer between all splits.\n for (uint256 _i; _i < _splits.length; ) {\n // Get a reference to the split being iterated on.\n JBSplit memory _split = _splits[_i];\n\n // The amount to send towards the split.\n uint256 _tokenCount = PRBMath.mulDiv(\n _amount,\n _split.percent,\n JBConstants.SPLITS_TOTAL_PERCENT\n );\n\n // Mints tokens for the split if needed.\n if (_tokenCount > 0) {\n _tokenStore.mintFor(\n // If an allocator is set in the splits, set it as the beneficiary.\n // Otherwise if a projectId is set in the split, set the project's owner as the beneficiary.\n // If the split has a beneficiary send to the split's beneficiary. Otherwise send to the msg.sender.\n _split.allocator != IJBSplitAllocator(address(0))\n ? address(_split.allocator)\n : _split.projectId != 0\n ? projects.ownerOf(_split.projectId)\n : _split.beneficiary != address(0)\n ? _split.beneficiary\n : msg.sender,\n _projectId,\n _tokenCount,\n _split.preferClaimed\n );\n\n // If there's an allocator set, trigger its `allocate` function.\n if (_split.allocator != IJBSplitAllocator(address(0)))\n _split.allocator.allocate(\n JBSplitAllocationData(\n address(_tokenStore.tokenOf(_projectId)),\n _tokenCount,\n 18,\n _projectId,\n _group,\n _split\n )\n );\n\n // Subtract from the amount to be sent to the beneficiary.\n leftoverAmount = leftoverAmount - _tokenCount;\n }\n\n emit DistributeToReservedTokenSplit(\n _projectId,\n _domain,\n _group,\n _split,\n _tokenCount,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n\n /// @notice Configures a funding cycle and stores information pertinent to the configuration.\n /// @param _projectId The ID of the project whose funding cycles are being reconfigured.\n /// @param _data Data that defines the funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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.\n /// @return configuration The configuration of the funding cycle that was successfully reconfigured.\n function _configure(\n uint256 _projectId,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] memory _groupedSplits,\n JBFundAccessConstraints[] memory _fundAccessConstraints\n ) internal returns (uint256) {\n // Make sure the provided reserved rate is valid.\n if (_metadata.reservedRate > JBConstants.MAX_RESERVED_RATE) revert INVALID_RESERVED_RATE();\n\n // Make sure the provided redemption rate is valid.\n if (_metadata.redemptionRate > JBConstants.MAX_REDEMPTION_RATE)\n revert INVALID_REDEMPTION_RATE();\n\n // Make sure the provided ballot redemption rate is valid.\n if (_metadata.ballotRedemptionRate > JBConstants.MAX_REDEMPTION_RATE)\n revert INVALID_BALLOT_REDEMPTION_RATE();\n\n // Configure the funding cycle's properties.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.configureFor(\n _projectId,\n _data,\n JBFundingCycleMetadataResolver.packFundingCycleMetadata(_metadata),\n _mustStartAtOrAfter\n );\n\n // Set splits for the group.\n splitsStore.set(_projectId, _fundingCycle.configuration, _groupedSplits);\n\n // Set the funds access constraints.\n fundAccessConstraintsStore.setFor(\n _projectId,\n _fundingCycle.configuration,\n _fundAccessConstraints\n );\n\n return _fundingCycle.configuration;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/introspection/ERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC165.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n *\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n" + }, + "@paulrberg/contracts/math/PRBMath.sol": { + "content": "// SPDX-License-Identifier: Unlicense\npragma solidity >=0.8.4;\n\nimport \"prb-math/contracts/PRBMath.sol\";\n" + }, + "contracts/interfaces/IJBController3_0_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBController3_0_1 {\n function reservedTokenBalanceOf(uint256 projectId) external view returns (uint256);\n\n function totalOutstandingTokensOf(uint256 projectId) external view returns (uint256);\n}\n" + }, + "contracts/interfaces/IJBController3_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBBallotState} from './../enums/JBBallotState.sol';\nimport {JBFundAccessConstraints} from './../structs/JBFundAccessConstraints.sol';\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\nimport {JBFundingCycleData} from './../structs/JBFundingCycleData.sol';\nimport {JBFundingCycleMetadata} from './../structs/JBFundingCycleMetadata.sol';\nimport {JBGroupedSplits} from './../structs/JBGroupedSplits.sol';\nimport {JBProjectMetadata} from './../structs/JBProjectMetadata.sol';\nimport {JBSplit} from './../structs/JBSplit.sol';\nimport {IJBController3_0_1} from './IJBController3_0_1.sol';\nimport {IJBDirectory} from './IJBDirectory.sol';\nimport {IJBFundAccessConstraintsStore} from './IJBFundAccessConstraintsStore.sol';\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\nimport {IJBMigratable} from './IJBMigratable.sol';\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\nimport {IJBProjects} from './IJBProjects.sol';\nimport {IJBSplitsStore} from './IJBSplitsStore.sol';\nimport {IJBTokenStore} from './IJBTokenStore.sol';\n\ninterface IJBController3_1 is IJBController3_0_1, IERC165 {\n event LaunchProject(uint256 configuration, uint256 projectId, string memo, address caller);\n\n event LaunchFundingCycles(uint256 configuration, uint256 projectId, string memo, address caller);\n\n event ReconfigureFundingCycles(\n uint256 configuration,\n uint256 projectId,\n string memo,\n address caller\n );\n\n event DistributeReservedTokens(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n address beneficiary,\n uint256 tokenCount,\n uint256 beneficiaryTokenCount,\n string memo,\n address caller\n );\n\n event DistributeToReservedTokenSplit(\n uint256 indexed projectId,\n uint256 indexed domain,\n uint256 indexed group,\n JBSplit split,\n uint256 tokenCount,\n address caller\n );\n\n event MintTokens(\n address indexed beneficiary,\n uint256 indexed projectId,\n uint256 tokenCount,\n uint256 beneficiaryTokenCount,\n string memo,\n uint256 reservedRate,\n address caller\n );\n\n event BurnTokens(\n address indexed holder,\n uint256 indexed projectId,\n uint256 tokenCount,\n string memo,\n address caller\n );\n\n event Migrate(uint256 indexed projectId, IJBMigratable to, address caller);\n\n event PrepMigration(uint256 indexed projectId, address from, address caller);\n\n function projects() external view returns (IJBProjects);\n\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\n\n function tokenStore() external view returns (IJBTokenStore);\n\n function splitsStore() external view returns (IJBSplitsStore);\n\n function fundAccessConstraintsStore() external view returns (IJBFundAccessConstraintsStore);\n\n function directory() external view returns (IJBDirectory);\n\n function reservedTokenBalanceOf(uint256 projectId) external view returns (uint256);\n\n function totalOutstandingTokensOf(uint256 projectId) external view returns (uint256);\n\n function getFundingCycleOf(\n uint256 projectId,\n uint256 configuration\n )\n external\n view\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata);\n\n function latestConfiguredFundingCycleOf(\n uint256 projectId\n )\n external\n view\n returns (JBFundingCycle memory, JBFundingCycleMetadata memory metadata, JBBallotState);\n\n function currentFundingCycleOf(\n uint256 projectId\n )\n external\n view\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata);\n\n function queuedFundingCycleOf(\n uint256 projectId\n )\n external\n view\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata);\n\n function launchProjectFor(\n address owner,\n JBProjectMetadata calldata projectMetadata,\n JBFundingCycleData calldata data,\n JBFundingCycleMetadata calldata metadata,\n uint256 mustStartAtOrAfter,\n JBGroupedSplits[] memory groupedSplits,\n JBFundAccessConstraints[] memory fundAccessConstraints,\n IJBPaymentTerminal[] memory terminals,\n string calldata memo\n ) external returns (uint256 projectId);\n\n function launchFundingCyclesFor(\n uint256 projectId,\n JBFundingCycleData calldata data,\n JBFundingCycleMetadata calldata metadata,\n uint256 mustStartAtOrAfter,\n JBGroupedSplits[] memory groupedSplits,\n JBFundAccessConstraints[] memory fundAccessConstraints,\n IJBPaymentTerminal[] memory terminals,\n string calldata memo\n ) external returns (uint256 configuration);\n\n function reconfigureFundingCyclesOf(\n uint256 projectId,\n JBFundingCycleData calldata data,\n JBFundingCycleMetadata calldata metadata,\n uint256 mustStartAtOrAfter,\n JBGroupedSplits[] memory groupedSplits,\n JBFundAccessConstraints[] memory fundAccessConstraints,\n string calldata memo\n ) external returns (uint256);\n\n function mintTokensOf(\n uint256 projectId,\n uint256 tokenCount,\n address beneficiary,\n string calldata memo,\n bool preferClaimedTokens,\n bool useReservedRate\n ) external returns (uint256 beneficiaryTokenCount);\n\n function burnTokensOf(\n address holder,\n uint256 projectId,\n uint256 tokenCount,\n string calldata memo,\n bool preferClaimedTokens\n ) external;\n\n function distributeReservedTokensOf(\n uint256 projectId,\n string memory memo\n ) external returns (uint256);\n\n function migrate(uint256 projectId, IJBMigratable to) external;\n}\n" + }, + "contracts/interfaces/IJBController.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBBallotState} from './../enums/JBBallotState.sol';\nimport {JBFundAccessConstraints} from './../structs/JBFundAccessConstraints.sol';\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\nimport {JBFundingCycleData} from './../structs/JBFundingCycleData.sol';\nimport {JBFundingCycleMetadata} from './../structs/JBFundingCycleMetadata.sol';\nimport {JBGroupedSplits} from './../structs/JBGroupedSplits.sol';\nimport {JBProjectMetadata} from './../structs/JBProjectMetadata.sol';\nimport {JBSplit} from './../structs/JBSplit.sol';\nimport {IJBDirectory} from './IJBDirectory.sol';\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\nimport {IJBMigratable} from './IJBMigratable.sol';\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\nimport {IJBProjects} from './IJBProjects.sol';\nimport {IJBSplitsStore} from './IJBSplitsStore.sol';\nimport {IJBTokenStore} from './IJBTokenStore.sol';\n\ninterface IJBController is IERC165 {\n event LaunchProject(uint256 configuration, uint256 projectId, string memo, address caller);\n\n event LaunchFundingCycles(uint256 configuration, uint256 projectId, string memo, address caller);\n\n event ReconfigureFundingCycles(\n uint256 configuration,\n uint256 projectId,\n string memo,\n address caller\n );\n\n event SetFundAccessConstraints(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n JBFundAccessConstraints constraints,\n address caller\n );\n\n event DistributeReservedTokens(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n address beneficiary,\n uint256 tokenCount,\n uint256 beneficiaryTokenCount,\n string memo,\n address caller\n );\n\n event DistributeToReservedTokenSplit(\n uint256 indexed projectId,\n uint256 indexed domain,\n uint256 indexed group,\n JBSplit split,\n uint256 tokenCount,\n address caller\n );\n\n event MintTokens(\n address indexed beneficiary,\n uint256 indexed projectId,\n uint256 tokenCount,\n uint256 beneficiaryTokenCount,\n string memo,\n uint256 reservedRate,\n address caller\n );\n\n event BurnTokens(\n address indexed holder,\n uint256 indexed projectId,\n uint256 tokenCount,\n string memo,\n address caller\n );\n\n event Migrate(uint256 indexed projectId, IJBMigratable to, address caller);\n\n event PrepMigration(uint256 indexed projectId, address from, address caller);\n\n function projects() external view returns (IJBProjects);\n\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\n\n function tokenStore() external view returns (IJBTokenStore);\n\n function splitsStore() external view returns (IJBSplitsStore);\n\n function directory() external view returns (IJBDirectory);\n\n function reservedTokenBalanceOf(\n uint256 projectId,\n uint256 reservedRate\n ) external view returns (uint256);\n\n function distributionLimitOf(\n uint256 projectId,\n uint256 configuration,\n IJBPaymentTerminal terminal,\n address token\n ) external view returns (uint256 distributionLimit, uint256 distributionLimitCurrency);\n\n function overflowAllowanceOf(\n uint256 projectId,\n uint256 configuration,\n IJBPaymentTerminal terminal,\n address token\n ) external view returns (uint256 overflowAllowance, uint256 overflowAllowanceCurrency);\n\n function totalOutstandingTokensOf(\n uint256 projectId,\n uint256 reservedRate\n ) external view returns (uint256);\n\n function getFundingCycleOf(\n uint256 projectId,\n uint256 configuration\n )\n external\n view\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata);\n\n function latestConfiguredFundingCycleOf(\n uint256 projectId\n )\n external\n view\n returns (JBFundingCycle memory, JBFundingCycleMetadata memory metadata, JBBallotState);\n\n function currentFundingCycleOf(\n uint256 projectId\n )\n external\n view\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata);\n\n function queuedFundingCycleOf(\n uint256 projectId\n )\n external\n view\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata);\n\n function launchProjectFor(\n address owner,\n JBProjectMetadata calldata projectMetadata,\n JBFundingCycleData calldata data,\n JBFundingCycleMetadata calldata metadata,\n uint256 mustStartAtOrAfter,\n JBGroupedSplits[] memory groupedSplits,\n JBFundAccessConstraints[] memory fundAccessConstraints,\n IJBPaymentTerminal[] memory terminals,\n string calldata memo\n ) external returns (uint256 projectId);\n\n function launchFundingCyclesFor(\n uint256 projectId,\n JBFundingCycleData calldata data,\n JBFundingCycleMetadata calldata metadata,\n uint256 mustStartAtOrAfter,\n JBGroupedSplits[] memory groupedSplits,\n JBFundAccessConstraints[] memory fundAccessConstraints,\n IJBPaymentTerminal[] memory terminals,\n string calldata memo\n ) external returns (uint256 configuration);\n\n function reconfigureFundingCyclesOf(\n uint256 projectId,\n JBFundingCycleData calldata data,\n JBFundingCycleMetadata calldata metadata,\n uint256 mustStartAtOrAfter,\n JBGroupedSplits[] memory groupedSplits,\n JBFundAccessConstraints[] memory fundAccessConstraints,\n string calldata memo\n ) external returns (uint256);\n\n function mintTokensOf(\n uint256 projectId,\n uint256 tokenCount,\n address beneficiary,\n string calldata memo,\n bool preferClaimedTokens,\n bool useReservedRate\n ) external returns (uint256 beneficiaryTokenCount);\n\n function burnTokensOf(\n address holder,\n uint256 projectId,\n uint256 tokenCount,\n string calldata memo,\n bool preferClaimedTokens\n ) external;\n\n function distributeReservedTokensOf(\n uint256 projectId,\n string memory memo\n ) external returns (uint256);\n\n function migrate(uint256 projectId, IJBMigratable to) external;\n}\n" + }, + "contracts/interfaces/IJBFundAccessConstraintsStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBFundAccessConstraints} from './../structs/JBFundAccessConstraints.sol';\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\n\ninterface IJBFundAccessConstraintsStore is IERC165 {\n event SetFundAccessConstraints(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed projectId,\n JBFundAccessConstraints constraints,\n address caller\n );\n\n function distributionLimitOf(\n uint256 projectId,\n uint256 configuration,\n IJBPaymentTerminal terminal,\n address token\n ) external view returns (uint256 distributionLimit, uint256 distributionLimitCurrency);\n\n function overflowAllowanceOf(\n uint256 projectId,\n uint256 configuration,\n IJBPaymentTerminal terminal,\n address token\n ) external view returns (uint256 overflowAllowance, uint256 overflowAllowanceCurrency);\n\n function setFor(\n uint256 projectId,\n uint256 configuration,\n JBFundAccessConstraints[] memory fundAccessConstaints\n ) external;\n}\n" + }, + "contracts/interfaces/IJBMigratable.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBMigratable {\n function prepForMigrationOf(uint256 projectId, address from) external;\n}\n" + }, + "contracts/interfaces/IJBSplitAllocator.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBSplitAllocationData} from '../structs/JBSplitAllocationData.sol';\n\n/// @title Split allocator\n/// @notice Provide a way to process a single split with extra logic\n/// @dev The contract address should be set as an allocator in the adequate split\ninterface IJBSplitAllocator is IERC165 {\n /// @notice This function is called by JBPaymentTerminal.distributePayoutOf(..), during the processing of the split including it\n /// @dev Critical business logic should be protected by an appropriate access control. The token and/or eth are optimistically transfered to the allocator for its logic.\n /// @param data the data passed by the terminal, as a JBSplitAllocationData struct:\n function allocate(JBSplitAllocationData calldata data) external payable;\n}\n" + }, + "contracts/interfaces/IJBSplitsStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBGroupedSplits} from './../structs/JBGroupedSplits.sol';\nimport {JBSplit} from './../structs/JBSplit.sol';\nimport {IJBDirectory} from './IJBDirectory.sol';\nimport {IJBProjects} from './IJBProjects.sol';\n\ninterface IJBSplitsStore {\n event SetSplit(\n uint256 indexed projectId,\n uint256 indexed domain,\n uint256 indexed group,\n JBSplit split,\n address caller\n );\n\n function projects() external view returns (IJBProjects);\n\n function directory() external view returns (IJBDirectory);\n\n function splitsOf(\n uint256 projectId,\n uint256 domain,\n uint256 group\n ) external view returns (JBSplit[] memory);\n\n function set(uint256 projectId, uint256 domain, JBGroupedSplits[] memory groupedSplits) external;\n}\n" + }, + "contracts/libraries/JBSplitsGroups.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nlibrary JBSplitsGroups {\n uint256 public constant ETH_PAYOUT = 1;\n uint256 public constant RESERVED_TOKENS = 2;\n}\n" + }, + "contracts/structs/JBSplitAllocationData.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBSplit} from './JBSplit.sol';\n\n/// @custom:member token The token being sent to the split allocator.\n/// @custom:member amount The amount being sent to the split allocator, as a fixed point number.\n/// @custom:member decimals The number of decimals in the amount.\n/// @custom:member projectId The project to which the split belongs.\n/// @custom:member group The group to which the split belongs.\n/// @custom:member split The split that caused the allocation.\nstruct JBSplitAllocationData {\n address token;\n uint256 amount;\n uint256 decimals;\n uint256 projectId;\n uint256 group;\n JBSplit split;\n}\n" + }, + "contracts/structs/JBFundAccessConstraints.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\n\n/// @custom:member terminal The terminal within which the distribution limit and the overflow allowance applies.\n/// @custom:member token The token for which the fund access constraints apply.\n/// @custom:member distributionLimit The amount of the distribution limit, as a fixed point number with the same number of decimals as the terminal within which the limit applies.\n/// @custom:member distributionLimitCurrency The currency of the distribution limit.\n/// @custom:member overflowAllowance The amount of the allowance, as a fixed point number with the same number of decimals as the terminal within which the allowance applies.\n/// @custom:member overflowAllowanceCurrency The currency of the overflow allowance.\nstruct JBFundAccessConstraints {\n IJBPaymentTerminal terminal;\n address token;\n uint256 distributionLimit;\n uint256 distributionLimitCurrency;\n uint256 overflowAllowance;\n uint256 overflowAllowanceCurrency;\n}\n" + }, + "contracts/structs/JBGroupedSplits.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBSplit} from './JBSplit.sol';\n\n/// @custom:member group The group indentifier.\n/// @custom:member splits The splits to associate with the group.\nstruct JBGroupedSplits {\n uint256 group;\n JBSplit[] splits;\n}\n" + }, + "contracts/structs/JBSplit.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBSplitAllocator} from './../interfaces/IJBSplitAllocator.sol';\n\n/// @custom:member preferClaimed A flag that only has effect if a projectId is also specified, and the project has a token contract attached. If so, this flag indicates if the tokens that result from making a payment to the project should be delivered claimed into the beneficiary's wallet, or unclaimed to save gas.\n/// @custom:member preferAddToBalance A flag indicating if a distribution to a project should prefer triggering it's addToBalance function instead of its pay function.\n/// @custom:member percent The percent of the whole group that this split occupies. This number is out of `JBConstants.SPLITS_TOTAL_PERCENT`.\n/// @custom:member projectId The ID of a project. If an allocator is not set but a projectId is set, funds will be sent to the protocol treasury belonging to the project who's ID is specified. Resulting tokens will be routed to the beneficiary with the claimed token preference respected.\n/// @custom:member beneficiary An address. The role the of the beneficary depends on whether or not projectId is specified, and whether or not an allocator is specified. If allocator is set, the beneficiary will be forwarded to the allocator for it to use. If allocator is not set but projectId is set, the beneficiary is the address to which the project's tokens will be sent that result from a payment to it. If neither allocator or projectId are set, the beneficiary is where the funds from the split will be sent.\n/// @custom:member lockedUntil Specifies if the split should be unchangeable until the specified time, with the exception of extending the locked period.\n/// @custom:member allocator If an allocator is specified, funds will be sent to the allocator contract along with all properties of this split.\nstruct JBSplit {\n bool preferClaimed;\n bool preferAddToBalance;\n uint256 percent;\n uint256 projectId;\n address payable beneficiary;\n uint256 lockedUntil;\n IJBSplitAllocator allocator;\n}\n" + }, + "prb-math/contracts/PRBMath.sol": { + "content": "// SPDX-License-Identifier: Unlicense\npragma solidity >=0.8.4;\n\n/// @notice Emitted when the result overflows uint256.\nerror PRBMath__MulDivFixedPointOverflow(uint256 prod1);\n\n/// @notice Emitted when the result overflows uint256.\nerror PRBMath__MulDivOverflow(uint256 prod1, uint256 denominator);\n\n/// @notice Emitted when one of the inputs is type(int256).min.\nerror PRBMath__MulDivSignedInputTooSmall();\n\n/// @notice Emitted when the intermediary absolute result overflows int256.\nerror PRBMath__MulDivSignedOverflow(uint256 rAbs);\n\n/// @notice Emitted when the input is MIN_SD59x18.\nerror PRBMathSD59x18__AbsInputTooSmall();\n\n/// @notice Emitted when ceiling a number overflows SD59x18.\nerror PRBMathSD59x18__CeilOverflow(int256 x);\n\n/// @notice Emitted when one of the inputs is MIN_SD59x18.\nerror PRBMathSD59x18__DivInputTooSmall();\n\n/// @notice Emitted when one of the intermediary unsigned results overflows SD59x18.\nerror PRBMathSD59x18__DivOverflow(uint256 rAbs);\n\n/// @notice Emitted when the input is greater than 133.084258667509499441.\nerror PRBMathSD59x18__ExpInputTooBig(int256 x);\n\n/// @notice Emitted when the input is greater than 192.\nerror PRBMathSD59x18__Exp2InputTooBig(int256 x);\n\n/// @notice Emitted when flooring a number underflows SD59x18.\nerror PRBMathSD59x18__FloorUnderflow(int256 x);\n\n/// @notice Emitted when converting a basic integer to the fixed-point format overflows SD59x18.\nerror PRBMathSD59x18__FromIntOverflow(int256 x);\n\n/// @notice Emitted when converting a basic integer to the fixed-point format underflows SD59x18.\nerror PRBMathSD59x18__FromIntUnderflow(int256 x);\n\n/// @notice Emitted when the product of the inputs is negative.\nerror PRBMathSD59x18__GmNegativeProduct(int256 x, int256 y);\n\n/// @notice Emitted when multiplying the inputs overflows SD59x18.\nerror PRBMathSD59x18__GmOverflow(int256 x, int256 y);\n\n/// @notice Emitted when the input is less than or equal to zero.\nerror PRBMathSD59x18__LogInputTooSmall(int256 x);\n\n/// @notice Emitted when one of the inputs is MIN_SD59x18.\nerror PRBMathSD59x18__MulInputTooSmall();\n\n/// @notice Emitted when the intermediary absolute result overflows SD59x18.\nerror PRBMathSD59x18__MulOverflow(uint256 rAbs);\n\n/// @notice Emitted when the intermediary absolute result overflows SD59x18.\nerror PRBMathSD59x18__PowuOverflow(uint256 rAbs);\n\n/// @notice Emitted when the input is negative.\nerror PRBMathSD59x18__SqrtNegativeInput(int256 x);\n\n/// @notice Emitted when the calculating the square root overflows SD59x18.\nerror PRBMathSD59x18__SqrtOverflow(int256 x);\n\n/// @notice Emitted when addition overflows UD60x18.\nerror PRBMathUD60x18__AddOverflow(uint256 x, uint256 y);\n\n/// @notice Emitted when ceiling a number overflows UD60x18.\nerror PRBMathUD60x18__CeilOverflow(uint256 x);\n\n/// @notice Emitted when the input is greater than 133.084258667509499441.\nerror PRBMathUD60x18__ExpInputTooBig(uint256 x);\n\n/// @notice Emitted when the input is greater than 192.\nerror PRBMathUD60x18__Exp2InputTooBig(uint256 x);\n\n/// @notice Emitted when converting a basic integer to the fixed-point format format overflows UD60x18.\nerror PRBMathUD60x18__FromUintOverflow(uint256 x);\n\n/// @notice Emitted when multiplying the inputs overflows UD60x18.\nerror PRBMathUD60x18__GmOverflow(uint256 x, uint256 y);\n\n/// @notice Emitted when the input is less than 1.\nerror PRBMathUD60x18__LogInputTooSmall(uint256 x);\n\n/// @notice Emitted when the calculating the square root overflows UD60x18.\nerror PRBMathUD60x18__SqrtOverflow(uint256 x);\n\n/// @notice Emitted when subtraction underflows UD60x18.\nerror PRBMathUD60x18__SubUnderflow(uint256 x, uint256 y);\n\n/// @dev Common mathematical functions used in both PRBMathSD59x18 and PRBMathUD60x18. Note that this shared library\n/// does not always assume the signed 59.18-decimal fixed-point or the unsigned 60.18-decimal fixed-point\n/// representation. When it does not, it is explicitly mentioned in the NatSpec documentation.\nlibrary PRBMath {\n /// STRUCTS ///\n\n struct SD59x18 {\n int256 value;\n }\n\n struct UD60x18 {\n uint256 value;\n }\n\n /// STORAGE ///\n\n /// @dev How many trailing decimals can be represented.\n uint256 internal constant SCALE = 1e18;\n\n /// @dev Largest power of two divisor of SCALE.\n uint256 internal constant SCALE_LPOTD = 262144;\n\n /// @dev SCALE inverted mod 2^256.\n uint256 internal constant SCALE_INVERSE =\n 78156646155174841979727994598816262306175212592076161876661_508869554232690281;\n\n /// FUNCTIONS ///\n\n /// @notice Calculates the binary exponent of x using the binary fraction method.\n /// @dev Has to use 192.64-bit fixed-point numbers.\n /// See https://ethereum.stackexchange.com/a/96594/24693.\n /// @param x The exponent as an unsigned 192.64-bit fixed-point number.\n /// @return result The result as an unsigned 60.18-decimal fixed-point number.\n function exp2(uint256 x) internal pure returns (uint256 result) {\n unchecked {\n // Start from 0.5 in the 192.64-bit fixed-point format.\n result = 0x800000000000000000000000000000000000000000000000;\n\n // Multiply the result by root(2, 2^-i) when the bit at position i is 1. None of the intermediary results overflows\n // because the initial result is 2^191 and all magic factors are less than 2^65.\n if (x & 0x8000000000000000 > 0) {\n result = (result * 0x16A09E667F3BCC909) >> 64;\n }\n if (x & 0x4000000000000000 > 0) {\n result = (result * 0x1306FE0A31B7152DF) >> 64;\n }\n if (x & 0x2000000000000000 > 0) {\n result = (result * 0x1172B83C7D517ADCE) >> 64;\n }\n if (x & 0x1000000000000000 > 0) {\n result = (result * 0x10B5586CF9890F62A) >> 64;\n }\n if (x & 0x800000000000000 > 0) {\n result = (result * 0x1059B0D31585743AE) >> 64;\n }\n if (x & 0x400000000000000 > 0) {\n result = (result * 0x102C9A3E778060EE7) >> 64;\n }\n if (x & 0x200000000000000 > 0) {\n result = (result * 0x10163DA9FB33356D8) >> 64;\n }\n if (x & 0x100000000000000 > 0) {\n result = (result * 0x100B1AFA5ABCBED61) >> 64;\n }\n if (x & 0x80000000000000 > 0) {\n result = (result * 0x10058C86DA1C09EA2) >> 64;\n }\n if (x & 0x40000000000000 > 0) {\n result = (result * 0x1002C605E2E8CEC50) >> 64;\n }\n if (x & 0x20000000000000 > 0) {\n result = (result * 0x100162F3904051FA1) >> 64;\n }\n if (x & 0x10000000000000 > 0) {\n result = (result * 0x1000B175EFFDC76BA) >> 64;\n }\n if (x & 0x8000000000000 > 0) {\n result = (result * 0x100058BA01FB9F96D) >> 64;\n }\n if (x & 0x4000000000000 > 0) {\n result = (result * 0x10002C5CC37DA9492) >> 64;\n }\n if (x & 0x2000000000000 > 0) {\n result = (result * 0x1000162E525EE0547) >> 64;\n }\n if (x & 0x1000000000000 > 0) {\n result = (result * 0x10000B17255775C04) >> 64;\n }\n if (x & 0x800000000000 > 0) {\n result = (result * 0x1000058B91B5BC9AE) >> 64;\n }\n if (x & 0x400000000000 > 0) {\n result = (result * 0x100002C5C89D5EC6D) >> 64;\n }\n if (x & 0x200000000000 > 0) {\n result = (result * 0x10000162E43F4F831) >> 64;\n }\n if (x & 0x100000000000 > 0) {\n result = (result * 0x100000B1721BCFC9A) >> 64;\n }\n if (x & 0x80000000000 > 0) {\n result = (result * 0x10000058B90CF1E6E) >> 64;\n }\n if (x & 0x40000000000 > 0) {\n result = (result * 0x1000002C5C863B73F) >> 64;\n }\n if (x & 0x20000000000 > 0) {\n result = (result * 0x100000162E430E5A2) >> 64;\n }\n if (x & 0x10000000000 > 0) {\n result = (result * 0x1000000B172183551) >> 64;\n }\n if (x & 0x8000000000 > 0) {\n result = (result * 0x100000058B90C0B49) >> 64;\n }\n if (x & 0x4000000000 > 0) {\n result = (result * 0x10000002C5C8601CC) >> 64;\n }\n if (x & 0x2000000000 > 0) {\n result = (result * 0x1000000162E42FFF0) >> 64;\n }\n if (x & 0x1000000000 > 0) {\n result = (result * 0x10000000B17217FBB) >> 64;\n }\n if (x & 0x800000000 > 0) {\n result = (result * 0x1000000058B90BFCE) >> 64;\n }\n if (x & 0x400000000 > 0) {\n result = (result * 0x100000002C5C85FE3) >> 64;\n }\n if (x & 0x200000000 > 0) {\n result = (result * 0x10000000162E42FF1) >> 64;\n }\n if (x & 0x100000000 > 0) {\n result = (result * 0x100000000B17217F8) >> 64;\n }\n if (x & 0x80000000 > 0) {\n result = (result * 0x10000000058B90BFC) >> 64;\n }\n if (x & 0x40000000 > 0) {\n result = (result * 0x1000000002C5C85FE) >> 64;\n }\n if (x & 0x20000000 > 0) {\n result = (result * 0x100000000162E42FF) >> 64;\n }\n if (x & 0x10000000 > 0) {\n result = (result * 0x1000000000B17217F) >> 64;\n }\n if (x & 0x8000000 > 0) {\n result = (result * 0x100000000058B90C0) >> 64;\n }\n if (x & 0x4000000 > 0) {\n result = (result * 0x10000000002C5C860) >> 64;\n }\n if (x & 0x2000000 > 0) {\n result = (result * 0x1000000000162E430) >> 64;\n }\n if (x & 0x1000000 > 0) {\n result = (result * 0x10000000000B17218) >> 64;\n }\n if (x & 0x800000 > 0) {\n result = (result * 0x1000000000058B90C) >> 64;\n }\n if (x & 0x400000 > 0) {\n result = (result * 0x100000000002C5C86) >> 64;\n }\n if (x & 0x200000 > 0) {\n result = (result * 0x10000000000162E43) >> 64;\n }\n if (x & 0x100000 > 0) {\n result = (result * 0x100000000000B1721) >> 64;\n }\n if (x & 0x80000 > 0) {\n result = (result * 0x10000000000058B91) >> 64;\n }\n if (x & 0x40000 > 0) {\n result = (result * 0x1000000000002C5C8) >> 64;\n }\n if (x & 0x20000 > 0) {\n result = (result * 0x100000000000162E4) >> 64;\n }\n if (x & 0x10000 > 0) {\n result = (result * 0x1000000000000B172) >> 64;\n }\n if (x & 0x8000 > 0) {\n result = (result * 0x100000000000058B9) >> 64;\n }\n if (x & 0x4000 > 0) {\n result = (result * 0x10000000000002C5D) >> 64;\n }\n if (x & 0x2000 > 0) {\n result = (result * 0x1000000000000162E) >> 64;\n }\n if (x & 0x1000 > 0) {\n result = (result * 0x10000000000000B17) >> 64;\n }\n if (x & 0x800 > 0) {\n result = (result * 0x1000000000000058C) >> 64;\n }\n if (x & 0x400 > 0) {\n result = (result * 0x100000000000002C6) >> 64;\n }\n if (x & 0x200 > 0) {\n result = (result * 0x10000000000000163) >> 64;\n }\n if (x & 0x100 > 0) {\n result = (result * 0x100000000000000B1) >> 64;\n }\n if (x & 0x80 > 0) {\n result = (result * 0x10000000000000059) >> 64;\n }\n if (x & 0x40 > 0) {\n result = (result * 0x1000000000000002C) >> 64;\n }\n if (x & 0x20 > 0) {\n result = (result * 0x10000000000000016) >> 64;\n }\n if (x & 0x10 > 0) {\n result = (result * 0x1000000000000000B) >> 64;\n }\n if (x & 0x8 > 0) {\n result = (result * 0x10000000000000006) >> 64;\n }\n if (x & 0x4 > 0) {\n result = (result * 0x10000000000000003) >> 64;\n }\n if (x & 0x2 > 0) {\n result = (result * 0x10000000000000001) >> 64;\n }\n if (x & 0x1 > 0) {\n result = (result * 0x10000000000000001) >> 64;\n }\n\n // We're doing two things at the same time:\n //\n // 1. Multiply the result by 2^n + 1, where \"2^n\" is the integer part and the one is added to account for\n // the fact that we initially set the result to 0.5. This is accomplished by subtracting from 191\n // rather than 192.\n // 2. Convert the result to the unsigned 60.18-decimal fixed-point format.\n //\n // This works because 2^(191-ip) = 2^ip / 2^191, where \"ip\" is the integer part \"2^n\".\n result *= SCALE;\n result >>= (191 - (x >> 64));\n }\n }\n\n /// @notice Finds the zero-based index of the first one in the binary representation of x.\n /// @dev See the note on msb in the \"Find First Set\" Wikipedia article https://en.wikipedia.org/wiki/Find_first_set\n /// @param x The uint256 number for which to find the index of the most significant bit.\n /// @return msb The index of the most significant bit as an uint256.\n function mostSignificantBit(uint256 x) internal pure returns (uint256 msb) {\n if (x >= 2**128) {\n x >>= 128;\n msb += 128;\n }\n if (x >= 2**64) {\n x >>= 64;\n msb += 64;\n }\n if (x >= 2**32) {\n x >>= 32;\n msb += 32;\n }\n if (x >= 2**16) {\n x >>= 16;\n msb += 16;\n }\n if (x >= 2**8) {\n x >>= 8;\n msb += 8;\n }\n if (x >= 2**4) {\n x >>= 4;\n msb += 4;\n }\n if (x >= 2**2) {\n x >>= 2;\n msb += 2;\n }\n if (x >= 2**1) {\n // No need to shift x any more.\n msb += 1;\n }\n }\n\n /// @notice Calculates floor(x*y÷denominator) with full precision.\n ///\n /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv.\n ///\n /// Requirements:\n /// - The denominator cannot be zero.\n /// - The result must fit within uint256.\n ///\n /// Caveats:\n /// - This function does not work with fixed-point numbers.\n ///\n /// @param x The multiplicand as an uint256.\n /// @param y The multiplier as an uint256.\n /// @param denominator The divisor as an uint256.\n /// @return result The result as an uint256.\n function mulDiv(\n uint256 x,\n uint256 y,\n uint256 denominator\n ) internal pure returns (uint256 result) {\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n // variables such that product = prod1 * 2^256 + prod0.\n uint256 prod0; // Least significant 256 bits of the product\n uint256 prod1; // Most significant 256 bits of the product\n assembly {\n let mm := mulmod(x, y, not(0))\n prod0 := mul(x, y)\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n }\n\n // Handle non-overflow cases, 256 by 256 division.\n if (prod1 == 0) {\n unchecked {\n result = prod0 / denominator;\n }\n return result;\n }\n\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\n if (prod1 >= denominator) {\n revert PRBMath__MulDivOverflow(prod1, denominator);\n }\n\n ///////////////////////////////////////////////\n // 512 by 256 division.\n ///////////////////////////////////////////////\n\n // Make division exact by subtracting the remainder from [prod1 prod0].\n uint256 remainder;\n assembly {\n // Compute remainder using mulmod.\n remainder := mulmod(x, y, denominator)\n\n // Subtract 256 bit number from 512 bit number.\n prod1 := sub(prod1, gt(remainder, prod0))\n prod0 := sub(prod0, remainder)\n }\n\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\n // See https://cs.stackexchange.com/q/138556/92363.\n unchecked {\n // Does not overflow because the denominator cannot be zero at this stage in the function.\n uint256 lpotdod = denominator & (~denominator + 1);\n assembly {\n // Divide denominator by lpotdod.\n denominator := div(denominator, lpotdod)\n\n // Divide [prod1 prod0] by lpotdod.\n prod0 := div(prod0, lpotdod)\n\n // Flip lpotdod such that it is 2^256 / lpotdod. If lpotdod is zero, then it becomes one.\n lpotdod := add(div(sub(0, lpotdod), lpotdod), 1)\n }\n\n // Shift in bits from prod1 into prod0.\n prod0 |= prod1 * lpotdod;\n\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\n // four bits. That is, denominator * inv = 1 mod 2^4.\n uint256 inverse = (3 * denominator) ^ 2;\n\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\n // in modular arithmetic, doubling the correct bits in each step.\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\n\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\n // is no longer required.\n result = prod0 * inverse;\n return result;\n }\n }\n\n /// @notice Calculates floor(x*y÷1e18) with full precision.\n ///\n /// @dev Variant of \"mulDiv\" with constant folding, i.e. in which the denominator is always 1e18. Before returning the\n /// final result, we add 1 if (x * y) % SCALE >= HALF_SCALE. Without this, 6.6e-19 would be truncated to 0 instead of\n /// being rounded to 1e-18. See \"Listing 6\" and text above it at https://accu.org/index.php/journals/1717.\n ///\n /// Requirements:\n /// - The result must fit within uint256.\n ///\n /// Caveats:\n /// - The body is purposely left uncommented; see the NatSpec comments in \"PRBMath.mulDiv\" to understand how this works.\n /// - It is assumed that the result can never be type(uint256).max when x and y solve the following two equations:\n /// 1. x * y = type(uint256).max * SCALE\n /// 2. (x * y) % SCALE >= SCALE / 2\n ///\n /// @param x The multiplicand as an unsigned 60.18-decimal fixed-point number.\n /// @param y The multiplier as an unsigned 60.18-decimal fixed-point number.\n /// @return result The result as an unsigned 60.18-decimal fixed-point number.\n function mulDivFixedPoint(uint256 x, uint256 y) internal pure returns (uint256 result) {\n uint256 prod0;\n uint256 prod1;\n assembly {\n let mm := mulmod(x, y, not(0))\n prod0 := mul(x, y)\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n }\n\n if (prod1 >= SCALE) {\n revert PRBMath__MulDivFixedPointOverflow(prod1);\n }\n\n uint256 remainder;\n uint256 roundUpUnit;\n assembly {\n remainder := mulmod(x, y, SCALE)\n roundUpUnit := gt(remainder, 499999999999999999)\n }\n\n if (prod1 == 0) {\n unchecked {\n result = (prod0 / SCALE) + roundUpUnit;\n return result;\n }\n }\n\n assembly {\n result := add(\n mul(\n or(\n div(sub(prod0, remainder), SCALE_LPOTD),\n mul(sub(prod1, gt(remainder, prod0)), add(div(sub(0, SCALE_LPOTD), SCALE_LPOTD), 1))\n ),\n SCALE_INVERSE\n ),\n roundUpUnit\n )\n }\n }\n\n /// @notice Calculates floor(x*y÷denominator) with full precision.\n ///\n /// @dev An extension of \"mulDiv\" for signed numbers. Works by computing the signs and the absolute values separately.\n ///\n /// Requirements:\n /// - None of the inputs can be type(int256).min.\n /// - The result must fit within int256.\n ///\n /// @param x The multiplicand as an int256.\n /// @param y The multiplier as an int256.\n /// @param denominator The divisor as an int256.\n /// @return result The result as an int256.\n function mulDivSigned(\n int256 x,\n int256 y,\n int256 denominator\n ) internal pure returns (int256 result) {\n if (x == type(int256).min || y == type(int256).min || denominator == type(int256).min) {\n revert PRBMath__MulDivSignedInputTooSmall();\n }\n\n // Get hold of the absolute values of x, y and the denominator.\n uint256 ax;\n uint256 ay;\n uint256 ad;\n unchecked {\n ax = x < 0 ? uint256(-x) : uint256(x);\n ay = y < 0 ? uint256(-y) : uint256(y);\n ad = denominator < 0 ? uint256(-denominator) : uint256(denominator);\n }\n\n // Compute the absolute value of (x*y)÷denominator. The result must fit within int256.\n uint256 rAbs = mulDiv(ax, ay, ad);\n if (rAbs > uint256(type(int256).max)) {\n revert PRBMath__MulDivSignedOverflow(rAbs);\n }\n\n // Get the signs of x, y and the denominator.\n uint256 sx;\n uint256 sy;\n uint256 sd;\n assembly {\n sx := sgt(x, sub(0, 1))\n sy := sgt(y, sub(0, 1))\n sd := sgt(denominator, sub(0, 1))\n }\n\n // XOR over sx, sy and sd. This is checking whether there are one or three negative signs in the inputs.\n // If yes, the result should be negative.\n result = sx ^ sy ^ sd == 0 ? -int256(rAbs) : int256(rAbs);\n }\n\n /// @notice Calculates the square root of x, rounding down.\n /// @dev Uses the Babylonian method https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method.\n ///\n /// Caveats:\n /// - This function does not work with fixed-point numbers.\n ///\n /// @param x The uint256 number for which to calculate the square root.\n /// @return result The result as an uint256.\n function sqrt(uint256 x) internal pure returns (uint256 result) {\n if (x == 0) {\n return 0;\n }\n\n // Set the initial guess to the closest power of two that is higher than x.\n uint256 xAux = uint256(x);\n result = 1;\n if (xAux >= 0x100000000000000000000000000000000) {\n xAux >>= 128;\n result <<= 64;\n }\n if (xAux >= 0x10000000000000000) {\n xAux >>= 64;\n result <<= 32;\n }\n if (xAux >= 0x100000000) {\n xAux >>= 32;\n result <<= 16;\n }\n if (xAux >= 0x10000) {\n xAux >>= 16;\n result <<= 8;\n }\n if (xAux >= 0x100) {\n xAux >>= 8;\n result <<= 4;\n }\n if (xAux >= 0x10) {\n xAux >>= 4;\n result <<= 2;\n }\n if (xAux >= 0x8) {\n result <<= 1;\n }\n\n // The operations can never overflow because the result is max 2^127 when it enters this block.\n unchecked {\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1; // Seven iterations should be enough\n uint256 roundedDownResult = x / result;\n return result >= roundedDownResult ? roundedDownResult : result;\n }\n }\n}\n" + }, + "contracts/JBSplitsStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {JBOperatable} from './abstract/JBOperatable.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {IJBSplitAllocator} from './interfaces/IJBSplitAllocator.sol';\nimport {JBConstants} from './libraries/JBConstants.sol';\nimport {JBOperations} from './libraries/JBOperations.sol';\nimport {JBGroupedSplits} from './structs/JBGroupedSplits.sol';\nimport {JBSplit} from './structs/JBSplit.sol';\n\n/// @notice Stores splits for each project.\ncontract JBSplitsStore is JBOperatable, IJBSplitsStore {\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error INVALID_LOCKED_UNTIL();\n error INVALID_PROJECT_ID();\n error INVALID_SPLIT_PERCENT();\n error INVALID_TOTAL_PERCENT();\n error PREVIOUS_LOCKED_SPLITS_NOT_INCLUDED();\n\n //*********************************************************************//\n // --------------------- private stored properties ------------------- //\n //*********************************************************************//\n\n /// @notice The number of splits currently set for each project ID's configurations.\n /// @custom:param _projectId The ID of the project to get the split count for.\n /// @custom:param _domain An identifier within which the returned splits should be considered active.\n /// @custom:param _group The identifying group of the splits.\n mapping(uint256 => mapping(uint256 => mapping(uint256 => uint256))) private _splitCountOf;\n\n /// @notice Packed data of splits for each project ID's configurations.\n /// @custom:param _projectId The ID of the project to get packed splits data for.\n /// @custom:param _domain An identifier within which the returned splits should be considered active.\n /// @custom:param _group The identifying group of the splits.\n /// @custom:param _index The indexed order that the split was set at.\n mapping(uint256 => mapping(uint256 => mapping(uint256 => mapping(uint256 => uint256))))\n private _packedSplitParts1Of;\n\n /// @notice More packed data of splits for each project ID's configurations.\n /// @dev This packed data is often 0.\n /// @custom:param _projectId The ID of the project to get packed splits data for.\n /// @custom:param _domain An identifier within which the returned splits should be considered active.\n /// @custom:param _group The identifying group of the splits.\n /// @custom:param _index The indexed order that the split was set at.\n mapping(uint256 => mapping(uint256 => mapping(uint256 => mapping(uint256 => uint256))))\n private _packedSplitParts2Of;\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice Mints ERC-721's that represent project ownership and transfers.\n IJBProjects public immutable override projects;\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Get all splits for the specified project ID, within the specified domain, for the specified group.\n /// @param _projectId The ID of the project to get splits for.\n /// @param _domain An identifier within which the returned splits should be considered active.\n /// @param _group The identifying group of the splits.\n /// @return An array of all splits for the project.\n function splitsOf(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group\n ) external view override returns (JBSplit[] memory) {\n return _getStructsFor(_projectId, _domain, _group);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n constructor(\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory\n ) JBOperatable(_operatorStore) {\n projects = _projects;\n directory = _directory;\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Sets a project's splits.\n /// @dev Only the owner or operator of a project, or the current controller contract of the project, can set its splits.\n /// @dev The new splits must include any currently set splits that are locked.\n /// @param _projectId The ID of the project for which splits are being added.\n /// @param _domain An identifier within which the splits should be considered active.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n function set(\n uint256 _projectId,\n uint256 _domain,\n JBGroupedSplits[] calldata _groupedSplits\n )\n external\n override\n requirePermissionAllowingOverride(\n projects.ownerOf(_projectId),\n _projectId,\n JBOperations.SET_SPLITS,\n address(directory.controllerOf(_projectId)) == msg.sender\n )\n {\n // Push array length in stack\n uint256 _groupedSplitsLength = _groupedSplits.length;\n\n // Set each grouped splits.\n for (uint256 _i; _i < _groupedSplitsLength; ) {\n // Get a reference to the grouped split being iterated on.\n JBGroupedSplits memory _groupedSplit = _groupedSplits[_i];\n\n // Set the splits for the group.\n _set(_projectId, _domain, _groupedSplit.group, _groupedSplit.splits);\n\n unchecked {\n ++_i;\n }\n }\n }\n\n //*********************************************************************//\n // --------------------- private helper functions -------------------- //\n //*********************************************************************//\n\n /// @notice Sets a project's splits.\n /// @dev The new splits must include any currently set splits that are locked.\n /// @param _projectId The ID of the project for which splits are being added.\n /// @param _domain An identifier within which the splits should be considered active.\n /// @param _group An identifier between of splits being set. All splits within this _group must add up to within 100%.\n /// @param _splits The splits to set.\n function _set(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group,\n JBSplit[] memory _splits\n ) internal {\n // Get a reference to the project's current splits.\n JBSplit[] memory _currentSplits = _getStructsFor(_projectId, _domain, _group);\n\n // Keep a reference to the number of splits.\n uint256 _currentSplitsLength = _currentSplits.length;\n\n // Check to see if all locked splits are included.\n for (uint256 _i; _i < _currentSplitsLength; ) {\n // If not locked, continue.\n if (\n block.timestamp < _currentSplits[_i].lockedUntil &&\n !_includesLocked(_splits, _currentSplits[_i])\n ) revert PREVIOUS_LOCKED_SPLITS_NOT_INCLUDED();\n\n unchecked {\n ++_i;\n }\n }\n\n // Add up all the percents to make sure they cumulatively are under 100%.\n uint256 _percentTotal;\n\n // Keep a reference to the number of splits.\n uint256 _splitsLength = _splits.length;\n\n for (uint256 _i; _i < _splitsLength; ) {\n // The percent should be greater than 0.\n if (_splits[_i].percent == 0) revert INVALID_SPLIT_PERCENT();\n\n // ProjectId should be within a uint56\n if (_splits[_i].projectId > type(uint56).max) revert INVALID_PROJECT_ID();\n\n // Add to the total percents.\n _percentTotal = _percentTotal + _splits[_i].percent;\n\n // Validate the total does not exceed the expected value.\n if (_percentTotal > JBConstants.SPLITS_TOTAL_PERCENT) revert INVALID_TOTAL_PERCENT();\n\n uint256 _packedSplitParts1;\n\n // prefer claimed in bit 0.\n if (_splits[_i].preferClaimed) _packedSplitParts1 = 1;\n // prefer add to balance in bit 1.\n if (_splits[_i].preferAddToBalance) _packedSplitParts1 |= 1 << 1;\n // percent in bits 2-33.\n _packedSplitParts1 |= _splits[_i].percent << 2;\n // projectId in bits 32-89.\n _packedSplitParts1 |= _splits[_i].projectId << 34;\n // beneficiary in bits 90-249.\n _packedSplitParts1 |= uint256(uint160(address(_splits[_i].beneficiary))) << 90;\n\n // Store the first split part.\n _packedSplitParts1Of[_projectId][_domain][_group][_i] = _packedSplitParts1;\n\n // If there's data to store in the second packed split part, pack and store.\n if (_splits[_i].lockedUntil > 0 || _splits[_i].allocator != IJBSplitAllocator(address(0))) {\n // Locked until should be within a uint48\n if (_splits[_i].lockedUntil > type(uint48).max) revert INVALID_LOCKED_UNTIL();\n\n // lockedUntil in bits 0-47.\n uint256 _packedSplitParts2 = uint48(_splits[_i].lockedUntil);\n // allocator in bits 48-207.\n _packedSplitParts2 |= uint256(uint160(address(_splits[_i].allocator))) << 48;\n\n // Store the second split part.\n _packedSplitParts2Of[_projectId][_domain][_group][_i] = _packedSplitParts2;\n\n // Otherwise if there's a value stored in the indexed position, delete it.\n } else if (_packedSplitParts2Of[_projectId][_domain][_group][_i] > 0)\n delete _packedSplitParts2Of[_projectId][_domain][_group][_i];\n\n emit SetSplit(_projectId, _domain, _group, _splits[_i], msg.sender);\n\n unchecked {\n ++_i;\n }\n }\n\n // Set the new length of the splits.\n _splitCountOf[_projectId][_domain][_group] = _splitsLength;\n }\n\n /// @notice A flag indiciating if the provided splits array includes the locked split.\n /// @param _splits The array of splits to check within.\n /// @param _lockedSplit The locked split.\n /// @return A flag indicating if the `_lockedSplit` is contained in the `_splits`.\n function _includesLocked(\n JBSplit[] memory _splits,\n JBSplit memory _lockedSplit\n ) private pure returns (bool) {\n // Keep a reference to the number of splits.\n uint256 _numberOfSplits = _splits.length;\n\n for (uint256 _i; _i < _numberOfSplits; ) {\n // Check for sameness.\n if (\n _splits[_i].percent == _lockedSplit.percent &&\n _splits[_i].beneficiary == _lockedSplit.beneficiary &&\n _splits[_i].allocator == _lockedSplit.allocator &&\n _splits[_i].projectId == _lockedSplit.projectId &&\n _splits[_i].preferClaimed == _lockedSplit.preferClaimed &&\n _splits[_i].preferAddToBalance == _lockedSplit.preferAddToBalance &&\n // Allow lock extention.\n _splits[_i].lockedUntil >= _lockedSplit.lockedUntil\n ) return true;\n\n unchecked {\n ++_i;\n }\n }\n\n return false;\n }\n\n /// @notice Unpack splits' packed stored values into easy-to-work-with split structs.\n /// @param _projectId The ID of the project to which the split belongs.\n /// @param _domain The identifier within which the returned splits should be considered active.\n /// @param _group The identifying group of the splits.\n /// @return splits The split structs.\n function _getStructsFor(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group\n ) private view returns (JBSplit[] memory) {\n // Get a reference to the number of splits that need to be added to the returned array.\n uint256 _splitCount = _splitCountOf[_projectId][_domain][_group];\n\n // Initialize an array to be returned that has the set length.\n JBSplit[] memory _splits = new JBSplit[](_splitCount);\n\n // Loop through each split and unpack the values into structs.\n for (uint256 _i; _i < _splitCount; ) {\n // Get a reference to the fist packed data.\n uint256 _packedSplitPart1 = _packedSplitParts1Of[_projectId][_domain][_group][_i];\n\n // Populate the split struct.\n JBSplit memory _split;\n\n // prefer claimed in bit 0.\n _split.preferClaimed = _packedSplitPart1 & 1 == 1;\n // prefer add to balance in bit 1.\n _split.preferAddToBalance = (_packedSplitPart1 >> 1) & 1 == 1;\n // percent in bits 2-33.\n _split.percent = uint256(uint32(_packedSplitPart1 >> 2));\n // projectId in bits 32-89.\n _split.projectId = uint256(uint56(_packedSplitPart1 >> 34));\n // beneficiary in bits 90-249.\n _split.beneficiary = payable(address(uint160(_packedSplitPart1 >> 90)));\n\n // Get a reference to the second packed data.\n uint256 _packedSplitPart2 = _packedSplitParts2Of[_projectId][_domain][_group][_i];\n\n // If there's anything in it, unpack.\n if (_packedSplitPart2 > 0) {\n // lockedUntil in bits 0-47.\n _split.lockedUntil = uint256(uint48(_packedSplitPart2));\n // allocator in bits 48-207.\n _split.allocator = IJBSplitAllocator(address(uint160(_packedSplitPart2 >> 48)));\n }\n\n // Add the split to the value being returned.\n _splits[_i] = _split;\n\n unchecked {\n ++_i;\n }\n }\n\n return _splits;\n }\n}\n" + }, + "contracts/JBETHERC20SplitsPayerDeployer.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Clones} from '@openzeppelin/contracts/proxy/Clones.sol';\nimport {IJBETHERC20SplitsPayerDeployer} from './interfaces/IJBETHERC20SplitsPayerDeployer.sol';\nimport {IJBSplitsPayer} from './interfaces/IJBSplitsPayer.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {JBSplit} from './structs/JBSplit.sol';\nimport {JBGroupedSplits} from './structs/JBGroupedSplits.sol';\nimport {JBETHERC20SplitsPayer} from './JBETHERC20SplitsPayer.sol';\n\n/// @notice Deploys splits payer contracts.\ncontract JBETHERC20SplitsPayerDeployer is IJBETHERC20SplitsPayerDeployer {\n //*********************************************************************//\n // --------------- public immutable stored properties ---------------- //\n //*********************************************************************//\n\n /// @notice The implementation contract on which Clones will be based.\n address immutable implementation;\n\n /// @notice The contract that stores splits for each project.\n IJBSplitsStore immutable splitsStore;\n\n //*********************************************************************//\n // ---------------------------- constructor -------------------------- //\n //*********************************************************************//\n\n /// @param _splitsStore The contract that stores splits for each project.\n constructor(IJBSplitsStore _splitsStore) {\n implementation = address(new JBETHERC20SplitsPayer(_splitsStore));\n splitsStore = _splitsStore;\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Allows anyone to deploy a new splits payer contract.\n /// @dev This contract must have Operator permissions over the SET_SPLITS permission of the specified `_defaultSplitsProjectId`.\n /// @param _defaultSplitsProjectId The ID of project for which the default splits are stored.\n /// @param _defaultSplits The splits to payout when this contract receives direct payments.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _defaultProjectId The ID of the project whose treasury should be forwarded the splits payer contract's received payment leftovers after distributing to the default splits group.\n /// @param _defaultBeneficiary The address that'll receive the project's tokens when the splits payer receives payments.\n /// @param _defaultPreferClaimedTokens A flag indicating whether issued tokens from the splits payer's received payments should be automatically claimed into the beneficiary's wallet.\n /// @param _defaultMemo The memo that'll be forwarded with the splits payer's received payments.\n /// @param _defaultMetadata The metadata that'll be forwarded with the splits payer's received payments.\n /// @param _defaultPreferAddToBalance A flag indicating if received payments should call the `pay` function or the `addToBalance` function of a project.\n /// @param _owner The address that will own the splits payer.\n /// @return splitsPayer The splits payer contract.\n function deploySplitsPayerWithSplits(\n uint256 _defaultSplitsProjectId,\n JBSplit[] memory _defaultSplits,\n IJBSplitsStore _splitsStore,\n uint256 _defaultProjectId,\n address payable _defaultBeneficiary,\n bool _defaultPreferClaimedTokens,\n string memory _defaultMemo,\n bytes memory _defaultMetadata,\n bool _defaultPreferAddToBalance,\n address _owner\n ) external override returns (IJBSplitsPayer splitsPayer) {\n // Use this contract's address as the domain.\n uint256 _domain = uint256(uint160(address(this)));\n\n // Create the random hash using data unique to this instance that'll be used as the storage domain.\n uint256 _group = uint256(keccak256(abi.encodePacked(msg.sender, block.number)));\n\n // Set the splits in the store.\n JBGroupedSplits[] memory _groupedSplits;\n _groupedSplits = new JBGroupedSplits[](1);\n _groupedSplits[0] = JBGroupedSplits(_group, _defaultSplits);\n _splitsStore.set(_defaultSplitsProjectId, _domain, _groupedSplits);\n\n return\n deploySplitsPayer(\n _defaultSplitsProjectId,\n _domain,\n _group,\n _defaultProjectId,\n _defaultBeneficiary,\n _defaultPreferClaimedTokens,\n _defaultMemo,\n _defaultMetadata,\n _defaultPreferAddToBalance,\n _owner\n );\n }\n\n //*********************************************************************//\n // ---------------------- public transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Allows anyone to deploy a new splits payer contract.\n /// @param _defaultSplitsProjectId The ID of project for which the default splits are stored.\n /// @param _defaultSplitsDomain The splits domain to payout when this contract receives direct payments.\n /// @param _defaultSplitsGroup The splits group to payout when this contract receives direct payments.\n /// @param _defaultProjectId The ID of the project whose treasury should be forwarded the splits payer contract's received payment leftovers after distributing to the default splits group.\n /// @param _defaultBeneficiary The address that'll receive the project's tokens when the splits payer receives payments.\n /// @param _defaultPreferClaimedTokens A flag indicating whether issued tokens from the splits payer's received payments should be automatically claimed into the beneficiary's wallet.\n /// @param _defaultMemo The memo that'll be forwarded with the splits payer's received payments.\n /// @param _defaultMetadata The metadata that'll be forwarded with the splits payer's received payments.\n /// @param _defaultPreferAddToBalance A flag indicating if received payments should call the `pay` function or the `addToBalance` function of a project.\n /// @param _owner The address that will own the splits payer.\n /// @return splitsPayer The splits payer contract.\n function deploySplitsPayer(\n uint256 _defaultSplitsProjectId,\n uint256 _defaultSplitsDomain,\n uint256 _defaultSplitsGroup,\n uint256 _defaultProjectId,\n address payable _defaultBeneficiary,\n bool _defaultPreferClaimedTokens,\n string memory _defaultMemo,\n bytes memory _defaultMetadata,\n bool _defaultPreferAddToBalance,\n address _owner\n ) public override returns (IJBSplitsPayer splitsPayer) {\n // Deploy the splits payer.\n splitsPayer = IJBSplitsPayer(payable(Clones.clone(implementation)));\n\n splitsPayer.initialize(\n _defaultSplitsProjectId,\n _defaultSplitsDomain,\n _defaultSplitsGroup,\n _defaultProjectId,\n _defaultBeneficiary,\n _defaultPreferClaimedTokens,\n _defaultMemo,\n _defaultMetadata,\n _defaultPreferAddToBalance,\n _owner\n );\n\n emit DeploySplitsPayer(\n splitsPayer,\n _defaultSplitsProjectId,\n _defaultSplitsDomain,\n _defaultSplitsGroup,\n splitsStore,\n _defaultProjectId,\n _defaultBeneficiary,\n _defaultPreferClaimedTokens,\n _defaultMemo,\n _defaultMetadata,\n _defaultPreferAddToBalance,\n _owner,\n msg.sender\n );\n }\n}\n" + }, + "@openzeppelin/contracts/proxy/Clones.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (proxy/Clones.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for\n * deploying minimal proxy contracts, also known as \"clones\".\n *\n * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies\n * > a minimal bytecode implementation that delegates all calls to a known, fixed address.\n *\n * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`\n * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the\n * deterministic method.\n *\n * _Available since v3.4._\n */\nlibrary Clones {\n /**\n * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.\n *\n * This function uses the create opcode, which should never revert.\n */\n function clone(address implementation) internal returns (address instance) {\n assembly {\n let ptr := mload(0x40)\n mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)\n mstore(add(ptr, 0x14), shl(0x60, implementation))\n mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)\n instance := create(0, ptr, 0x37)\n }\n require(instance != address(0), \"ERC1167: create failed\");\n }\n\n /**\n * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.\n *\n * This function uses the create2 opcode and a `salt` to deterministically deploy\n * the clone. Using the same `implementation` and `salt` multiple time will revert, since\n * the clones cannot be deployed twice at the same address.\n */\n function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {\n assembly {\n let ptr := mload(0x40)\n mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)\n mstore(add(ptr, 0x14), shl(0x60, implementation))\n mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)\n instance := create2(0, ptr, 0x37, salt)\n }\n require(instance != address(0), \"ERC1167: create2 failed\");\n }\n\n /**\n * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.\n */\n function predictDeterministicAddress(\n address implementation,\n bytes32 salt,\n address deployer\n ) internal pure returns (address predicted) {\n assembly {\n let ptr := mload(0x40)\n mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)\n mstore(add(ptr, 0x14), shl(0x60, implementation))\n mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf3ff00000000000000000000000000000000)\n mstore(add(ptr, 0x38), shl(0x60, deployer))\n mstore(add(ptr, 0x4c), salt)\n mstore(add(ptr, 0x6c), keccak256(ptr, 0x37))\n predicted := keccak256(add(ptr, 0x37), 0x55)\n }\n }\n\n /**\n * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.\n */\n function predictDeterministicAddress(address implementation, bytes32 salt)\n internal\n view\n returns (address predicted)\n {\n return predictDeterministicAddress(implementation, salt, address(this));\n }\n}\n" + }, + "contracts/interfaces/IJBETHERC20SplitsPayerDeployer.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBSplitsPayer} from './IJBSplitsPayer.sol';\nimport {IJBSplitsStore} from './IJBSplitsStore.sol';\nimport {JBSplit} from './../structs/JBSplit.sol';\n\ninterface IJBETHERC20SplitsPayerDeployer {\n event DeploySplitsPayer(\n IJBSplitsPayer indexed splitsPayer,\n uint256 defaultSplitsProjectId,\n uint256 defaultSplitsDomain,\n uint256 defaultSplitsGroup,\n IJBSplitsStore splitsStore,\n uint256 defaultProjectId,\n address defaultBeneficiary,\n bool defaultPreferClaimedTokens,\n string defaultMemo,\n bytes defaultMetadata,\n bool preferAddToBalance,\n address owner,\n address caller\n );\n\n function deploySplitsPayer(\n uint256 defaultSplitsProjectId,\n uint256 defaultSplitsDomain,\n uint256 defaultSplitsGroup,\n uint256 defaultProjectId,\n address payable defaultBeneficiary,\n bool defaultPreferClaimedTokens,\n string calldata defaultMemo,\n bytes calldata defaultMetadata,\n bool preferAddToBalance,\n address owner\n ) external returns (IJBSplitsPayer splitsPayer);\n\n function deploySplitsPayerWithSplits(\n uint256 defaultSplitsProjectId,\n JBSplit[] memory defaultSplits,\n IJBSplitsStore splitsStore,\n uint256 defaultProjectId,\n address payable defaultBeneficiary,\n bool defaultPreferClaimedTokens,\n string memory defaultMemo,\n bytes memory defaultMetadata,\n bool defaultPreferAddToBalance,\n address owner\n ) external returns (IJBSplitsPayer splitsPayer);\n}\n" + }, + "contracts/interfaces/IJBSplitsPayer.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBSplit} from './../structs/JBSplit.sol';\nimport {JBGroupedSplits} from './../structs/JBGroupedSplits.sol';\nimport {IJBSplitsStore} from './IJBSplitsStore.sol';\n\ninterface IJBSplitsPayer is IERC165 {\n event SetDefaultSplitsReference(\n uint256 indexed projectId,\n uint256 indexed domain,\n uint256 indexed group,\n address caller\n );\n event Pay(\n uint256 indexed projectId,\n address beneficiary,\n address token,\n uint256 amount,\n uint256 decimals,\n uint256 leftoverAmount,\n uint256 minReturnedTokens,\n bool preferClaimedTokens,\n string memo,\n bytes metadata,\n address caller\n );\n\n event AddToBalance(\n uint256 indexed projectId,\n address beneficiary,\n address token,\n uint256 amount,\n uint256 decimals,\n uint256 leftoverAmount,\n string memo,\n bytes metadata,\n address caller\n );\n\n event DistributeToSplitGroup(\n uint256 indexed projectId,\n uint256 indexed domain,\n uint256 indexed group,\n address caller\n );\n\n event DistributeToSplit(\n JBSplit split,\n uint256 amount,\n address defaultBeneficiary,\n address caller\n );\n\n function defaultSplitsProjectId() external view returns (uint256);\n\n function defaultSplitsDomain() external view returns (uint256);\n\n function defaultSplitsGroup() external view returns (uint256);\n\n function splitsStore() external view returns (IJBSplitsStore);\n\n function initialize(\n uint256 defaultSplitsProjectId,\n uint256 defaultSplitsDomain,\n uint256 defaultSplitsGroup,\n uint256 defaultProjectId,\n address payable defaultBeneficiary,\n bool defaultPreferClaimedTokens,\n string memory defaultMemo,\n bytes memory defaultMetadata,\n bool preferAddToBalance,\n address owner\n ) external;\n\n function setDefaultSplitsReference(uint256 projectId, uint256 domain, uint256 group) external;\n\n function setDefaultSplits(\n uint256 projectId,\n uint256 domain,\n uint256 group,\n JBGroupedSplits[] memory splitsGroup\n ) external;\n}\n" + }, + "contracts/JBETHERC20SplitsPayer.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {ReentrancyGuard} from '@openzeppelin/contracts/security/ReentrancyGuard.sol';\nimport {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';\nimport {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';\nimport {Address} from '@openzeppelin/contracts/utils/Address.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {IJBSplitsPayer} from './interfaces/IJBSplitsPayer.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {JBConstants} from './libraries/JBConstants.sol';\nimport {JBETHERC20ProjectPayer} from './JBETHERC20ProjectPayer.sol';\nimport {IJBSplitAllocator} from './interfaces/IJBSplitAllocator.sol';\nimport {JBTokens} from './libraries/JBTokens.sol';\nimport {JBGroupedSplits} from './structs/JBGroupedSplits.sol';\nimport {JBSplit} from './structs/JBSplit.sol';\nimport {JBSplitAllocationData} from './structs/JBSplitAllocationData.sol';\n\n/// @notice Sends ETH or ERC20's to a group of splits as it receives direct payments or has its functions called.\n/// @dev Inherit from this contract or borrow from its logic to forward ETH or ERC20's to a group of splits from within other contracts.\ncontract JBETHERC20SplitsPayer is JBETHERC20ProjectPayer, ReentrancyGuard, IJBSplitsPayer {\n using SafeERC20 for IERC20;\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice The contract that stores splits for each project.\n IJBSplitsStore public immutable override splitsStore;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The ID of project for which the default splits are stored.\n uint256 public override defaultSplitsProjectId;\n\n /// @notice The domain within which the default splits are stored.\n uint256 public override defaultSplitsDomain;\n\n /// @notice The group within which the default splits are stored.\n uint256 public override defaultSplitsGroup;\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if this contract adheres to the specified interface.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(JBETHERC20ProjectPayer, IERC165) returns (bool) {\n return\n _interfaceId == type(IJBSplitsPayer).interfaceId || super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _splitsStore A contract that stores splits for each project.\n constructor(IJBSplitsStore _splitsStore) JBETHERC20ProjectPayer(_splitsStore.directory()) {\n splitsStore = _splitsStore;\n }\n\n /// @dev The re-initialize check is done in the inherited paroject payer\n /// @param _defaultSplitsProjectId The ID of project for which the default splits are stored.\n /// @param _defaultSplitsDomain The splits domain to payout when this contract receives direct payments.\n /// @param _defaultSplitsGroup The splits group to payout when this contract receives direct payments.\n /// @param _defaultProjectId The ID of the project whose treasury should be forwarded the splits payer contract's received payment leftovers after distributing to the default splits group.\n /// @param _defaultBeneficiary The address that'll receive the project's tokens.\n /// @param _defaultPreferClaimedTokens A flag indicating whether issued tokens should be automatically claimed into the beneficiary's wallet.\n /// @param _defaultMemo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _defaultMetadata Bytes to send along to the project's data source and delegate, if provided.\n /// @param _preferAddToBalance A flag indicating if received payments should call the `pay` function or the `addToBalance` function of a project.\n /// @param _owner The address that will own the contract.\n function initialize(\n uint256 _defaultSplitsProjectId,\n uint256 _defaultSplitsDomain,\n uint256 _defaultSplitsGroup,\n uint256 _defaultProjectId,\n address payable _defaultBeneficiary,\n bool _defaultPreferClaimedTokens,\n string memory _defaultMemo,\n bytes memory _defaultMetadata,\n bool _preferAddToBalance,\n address _owner\n ) external override {\n super.initialize(\n _defaultProjectId,\n _defaultBeneficiary,\n _defaultPreferClaimedTokens,\n _defaultMemo,\n _defaultMetadata,\n _preferAddToBalance,\n _owner\n );\n\n defaultSplitsProjectId = _defaultSplitsProjectId;\n defaultSplitsDomain = _defaultSplitsDomain;\n defaultSplitsGroup = _defaultSplitsGroup;\n }\n\n //*********************************************************************//\n // ------------------------- default receive ------------------------- //\n //*********************************************************************//\n\n /// @notice Received funds are paid to the default split group using the stored default properties.\n /// @dev This function is called automatically when the contract receives an ETH payment.\n receive() external payable virtual override nonReentrant {\n // Pay the splits and get a reference to the amount leftover.\n uint256 _leftoverAmount = _payToSplits(\n defaultSplitsProjectId,\n defaultSplitsDomain,\n defaultSplitsGroup,\n JBTokens.ETH,\n address(this).balance,\n 18, // decimals.\n defaultBeneficiary != address(0) ? defaultBeneficiary : tx.origin\n );\n\n // If there is no leftover amount, nothing left to pay.\n if (_leftoverAmount == 0) return;\n\n // If there's a default project ID, try to pay it.\n if (defaultProjectId != 0)\n if (defaultPreferAddToBalance)\n // Pay the project by adding to its balance if prefered.\n _addToBalanceOf(\n defaultProjectId,\n JBTokens.ETH,\n _leftoverAmount,\n 18, // decimals.\n defaultMemo,\n defaultMetadata\n );\n // Otherwise, issue a payment to the project.\n else\n _pay(\n defaultProjectId,\n JBTokens.ETH,\n _leftoverAmount,\n 18, // decimals.\n defaultBeneficiary != address(0) ? defaultBeneficiary : tx.origin,\n 0, // min returned tokens.\n defaultPreferClaimedTokens,\n defaultMemo,\n defaultMetadata\n );\n // If no project was specified, send the funds directly to the beneficiary or the tx.origin.\n else\n Address.sendValue(\n defaultBeneficiary != address(0) ? payable(defaultBeneficiary) : payable(tx.origin),\n _leftoverAmount\n );\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Sets the splits in the splits store that payments this contract receives will be split between.\n /// @param _projectId The ID of project for which the default splits are stored.\n /// @param _domain The domain within which the default splits are stored.\n /// @param _group The group within which the default splits are stored.\n /// @param _groupedSplits The split groups to set.\n function setDefaultSplits(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group,\n JBGroupedSplits[] memory _groupedSplits\n ) external virtual override onlyOwner {\n // Set the splits in the store.\n splitsStore.set(_projectId, _domain, _groupedSplits);\n\n // Set the splits reference.\n setDefaultSplitsReference(_projectId, _domain, _group);\n }\n\n //*********************************************************************//\n // ----------------------- public transactions ----------------------- //\n //*********************************************************************//\n\n /// @notice Sets the location of the splits that payments this contract receives will be split between.\n /// @param _projectId The ID of project for which the default splits are stored.\n /// @param _domain The domain within which the default splits are stored.\n /// @param _group The group within which the default splits are stored.\n function setDefaultSplitsReference(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group\n ) public virtual override onlyOwner {\n // Set the default splits project ID if it's changing.\n if (_projectId != defaultSplitsProjectId) defaultSplitsProjectId = _projectId;\n\n // Set the default splits domain if it's changing.\n if (_domain != defaultSplitsDomain) defaultSplitsDomain = _domain;\n\n // Set the default splits group if it's changing.\n if (_group != defaultSplitsGroup) defaultSplitsGroup = _group;\n\n emit SetDefaultSplitsReference(_projectId, _domain, _group, msg.sender);\n }\n\n /// @notice Make a payment to the specified project after first splitting the amount among the stored default splits.\n /// @param _projectId The ID of the project that is being paid after.\n /// @param _token The token being paid in.\n /// @param _amount The amount of tokens being paid, as a fixed point number. If the token is ETH, this is ignored and msg.value is used in its place.\n /// @param _decimals The number of decimals in the `_amount` fixed point number. If the token is ETH, this is ignored and 18 is used in its place, which corresponds to the amount of decimals expected in msg.value.\n /// @param _beneficiary The address who will receive tokens from the payment made with leftover funds.\n /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with 18 decimals.\n /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\n /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n function pay(\n uint256 _projectId,\n address _token,\n uint256 _amount,\n uint256 _decimals,\n address _beneficiary,\n uint256 _minReturnedTokens,\n bool _preferClaimedTokens,\n string calldata _memo,\n bytes calldata _metadata\n ) public payable virtual override nonReentrant {\n // ETH shouldn't be sent if the token isn't ETH.\n if (address(_token) != JBTokens.ETH) {\n if (msg.value > 0) revert NO_MSG_VALUE_ALLOWED();\n\n // Get a reference to the balance before receiving tokens.\n uint256 _balanceBefore = IERC20(_token).balanceOf(address(this));\n\n // Transfer tokens to this contract from the msg sender.\n IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount);\n\n // The amount should reflect the change in balance.\n _amount = IERC20(_token).balanceOf(address(this)) - _balanceBefore;\n } else {\n // If ETH is being paid, set the amount to the message value, and decimals to 18.\n _amount = msg.value;\n _decimals = 18;\n }\n\n // Pay the splits and get a reference to the amount leftover.\n uint256 _leftoverAmount = _payToSplits(\n defaultSplitsProjectId,\n defaultSplitsDomain,\n defaultSplitsGroup,\n _token,\n _amount,\n _decimals,\n defaultBeneficiary != address(0) ? defaultBeneficiary : tx.origin\n );\n\n // Pay any leftover amount.\n if (_leftoverAmount > 0) {\n // If there's a default project ID, try to pay it.\n if (_projectId != 0) {\n _pay(\n _projectId,\n _token,\n _leftoverAmount,\n _decimals,\n _beneficiary != address(0) ? _beneficiary : defaultBeneficiary != address(0)\n ? defaultBeneficiary\n : tx.origin,\n _minReturnedTokens,\n _preferClaimedTokens,\n _memo,\n _metadata\n );\n }\n // If no project was specified, send the funds directly to the beneficiary or the tx.origin.\n else {\n // Transfer the ETH.\n if (_token == JBTokens.ETH)\n Address.sendValue(\n // If there's a beneficiary, send the funds directly to the beneficiary. Otherwise send to the tx.origin.\n _beneficiary != address(0) ? payable(_beneficiary) : defaultBeneficiary != address(0)\n ? defaultBeneficiary\n : payable(tx.origin),\n _leftoverAmount\n );\n // Or, transfer the ERC20.\n else\n IERC20(_token).safeTransfer(\n // If there's a beneficiary, send the funds directly to the beneficiary. Otherwise send to the tx.origin.\n _beneficiary != address(0) ? _beneficiary : defaultBeneficiary != address(0)\n ? defaultBeneficiary\n : tx.origin,\n _leftoverAmount\n );\n }\n }\n\n emit Pay(\n _projectId,\n _beneficiary != address(0) ? _beneficiary : defaultBeneficiary != address(0)\n ? defaultBeneficiary\n : tx.origin,\n _token,\n _amount,\n _decimals,\n _leftoverAmount,\n _minReturnedTokens,\n _preferClaimedTokens,\n _memo,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Add to the balance of the specified project after first splitting the amount among the stored default splits.\n /// @param _projectId The ID of the project that is being paid after.\n /// @param _token The token being paid in.\n /// @param _amount The amount of tokens being paid, as a fixed point number. If the token is ETH, this is ignored and msg.value is used in its place.\n /// @param _decimals The number of decimals in the `_amount` fixed point number. If the token is ETH, this is ignored and 18 is used in its place, which corresponds to the amount of decimals expected in msg.value.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the terminal.\n function addToBalanceOf(\n uint256 _projectId,\n address _token,\n uint256 _amount,\n uint256 _decimals,\n string calldata _memo,\n bytes calldata _metadata\n ) public payable virtual override nonReentrant {\n // ETH shouldn't be sent if this terminal's token isn't ETH.\n if (address(_token) != JBTokens.ETH) {\n if (msg.value > 0) revert NO_MSG_VALUE_ALLOWED();\n\n // Get a reference to the balance before receiving tokens.\n uint256 _balanceBefore = IERC20(_token).balanceOf(address(this));\n\n // Transfer tokens to this contract from the msg sender.\n IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount);\n\n // The amount should reflect the change in balance.\n _amount = IERC20(_token).balanceOf(address(this)) - _balanceBefore;\n } else {\n // If ETH is being paid, set the amount to the message value, and decimals to 18.\n _amount = msg.value;\n _decimals = 18;\n }\n\n // Pay the splits and get a reference to the amount leftover.\n uint256 _leftoverAmount = _payToSplits(\n defaultSplitsProjectId,\n defaultSplitsDomain,\n defaultSplitsGroup,\n _token,\n _amount,\n _decimals,\n defaultBeneficiary != address(0) ? defaultBeneficiary : tx.origin\n );\n\n // Distribute any leftover amount.\n if (_leftoverAmount > 0) {\n // If there's a default project ID, try to add to its balance.\n if (_projectId != 0)\n // Add to the project's balance.\n _addToBalanceOf(_projectId, _token, _leftoverAmount, _decimals, _memo, _metadata);\n\n // Otherwise, send a payment to the beneficiary.\n else {\n // Transfer the ETH.\n if (_token == JBTokens.ETH)\n Address.sendValue(\n // If there's a default beneficiary, send the funds directly to the beneficiary. Otherwise send to the tx.origin.\n defaultBeneficiary != address(0) ? defaultBeneficiary : payable(tx.origin),\n _leftoverAmount\n );\n // Or, transfer the ERC20.\n else\n IERC20(_token).safeTransfer(\n // If there's a default beneficiary, send the funds directly to the beneficiary. Otherwise send to the tx.origin.\n defaultBeneficiary != address(0) ? defaultBeneficiary : tx.origin,\n _leftoverAmount\n );\n }\n }\n\n emit AddToBalance(\n _projectId,\n defaultBeneficiary != address(0) ? defaultBeneficiary : tx.origin,\n _token,\n _amount,\n _decimals,\n _leftoverAmount,\n _memo,\n _metadata,\n msg.sender\n );\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Split an amount between all splits.\n /// @param _splitsProjectId The ID of the project to which the splits belong.\n /// @param _splitsDomain The splits domain to which the group belongs.\n /// @param _splitsGroup The splits group to pay.\n /// @param _token The token the amonut being split is in.\n /// @param _amount The amount of tokens being split, as a fixed point number. If the `_token` is ETH, this is ignored and msg.value is used in its place.\n /// @param _decimals The number of decimals in the `_amount` fixed point number.\n /// @param _defaultBeneficiary The address that will benefit from any non-specified beneficiaries in splits.\n /// @return leftoverAmount The amount leftover after all splits were paid.\n function _payToSplits(\n uint256 _splitsProjectId,\n uint256 _splitsDomain,\n uint256 _splitsGroup,\n address _token,\n uint256 _amount,\n uint256 _decimals,\n address _defaultBeneficiary\n ) internal virtual returns (uint256 leftoverAmount) {\n // Pay the splits.\n leftoverAmount = _payTo(\n splitsStore.splitsOf(_splitsProjectId, _splitsDomain, _splitsGroup),\n _token,\n _amount,\n _decimals,\n _defaultBeneficiary\n );\n emit DistributeToSplitGroup(_splitsProjectId, _splitsDomain, _splitsGroup, msg.sender);\n }\n\n /// @notice Split an amount between all splits.\n /// @param _splits The splits.\n /// @param _token The token the amonut being split is in.\n /// @param _amount The amount of tokens being split, as a fixed point number. If the `_token` is ETH, this is ignored and msg.value is used in its place.\n /// @param _decimals The number of decimals in the `_amount` fixed point number.\n /// @param _defaultBeneficiary The address that will benefit from any non-specified beneficiaries in splits.\n /// @return leftoverAmount The amount leftover after all splits were paid.\n function _payTo(\n JBSplit[] memory _splits,\n address _token,\n uint256 _amount,\n uint256 _decimals,\n address _defaultBeneficiary\n ) internal virtual returns (uint256 leftoverAmount) {\n // Set the leftover amount to the initial balance.\n leftoverAmount = _amount;\n\n // Settle between all splits.\n for (uint256 i; i < _splits.length; ) {\n // Get a reference to the split being iterated on.\n JBSplit memory _split = _splits[i];\n\n // The amount to send towards the split.\n uint256 _splitAmount = PRBMath.mulDiv(\n _amount,\n _split.percent,\n JBConstants.SPLITS_TOTAL_PERCENT\n );\n\n if (_splitAmount > 0) {\n // Transfer tokens to the split.\n // If there's an allocator set, transfer to its `allocate` function.\n if (_split.allocator != IJBSplitAllocator(address(0))) {\n // Create the data to send to the allocator.\n JBSplitAllocationData memory _data = JBSplitAllocationData(\n _token,\n _splitAmount,\n _decimals,\n defaultProjectId,\n 0,\n _split\n );\n\n // Approve the `_amount` of tokens for the split allocator to transfer tokens from this contract.\n if (_token != JBTokens.ETH)\n IERC20(_token).safeApprove(address(_split.allocator), _splitAmount);\n\n // If the token is ETH, send it in msg.value.\n uint256 _payableValue = _token == JBTokens.ETH ? _splitAmount : 0;\n\n // Trigger the allocator's `allocate` function.\n _split.allocator.allocate{value: _payableValue}(_data);\n\n // Otherwise, if a project is specified, make a payment to it.\n } else if (_split.projectId != 0) {\n if (_split.preferAddToBalance)\n _addToBalanceOf(\n _split.projectId,\n _token,\n _splitAmount,\n _decimals,\n defaultMemo,\n defaultMetadata\n );\n else\n _pay(\n _split.projectId,\n _token,\n _splitAmount,\n _decimals,\n _split.beneficiary != address(0) ? _split.beneficiary : _defaultBeneficiary,\n 0,\n _split.preferClaimed,\n defaultMemo,\n defaultMetadata\n );\n } else {\n // Transfer the ETH.\n if (_token == JBTokens.ETH)\n Address.sendValue(\n // Get a reference to the address receiving the tokens. If there's a beneficiary, send the funds directly to the beneficiary. Otherwise send to _defaultBeneficiary.\n _split.beneficiary != address(0) ? _split.beneficiary : payable(_defaultBeneficiary),\n _splitAmount\n );\n // Or, transfer the ERC20.\n else {\n IERC20(_token).safeTransfer(\n // Get a reference to the address receiving the tokens. If there's a beneficiary, send the funds directly to the beneficiary. Otherwise send to _defaultBeneficiary.\n _split.beneficiary != address(0) ? _split.beneficiary : _defaultBeneficiary,\n _splitAmount\n );\n }\n }\n\n // Subtract from the amount to be sent to the beneficiary.\n leftoverAmount = leftoverAmount - _splitAmount;\n }\n\n emit DistributeToSplit(_split, _splitAmount, _defaultBeneficiary, msg.sender);\n\n unchecked {\n ++i;\n }\n }\n }\n}\n" + }, + "@openzeppelin/contracts/security/ReentrancyGuard.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuard {\n // Booleans are more expensive than uint256 or any type that takes up a full\n // word because each write operation emits an extra SLOAD to first read the\n // slot's contents, replace the bits taken up by the boolean, and then write\n // back. This is the compiler's defense against contract upgrades and\n // pointer aliasing, and it cannot be disabled.\n\n // The values being non-zero value makes deployment a bit more expensive,\n // but in exchange the refund on every call to nonReentrant will be lower in\n // amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to\n // increase the likelihood of the full refund coming into effect.\n uint256 private constant _NOT_ENTERED = 1;\n uint256 private constant _ENTERED = 2;\n\n uint256 private _status;\n\n constructor() {\n _status = _NOT_ENTERED;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a `nonReentrant` function from another `nonReentrant`\n * function is not supported. It is possible to prevent this from happening\n * by making the `nonReentrant` function external, and making it call a\n * `private` function that does the actual work.\n */\n modifier nonReentrant() {\n // On the first call to nonReentrant, _notEntered will be true\n require(_status != _ENTERED, \"ReentrancyGuard: reentrant call\");\n\n // Any calls to nonReentrant after this point will fail\n _status = _ENTERED;\n\n _;\n\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _status = _NOT_ENTERED;\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length > 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Address.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n *\n * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCall(target, data, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n require(isContract(target), \"Address: call to non-contract\");\n\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n require(isContract(target), \"Address: static call to non-contract\");\n\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(isContract(target), \"Address: delegate call to non-contract\");\n\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n }\n}\n" + }, + "contracts/JBETHERC20ProjectPayer.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';\nimport {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';\nimport {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';\nimport {ERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBProjectPayer} from './interfaces/IJBProjectPayer.sol';\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\nimport {JBTokens} from './libraries/JBTokens.sol';\n\n/// @notice Sends ETH or ERC20's to a project treasury as it receives direct payments or has it's functions called.\n/// @dev Inherit from this contract or borrow from its logic to forward ETH or ERC20's to project treasuries from within other contracts.\ncontract JBETHERC20ProjectPayer is Ownable, ERC165, IJBProjectPayer {\n using SafeERC20 for IERC20;\n\n //*********************************************************************//\n // -------------------------- custom errors -------------------------- //\n //*********************************************************************//\n error INCORRECT_DECIMAL_AMOUNT();\n error ALREADY_INITIALIZED();\n error NO_MSG_VALUE_ALLOWED();\n error TERMINAL_NOT_FOUND();\n\n //*********************************************************************//\n // ------------------- public immutable properties ------------------- //\n //*********************************************************************//\n\n /// @notice A contract storing directories of terminals and controllers for each project.\n IJBDirectory public immutable override directory;\n\n /// @notice The deployer associated with this implementation. Used to rule out double initialization.\n address public immutable override projectPayerDeployer;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The ID of the project that should be used to forward this contract's received payments.\n uint256 public override defaultProjectId;\n\n /// @notice The beneficiary that should be used in the payment made when this contract receives payments.\n address payable public override defaultBeneficiary;\n\n /// @notice A flag indicating whether issued tokens should be automatically claimed into the beneficiary's wallet. Leaving tokens unclaimed saves gas.\n bool public override defaultPreferClaimedTokens;\n\n /// @notice The memo that should be used in the payment made when this contract receives payments.\n string public override defaultMemo;\n\n /// @notice The metadata that should be used in the payment made when this contract receives payments.\n bytes public override defaultMetadata;\n\n /// @notice A flag indicating if received payments should call the `pay` function or the `addToBalance` function of a project.\n bool public override defaultPreferAddToBalance;\n\n //*********************************************************************//\n // ------------------------- public views ---------------------------- //\n //*********************************************************************//\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if the provided interface ID is supported.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(ERC165, IERC165) returns (bool) {\n return\n _interfaceId == type(IJBProjectPayer).interfaceId || super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // -------------------------- constructors --------------------------- //\n //*********************************************************************//\n\n /// @dev This is the constructor of the implementation. The directory is shared between project payers and is immutable. If a new JBDirectory is needed, a new JBProjectPayerDeployer should be deployed.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n constructor(IJBDirectory _directory) {\n directory = _directory;\n projectPayerDeployer = msg.sender;\n }\n\n /// @param _defaultProjectId The ID of the project whose treasury should be forwarded this contract's received payments.\n /// @param _defaultBeneficiary The address that'll receive the project's tokens.\n /// @param _defaultPreferClaimedTokens A flag indicating whether issued tokens should be automatically claimed into the beneficiary's wallet.\n /// @param _defaultMemo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _defaultMetadata Bytes to send along to the project's data source and delegate, if provided.\n /// @param _defaultPreferAddToBalance A flag indicating if received payments should call the `pay` function or the `addToBalance` function of a project.\n /// @param _owner The address that will own the contract.\n function initialize(\n uint256 _defaultProjectId,\n address payable _defaultBeneficiary,\n bool _defaultPreferClaimedTokens,\n string memory _defaultMemo,\n bytes memory _defaultMetadata,\n bool _defaultPreferAddToBalance,\n address _owner\n ) public {\n if (msg.sender != projectPayerDeployer) revert ALREADY_INITIALIZED();\n\n defaultProjectId = _defaultProjectId;\n defaultBeneficiary = _defaultBeneficiary;\n defaultPreferClaimedTokens = _defaultPreferClaimedTokens;\n defaultMemo = _defaultMemo;\n defaultMetadata = _defaultMetadata;\n defaultPreferAddToBalance = _defaultPreferAddToBalance;\n _transferOwnership(_owner);\n }\n\n //*********************************************************************//\n // ------------------------- default receive ------------------------- //\n //*********************************************************************//\n\n /// @notice Received funds are paid to the default project ID using the stored default properties.\n /// @dev Use the `addToBalance` function if there's a preference to do so. Otherwise use `pay`.\n /// @dev This function is called automatically when the contract receives an ETH payment.\n receive() external payable virtual override {\n if (defaultPreferAddToBalance)\n _addToBalanceOf(\n defaultProjectId,\n JBTokens.ETH,\n address(this).balance,\n 18, // balance is a fixed point number with 18 decimals.\n defaultMemo,\n defaultMetadata\n );\n else\n _pay(\n defaultProjectId,\n JBTokens.ETH,\n address(this).balance,\n 18, // balance is a fixed point number with 18 decimals.\n defaultBeneficiary == address(0) ? tx.origin : defaultBeneficiary,\n 0, // Can't determine expectation of returned tokens ahead of time.\n defaultPreferClaimedTokens,\n defaultMemo,\n defaultMetadata\n );\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Sets the default values that determine how to interact with a protocol treasury when this contract receives ETH directly.\n /// @param _projectId The ID of the project whose treasury should be forwarded this contract's received payments.\n /// @param _beneficiary The address that'll receive the project's tokens.\n /// @param _preferClaimedTokens A flag indicating whether issued tokens should be automatically claimed into the beneficiary's wallet.\n /// @param _memo The memo that'll be used.\n /// @param _metadata The metadata that'll be sent.\n /// @param _defaultPreferAddToBalance A flag indicating if received payments should call the `pay` function or the `addToBalance` function of a project.\n function setDefaultValues(\n uint256 _projectId,\n address payable _beneficiary,\n bool _preferClaimedTokens,\n string memory _memo,\n bytes memory _metadata,\n bool _defaultPreferAddToBalance\n ) external virtual override onlyOwner {\n // Set the default project ID if it has changed.\n if (_projectId != defaultProjectId) defaultProjectId = _projectId;\n\n // Set the default beneficiary if it has changed.\n if (_beneficiary != defaultBeneficiary) defaultBeneficiary = _beneficiary;\n\n // Set the default claimed token preference if it has changed.\n if (_preferClaimedTokens != defaultPreferClaimedTokens)\n defaultPreferClaimedTokens = _preferClaimedTokens;\n\n // Set the default memo if it has changed.\n if (keccak256(abi.encodePacked(_memo)) != keccak256(abi.encodePacked(defaultMemo)))\n defaultMemo = _memo;\n\n // Set the default metadata if it has changed.\n if (keccak256(abi.encodePacked(_metadata)) != keccak256(abi.encodePacked(defaultMetadata)))\n defaultMetadata = _metadata;\n\n // Set the add to balance preference if it has changed.\n if (_defaultPreferAddToBalance != defaultPreferAddToBalance)\n defaultPreferAddToBalance = _defaultPreferAddToBalance;\n\n emit SetDefaultValues(\n _projectId,\n _beneficiary,\n _preferClaimedTokens,\n _memo,\n _metadata,\n _defaultPreferAddToBalance,\n msg.sender\n );\n }\n\n //*********************************************************************//\n // ----------------------- public transactions ----------------------- //\n //*********************************************************************//\n\n /// @notice Make a payment to the specified project.\n /// @param _projectId The ID of the project that is being paid.\n /// @param _token The token being paid in.\n /// @param _amount The amount of tokens being paid, as a fixed point number. If the token is ETH, this is ignored and msg.value is used in its place.\n /// @param _decimals The number of decimals in the `_amount` fixed point number. If the token is ETH, this is ignored and 18 is used in its place, which corresponds to the amount of decimals expected in msg.value.\n /// @param _beneficiary The address who will receive tokens from the payment.\n /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with 18 decimals.\n /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\n /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n function pay(\n uint256 _projectId,\n address _token,\n uint256 _amount,\n uint256 _decimals,\n address _beneficiary,\n uint256 _minReturnedTokens,\n bool _preferClaimedTokens,\n string calldata _memo,\n bytes calldata _metadata\n ) public payable virtual override {\n // ETH shouldn't be sent if the token isn't ETH.\n if (address(_token) != JBTokens.ETH) {\n if (msg.value > 0) revert NO_MSG_VALUE_ALLOWED();\n\n // Get a reference to the balance before receiving tokens.\n uint256 _balanceBefore = IERC20(_token).balanceOf(address(this));\n\n // Transfer tokens to this contract from the msg sender.\n IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount);\n\n // The amount should reflect the change in balance.\n _amount = IERC20(_token).balanceOf(address(this)) - _balanceBefore;\n } else {\n // If ETH is being paid, set the amount to the message value, and decimals to 18.\n _amount = msg.value;\n _decimals = 18;\n }\n\n _pay(\n _projectId,\n _token,\n _amount,\n _decimals,\n _beneficiary,\n _minReturnedTokens,\n _preferClaimedTokens,\n _memo,\n _metadata\n );\n }\n\n /// @notice Add to the balance of the specified project.\n /// @param _projectId The ID of the project that is being paid.\n /// @param _token The token being paid in.\n /// @param _amount The amount of tokens being paid, as a fixed point number. If the token is ETH, this is ignored and msg.value is used in its place.\n /// @param _decimals The number of decimals in the `_amount` fixed point number. If the token is ETH, this is ignored and 18 is used in its place, which corresponds to the amount of decimals expected in msg.value.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the terminal.\n function addToBalanceOf(\n uint256 _projectId,\n address _token,\n uint256 _amount,\n uint256 _decimals,\n string calldata _memo,\n bytes calldata _metadata\n ) public payable virtual override {\n // ETH shouldn't be sent if the token isn't ETH.\n if (address(_token) != JBTokens.ETH) {\n if (msg.value > 0) revert NO_MSG_VALUE_ALLOWED();\n\n // Get a reference to the balance before receiving tokens.\n uint256 _balanceBefore = IERC20(_token).balanceOf(address(this));\n\n // Transfer tokens to this contract from the msg sender.\n IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount);\n\n // The amount should reflect the change in balance.\n _amount = IERC20(_token).balanceOf(address(this)) - _balanceBefore;\n } else {\n // If ETH is being paid, set the amount to the message value, and decimals to 18.\n _amount = msg.value;\n _decimals = 18;\n }\n\n _addToBalanceOf(_projectId, _token, _amount, _decimals, _memo, _metadata);\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Make a payment to the specified project.\n /// @param _projectId The ID of the project that is being paid.\n /// @param _token The token being paid in.\n /// @param _amount The amount of tokens being paid, as a fixed point number.\n /// @param _decimals The number of decimals in the `_amount` fixed point number.\n /// @param _beneficiary The address who will receive tokens from the payment.\n /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with 18 decimals.\n /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\n /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _metadata Bytes to send along to the data source and delegate, if provided.\n function _pay(\n uint256 _projectId,\n address _token,\n uint256 _amount,\n uint256 _decimals,\n address _beneficiary,\n uint256 _minReturnedTokens,\n bool _preferClaimedTokens,\n string memory _memo,\n bytes memory _metadata\n ) internal virtual {\n // Find the terminal for the specified project.\n IJBPaymentTerminal _terminal = directory.primaryTerminalOf(_projectId, _token);\n\n // There must be a terminal.\n if (_terminal == IJBPaymentTerminal(address(0))) revert TERMINAL_NOT_FOUND();\n\n // The amount's decimals must match the terminal's expected decimals.\n if (_terminal.decimalsForToken(_token) != _decimals) revert INCORRECT_DECIMAL_AMOUNT();\n\n // Approve the `_amount` of tokens from the destination terminal to transfer tokens from this contract.\n if (_token != JBTokens.ETH) IERC20(_token).safeApprove(address(_terminal), _amount);\n\n // If the token is ETH, send it in msg.value.\n uint256 _payableValue = _token == JBTokens.ETH ? _amount : 0;\n\n // Send funds to the terminal.\n // If the token is ETH, send it in msg.value.\n _terminal.pay{value: _payableValue}(\n _projectId,\n _amount, // ignored if the token is JBTokens.ETH.\n _token,\n _beneficiary != address(0) ? _beneficiary : defaultBeneficiary != address(0)\n ? defaultBeneficiary\n : tx.origin,\n _minReturnedTokens,\n _preferClaimedTokens,\n _memo,\n _metadata\n );\n }\n\n /// @notice Add to the balance of the specified project.\n /// @param _projectId The ID of the project that is being paid.\n /// @param _token The token being paid in.\n /// @param _amount The amount of tokens being paid, as a fixed point number. If the token is ETH, this is ignored and msg.value is used in its place.\n /// @param _decimals The number of decimals in the `_amount` fixed point number. If the token is ETH, this is ignored and 18 is used in its place, which corresponds to the amount of decimals expected in msg.value.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the terminal.\n function _addToBalanceOf(\n uint256 _projectId,\n address _token,\n uint256 _amount,\n uint256 _decimals,\n string memory _memo,\n bytes memory _metadata\n ) internal virtual {\n // Find the terminal for the specified project.\n IJBPaymentTerminal _terminal = directory.primaryTerminalOf(_projectId, _token);\n\n // There must be a terminal.\n if (_terminal == IJBPaymentTerminal(address(0))) revert TERMINAL_NOT_FOUND();\n\n // The amount's decimals must match the terminal's expected decimals.\n if (_terminal.decimalsForToken(_token) != _decimals) revert INCORRECT_DECIMAL_AMOUNT();\n\n // Approve the `_amount` of tokens from the destination terminal to transfer tokens from this contract.\n if (_token != JBTokens.ETH) IERC20(_token).safeApprove(address(_terminal), _amount);\n\n // If the token is ETH, send it in msg.value.\n uint256 _payableValue = _token == JBTokens.ETH ? _amount : 0;\n\n // Add to balance so tokens don't get issued.\n _terminal.addToBalanceOf{value: _payableValue}(_projectId, _amount, _token, _memo, _metadata);\n }\n}\n" + }, + "contracts/libraries/JBTokens.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nlibrary JBTokens {\n /// @notice The ETH token address in Juicebox is represented by 0x000000000000000000000000000000000000EEEe.\n address public constant ETH = address(0x000000000000000000000000000000000000EEEe);\n}\n" + }, + "contracts/interfaces/IJBProjectPayer.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {IJBDirectory} from './IJBDirectory.sol';\n\ninterface IJBProjectPayer is IERC165 {\n event SetDefaultValues(\n uint256 indexed projectId,\n address indexed beneficiary,\n bool preferClaimedTokens,\n string memo,\n bytes metadata,\n bool preferAddToBalance,\n address caller\n );\n\n function directory() external view returns (IJBDirectory);\n\n function projectPayerDeployer() external view returns (address);\n\n function defaultProjectId() external view returns (uint256);\n\n function defaultBeneficiary() external view returns (address payable);\n\n function defaultPreferClaimedTokens() external view returns (bool);\n\n function defaultMemo() external view returns (string memory);\n\n function defaultMetadata() external view returns (bytes memory);\n\n function defaultPreferAddToBalance() external view returns (bool);\n\n function initialize(\n uint256 defaultProjectId,\n address payable defaultBeneficiary,\n bool defaultPreferClaimedTokens,\n string memory defaultMemo,\n bytes memory defaultMetadata,\n bool defaultPreferAddToBalance,\n address owner\n ) external;\n\n function setDefaultValues(\n uint256 projectId,\n address payable beneficiary,\n bool preferClaimedTokens,\n string memory memo,\n bytes memory metadata,\n bool defaultPreferAddToBalance\n ) external;\n\n function pay(\n uint256 projectId,\n address token,\n uint256 amount,\n uint256 decimals,\n address beneficiary,\n uint256 minReturnedTokens,\n bool preferClaimedTokens,\n string memory memo,\n bytes memory metadata\n ) external payable;\n\n function addToBalanceOf(\n uint256 projectId,\n address token,\n uint256 amount,\n uint256 decimals,\n string memory memo,\n bytes memory metadata\n ) external payable;\n\n receive() external payable;\n}\n" + }, + "contracts/JBController3_0_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {ERC165, IERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {SafeCast} from '@openzeppelin/contracts/utils/math/SafeCast.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {JBOperatable} from './abstract/JBOperatable.sol';\nimport {JBBallotState} from './enums/JBBallotState.sol';\nimport {IJBController3_0_1} from './interfaces/IJBController3_0_1.sol';\nimport {IJBController} from './interfaces/IJBController.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol';\nimport {IJBMigratable} from './interfaces/IJBMigratable.sol';\nimport {IJBOperatable} from './interfaces/IJBOperatable.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {IJBSplitAllocator} from './interfaces/IJBSplitAllocator.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {IJBTokenStore} from './interfaces/IJBTokenStore.sol';\nimport {JBConstants} from './libraries/JBConstants.sol';\nimport {JBFundingCycleMetadataResolver} from './libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBOperations} from './libraries/JBOperations.sol';\nimport {JBSplitsGroups} from './libraries/JBSplitsGroups.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\nimport {JBSplitAllocationData} from './structs/JBSplitAllocationData.sol';\nimport {JBFundAccessConstraints} from './structs/JBFundAccessConstraints.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\nimport {JBFundingCycleData} from './structs/JBFundingCycleData.sol';\nimport {JBFundingCycleMetadata} from './structs/JBFundingCycleMetadata.sol';\nimport {JBGroupedSplits} from './structs/JBGroupedSplits.sol';\nimport {JBProjectMetadata} from './structs/JBProjectMetadata.sol';\nimport {JBSplit} from './structs/JBSplit.sol';\n\n/// @notice Stitches together funding cycles and project tokens, making sure all activity is accounted for and correct.\n/// @dev This Controller manages a project's reserved tokens explicitly instead of through a passive tracker property.\n/// @dev It is backwards compatible with the original IJBController, and exposes convenience view methods as part of IJBController3_1 for clearer queries.\ncontract JBController3_0_1 is\n JBOperatable,\n ERC165,\n IJBController,\n IJBController3_0_1,\n IJBMigratable\n{\n // A library that parses the packed funding cycle metadata into a more friendly format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error BURN_PAUSED_AND_SENDER_NOT_VALID_TERMINAL_DELEGATE();\n error FUNDING_CYCLE_ALREADY_LAUNCHED();\n error INVALID_BALLOT_REDEMPTION_RATE();\n error INVALID_DISTRIBUTION_LIMIT();\n error INVALID_DISTRIBUTION_LIMIT_CURRENCY();\n error INVALID_OVERFLOW_ALLOWANCE();\n error INVALID_OVERFLOW_ALLOWANCE_CURRENCY();\n error INVALID_REDEMPTION_RATE();\n error INVALID_RESERVED_RATE();\n error MIGRATION_NOT_ALLOWED();\n error MINT_NOT_ALLOWED_AND_NOT_TERMINAL_DELEGATE();\n error NO_BURNABLE_TOKENS();\n error NOT_CURRENT_CONTROLLER();\n error ZERO_TOKENS_TO_MINT();\n\n //*********************************************************************//\n // --------------------- internal stored properties ------------------ //\n //*********************************************************************//\n\n /// @notice Data regarding the distribution limit of a project during a configuration.\n /// @dev bits 0-231: The amount of token that a project can distribute per funding cycle.\n /// @dev bits 232-255: The currency of amount that a project can distribute.\n /// @custom:param _projectId The ID of the project to get the packed distribution limit data of.\n /// @custom:param _configuration The configuration during which the packed distribution limit data applies.\n /// @custom:param _terminal The terminal from which distributions are being limited.\n /// @custom:param _token The token for which distributions are being limited.\n mapping(uint256 => mapping(uint256 => mapping(IJBPaymentTerminal => mapping(address => uint256))))\n internal _packedDistributionLimitDataOf;\n\n /// @notice Data regarding the overflow allowance of a project during a configuration.\n /// @dev bits 0-231: The amount of overflow that a project is allowed to tap into on-demand throughout the configuration.\n /// @dev bits 232-255: The currency of the amount of overflow that a project is allowed to tap.\n /// @custom:param _projectId The ID of the project to get the packed overflow allowance data of.\n /// @custom:param _configuration The configuration during which the packed overflow allowance data applies.\n /// @custom:param _terminal The terminal managing the overflow.\n /// @custom:param _token The token for which overflow is being allowed.\n mapping(uint256 => mapping(uint256 => mapping(IJBPaymentTerminal => mapping(address => uint256))))\n internal _packedOverflowAllowanceDataOf;\n\n /// @notice The current undistributed reserved token balance of.\n /// @custom:param _projectId The ID of the project to get a reserved token balance of.\n mapping(uint256 => uint256) internal _reservedTokenBalanceOf;\n\n //*********************************************************************//\n // --------------- public immutable stored properties ---------------- //\n //*********************************************************************//\n\n /// @notice Mints ERC-721's that represent project ownership.\n IJBProjects public immutable override projects;\n\n /// @notice The contract storing all funding cycle configurations.\n IJBFundingCycleStore public immutable override fundingCycleStore;\n\n /// @notice The contract that manages token minting and burning.\n IJBTokenStore public immutable override tokenStore;\n\n /// @notice The contract that stores splits for each project.\n IJBSplitsStore public immutable override splitsStore;\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice The amount of token that a project can distribute per funding cycle, and the currency it's in terms of.\n /// @dev The number of decimals in the returned fixed point amount is the same as that of the specified terminal.\n /// @param _projectId The ID of the project to get the distribution limit of.\n /// @param _configuration The configuration during which the distribution limit applies.\n /// @param _terminal The terminal from which distributions are being limited.\n /// @param _token The token for which the distribution limit applies.\n /// @return The distribution limit, as a fixed point number with the same number of decimals as the provided terminal.\n /// @return The currency of the distribution limit.\n function distributionLimitOf(\n uint256 _projectId,\n uint256 _configuration,\n IJBPaymentTerminal _terminal,\n address _token\n ) external view override returns (uint256, uint256) {\n // Get a reference to the packed data.\n uint256 _data = _packedDistributionLimitDataOf[_projectId][_configuration][_terminal][_token];\n\n // The limit is in bits 0-231. The currency is in bits 232-255.\n return (uint256(uint232(_data)), _data >> 232);\n }\n\n /// @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.\n /// @dev The number of decimals in the returned fixed point amount is the same as that of the specified terminal.\n /// @param _projectId The ID of the project to get the overflow allowance of.\n /// @param _configuration The configuration of the during which the allowance applies.\n /// @param _terminal The terminal managing the overflow.\n /// @param _token The token for which the overflow allowance applies.\n /// @return The overflow allowance, as a fixed point number with the same number of decimals as the provided terminal.\n /// @return The currency of the overflow allowance.\n function overflowAllowanceOf(\n uint256 _projectId,\n uint256 _configuration,\n IJBPaymentTerminal _terminal,\n address _token\n ) external view override returns (uint256, uint256) {\n // Get a reference to the packed data.\n uint256 _data = _packedOverflowAllowanceDataOf[_projectId][_configuration][_terminal][_token];\n\n // The allowance is in bits 0-231. The currency is in bits 232-255.\n return (uint256(uint232(_data)), _data >> 232);\n }\n\n /// @notice A project's funding cycle for the specified configuration along with its metadata.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The funding cycle.\n /// @return metadata The funding cycle's metadata.\n function getFundingCycleOf(\n uint256 _projectId,\n uint256 _configuration\n )\n external\n view\n override\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata)\n {\n fundingCycle = fundingCycleStore.get(_projectId, _configuration);\n metadata = fundingCycle.expandMetadata();\n }\n\n /// @notice A project's latest configured funding cycle along with its metadata and the ballot state of the configuration.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The latest configured funding cycle.\n /// @return metadata The latest configured funding cycle's metadata.\n /// @return ballotState The state of the configuration.\n function latestConfiguredFundingCycleOf(\n uint256 _projectId\n )\n external\n view\n override\n returns (\n JBFundingCycle memory fundingCycle,\n JBFundingCycleMetadata memory metadata,\n JBBallotState ballotState\n )\n {\n (fundingCycle, ballotState) = fundingCycleStore.latestConfiguredOf(_projectId);\n metadata = fundingCycle.expandMetadata();\n }\n\n /// @notice A project's current funding cycle along with its metadata.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The current funding cycle.\n /// @return metadata The current funding cycle's metadata.\n function currentFundingCycleOf(\n uint256 _projectId\n )\n external\n view\n override\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata)\n {\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n metadata = fundingCycle.expandMetadata();\n }\n\n /// @notice A project's queued funding cycle along with its metadata.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The queued funding cycle.\n /// @return metadata The queued funding cycle's metadata.\n function queuedFundingCycleOf(\n uint256 _projectId\n )\n external\n view\n override\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata)\n {\n fundingCycle = fundingCycleStore.queuedOf(_projectId);\n metadata = fundingCycle.expandMetadata();\n }\n\n /// @notice\tGets the amount of reserved tokens that a project has available to distribute.\n /// @param _projectId The ID of the project to get a reserved token balance of.\n /// @return The current amount of reserved tokens.\n function reservedTokenBalanceOf(uint256 _projectId) external view override returns (uint256) {\n return _reservedTokenBalanceOf[_projectId];\n }\n\n /// @notice\tGets the amount of reserved tokens that a project has available to distribute.\n /// @dev This is just for IJBController backwards compatibility.\n /// @param _projectId The ID of the project to get a reserved token balance of.\n /// @param _reservedRate The reserved rate to use when making the calculation.\n /// @return The current amount of reserved tokens.\n function reservedTokenBalanceOf(\n uint256 _projectId,\n uint256 _reservedRate\n ) external view override returns (uint256) {\n _reservedRate;\n return _reservedTokenBalanceOf[_projectId];\n }\n\n /// @notice\tGets the current total amount of outstanding tokens for a project, given a reserved rate.\n /// @dev This is just for IJBController backwards compatibility.\n /// @param _projectId The ID of the project to get total outstanding tokens of.\n /// @param _reservedRate The reserved rate to use when making the calculation.\n /// @return The current total amount of outstanding tokens for the project.\n function totalOutstandingTokensOf(\n uint256 _projectId,\n uint256 _reservedRate\n ) external view override returns (uint256) {\n _reservedRate;\n // Add the reserved tokens to the total supply.\n return totalOutstandingTokensOf(_projectId);\n }\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice Gets the current total amount of outstanding tokens for a project.\n /// @param _projectId The ID of the project to get total outstanding tokens of.\n /// @return The current total amount of outstanding tokens for the project.\n function totalOutstandingTokensOf(uint256 _projectId) public view override returns (uint256) {\n // Add the reserved tokens to the total supply.\n return tokenStore.totalSupplyOf(_projectId) + _reservedTokenBalanceOf[_projectId];\n }\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if the provided interface ID is supported.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(ERC165, IERC165) returns (bool) {\n return\n _interfaceId == type(IJBController3_0_1).interfaceId ||\n _interfaceId == type(IJBMigratable).interfaceId ||\n _interfaceId == type(IJBOperatable).interfaceId ||\n super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // ---------------------------- constructor -------------------------- //\n //*********************************************************************//\n\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _fundingCycleStore A contract storing all funding cycle configurations.\n /// @param _tokenStore A contract that manages token minting and burning.\n /// @param _splitsStore A contract that stores splits for each project.\n constructor(\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBFundingCycleStore _fundingCycleStore,\n IJBTokenStore _tokenStore,\n IJBSplitsStore _splitsStore\n ) JBOperatable(_operatorStore) {\n projects = _projects;\n directory = _directory;\n fundingCycleStore = _fundingCycleStore;\n tokenStore = _tokenStore;\n splitsStore = _splitsStore;\n }\n\n //*********************************************************************//\n // --------------------- external transactions ----------------------- //\n //*********************************************************************//\n\n /// @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.\n /// @dev Each operation within this transaction can be done in sequence separately.\n /// @dev Anyone can deploy a project on an owner's behalf.\n /// @param _owner The address to set as the owner of the project. The project ERC-721 will be owned by this address.\n /// @param _projectMetadata Metadata to associate with the project within a particular domain. This can be updated any time by the owner of the project.\n /// @param _data Data that defines the project's first funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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`.\n /// @param _terminals Payment terminals to add for the project.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return projectId The ID of the project.\n function launchProjectFor(\n address _owner,\n JBProjectMetadata calldata _projectMetadata,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] calldata _groupedSplits,\n JBFundAccessConstraints[] calldata _fundAccessConstraints,\n IJBPaymentTerminal[] memory _terminals,\n string memory _memo\n ) external virtual override returns (uint256 projectId) {\n // Keep a reference to the directory.\n IJBDirectory _directory = directory;\n\n // Mint the project into the wallet of the owner.\n projectId = projects.createFor(_owner, _projectMetadata);\n\n // Set this contract as the project's controller in the directory.\n _directory.setControllerOf(projectId, address(this));\n\n // Configure the first funding cycle.\n uint256 _configuration = _configure(\n projectId,\n _data,\n _metadata,\n _mustStartAtOrAfter,\n _groupedSplits,\n _fundAccessConstraints\n );\n\n // Add the provided terminals to the list of terminals.\n if (_terminals.length > 0) _directory.setTerminalsOf(projectId, _terminals);\n\n emit LaunchProject(_configuration, projectId, _memo, msg.sender);\n }\n\n /// @notice Creates a funding cycle for an already existing project ERC-721.\n /// @dev Each operation within this transaction can be done in sequence separately.\n /// @dev Only a project owner or operator can launch its funding cycles.\n /// @param _projectId The ID of the project to launch funding cycles for.\n /// @param _data Data that defines the project's first funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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`.\n /// @param _terminals Payment terminals to add for the project.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return configuration The configuration of the funding cycle that was successfully created.\n function launchFundingCyclesFor(\n uint256 _projectId,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] calldata _groupedSplits,\n JBFundAccessConstraints[] memory _fundAccessConstraints,\n IJBPaymentTerminal[] memory _terminals,\n string memory _memo\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.RECONFIGURE)\n returns (uint256 configuration)\n {\n // If there is a previous configuration, reconfigureFundingCyclesOf should be called instead\n if (fundingCycleStore.latestConfigurationOf(_projectId) > 0)\n revert FUNDING_CYCLE_ALREADY_LAUNCHED();\n\n // Set this contract as the project's controller in the directory.\n directory.setControllerOf(_projectId, address(this));\n\n // Configure the first funding cycle.\n configuration = _configure(\n _projectId,\n _data,\n _metadata,\n _mustStartAtOrAfter,\n _groupedSplits,\n _fundAccessConstraints\n );\n\n // Add the provided terminals to the list of terminals.\n if (_terminals.length > 0) directory.setTerminalsOf(_projectId, _terminals);\n\n emit LaunchFundingCycles(configuration, _projectId, _memo, msg.sender);\n }\n\n /// @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.\n /// @dev Only a project's owner or a designated operator can configure its funding cycles.\n /// @param _projectId The ID of the project whose funding cycles are being reconfigured.\n /// @param _data Data that defines the funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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`.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return configuration The configuration of the funding cycle that was successfully reconfigured.\n function reconfigureFundingCyclesOf(\n uint256 _projectId,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] calldata _groupedSplits,\n JBFundAccessConstraints[] calldata _fundAccessConstraints,\n string calldata _memo\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.RECONFIGURE)\n returns (uint256 configuration)\n {\n // Configure the next funding cycle.\n configuration = _configure(\n _projectId,\n _data,\n _metadata,\n _mustStartAtOrAfter,\n _groupedSplits,\n _fundAccessConstraints\n );\n\n emit ReconfigureFundingCycles(configuration, _projectId, _memo, msg.sender);\n }\n\n /// @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.\n /// @dev Only a project's owner, a designated operator, one of its terminals, or the current data source can mint its tokens.\n /// @param _projectId The ID of the project to which the tokens being minted belong.\n /// @param _tokenCount The amount of tokens to mint in total, counting however many should be reserved.\n /// @param _beneficiary The account that the tokens are being minted for.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _preferClaimedTokens A flag indicating whether a project's attached token contract should be minted if they have been issued.\n /// @param _useReservedRate Whether to use the current funding cycle's reserved rate in the mint calculation.\n /// @return beneficiaryTokenCount The amount of tokens minted for the beneficiary.\n function mintTokensOf(\n uint256 _projectId,\n uint256 _tokenCount,\n address _beneficiary,\n string calldata _memo,\n bool _preferClaimedTokens,\n bool _useReservedRate\n ) external virtual override returns (uint256 beneficiaryTokenCount) {\n // There should be tokens to mint.\n if (_tokenCount == 0) revert ZERO_TOKENS_TO_MINT();\n\n // Define variables that will be needed outside scoped section below.\n // Keep a reference to the reserved rate to use\n uint256 _reservedRate;\n\n // Scoped section prevents stack too deep. `_fundingCycle` only used within scope.\n {\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Minting limited to: project owner, authorized callers, project terminal and current funding cycle data source\n _requirePermissionAllowingOverride(\n projects.ownerOf(_projectId),\n _projectId,\n JBOperations.MINT,\n directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender)) ||\n msg.sender == address(_fundingCycle.dataSource())\n );\n\n // If the message sender is not a terminal or a datasource, the current funding cycle must allow minting.\n if (\n !_fundingCycle.mintingAllowed() &&\n !directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender)) &&\n msg.sender != address(_fundingCycle.dataSource())\n ) revert MINT_NOT_ALLOWED_AND_NOT_TERMINAL_DELEGATE();\n\n // Determine the reserved rate to use.\n _reservedRate = _useReservedRate ? _fundingCycle.reservedRate() : 0;\n\n // Override the claimed token preference with the funding cycle value.\n _preferClaimedTokens = _preferClaimedTokens == true\n ? _preferClaimedTokens\n : _fundingCycle.preferClaimedTokenOverride();\n }\n\n if (_reservedRate != JBConstants.MAX_RESERVED_RATE) {\n // The unreserved token count that will be minted for the beneficiary.\n beneficiaryTokenCount = PRBMath.mulDiv(\n _tokenCount,\n JBConstants.MAX_RESERVED_RATE - _reservedRate,\n JBConstants.MAX_RESERVED_RATE\n );\n\n // Mint the tokens.\n tokenStore.mintFor(_beneficiary, _projectId, beneficiaryTokenCount, _preferClaimedTokens);\n }\n\n // Add reserved tokens if needed\n if (_reservedRate > 0)\n _reservedTokenBalanceOf[_projectId] += _tokenCount - beneficiaryTokenCount;\n\n emit MintTokens(\n _beneficiary,\n _projectId,\n _tokenCount,\n beneficiaryTokenCount,\n _memo,\n _reservedRate,\n msg.sender\n );\n }\n\n /// @notice Burns a token holder's supply.\n /// @dev Only a token's holder, a designated operator, or a project's terminal can burn it.\n /// @param _holder The account that is having its tokens burned.\n /// @param _projectId The ID of the project to which the tokens being burned belong.\n /// @param _tokenCount The number of tokens to burn.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _preferClaimedTokens A flag indicating whether a project's attached token contract should be burned first if they have been issued.\n function burnTokensOf(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n string calldata _memo,\n bool _preferClaimedTokens\n )\n external\n virtual\n override\n requirePermissionAllowingOverride(\n _holder,\n _projectId,\n JBOperations.BURN,\n directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender))\n )\n {\n // There should be tokens to burn\n if (_tokenCount == 0) revert NO_BURNABLE_TOKENS();\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // If the message sender is a terminal, the current funding cycle must not be paused.\n if (\n _fundingCycle.burnPaused() &&\n !directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender))\n ) revert BURN_PAUSED_AND_SENDER_NOT_VALID_TERMINAL_DELEGATE();\n\n // Burn the tokens.\n tokenStore.burnFrom(_holder, _projectId, _tokenCount, _preferClaimedTokens);\n\n emit BurnTokens(_holder, _projectId, _tokenCount, _memo, msg.sender);\n }\n\n /// @notice Distributes all outstanding reserved tokens for a project.\n /// @param _projectId The ID of the project to which the reserved tokens belong.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return The amount of minted reserved tokens.\n function distributeReservedTokensOf(\n uint256 _projectId,\n string calldata _memo\n ) external virtual override returns (uint256) {\n return _distributeReservedTokensOf(_projectId, _memo);\n }\n\n /// @notice Allows other controllers to signal to this one that a migration is expected for the specified project.\n /// @dev This controller should not yet be the project's controller.\n /// @param _projectId The ID of the project that will be migrated to this controller.\n /// @param _from The controller being migrated from.\n function prepForMigrationOf(uint256 _projectId, address _from) external virtual override {\n _projectId; // Prevents unused var compiler and natspec complaints.\n _from; // Prevents unused var compiler and natspec complaints.\n }\n\n /// @notice Allows a project to migrate from this controller to another.\n /// @dev Only a project's owner or a designated operator can migrate it.\n /// @param _projectId The ID of the project that will be migrated from this controller.\n /// @param _to The controller to which the project is migrating.\n function migrate(\n uint256 _projectId,\n IJBMigratable _to\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.MIGRATE_CONTROLLER)\n {\n // Keep a reference to the directory.\n IJBDirectory _directory = directory;\n\n // This controller must be the project's current controller.\n if (_directory.controllerOf(_projectId) != address(this)) revert NOT_CURRENT_CONTROLLER();\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Migration must be allowed.\n if (!_fundingCycle.controllerMigrationAllowed()) revert MIGRATION_NOT_ALLOWED();\n\n // All reserved tokens must be minted before migrating.\n if (_reservedTokenBalanceOf[_projectId] != 0) _distributeReservedTokensOf(_projectId, '');\n\n // Make sure the new controller is prepped for the migration.\n _to.prepForMigrationOf(_projectId, address(this));\n\n // Set the new controller.\n _directory.setControllerOf(_projectId, address(_to));\n\n emit Migrate(_projectId, _to, msg.sender);\n }\n\n //*********************************************************************//\n // ------------------------ internal functions ----------------------- //\n //*********************************************************************//\n\n /// @notice Distributes all outstanding reserved tokens for a project.\n /// @param _projectId The ID of the project to which the reserved tokens belong.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return tokenCount The amount of minted reserved tokens.\n function _distributeReservedTokensOf(\n uint256 _projectId,\n string memory _memo\n ) internal returns (uint256 tokenCount) {\n // Keep a reference to the token store.\n IJBTokenStore _tokenStore = tokenStore;\n\n // Get the current funding cycle to read the reserved rate from.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Get a reference to the number of tokens that need to be minted.\n tokenCount = _reservedTokenBalanceOf[_projectId];\n\n // Reset the reserved token balance\n _reservedTokenBalanceOf[_projectId] = 0;\n\n // Get a reference to the project owner.\n address _owner = projects.ownerOf(_projectId);\n\n // Distribute tokens to splits and get a reference to the leftover amount to mint after all splits have gotten their share.\n uint256 _leftoverTokenCount = tokenCount == 0\n ? 0\n : _distributeToReservedTokenSplitsOf(\n _projectId,\n _fundingCycle.configuration,\n JBSplitsGroups.RESERVED_TOKENS,\n tokenCount\n );\n\n // Mint any leftover tokens to the project owner.\n if (_leftoverTokenCount > 0)\n _tokenStore.mintFor(_owner, _projectId, _leftoverTokenCount, false);\n\n emit DistributeReservedTokens(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _owner,\n tokenCount,\n _leftoverTokenCount,\n _memo,\n msg.sender\n );\n }\n\n /// @notice Distribute tokens to the splits according to the specified funding cycle configuration.\n /// @param _projectId The ID of the project for which reserved token splits are being distributed.\n /// @param _domain The domain of the splits to distribute the reserved tokens between.\n /// @param _group The group of the splits to distribute the reserved tokens between.\n /// @param _amount The total amount of tokens to mint.\n /// @return leftoverAmount If the splits percents dont add up to 100%, the leftover amount is returned.\n function _distributeToReservedTokenSplitsOf(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group,\n uint256 _amount\n ) internal returns (uint256 leftoverAmount) {\n // Keep a reference to the token store.\n IJBTokenStore _tokenStore = tokenStore;\n\n // Set the leftover amount to the initial amount.\n leftoverAmount = _amount;\n\n // Get a reference to the project's reserved token splits.\n JBSplit[] memory _splits = splitsStore.splitsOf(_projectId, _domain, _group);\n\n //Transfer between all splits.\n for (uint256 _i; _i < _splits.length; ) {\n // Get a reference to the split being iterated on.\n JBSplit memory _split = _splits[_i];\n\n // The amount to send towards the split.\n uint256 _tokenCount = PRBMath.mulDiv(\n _amount,\n _split.percent,\n JBConstants.SPLITS_TOTAL_PERCENT\n );\n\n // Mints tokens for the split if needed.\n if (_tokenCount > 0) {\n _tokenStore.mintFor(\n // If an allocator is set in the splits, set it as the beneficiary.\n // Otherwise if a projectId is set in the split, set the project's owner as the beneficiary.\n // If the split has a beneficiary send to the split's beneficiary. Otherwise send to the msg.sender.\n _split.allocator != IJBSplitAllocator(address(0))\n ? address(_split.allocator)\n : _split.projectId != 0\n ? projects.ownerOf(_split.projectId)\n : _split.beneficiary != address(0)\n ? _split.beneficiary\n : msg.sender,\n _projectId,\n _tokenCount,\n _split.preferClaimed\n );\n\n // If there's an allocator set, trigger its `allocate` function.\n if (_split.allocator != IJBSplitAllocator(address(0)))\n _split.allocator.allocate(\n JBSplitAllocationData(\n address(_tokenStore.tokenOf(_projectId)),\n _tokenCount,\n 18,\n _projectId,\n _group,\n _split\n )\n );\n\n // Subtract from the amount to be sent to the beneficiary.\n leftoverAmount = leftoverAmount - _tokenCount;\n }\n\n emit DistributeToReservedTokenSplit(\n _projectId,\n _domain,\n _group,\n _split,\n _tokenCount,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n\n /// @notice Configures a funding cycle and stores information pertinent to the configuration.\n /// @param _projectId The ID of the project whose funding cycles are being reconfigured.\n /// @param _data Data that defines the funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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.\n /// @return configuration The configuration of the funding cycle that was successfully reconfigured.\n function _configure(\n uint256 _projectId,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] memory _groupedSplits,\n JBFundAccessConstraints[] memory _fundAccessConstraints\n ) internal returns (uint256) {\n // Make sure the provided reserved rate is valid.\n if (_metadata.reservedRate > JBConstants.MAX_RESERVED_RATE) revert INVALID_RESERVED_RATE();\n\n // Make sure the provided redemption rate is valid.\n if (_metadata.redemptionRate > JBConstants.MAX_REDEMPTION_RATE)\n revert INVALID_REDEMPTION_RATE();\n\n // Make sure the provided ballot redemption rate is valid.\n if (_metadata.ballotRedemptionRate > JBConstants.MAX_REDEMPTION_RATE)\n revert INVALID_BALLOT_REDEMPTION_RATE();\n\n // Configure the funding cycle's properties.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.configureFor(\n _projectId,\n _data,\n JBFundingCycleMetadataResolver.packFundingCycleMetadata(_metadata),\n _mustStartAtOrAfter\n );\n\n // Set splits for the group.\n splitsStore.set(_projectId, _fundingCycle.configuration, _groupedSplits);\n\n // Set distribution limits if there are any.\n for (uint256 _i; _i < _fundAccessConstraints.length; ) {\n JBFundAccessConstraints memory _constraints = _fundAccessConstraints[_i];\n\n // If distribution limit value is larger than 232 bits, revert.\n if (_constraints.distributionLimit > type(uint232).max) revert INVALID_DISTRIBUTION_LIMIT();\n\n // If distribution limit currency value is larger than 24 bits, revert.\n if (_constraints.distributionLimitCurrency > type(uint24).max)\n revert INVALID_DISTRIBUTION_LIMIT_CURRENCY();\n\n // If overflow allowance value is larger than 232 bits, revert.\n if (_constraints.overflowAllowance > type(uint232).max) revert INVALID_OVERFLOW_ALLOWANCE();\n\n // If overflow allowance currency value is larger than 24 bits, revert.\n if (_constraints.overflowAllowanceCurrency > type(uint24).max)\n revert INVALID_OVERFLOW_ALLOWANCE_CURRENCY();\n\n // Set the distribution limit if there is one.\n if (_constraints.distributionLimit > 0)\n _packedDistributionLimitDataOf[_projectId][_fundingCycle.configuration][\n _constraints.terminal\n ][_constraints.token] =\n _constraints.distributionLimit |\n (_constraints.distributionLimitCurrency << 232);\n\n // Set the overflow allowance if there is one.\n if (_constraints.overflowAllowance > 0)\n _packedOverflowAllowanceDataOf[_projectId][_fundingCycle.configuration][\n _constraints.terminal\n ][_constraints.token] =\n _constraints.overflowAllowance |\n (_constraints.overflowAllowanceCurrency << 232);\n\n emit SetFundAccessConstraints(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _constraints,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n\n return _fundingCycle.configuration;\n }\n}\n" + }, + "contracts/JBProjects.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';\nimport {ERC721Votes, ERC721, EIP712} from '@openzeppelin/contracts/token/ERC721/extensions/draft-ERC721Votes.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBOperatable} from './abstract/JBOperatable.sol';\nimport {IJBOperatable} from './interfaces/IJBOperatable.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {IJBTokenUriResolver} from './interfaces/IJBTokenUriResolver.sol';\nimport {JBOperations} from './libraries/JBOperations.sol';\nimport {JBProjectMetadata} from './structs/JBProjectMetadata.sol';\n\n/// @notice Stores project ownership and metadata.\n/// @dev Projects are represented as ERC-721's.\ncontract JBProjects is JBOperatable, ERC721Votes, Ownable, IJBProjects {\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The number of projects that have been created using this contract.\n /// @dev The count is incremented with each new project created.\n /// @dev The resulting ERC-721 token ID for each project is the newly incremented count value.\n uint256 public override count = 0;\n\n /// @notice The metadata for each project, which can be used across several domains.\n /// @custom:param _projectId The ID of the project to which the metadata belongs.\n /// @custom:param _domain The domain within which the metadata applies. Applications can use the domain namespace as they wish.\n mapping(uint256 => mapping(uint256 => string)) public override metadataContentOf;\n\n /// @notice The contract resolving each project ID to its ERC721 URI.\n IJBTokenUriResolver public override tokenUriResolver;\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice Returns the URI where the ERC-721 standard JSON of a project is hosted.\n /// @param _projectId The ID of the project to get a URI of.\n /// @return The token URI to use for the provided `_projectId`.\n function tokenURI(uint256 _projectId) public view override returns (string memory) {\n // Keep a reference to the resolver.\n IJBTokenUriResolver _tokenUriResolver = tokenUriResolver;\n\n // If there's no resolver, there's no URI.\n if (_tokenUriResolver == IJBTokenUriResolver(address(0))) return '';\n\n // Return the resolved URI.\n return _tokenUriResolver.getUri(_projectId);\n }\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if the provided interface ID is supported.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(IERC165, ERC721) returns (bool) {\n return\n _interfaceId == type(IJBProjects).interfaceId ||\n _interfaceId == type(IJBOperatable).interfaceId ||\n super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _operatorStore A contract storing operator assignments.\n constructor(\n IJBOperatorStore _operatorStore\n )\n ERC721('Juicebox Projects', 'JUICEBOX')\n EIP712('Juicebox Projects', '1')\n JBOperatable(_operatorStore)\n // solhint-disable-next-line no-empty-blocks\n {\n\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Create a new project for the specified owner, which mints an NFT (ERC-721) into their wallet.\n /// @dev Anyone can create a project on an owner's behalf.\n /// @param _owner The address that will be the owner of the project.\n /// @param _metadata A struct containing metadata content about the project, and domain within which the metadata applies.\n /// @return projectId The token ID of the newly created project.\n function createFor(\n address _owner,\n JBProjectMetadata calldata _metadata\n ) external override returns (uint256 projectId) {\n // Increment the count, which will be used as the ID.\n projectId = ++count;\n\n // Mint the project.\n _safeMint(_owner, projectId);\n\n // Set the metadata if one was provided.\n if (bytes(_metadata.content).length > 0)\n metadataContentOf[projectId][_metadata.domain] = _metadata.content;\n\n emit Create(projectId, _owner, _metadata, msg.sender);\n }\n\n /// @notice Allows a project owner to set the project's metadata content for a particular domain namespace.\n /// @dev Only a project's owner or operator can set its metadata.\n /// @dev Applications can use the domain namespace as they wish.\n /// @param _projectId The ID of the project who's metadata is being changed.\n /// @param _metadata A struct containing metadata content, and domain within which the metadata applies.\n function setMetadataOf(\n uint256 _projectId,\n JBProjectMetadata calldata _metadata\n )\n external\n override\n requirePermission(ownerOf(_projectId), _projectId, JBOperations.SET_METADATA)\n {\n // Set the project's new metadata content within the specified domain.\n metadataContentOf[_projectId][_metadata.domain] = _metadata.content;\n\n emit SetMetadata(_projectId, _metadata, msg.sender);\n }\n\n /// @notice Sets the address of the resolver used to retrieve the tokenURI of projects.\n /// @param _newResolver The address of the new resolver.\n function setTokenUriResolver(IJBTokenUriResolver _newResolver) external override onlyOwner {\n // Store the new resolver.\n tokenUriResolver = _newResolver;\n\n emit SetTokenUriResolver(_newResolver, msg.sender);\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC721/extensions/draft-ERC721Votes.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (token/ERC721/extensions/draft-ERC721Votes.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../ERC721.sol\";\nimport \"../../../governance/utils/Votes.sol\";\n\n/**\n * @dev Extension of ERC721 to support voting and delegation as implemented by {Votes}, where each individual NFT counts\n * as 1 vote unit.\n *\n * Tokens do not count as votes until they are delegated, because votes must be tracked which incurs an additional cost\n * on every transfer. Token holders can either delegate to a trusted representative who will decide how to make use of\n * the votes in governance decisions, or they can delegate to themselves to be their own representative.\n *\n * _Available since v4.5._\n */\nabstract contract ERC721Votes is ERC721, Votes {\n /**\n * @dev Adjusts votes when tokens are transferred.\n *\n * Emits a {Votes-DelegateVotesChanged} event.\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 tokenId\n ) internal virtual override {\n _transferVotingUnits(from, to, 1);\n super._afterTokenTransfer(from, to, tokenId);\n }\n\n /**\n * @dev Returns the balance of `account`.\n */\n function _getVotingUnits(address account) internal virtual override returns (uint256) {\n return balanceOf(account);\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC721/ERC721.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (token/ERC721/ERC721.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC721.sol\";\nimport \"./IERC721Receiver.sol\";\nimport \"./extensions/IERC721Metadata.sol\";\nimport \"../../utils/Address.sol\";\nimport \"../../utils/Context.sol\";\nimport \"../../utils/Strings.sol\";\nimport \"../../utils/introspection/ERC165.sol\";\n\n/**\n * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including\n * the Metadata extension, but not including the Enumerable extension, which is available separately as\n * {ERC721Enumerable}.\n */\ncontract ERC721 is Context, ERC165, IERC721, IERC721Metadata {\n using Address for address;\n using Strings for uint256;\n\n // Token name\n string private _name;\n\n // Token symbol\n string private _symbol;\n\n // Mapping from token ID to owner address\n mapping(uint256 => address) private _owners;\n\n // Mapping owner address to token count\n mapping(address => uint256) private _balances;\n\n // Mapping from token ID to approved address\n mapping(uint256 => address) private _tokenApprovals;\n\n // Mapping from owner to operator approvals\n mapping(address => mapping(address => bool)) private _operatorApprovals;\n\n /**\n * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {\n return\n interfaceId == type(IERC721).interfaceId ||\n interfaceId == type(IERC721Metadata).interfaceId ||\n super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev See {IERC721-balanceOf}.\n */\n function balanceOf(address owner) public view virtual override returns (uint256) {\n require(owner != address(0), \"ERC721: balance query for the zero address\");\n return _balances[owner];\n }\n\n /**\n * @dev See {IERC721-ownerOf}.\n */\n function ownerOf(uint256 tokenId) public view virtual override returns (address) {\n address owner = _owners[tokenId];\n require(owner != address(0), \"ERC721: owner query for nonexistent token\");\n return owner;\n }\n\n /**\n * @dev See {IERC721Metadata-name}.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev See {IERC721Metadata-symbol}.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev See {IERC721Metadata-tokenURI}.\n */\n function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {\n require(_exists(tokenId), \"ERC721Metadata: URI query for nonexistent token\");\n\n string memory baseURI = _baseURI();\n return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : \"\";\n }\n\n /**\n * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each\n * token will be the concatenation of the `baseURI` and the `tokenId`. Empty\n * by default, can be overriden in child contracts.\n */\n function _baseURI() internal view virtual returns (string memory) {\n return \"\";\n }\n\n /**\n * @dev See {IERC721-approve}.\n */\n function approve(address to, uint256 tokenId) public virtual override {\n address owner = ERC721.ownerOf(tokenId);\n require(to != owner, \"ERC721: approval to current owner\");\n\n require(\n _msgSender() == owner || isApprovedForAll(owner, _msgSender()),\n \"ERC721: approve caller is not owner nor approved for all\"\n );\n\n _approve(to, tokenId);\n }\n\n /**\n * @dev See {IERC721-getApproved}.\n */\n function getApproved(uint256 tokenId) public view virtual override returns (address) {\n require(_exists(tokenId), \"ERC721: approved query for nonexistent token\");\n\n return _tokenApprovals[tokenId];\n }\n\n /**\n * @dev See {IERC721-setApprovalForAll}.\n */\n function setApprovalForAll(address operator, bool approved) public virtual override {\n _setApprovalForAll(_msgSender(), operator, approved);\n }\n\n /**\n * @dev See {IERC721-isApprovedForAll}.\n */\n function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {\n return _operatorApprovals[owner][operator];\n }\n\n /**\n * @dev See {IERC721-transferFrom}.\n */\n function transferFrom(\n address from,\n address to,\n uint256 tokenId\n ) public virtual override {\n //solhint-disable-next-line max-line-length\n require(_isApprovedOrOwner(_msgSender(), tokenId), \"ERC721: transfer caller is not owner nor approved\");\n\n _transfer(from, to, tokenId);\n }\n\n /**\n * @dev See {IERC721-safeTransferFrom}.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId\n ) public virtual override {\n safeTransferFrom(from, to, tokenId, \"\");\n }\n\n /**\n * @dev See {IERC721-safeTransferFrom}.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId,\n bytes memory _data\n ) public virtual override {\n require(_isApprovedOrOwner(_msgSender(), tokenId), \"ERC721: transfer caller is not owner nor approved\");\n _safeTransfer(from, to, tokenId, _data);\n }\n\n /**\n * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\n * are aware of the ERC721 protocol to prevent tokens from being forever locked.\n *\n * `_data` is additional data, it has no specified format and it is sent in call to `to`.\n *\n * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.\n * implement alternative mechanisms to perform token transfer, such as signature-based.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must exist and be owned by `from`.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function _safeTransfer(\n address from,\n address to,\n uint256 tokenId,\n bytes memory _data\n ) internal virtual {\n _transfer(from, to, tokenId);\n require(_checkOnERC721Received(from, to, tokenId, _data), \"ERC721: transfer to non ERC721Receiver implementer\");\n }\n\n /**\n * @dev Returns whether `tokenId` exists.\n *\n * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.\n *\n * Tokens start existing when they are minted (`_mint`),\n * and stop existing when they are burned (`_burn`).\n */\n function _exists(uint256 tokenId) internal view virtual returns (bool) {\n return _owners[tokenId] != address(0);\n }\n\n /**\n * @dev Returns whether `spender` is allowed to manage `tokenId`.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n */\n function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {\n require(_exists(tokenId), \"ERC721: operator query for nonexistent token\");\n address owner = ERC721.ownerOf(tokenId);\n return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));\n }\n\n /**\n * @dev Safely mints `tokenId` and transfers it to `to`.\n *\n * Requirements:\n *\n * - `tokenId` must not exist.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function _safeMint(address to, uint256 tokenId) internal virtual {\n _safeMint(to, tokenId, \"\");\n }\n\n /**\n * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is\n * forwarded in {IERC721Receiver-onERC721Received} to contract recipients.\n */\n function _safeMint(\n address to,\n uint256 tokenId,\n bytes memory _data\n ) internal virtual {\n _mint(to, tokenId);\n require(\n _checkOnERC721Received(address(0), to, tokenId, _data),\n \"ERC721: transfer to non ERC721Receiver implementer\"\n );\n }\n\n /**\n * @dev Mints `tokenId` and transfers it to `to`.\n *\n * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible\n *\n * Requirements:\n *\n * - `tokenId` must not exist.\n * - `to` cannot be the zero address.\n *\n * Emits a {Transfer} event.\n */\n function _mint(address to, uint256 tokenId) internal virtual {\n require(to != address(0), \"ERC721: mint to the zero address\");\n require(!_exists(tokenId), \"ERC721: token already minted\");\n\n _beforeTokenTransfer(address(0), to, tokenId);\n\n _balances[to] += 1;\n _owners[tokenId] = to;\n\n emit Transfer(address(0), to, tokenId);\n\n _afterTokenTransfer(address(0), to, tokenId);\n }\n\n /**\n * @dev Destroys `tokenId`.\n * The approval is cleared when the token is burned.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n *\n * Emits a {Transfer} event.\n */\n function _burn(uint256 tokenId) internal virtual {\n address owner = ERC721.ownerOf(tokenId);\n\n _beforeTokenTransfer(owner, address(0), tokenId);\n\n // Clear approvals\n _approve(address(0), tokenId);\n\n _balances[owner] -= 1;\n delete _owners[tokenId];\n\n emit Transfer(owner, address(0), tokenId);\n\n _afterTokenTransfer(owner, address(0), tokenId);\n }\n\n /**\n * @dev Transfers `tokenId` from `from` to `to`.\n * As opposed to {transferFrom}, this imposes no restrictions on msg.sender.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - `tokenId` token must be owned by `from`.\n *\n * Emits a {Transfer} event.\n */\n function _transfer(\n address from,\n address to,\n uint256 tokenId\n ) internal virtual {\n require(ERC721.ownerOf(tokenId) == from, \"ERC721: transfer from incorrect owner\");\n require(to != address(0), \"ERC721: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, tokenId);\n\n // Clear approvals from the previous owner\n _approve(address(0), tokenId);\n\n _balances[from] -= 1;\n _balances[to] += 1;\n _owners[tokenId] = to;\n\n emit Transfer(from, to, tokenId);\n\n _afterTokenTransfer(from, to, tokenId);\n }\n\n /**\n * @dev Approve `to` to operate on `tokenId`\n *\n * Emits a {Approval} event.\n */\n function _approve(address to, uint256 tokenId) internal virtual {\n _tokenApprovals[tokenId] = to;\n emit Approval(ERC721.ownerOf(tokenId), to, tokenId);\n }\n\n /**\n * @dev Approve `operator` to operate on all of `owner` tokens\n *\n * Emits a {ApprovalForAll} event.\n */\n function _setApprovalForAll(\n address owner,\n address operator,\n bool approved\n ) internal virtual {\n require(owner != operator, \"ERC721: approve to caller\");\n _operatorApprovals[owner][operator] = approved;\n emit ApprovalForAll(owner, operator, approved);\n }\n\n /**\n * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.\n * The call is not executed if the target address is not a contract.\n *\n * @param from address representing the previous owner of the given token ID\n * @param to target address that will receive the tokens\n * @param tokenId uint256 ID of the token to be transferred\n * @param _data bytes optional data to send along with the call\n * @return bool whether the call correctly returned the expected magic value\n */\n function _checkOnERC721Received(\n address from,\n address to,\n uint256 tokenId,\n bytes memory _data\n ) private returns (bool) {\n if (to.isContract()) {\n try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) {\n return retval == IERC721Receiver.onERC721Received.selector;\n } catch (bytes memory reason) {\n if (reason.length == 0) {\n revert(\"ERC721: transfer to non ERC721Receiver implementer\");\n } else {\n assembly {\n revert(add(32, reason), mload(reason))\n }\n }\n }\n } else {\n return true;\n }\n }\n\n /**\n * @dev Hook that is called before any token transfer. This includes minting\n * and burning.\n *\n * Calling conditions:\n *\n * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be\n * transferred to `to`.\n * - When `from` is zero, `tokenId` will be minted for `to`.\n * - When `to` is zero, ``from``'s `tokenId` will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 tokenId\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 tokenId\n ) internal virtual {}\n}\n" + }, + "@openzeppelin/contracts/governance/utils/Votes.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (governance/utils/Votes.sol)\npragma solidity ^0.8.0;\n\nimport \"../../utils/Context.sol\";\nimport \"../../utils/Counters.sol\";\nimport \"../../utils/Checkpoints.sol\";\nimport \"../../utils/cryptography/draft-EIP712.sol\";\nimport \"./IVotes.sol\";\n\n/**\n * @dev This is a base abstract contract that tracks voting units, which are a measure of voting power that can be\n * transferred, and provides a system of vote delegation, where an account can delegate its voting units to a sort of\n * \"representative\" that will pool delegated voting units from different accounts and can then use it to vote in\n * decisions. In fact, voting units _must_ be delegated in order to count as actual votes, and an account has to\n * delegate those votes to itself if it wishes to participate in decisions and does not have a trusted representative.\n *\n * This contract is often combined with a token contract such that voting units correspond to token units. For an\n * example, see {ERC721Votes}.\n *\n * The full history of delegate votes is tracked on-chain so that governance protocols can consider votes as distributed\n * at a particular block number to protect against flash loans and double voting. The opt-in delegate system makes the\n * cost of this history tracking optional.\n *\n * When using this module the derived contract must implement {_getVotingUnits} (for example, make it return\n * {ERC721-balanceOf}), and can use {_transferVotingUnits} to track a change in the distribution of those units (in the\n * previous example, it would be included in {ERC721-_beforeTokenTransfer}).\n *\n * _Available since v4.5._\n */\nabstract contract Votes is IVotes, Context, EIP712 {\n using Checkpoints for Checkpoints.History;\n using Counters for Counters.Counter;\n\n bytes32 private constant _DELEGATION_TYPEHASH =\n keccak256(\"Delegation(address delegatee,uint256 nonce,uint256 expiry)\");\n\n mapping(address => address) private _delegation;\n mapping(address => Checkpoints.History) private _delegateCheckpoints;\n Checkpoints.History private _totalCheckpoints;\n\n mapping(address => Counters.Counter) private _nonces;\n\n /**\n * @dev Returns the current amount of votes that `account` has.\n */\n function getVotes(address account) public view virtual override returns (uint256) {\n return _delegateCheckpoints[account].latest();\n }\n\n /**\n * @dev Returns the amount of votes that `account` had at the end of a past block (`blockNumber`).\n *\n * Requirements:\n *\n * - `blockNumber` must have been already mined\n */\n function getPastVotes(address account, uint256 blockNumber) public view virtual override returns (uint256) {\n return _delegateCheckpoints[account].getAtBlock(blockNumber);\n }\n\n /**\n * @dev Returns the total supply of votes available at the end of a past block (`blockNumber`).\n *\n * NOTE: This value is the sum of all available votes, which is not necessarily the sum of all delegated votes.\n * Votes that have not been delegated are still part of total supply, even though they would not participate in a\n * vote.\n *\n * Requirements:\n *\n * - `blockNumber` must have been already mined\n */\n function getPastTotalSupply(uint256 blockNumber) public view virtual override returns (uint256) {\n require(blockNumber < block.number, \"Votes: block not yet mined\");\n return _totalCheckpoints.getAtBlock(blockNumber);\n }\n\n /**\n * @dev Returns the current total supply of votes.\n */\n function _getTotalSupply() internal view virtual returns (uint256) {\n return _totalCheckpoints.latest();\n }\n\n /**\n * @dev Returns the delegate that `account` has chosen.\n */\n function delegates(address account) public view virtual override returns (address) {\n return _delegation[account];\n }\n\n /**\n * @dev Delegates votes from the sender to `delegatee`.\n */\n function delegate(address delegatee) public virtual override {\n address account = _msgSender();\n _delegate(account, delegatee);\n }\n\n /**\n * @dev Delegates votes from signer to `delegatee`.\n */\n function delegateBySig(\n address delegatee,\n uint256 nonce,\n uint256 expiry,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) public virtual override {\n require(block.timestamp <= expiry, \"Votes: signature expired\");\n address signer = ECDSA.recover(\n _hashTypedDataV4(keccak256(abi.encode(_DELEGATION_TYPEHASH, delegatee, nonce, expiry))),\n v,\n r,\n s\n );\n require(nonce == _useNonce(signer), \"Votes: invalid nonce\");\n _delegate(signer, delegatee);\n }\n\n /**\n * @dev Delegate all of `account`'s voting units to `delegatee`.\n *\n * Emits events {DelegateChanged} and {DelegateVotesChanged}.\n */\n function _delegate(address account, address delegatee) internal virtual {\n address oldDelegate = delegates(account);\n _delegation[account] = delegatee;\n\n emit DelegateChanged(account, oldDelegate, delegatee);\n _moveDelegateVotes(oldDelegate, delegatee, _getVotingUnits(account));\n }\n\n /**\n * @dev Transfers, mints, or burns voting units. To register a mint, `from` should be zero. To register a burn, `to`\n * should be zero. Total supply of voting units will be adjusted with mints and burns.\n */\n function _transferVotingUnits(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n if (from == address(0)) {\n _totalCheckpoints.push(_add, amount);\n }\n if (to == address(0)) {\n _totalCheckpoints.push(_subtract, amount);\n }\n _moveDelegateVotes(delegates(from), delegates(to), amount);\n }\n\n /**\n * @dev Moves delegated votes from one delegate to another.\n */\n function _moveDelegateVotes(\n address from,\n address to,\n uint256 amount\n ) private {\n if (from != to && amount > 0) {\n if (from != address(0)) {\n (uint256 oldValue, uint256 newValue) = _delegateCheckpoints[from].push(_subtract, amount);\n emit DelegateVotesChanged(from, oldValue, newValue);\n }\n if (to != address(0)) {\n (uint256 oldValue, uint256 newValue) = _delegateCheckpoints[to].push(_add, amount);\n emit DelegateVotesChanged(to, oldValue, newValue);\n }\n }\n }\n\n function _add(uint256 a, uint256 b) private pure returns (uint256) {\n return a + b;\n }\n\n function _subtract(uint256 a, uint256 b) private pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Consumes a nonce.\n *\n * Returns the current value and increments nonce.\n */\n function _useNonce(address owner) internal virtual returns (uint256 current) {\n Counters.Counter storage nonce = _nonces[owner];\n current = nonce.current();\n nonce.increment();\n }\n\n /**\n * @dev Returns an address nonce.\n */\n function nonces(address owner) public view virtual returns (uint256) {\n return _nonces[owner].current();\n }\n\n /**\n * @dev Returns the contract's {EIP712} domain separator.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32) {\n return _domainSeparatorV4();\n }\n\n /**\n * @dev Must return the voting units held by an account.\n */\n function _getVotingUnits(address) internal virtual returns (uint256);\n}\n" + }, + "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721Receiver.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @title ERC721 token receiver interface\n * @dev Interface for any contract that wants to support safeTransfers\n * from ERC721 asset contracts.\n */\ninterface IERC721Receiver {\n /**\n * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}\n * by `operator` from `from`, this function is called.\n *\n * It must return its Solidity selector to confirm the token transfer.\n * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.\n *\n * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`.\n */\n function onERC721Received(\n address operator,\n address from,\n uint256 tokenId,\n bytes calldata data\n ) external returns (bytes4);\n}\n" + }, + "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC721.sol\";\n\n/**\n * @title ERC-721 Non-Fungible Token Standard, optional metadata extension\n * @dev See https://eips.ethereum.org/EIPS/eip-721\n */\ninterface IERC721Metadata is IERC721 {\n /**\n * @dev Returns the token collection name.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the token collection symbol.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.\n */\n function tokenURI(uint256 tokenId) external view returns (string memory);\n}\n" + }, + "@openzeppelin/contracts/utils/Checkpoints.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (utils/Checkpoints.sol)\npragma solidity ^0.8.0;\n\nimport \"./math/Math.sol\";\nimport \"./math/SafeCast.sol\";\n\n/**\n * @dev This library defines the `History` struct, for checkpointing values as they change at different points in\n * time, and later looking up past values by block number. See {Votes} as an example.\n *\n * To create a history of checkpoints define a variable type `Checkpoints.History` in your contract, and store a new\n * checkpoint for the current transaction block using the {push} function.\n *\n * _Available since v4.5._\n */\nlibrary Checkpoints {\n struct Checkpoint {\n uint32 _blockNumber;\n uint224 _value;\n }\n\n struct History {\n Checkpoint[] _checkpoints;\n }\n\n /**\n * @dev Returns the value in the latest checkpoint, or zero if there are no checkpoints.\n */\n function latest(History storage self) internal view returns (uint256) {\n uint256 pos = self._checkpoints.length;\n return pos == 0 ? 0 : self._checkpoints[pos - 1]._value;\n }\n\n /**\n * @dev Returns the value at a given block number. If a checkpoint is not available at that block, the closest one\n * before it is returned, or zero otherwise.\n */\n function getAtBlock(History storage self, uint256 blockNumber) internal view returns (uint256) {\n require(blockNumber < block.number, \"Checkpoints: block not yet mined\");\n\n uint256 high = self._checkpoints.length;\n uint256 low = 0;\n while (low < high) {\n uint256 mid = Math.average(low, high);\n if (self._checkpoints[mid]._blockNumber > blockNumber) {\n high = mid;\n } else {\n low = mid + 1;\n }\n }\n return high == 0 ? 0 : self._checkpoints[high - 1]._value;\n }\n\n /**\n * @dev Pushes a value onto a History so that it is stored as the checkpoint for the current block.\n *\n * Returns previous value and new value.\n */\n function push(History storage self, uint256 value) internal returns (uint256, uint256) {\n uint256 pos = self._checkpoints.length;\n uint256 old = latest(self);\n if (pos > 0 && self._checkpoints[pos - 1]._blockNumber == block.number) {\n self._checkpoints[pos - 1]._value = SafeCast.toUint224(value);\n } else {\n self._checkpoints.push(\n Checkpoint({_blockNumber: SafeCast.toUint32(block.number), _value: SafeCast.toUint224(value)})\n );\n }\n return (old, value);\n }\n\n /**\n * @dev Pushes a value onto a History, by updating the latest value using binary operation `op`. The new value will\n * be set to `op(latest, delta)`.\n *\n * Returns previous value and new value.\n */\n function push(\n History storage self,\n function(uint256, uint256) view returns (uint256) op,\n uint256 delta\n ) internal returns (uint256, uint256) {\n return push(self, op(latest(self), delta));\n }\n}\n" + }, + "contracts/JBDirectory.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';\nimport {JBOperatable} from './abstract/JBOperatable.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {JBFundingCycleMetadataResolver} from './libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBOperations} from './libraries/JBOperations.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\n\n/// @notice Keeps a reference of which terminal contracts each project is currently accepting funds through, and which controller contract is managing each project's tokens and funding cycles.\ncontract JBDirectory is JBOperatable, Ownable, IJBDirectory {\n // A library that parses the packed funding cycle metadata into a friendlier format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error DUPLICATE_TERMINALS();\n error INVALID_PROJECT_ID_IN_DIRECTORY();\n error SET_CONTROLLER_NOT_ALLOWED();\n error SET_TERMINALS_NOT_ALLOWED();\n error TOKEN_NOT_ACCEPTED();\n\n //*********************************************************************//\n // --------------------- private stored properties ------------------- //\n //*********************************************************************//\n\n /// @notice For each project ID, the terminals that are currently managing its funds.\n /// @custom:member _projectId The ID of the project to get terminals of.\n mapping(uint256 => IJBPaymentTerminal[]) private _terminalsOf;\n\n /// @notice The project's primary terminal for a token.\n /// @custom:member _projectId The ID of the project to get the primary terminal of.\n /// @custom:member _token The token to get the project's primary terminal of.\n mapping(uint256 => mapping(address => IJBPaymentTerminal)) private _primaryTerminalOf;\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice Mints ERC-721's that represent project ownership and transfers.\n IJBProjects public immutable override projects;\n\n /// @notice The contract storing all funding cycle configurations.\n IJBFundingCycleStore public immutable override fundingCycleStore;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice For each project ID, the controller that manages how terminals interact with tokens and funding cycles.\n /// @custom:member _projectId The ID of the project to get the controller of.\n mapping(uint256 => address) public override controllerOf;\n\n /// @notice Addresses that can set a project's first controller on their behalf. These addresses/contracts have been vetted and verified by this contract's owner.\n /// @custom:param _address The address that is either allowed or not.\n mapping(address => bool) public override isAllowedToSetFirstController;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice For each project ID, the terminals that are currently managing its funds.\n /// @param _projectId The ID of the project to get terminals of.\n /// @return An array of terminal addresses.\n function terminalsOf(uint256 _projectId)\n external\n view\n override\n returns (IJBPaymentTerminal[] memory)\n {\n return _terminalsOf[_projectId];\n }\n\n /// @notice The primary terminal that is managing funds for a project for a specified token.\n /// @dev The zero address is returned if a terminal isn't found for the specified token.\n /// @param _projectId The ID of the project to get a terminal for.\n /// @param _token The token the terminal accepts.\n /// @return The primary terminal for the project for the specified token.\n function primaryTerminalOf(uint256 _projectId, address _token)\n external\n view\n override\n returns (IJBPaymentTerminal)\n {\n // Keep a reference to the primary terminal for the provided project ID and token.\n IJBPaymentTerminal _primaryTerminal = _primaryTerminalOf[_projectId][_token];\n\n // If a primary terminal for the token was specifically set and it's one of the project's terminals, return it.\n if (\n _primaryTerminal != IJBPaymentTerminal(address(0)) &&\n isTerminalOf(_projectId, _primaryTerminal)\n ) return _primaryTerminal;\n\n // Keep a reference to the number of terminals the project has.\n uint256 _numberOfTerminals = _terminalsOf[_projectId].length;\n\n // Return the first terminal which accepts the specified token.\n for (uint256 _i; _i < _numberOfTerminals; ) {\n // Keep a reference to the terminal being iterated on.\n IJBPaymentTerminal _terminal = _terminalsOf[_projectId][_i];\n\n // If the terminal accepts the specified token, return it.\n if (_terminal.acceptsToken(_token, _projectId)) return _terminal;\n\n unchecked {\n ++_i;\n }\n }\n\n // Not found.\n return IJBPaymentTerminal(address(0));\n }\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice Whether or not a specified terminal is a terminal of the specified project.\n /// @param _projectId The ID of the project to check within.\n /// @param _terminal The address of the terminal to check for.\n /// @return A flag indicating whether or not the specified terminal is a terminal of the specified project.\n function isTerminalOf(uint256 _projectId, IJBPaymentTerminal _terminal)\n public\n view\n override\n returns (bool)\n {\n // Keep a reference to the number of terminals the project has.\n uint256 _numberOfTerminals = _terminalsOf[_projectId].length;\n\n // Loop through and return true if the terminal is contained.\n for (uint256 _i; _i < _numberOfTerminals; ) {\n // If the terminal being iterated on matches the provided terminal, return true.\n if (_terminalsOf[_projectId][_i] == _terminal) return true;\n\n unchecked {\n ++_i;\n }\n }\n\n // Otherwise, return false.\n return false;\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _fundingCycleStore A contract storing all funding cycle configurations.\n /// @param _owner The address that will own the contract.\n constructor(\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBFundingCycleStore _fundingCycleStore,\n address _owner\n ) JBOperatable(_operatorStore) {\n projects = _projects;\n fundingCycleStore = _fundingCycleStore;\n\n _transferOwnership(_owner);\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Update the controller that manages how terminals interact with the ecosystem.\n /// @dev A controller can be set if:\n /// @dev - the message sender is the project owner or an operator having the correct authorization.\n /// @dev - the message sender is the project's current controller.\n /// @dev - or, an allowedlisted address is setting a controller for a project that doesn't already have a controller.\n /// @param _projectId The ID of the project to set a new controller for.\n /// @param _controller The new controller to set.\n function setControllerOf(uint256 _projectId, address _controller)\n external\n override\n requirePermissionAllowingOverride(\n projects.ownerOf(_projectId),\n _projectId,\n JBOperations.SET_CONTROLLER,\n (msg.sender == address(controllerOf[_projectId]) ||\n (isAllowedToSetFirstController[msg.sender] && controllerOf[_projectId] == address(0)))\n )\n {\n // The project must exist.\n if (projects.count() < _projectId) revert INVALID_PROJECT_ID_IN_DIRECTORY();\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Setting controller is allowed if called from the current controller, or if the project doesn't have a current controller, or if the project's funding cycle allows setting the controller. Revert otherwise.\n if (\n msg.sender != address(controllerOf[_projectId]) &&\n controllerOf[_projectId] != address(0) &&\n !_fundingCycle.global().allowSetController\n ) revert SET_CONTROLLER_NOT_ALLOWED();\n\n // Set the new controller.\n controllerOf[_projectId] = _controller;\n\n emit SetController(_projectId, _controller, msg.sender);\n }\n\n /// @notice Set a project's terminals.\n /// @dev Only a project owner, an operator, or its controller can set its terminals.\n /// @param _projectId The ID of the project having terminals set.\n /// @param _terminals The terminal to set.\n function setTerminalsOf(uint256 _projectId, IJBPaymentTerminal[] calldata _terminals)\n external\n override\n requirePermissionAllowingOverride(\n projects.ownerOf(_projectId),\n _projectId,\n JBOperations.SET_TERMINALS,\n msg.sender == address(controllerOf[_projectId])\n )\n {\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Setting terminals must be allowed if not called from the current controller.\n if (\n msg.sender != address(controllerOf[_projectId]) && !_fundingCycle.global().allowSetTerminals\n ) revert SET_TERMINALS_NOT_ALLOWED();\n\n // Set the stored terminals for the project.\n _terminalsOf[_projectId] = _terminals;\n\n // Make sure duplicates were not added.\n if (_terminals.length > 1) {\n for (uint256 _i; _i < _terminals.length; ) {\n for (uint256 _j = _i + 1; _j < _terminals.length; ) {\n if (_terminals[_i] == _terminals[_j]) revert DUPLICATE_TERMINALS();\n\n unchecked {\n ++_j;\n }\n }\n\n unchecked {\n ++_i;\n }\n }\n }\n emit SetTerminals(_projectId, _terminals, msg.sender);\n }\n\n /// @notice Project's can set which terminal should be their primary for a particular token. \n /// @dev This is useful in case a project has several terminals connected for a particular token.\n /// @dev The terminal will be set as the primary terminal where ecosystem contracts should route tokens.\n /// @dev If setting a newly added terminal and the funding cycle doesn't allow new terminals, the caller must be the current controller.\n /// @param _projectId The ID of the project for which a primary token is being set.\n /// @param _token The token to set the primary terminal of.\n /// @param _terminal The terminal to make primary.\n function setPrimaryTerminalOf(\n uint256 _projectId,\n address _token,\n IJBPaymentTerminal _terminal\n )\n external\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.SET_PRIMARY_TERMINAL)\n {\n // Can't set the primary terminal for a token if it doesn't accept the token.\n if (!_terminal.acceptsToken(_token, _projectId)) revert TOKEN_NOT_ACCEPTED();\n\n // Add the terminal to the project if it hasn't been already.\n _addTerminalIfNeeded(_projectId, _terminal);\n\n // Store the terminal as the primary for the particular token.\n _primaryTerminalOf[_projectId][_token] = _terminal;\n\n emit SetPrimaryTerminal(_projectId, _token, _terminal, msg.sender);\n }\n\n /// @notice Set a contract to the list of trusted addresses that can set a first controller for any project.\t\n /// @dev The owner can add addresses which are allowed to change projects' first controllers. \n /// @dev These addresses are known and vetted controllers as well as contracts designed to launch new projects. \n /// @dev A project can set its own controller without it being on the allow list.\n /// @dev If you would like an address/contract allowlisted, please reach out to the contract owner.\n /// @param _address The address to allow or revoke allowance from.\n /// @param _flag Whether allowance is being added or revoked.\n function setIsAllowedToSetFirstController(address _address, bool _flag)\n external\n override\n onlyOwner\n {\n // Set the flag in the allowlist.\n isAllowedToSetFirstController[_address] = _flag;\n\n emit SetIsAllowedToSetFirstController(_address, _flag, msg.sender);\n }\n\n //*********************************************************************//\n // --------------------- private helper functions -------------------- //\n //*********************************************************************//\n\n /// @notice Add a terminal to a project's list of terminals if it hasn't been already.\n /// @param _projectId The ID of the project having a terminal added.\n /// @param _terminal The terminal to add.\n function _addTerminalIfNeeded(uint256 _projectId, IJBPaymentTerminal _terminal) private {\n // Check that the terminal has not already been added.\n if (isTerminalOf(_projectId, _terminal)) return;\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Setting terminals must be allowed if not called from the current controller.\n if (\n msg.sender != address(controllerOf[_projectId]) && !_fundingCycle.global().allowSetTerminals\n ) revert SET_TERMINALS_NOT_ALLOWED();\n\n // Add the new terminal.\n _terminalsOf[_projectId].push(_terminal);\n\n emit AddTerminal(_projectId, _terminal, msg.sender);\n }\n}\n" + }, + "contracts/JBSingleTokenPaymentTerminalStore3_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {ReentrancyGuard} from '@openzeppelin/contracts/security/ReentrancyGuard.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {JBBallotState} from './enums/JBBallotState.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBController3_1} from './interfaces/IJBController3_1.sol';\nimport {IJBFundingCycleDataSource} from './interfaces/IJBFundingCycleDataSource.sol';\nimport {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol';\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\nimport {IJBSingleTokenPaymentTerminal} from './interfaces/IJBSingleTokenPaymentTerminal.sol';\nimport {IJBSingleTokenPaymentTerminalStore} from './interfaces/IJBSingleTokenPaymentTerminalStore.sol';\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\nimport {JBConstants} from './libraries/JBConstants.sol';\nimport {JBCurrencies} from './libraries/JBCurrencies.sol';\nimport {JBFixedPointNumber} from './libraries/JBFixedPointNumber.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\nimport {JBFundingCycleMetadataResolver} from './libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBPayDelegateAllocation} from './structs/JBPayDelegateAllocation.sol';\nimport {JBPayParamsData} from './structs/JBPayParamsData.sol';\nimport {JBRedeemParamsData} from './structs/JBRedeemParamsData.sol';\nimport {JBRedemptionDelegateAllocation} from './structs/JBRedemptionDelegateAllocation.sol';\nimport {JBTokenAmount} from './structs/JBTokenAmount.sol';\n\n/// @notice Manages all bookkeeping for inflows and outflows of funds from any ISingleTokenPaymentTerminal.\n/// @dev This Store expects a project's controller to be an IJBController3_1. This is the only difference between this version and the original.\ncontract JBSingleTokenPaymentTerminalStore3_1 is\n ReentrancyGuard,\n IJBSingleTokenPaymentTerminalStore\n{\n // A library that parses the packed funding cycle metadata into a friendlier format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error INVALID_AMOUNT_TO_SEND_DELEGATE();\n error CURRENCY_MISMATCH();\n error DISTRIBUTION_AMOUNT_LIMIT_REACHED();\n error FUNDING_CYCLE_PAYMENT_PAUSED();\n error FUNDING_CYCLE_DISTRIBUTION_PAUSED();\n error FUNDING_CYCLE_REDEEM_PAUSED();\n error INADEQUATE_CONTROLLER_ALLOWANCE();\n error INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n error INSUFFICIENT_TOKENS();\n error INVALID_FUNDING_CYCLE();\n error PAYMENT_TERMINAL_MIGRATION_NOT_ALLOWED();\n\n //*********************************************************************//\n // -------------------------- private constants ---------------------- //\n //*********************************************************************//\n\n /// @notice Ensures a maximum number of decimal points of persisted fidelity on mulDiv operations of fixed point numbers.\n uint256 private constant _MAX_FIXED_POINT_FIDELITY = 18;\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n /// @notice The contract storing all funding cycle configurations.\n IJBFundingCycleStore public immutable override fundingCycleStore;\n\n /// @notice The contract that exposes price feeds.\n IJBPrices public immutable override prices;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The amount of tokens that each project has for each terminal, in terms of the terminal's token.\n /// @dev The used distribution limit is represented as a fixed point number with the same amount of decimals as its relative terminal.\n /// @custom:param _terminal The terminal to which the balance applies.\n /// @custom:param _projectId The ID of the project to get the balance of.\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => uint256)) public override balanceOf;\n\n /// @notice The amount of funds that a project has distributed from its limit during the current funding cycle for each terminal, in terms of the distribution limit's currency.\n /// @dev Increases as projects use their preconfigured distribution limits.\n /// @dev The used distribution limit is represented as a fixed point number with the same amount of decimals as its relative terminal.\n /// @custom:param _terminal The terminal to which the used distribution limit applies.\n /// @custom:param _projectId The ID of the project to get the used distribution limit of.\n /// @custom:param _fundingCycleNumber The number of the funding cycle during which the distribution limit was used.\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => mapping(uint256 => uint256)))\n public\n override usedDistributionLimitOf;\n\n /// @notice The amount of funds that a project has used from its allowance during the current funding cycle configuration for each terminal, in terms of the overflow allowance's currency.\n /// @dev Increases as projects use their allowance.\n /// @dev The used allowance is represented as a fixed point number with the same amount of decimals as its relative terminal.\n /// @custom:param _terminal The terminal to which the overflow allowance applies.\n /// @custom:param _projectId The ID of the project to get the used overflow allowance of.\n /// @custom:param _configuration The configuration of the during which the allowance was used.\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => mapping(uint256 => uint256)))\n public\n override usedOverflowAllowanceOf;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Gets the current overflowed amount in a terminal for a specified project.\n /// @dev The current overflow is represented as a fixed point number with the same amount of decimals as the specified terminal.\n /// @param _terminal The terminal for which the overflow is being calculated.\n /// @param _projectId The ID of the project to get overflow for.\n /// @return The current amount of overflow that project has in the specified terminal.\n function currentOverflowOf(\n IJBSingleTokenPaymentTerminal _terminal,\n uint256 _projectId\n ) external view override returns (uint256) {\n // Return the overflow during the project's current funding cycle.\n return\n _overflowDuring(\n _terminal,\n _projectId,\n fundingCycleStore.currentOf(_projectId),\n _terminal.currency()\n );\n }\n\n /// @notice Gets the current overflowed amount for a specified project across all terminals.\n /// @param _projectId The ID of the project to get total overflow for.\n /// @param _decimals The number of decimals that the fixed point overflow should include.\n /// @param _currency The currency that the total overflow should be in terms of.\n /// @return The current total amount of overflow that project has across all terminals.\n function currentTotalOverflowOf(\n uint256 _projectId,\n uint256 _decimals,\n uint256 _currency\n ) external view override returns (uint256) {\n return _currentTotalOverflowOf(_projectId, _decimals, _currency);\n }\n\n /// @notice The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the total token supply and overflow in the ecosystem.\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\n /// @dev The current reclaimable overflow is returned in terms of the specified terminal's currency.\n /// @dev The reclaimable overflow is represented as a fixed point number with the same amount of decimals as the specified terminal.\n /// @param _terminal The terminal from which the reclaimable amount would come.\n /// @param _projectId The ID of the project to get the reclaimable overflow amount for.\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _useTotalOverflow A flag indicating whether the overflow used in the calculation should be summed from all of the project's terminals. If false, overflow should be limited to the amount in the specified `_terminal`.\n /// @return The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_terminal`.\n function currentReclaimableOverflowOf(\n IJBSingleTokenPaymentTerminal _terminal,\n uint256 _projectId,\n uint256 _tokenCount,\n bool _useTotalOverflow\n ) external view override returns (uint256) {\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Get the amount of current overflow.\n // Use the project's total overflow across all of its terminals if the flag species specifies so. Otherwise, use the overflow local to the specified terminal.\n uint256 _currentOverflow = _useTotalOverflow\n ? _currentTotalOverflowOf(_projectId, _terminal.decimals(), _terminal.currency())\n : _overflowDuring(_terminal, _projectId, _fundingCycle, _terminal.currency());\n\n // If there's no overflow, there's no reclaimable overflow.\n if (_currentOverflow == 0) return 0;\n\n // Get the number of outstanding tokens the project has.\n uint256 _totalSupply = IJBController3_1(directory.controllerOf(_projectId))\n .totalOutstandingTokensOf(_projectId);\n\n // Can't redeem more tokens that is in the supply.\n if (_tokenCount > _totalSupply) return 0;\n\n // Return the reclaimable overflow amount.\n return\n _reclaimableOverflowDuring(\n _projectId,\n _fundingCycle,\n _tokenCount,\n _totalSupply,\n _currentOverflow\n );\n }\n\n /// @notice The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the specified total token supply and overflow amounts.\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\n /// @param _projectId The ID of the project to get the reclaimable overflow amount for.\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _totalSupply The total number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _overflow The amount of overflow to make the calculation with, as a fixed point number.\n /// @return The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_overflow`.\n function currentReclaimableOverflowOf(\n uint256 _projectId,\n uint256 _tokenCount,\n uint256 _totalSupply,\n uint256 _overflow\n ) external view override returns (uint256) {\n // If there's no overflow, there's no reclaimable overflow.\n if (_overflow == 0) return 0;\n\n // Can't redeem more tokens that is in the supply.\n if (_tokenCount > _totalSupply) return 0;\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Return the reclaimable overflow amount.\n return\n _reclaimableOverflowDuring(_projectId, _fundingCycle, _tokenCount, _totalSupply, _overflow);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _fundingCycleStore A contract storing all funding cycle configurations.\n /// @param _prices A contract that exposes price feeds.\n constructor(IJBDirectory _directory, IJBFundingCycleStore _fundingCycleStore, IJBPrices _prices) {\n directory = _directory;\n fundingCycleStore = _fundingCycleStore;\n prices = _prices;\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Records newly contributed tokens to a project.\n /// @dev Mints the project's tokens according to values provided by a configured data source. If no data source is configured, mints tokens proportional to the amount of the contribution.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.sender's tokens.\n /// @param _payer The original address that sent the payment to the terminal.\n /// @param _amount The amount of tokens being paid. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\n /// @param _projectId The ID of the project being paid.\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _beneficiary The specified address that should be the beneficiary of anything that results from the payment.\n /// @param _memo A memo to pass along to the emitted event, and passed along to the funding cycle's data source.\n /// @param _metadata Bytes to send along to the data source, if one is provided.\n /// @return fundingCycle The project's funding cycle during which payment was made.\n /// @return tokenCount The number of project tokens that were minted, as a fixed point number with 18 decimals.\n /// @return delegateAllocations The amount to send to delegates instead of adding to the local balance.\n /// @return memo A memo that should be passed along to the emitted event.\n function recordPaymentFrom(\n address _payer,\n JBTokenAmount calldata _amount,\n uint256 _projectId,\n uint256 _baseWeightCurrency,\n address _beneficiary,\n string calldata _memo,\n bytes memory _metadata\n )\n external\n override\n nonReentrant\n returns (\n JBFundingCycle memory fundingCycle,\n uint256 tokenCount,\n JBPayDelegateAllocation[] memory delegateAllocations,\n string memory memo\n )\n {\n // Get a reference to the current funding cycle for the project.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // The project must have a funding cycle configured.\n if (fundingCycle.number == 0) revert INVALID_FUNDING_CYCLE();\n\n // Must not be paused.\n if (fundingCycle.payPaused()) revert FUNDING_CYCLE_PAYMENT_PAUSED();\n\n // The weight according to which new token supply is to be minted, as a fixed point number with 18 decimals.\n uint256 _weight;\n\n // If the funding cycle has configured a data source, use it to derive a weight and memo.\n if (fundingCycle.useDataSourceForPay() && fundingCycle.dataSource() != address(0)) {\n // Create the params that'll be sent to the data source.\n JBPayParamsData memory _data = JBPayParamsData(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _payer,\n _amount,\n _projectId,\n fundingCycle.configuration,\n _beneficiary,\n fundingCycle.weight,\n fundingCycle.reservedRate(),\n _memo,\n _metadata\n );\n (_weight, memo, delegateAllocations) = IJBFundingCycleDataSource(fundingCycle.dataSource())\n .payParams(_data);\n }\n // Otherwise use the funding cycle's weight\n else {\n _weight = fundingCycle.weight;\n memo = _memo;\n }\n\n // Scoped section prevents stack too deep. `_balanceDiff` only used within scope.\n {\n // Keep a reference to the amount that should be added to the project's balance.\n uint256 _balanceDiff = _amount.value;\n\n // Validate all delegated amounts. This needs to be done before returning the delegate allocations to ensure valid delegated amounts.\n if (delegateAllocations.length != 0) {\n for (uint256 _i; _i < delegateAllocations.length; ) {\n // Get a reference to the amount to be delegated.\n uint256 _delegatedAmount = delegateAllocations[_i].amount;\n\n // Validate if non-zero.\n if (_delegatedAmount != 0) {\n // Can't delegate more than was paid.\n if (_delegatedAmount > _balanceDiff) revert INVALID_AMOUNT_TO_SEND_DELEGATE();\n\n // Decrement the total amount being added to the balance.\n _balanceDiff = _balanceDiff - _delegatedAmount;\n }\n\n unchecked {\n ++_i;\n }\n }\n }\n\n // If there's no amount being recorded, there's nothing left to do.\n if (_amount.value == 0) return (fundingCycle, 0, delegateAllocations, memo);\n\n // Add the correct balance difference to the token balance of the project.\n if (_balanceDiff != 0)\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] +\n _balanceDiff;\n }\n\n // If there's no weight, token count must be 0 so there's nothing left to do.\n if (_weight == 0) return (fundingCycle, 0, delegateAllocations, memo);\n\n // Get a reference to the number of decimals in the amount. (prevents stack too deep).\n uint256 _decimals = _amount.decimals;\n\n // If the terminal should base its weight on a different currency from the terminal's currency, determine the factor.\n // The weight is always a fixed point mumber with 18 decimals. To ensure this, the ratio should use the same number of decimals as the `_amount`.\n uint256 _weightRatio = _amount.currency == _baseWeightCurrency\n ? 10 ** _decimals\n : prices.priceFor(_amount.currency, _baseWeightCurrency, _decimals);\n\n // Find the number of tokens to mint, as a fixed point number with as many decimals as `weight` has.\n tokenCount = PRBMath.mulDiv(_amount.value, _weight, _weightRatio);\n }\n\n /// @notice Records newly redeemed tokens of a project.\n /// @dev Redeems the project's tokens according to values provided by a configured data source. If no data source is configured, redeems tokens along a redemption bonding curve that is a function of the number of tokens being burned.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.senders tokens.\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the data source, if one is provided.\n /// @return fundingCycle The funding cycle during which the redemption was made.\n /// @return reclaimAmount The amount of terminal tokens reclaimed, as a fixed point number with 18 decimals.\n /// @return delegateAllocations The amount to send to delegates instead of sending to the beneficiary.\n /// @return memo A memo that should be passed along to the emitted event.\n function recordRedemptionFor(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n string memory _memo,\n bytes memory _metadata\n )\n external\n override\n nonReentrant\n returns (\n JBFundingCycle memory fundingCycle,\n uint256 reclaimAmount,\n JBRedemptionDelegateAllocation[] memory delegateAllocations,\n string memory memo\n )\n {\n // Get a reference to the project's current funding cycle.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // The current funding cycle must not be paused.\n if (fundingCycle.redeemPaused()) revert FUNDING_CYCLE_REDEEM_PAUSED();\n\n // Scoped section prevents stack too deep. `_reclaimedTokenAmount`, `_currentOverflow`, and `_totalSupply` only used within scope.\n {\n // Get a reference to the reclaimed token amount struct, the current overflow, and the total token supply.\n JBTokenAmount memory _reclaimedTokenAmount;\n uint256 _currentOverflow;\n uint256 _totalSupply;\n\n // Another scoped section prevents stack too deep. `_token`, `_decimals`, and `_currency` only used within scope.\n {\n // Get a reference to the terminal's tokens.\n address _token = IJBSingleTokenPaymentTerminal(msg.sender).token();\n\n // Get a reference to the terminal's decimals.\n uint256 _decimals = IJBSingleTokenPaymentTerminal(msg.sender).decimals();\n\n // Get areference to the terminal's currency.\n uint256 _currency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\n\n // Get the amount of current overflow.\n // Use the local overflow if the funding cycle specifies that it should be used. Otherwise, use the project's total overflow across all of its terminals.\n _currentOverflow = fundingCycle.useTotalOverflowForRedemptions()\n ? _currentTotalOverflowOf(_projectId, _decimals, _currency)\n : _overflowDuring(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _projectId,\n fundingCycle,\n _currency\n );\n\n // Get the number of outstanding tokens the project has.\n _totalSupply = IJBController3_1(directory.controllerOf(_projectId))\n .totalOutstandingTokensOf(_projectId);\n\n // Can't redeem more tokens that is in the supply.\n if (_tokenCount > _totalSupply) revert INSUFFICIENT_TOKENS();\n\n if (_currentOverflow != 0)\n // Calculate reclaim amount using the current overflow amount.\n reclaimAmount = _reclaimableOverflowDuring(\n _projectId,\n fundingCycle,\n _tokenCount,\n _totalSupply,\n _currentOverflow\n );\n\n _reclaimedTokenAmount = JBTokenAmount(_token, reclaimAmount, _decimals, _currency);\n }\n\n // If the funding cycle has configured a data source, use it to derive a claim amount and memo.\n if (fundingCycle.useDataSourceForRedeem() && fundingCycle.dataSource() != address(0)) {\n // Yet another scoped section prevents stack too deep. `_state` only used within scope.\n {\n // Get a reference to the ballot state.\n JBBallotState _state = fundingCycleStore.currentBallotStateOf(_projectId);\n\n // Create the params that'll be sent to the data source.\n JBRedeemParamsData memory _data = JBRedeemParamsData(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _holder,\n _projectId,\n fundingCycle.configuration,\n _tokenCount,\n _totalSupply,\n _currentOverflow,\n _reclaimedTokenAmount,\n fundingCycle.useTotalOverflowForRedemptions(),\n _state == JBBallotState.Active\n ? fundingCycle.ballotRedemptionRate()\n : fundingCycle.redemptionRate(),\n _memo,\n _metadata\n );\n (reclaimAmount, memo, delegateAllocations) = IJBFundingCycleDataSource(\n fundingCycle.dataSource()\n ).redeemParams(_data);\n }\n } else {\n memo = _memo;\n }\n }\n\n // Keep a reference to the amount that should be subtracted from the project's balance.\n uint256 _balanceDiff = reclaimAmount;\n\n if (delegateAllocations.length != 0) {\n // Validate all delegated amounts.\n for (uint256 _i; _i < delegateAllocations.length; ) {\n // Get a reference to the amount to be delegated.\n uint256 _delegatedAmount = delegateAllocations[_i].amount;\n\n // Validate if non-zero.\n if (_delegatedAmount != 0)\n // Increment the total amount being subtracted from the balance.\n _balanceDiff = _balanceDiff + _delegatedAmount;\n\n unchecked {\n ++_i;\n }\n }\n }\n\n // The amount being reclaimed must be within the project's balance.\n if (_balanceDiff > balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId])\n revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n\n // Remove the reclaimed funds from the project's balance.\n if (_balanceDiff != 0) {\n unchecked {\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\n _balanceDiff;\n }\n }\n }\n\n /// @notice Records newly distributed funds for a project.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\n /// @param _projectId The ID of the project that is having funds distributed.\n /// @param _amount The amount to use from the distribution limit, as a fixed point number.\n /// @param _currency The currency of the `_amount`. This must match the project's current funding cycle's currency.\n /// @return fundingCycle The funding cycle during which the distribution was made.\n /// @return distributedAmount The amount of terminal tokens distributed, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordDistributionFor(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency\n )\n external\n override\n nonReentrant\n returns (JBFundingCycle memory fundingCycle, uint256 distributedAmount)\n {\n // Get a reference to the project's current funding cycle.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // The funding cycle must not be configured to have distributions paused.\n if (fundingCycle.distributionsPaused()) revert FUNDING_CYCLE_DISTRIBUTION_PAUSED();\n\n // The new total amount that has been distributed during this funding cycle.\n uint256 _newUsedDistributionLimitOf = usedDistributionLimitOf[\n IJBSingleTokenPaymentTerminal(msg.sender)\n ][_projectId][fundingCycle.number] + _amount;\n\n // Amount must be within what is still distributable.\n (uint256 _distributionLimitOf, uint256 _distributionLimitCurrencyOf) = IJBController3_1(\n directory.controllerOf(_projectId)\n ).fundAccessConstraintsStore().distributionLimitOf(\n _projectId,\n fundingCycle.configuration,\n IJBSingleTokenPaymentTerminal(msg.sender),\n IJBSingleTokenPaymentTerminal(msg.sender).token()\n );\n\n // Make sure the new used amount is within the distribution limit.\n if (_newUsedDistributionLimitOf > _distributionLimitOf || _distributionLimitOf == 0)\n revert DISTRIBUTION_AMOUNT_LIMIT_REACHED();\n\n // Make sure the currencies match.\n if (_currency != _distributionLimitCurrencyOf) revert CURRENCY_MISMATCH();\n\n // Get a reference to the terminal's currency.\n uint256 _balanceCurrency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\n\n // Convert the amount to the balance's currency.\n distributedAmount = (_currency == _balanceCurrency)\n ? _amount\n : PRBMath.mulDiv(\n _amount,\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\n prices.priceFor(_currency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\n );\n\n // The amount being distributed must be available.\n if (distributedAmount > balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId])\n revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n\n // Store the new amount.\n usedDistributionLimitOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId][\n fundingCycle.number\n ] = _newUsedDistributionLimitOf;\n\n // Removed the distributed funds from the project's token balance.\n unchecked {\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\n distributedAmount;\n }\n }\n\n /// @notice Records newly used allowance funds of a project.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\n /// @param _projectId The ID of the project to use the allowance of.\n /// @param _amount The amount to use from the allowance, as a fixed point number.\n /// @param _currency The currency of the `_amount`. Must match the currency of the overflow allowance.\n /// @return fundingCycle The funding cycle during which the overflow allowance is being used.\n /// @return usedAmount The amount of terminal tokens used, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordUsedAllowanceOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency\n )\n external\n override\n nonReentrant\n returns (JBFundingCycle memory fundingCycle, uint256 usedAmount)\n {\n // Get a reference to the project's current funding cycle.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Get a reference to the new used overflow allowance for this funding cycle configuration.\n uint256 _newUsedOverflowAllowanceOf = usedOverflowAllowanceOf[\n IJBSingleTokenPaymentTerminal(msg.sender)\n ][_projectId][fundingCycle.configuration] + _amount;\n\n // There must be sufficient allowance available.\n (uint256 _overflowAllowanceOf, uint256 _overflowAllowanceCurrency) = IJBController3_1(\n directory.controllerOf(_projectId)\n ).fundAccessConstraintsStore().overflowAllowanceOf(\n _projectId,\n fundingCycle.configuration,\n IJBSingleTokenPaymentTerminal(msg.sender),\n IJBSingleTokenPaymentTerminal(msg.sender).token()\n );\n\n // Make sure the new used amount is within the allowance.\n if (_newUsedOverflowAllowanceOf > _overflowAllowanceOf || _overflowAllowanceOf == 0)\n revert INADEQUATE_CONTROLLER_ALLOWANCE();\n\n // Make sure the currencies match.\n if (_currency != _overflowAllowanceCurrency) revert CURRENCY_MISMATCH();\n\n // Get a reference to the terminal's currency.\n uint256 _balanceCurrency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\n\n // Convert the amount to this store's terminal's token.\n usedAmount = (_currency == _balanceCurrency)\n ? _amount\n : PRBMath.mulDiv(\n _amount,\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\n prices.priceFor(_currency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\n );\n\n // The amount being distributed must be available in the overflow.\n if (\n usedAmount >\n _overflowDuring(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _projectId,\n fundingCycle,\n _balanceCurrency\n )\n ) revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n\n // Store the incremented value.\n usedOverflowAllowanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId][\n fundingCycle.configuration\n ] = _newUsedOverflowAllowanceOf;\n\n // Update the project's balance.\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\n usedAmount;\n }\n\n /// @notice Records newly added funds for the project.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\n /// @param _projectId The ID of the project to which the funds being added belong.\n /// @param _amount The amount of terminal tokens added, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordAddedBalanceFor(uint256 _projectId, uint256 _amount) external override {\n // Increment the balance.\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] +\n _amount;\n }\n\n /// @notice Records the migration of funds from this store.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount returned is in terms of the msg.senders tokens.\n /// @param _projectId The ID of the project being migrated.\n /// @return balance The project's migrated balance, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordMigration(\n uint256 _projectId\n ) external override nonReentrant returns (uint256 balance) {\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n // Migration must be allowed.\n if (!_fundingCycle.terminalMigrationAllowed()) revert PAYMENT_TERMINAL_MIGRATION_NOT_ALLOWED();\n\n // Return the current balance.\n balance = balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId];\n\n // Set the balance to 0.\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] = 0;\n }\n\n //*********************************************************************//\n // --------------------- private helper functions -------------------- //\n //*********************************************************************//\n\n /// @notice The amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens when measured from the specified.\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\n /// @param _projectId The ID of the project to get the reclaimable overflow amount for.\n /// @param _fundingCycle The funding cycle during which reclaimable overflow is being calculated.\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _totalSupply The total supply of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _overflow The amount of overflow to make the calculation with.\n /// @return The amount of overflowed tokens that can be reclaimed.\n function _reclaimableOverflowDuring(\n uint256 _projectId,\n JBFundingCycle memory _fundingCycle,\n uint256 _tokenCount,\n uint256 _totalSupply,\n uint256 _overflow\n ) private view returns (uint256) {\n // If the amount being redeemed is the total supply, return the rest of the overflow.\n if (_tokenCount == _totalSupply) return _overflow;\n\n // Use the ballot redemption rate if the queued cycle is pending approval according to the previous funding cycle's ballot.\n uint256 _redemptionRate = fundingCycleStore.currentBallotStateOf(_projectId) ==\n JBBallotState.Active\n ? _fundingCycle.ballotRedemptionRate()\n : _fundingCycle.redemptionRate();\n\n // If the redemption rate is 0, nothing is claimable.\n if (_redemptionRate == 0) return 0;\n\n // Get a reference to the linear proportion.\n uint256 _base = PRBMath.mulDiv(_overflow, _tokenCount, _totalSupply);\n\n // These conditions are all part of the same curve. Edge conditions are separated because fewer operation are necessary.\n if (_redemptionRate == JBConstants.MAX_REDEMPTION_RATE) return _base;\n\n return\n PRBMath.mulDiv(\n _base,\n _redemptionRate +\n PRBMath.mulDiv(\n _tokenCount,\n JBConstants.MAX_REDEMPTION_RATE - _redemptionRate,\n _totalSupply\n ),\n JBConstants.MAX_REDEMPTION_RATE\n );\n }\n\n /// @notice Gets the amount that is overflowing when measured from the specified funding cycle.\n /// @dev This amount changes as the value of the balance changes in relation to the currency being used to measure the distribution limit.\n /// @param _terminal The terminal for which the overflow is being calculated.\n /// @param _fundingCycle The ID of the funding cycle to base the overflow on.\n /// @param _balanceCurrency The currency that the stored balance is expected to be in terms of.\n /// @return overflow The overflow of funds, as a fixed point number with 18 decimals.\n function _overflowDuring(\n IJBSingleTokenPaymentTerminal _terminal,\n uint256 _projectId,\n JBFundingCycle memory _fundingCycle,\n uint256 _balanceCurrency\n ) private view returns (uint256) {\n // Get the current balance of the project.\n uint256 _balanceOf = balanceOf[_terminal][_projectId];\n\n // If there's no balance, there's no overflow.\n if (_balanceOf == 0) return 0;\n\n // Get a reference to the distribution limit during the funding cycle.\n (uint256 _distributionLimit, uint256 _distributionLimitCurrency) = IJBController3_1(\n directory.controllerOf(_projectId)\n ).fundAccessConstraintsStore().distributionLimitOf(\n _projectId,\n _fundingCycle.configuration,\n _terminal,\n _terminal.token()\n );\n\n // Get a reference to the amount still distributable during the funding cycle.\n uint256 _distributionLimitRemaining = _distributionLimit -\n usedDistributionLimitOf[_terminal][_projectId][_fundingCycle.number];\n\n // Convert the _distributionRemaining to be in terms of the provided currency.\n if (_distributionLimitRemaining != 0 && _distributionLimitCurrency != _balanceCurrency)\n _distributionLimitRemaining = PRBMath.mulDiv(\n _distributionLimitRemaining,\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\n prices.priceFor(_distributionLimitCurrency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\n );\n\n // Overflow is the balance of this project minus the amount that can still be distributed.\n unchecked {\n return\n _balanceOf > _distributionLimitRemaining ? _balanceOf - _distributionLimitRemaining : 0;\n }\n }\n\n /// @notice Gets the amount that is currently overflowing across all of a project's terminals.\n /// @dev This amount changes as the value of the balances changes in relation to the currency being used to measure the project's distribution limits.\n /// @param _projectId The ID of the project to get the total overflow for.\n /// @param _decimals The number of decimals that the fixed point overflow should include.\n /// @param _currency The currency that the overflow should be in terms of.\n /// @return overflow The total overflow of a project's funds.\n function _currentTotalOverflowOf(\n uint256 _projectId,\n uint256 _decimals,\n uint256 _currency\n ) private view returns (uint256) {\n // Get a reference to the project's terminals.\n IJBPaymentTerminal[] memory _terminals = directory.terminalsOf(_projectId);\n\n // Keep a reference to the ETH overflow across all terminals, as a fixed point number with 18 decimals.\n uint256 _ethOverflow;\n\n // Add the current ETH overflow for each terminal.\n for (uint256 _i; _i < _terminals.length; ) {\n _ethOverflow = _ethOverflow + _terminals[_i].currentEthOverflowOf(_projectId);\n unchecked {\n ++_i;\n }\n }\n\n // Convert the ETH overflow to the specified currency if needed, maintaining a fixed point number with 18 decimals.\n uint256 _totalOverflow18Decimal = _currency == JBCurrencies.ETH\n ? _ethOverflow\n : PRBMath.mulDiv(_ethOverflow, 10 ** 18, prices.priceFor(JBCurrencies.ETH, _currency, 18));\n\n // Adjust the decimals of the fixed point number if needed to match the target decimals.\n return\n (_decimals == 18)\n ? _totalOverflow18Decimal\n : JBFixedPointNumber.adjustDecimals(_totalOverflow18Decimal, 18, _decimals);\n }\n}\n" + }, + "contracts/interfaces/IJBFundingCycleDataSource.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBPayDelegateAllocation} from './../structs/JBPayDelegateAllocation.sol';\nimport {JBPayParamsData} from './../structs/JBPayParamsData.sol';\nimport {JBRedeemParamsData} from './../structs/JBRedeemParamsData.sol';\nimport {JBRedemptionDelegateAllocation} from './../structs/JBRedemptionDelegateAllocation.sol';\n\n/// @title Datasource\n/// @notice The datasource is called by JBPayoutRedemptionPaymentTerminals on pay and redemption, and provide an extra layer of logic to use a custom weight, a custom memo and/or a pay/redeem delegate\ninterface IJBFundingCycleDataSource is IERC165 {\n /// @notice The datasource implementation for JBPaymentTerminal.pay(..)\n /// @param data the data passed to the data source in terminal.pay(..), as a JBPayParamsData struct:\n /// @return weight the weight to use to override the funding cycle weight\n /// @return memo the memo to override the pay(..) memo\n /// @return delegateAllocations The amount to send to delegates instead of adding to the local balance.\n function payParams(\n JBPayParamsData calldata data\n )\n external\n returns (\n uint256 weight,\n string memory memo,\n JBPayDelegateAllocation[] memory delegateAllocations\n );\n\n /// @notice The datasource implementation for JBPaymentTerminal.redeemTokensOf(..)\n /// @param data the data passed to the data source in terminal.redeemTokensOf(..), as a JBRedeemParamsData struct:\n /// @return reclaimAmount The amount to claim, overriding the terminal logic.\n /// @return memo The memo to override the redeemTokensOf(..) memo.\n /// @return delegateAllocations The amount to send to delegates instead of adding to the beneficiary.\n function redeemParams(\n JBRedeemParamsData calldata data\n )\n external\n returns (\n uint256 reclaimAmount,\n string memory memo,\n JBRedemptionDelegateAllocation[] memory delegateAllocations\n );\n}\n" + }, + "contracts/interfaces/IJBSingleTokenPaymentTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\n\ninterface IJBSingleTokenPaymentTerminal is IJBPaymentTerminal {\n function token() external view returns (address);\n\n function currency() external view returns (uint256);\n\n function decimals() external view returns (uint256);\n}\n" + }, + "contracts/interfaces/IJBSingleTokenPaymentTerminalStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\nimport {JBPayDelegateAllocation} from './../structs/JBPayDelegateAllocation.sol';\nimport {JBRedemptionDelegateAllocation} from './../structs/JBRedemptionDelegateAllocation.sol';\nimport {JBTokenAmount} from './../structs/JBTokenAmount.sol';\nimport {IJBDirectory} from './IJBDirectory.sol';\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\nimport {IJBPrices} from './IJBPrices.sol';\nimport {IJBSingleTokenPaymentTerminal} from './IJBSingleTokenPaymentTerminal.sol';\n\ninterface IJBSingleTokenPaymentTerminalStore {\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\n\n function directory() external view returns (IJBDirectory);\n\n function prices() external view returns (IJBPrices);\n\n function balanceOf(\n IJBSingleTokenPaymentTerminal terminal,\n uint256 projectId\n ) external view returns (uint256);\n\n function usedDistributionLimitOf(\n IJBSingleTokenPaymentTerminal terminal,\n uint256 projectId,\n uint256 fundingCycleNumber\n ) external view returns (uint256);\n\n function usedOverflowAllowanceOf(\n IJBSingleTokenPaymentTerminal terminal,\n uint256 projectId,\n uint256 fundingCycleConfiguration\n ) external view returns (uint256);\n\n function currentOverflowOf(\n IJBSingleTokenPaymentTerminal terminal,\n uint256 projectId\n ) external view returns (uint256);\n\n function currentTotalOverflowOf(\n uint256 projectId,\n uint256 decimals,\n uint256 currency\n ) external view returns (uint256);\n\n function currentReclaimableOverflowOf(\n IJBSingleTokenPaymentTerminal terminal,\n uint256 projectId,\n uint256 tokenCount,\n bool useTotalOverflow\n ) external view returns (uint256);\n\n function currentReclaimableOverflowOf(\n uint256 projectId,\n uint256 tokenCount,\n uint256 totalSupply,\n uint256 overflow\n ) external view returns (uint256);\n\n function recordPaymentFrom(\n address payer,\n JBTokenAmount memory amount,\n uint256 projectId,\n uint256 baseWeightCurrency,\n address beneficiary,\n string calldata inputMemo,\n bytes calldata metadata\n )\n external\n returns (\n JBFundingCycle memory fundingCycle,\n uint256 tokenCount,\n JBPayDelegateAllocation[] memory delegateAllocations,\n string memory outputMemo\n );\n\n function recordRedemptionFor(\n address holder,\n uint256 projectId,\n uint256 tokenCount,\n string calldata inputMemo,\n bytes calldata metadata\n )\n external\n returns (\n JBFundingCycle memory fundingCycle,\n uint256 reclaimAmount,\n JBRedemptionDelegateAllocation[] memory delegateAllocations,\n string memory outputMemo\n );\n\n function recordDistributionFor(\n uint256 projectId,\n uint256 amount,\n uint256 currency\n ) external returns (JBFundingCycle memory fundingCycle, uint256 distributedAmount);\n\n function recordUsedAllowanceOf(\n uint256 projectId,\n uint256 amount,\n uint256 currency\n ) external returns (JBFundingCycle memory fundingCycle, uint256 withdrawnAmount);\n\n function recordAddedBalanceFor(uint256 projectId, uint256 amount) external;\n\n function recordMigration(uint256 projectId) external returns (uint256 balance);\n}\n" + }, + "contracts/interfaces/IJBPrices.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBPriceFeed} from './IJBPriceFeed.sol';\n\ninterface IJBPrices {\n event AddFeed(uint256 indexed currency, uint256 indexed base, IJBPriceFeed feed);\n\n function feedFor(uint256 currency, uint256 base) external view returns (IJBPriceFeed);\n\n function priceFor(\n uint256 currency,\n uint256 base,\n uint256 decimals\n ) external view returns (uint256);\n\n function addFeedFor(uint256 currency, uint256 base, IJBPriceFeed priceFeed) external;\n}\n" + }, + "contracts/libraries/JBCurrencies.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nlibrary JBCurrencies {\n uint256 public constant ETH = 1;\n uint256 public constant USD = 2;\n}\n" + }, + "contracts/libraries/JBFixedPointNumber.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nlibrary JBFixedPointNumber {\n function adjustDecimals(\n uint256 _value,\n uint256 _decimals,\n uint256 _targetDecimals\n ) internal pure returns (uint256) {\n // If decimals need adjusting, multiply or divide the price by the decimal adjuster to get the normalized result.\n if (_targetDecimals == _decimals) return _value;\n else if (_targetDecimals > _decimals) return _value * 10**(_targetDecimals - _decimals);\n else return _value / 10**(_decimals - _targetDecimals);\n }\n}\n" + }, + "contracts/structs/JBPayDelegateAllocation.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBPayDelegate} from '../interfaces/IJBPayDelegate.sol';\n\n/// @custom:member delegate A delegate contract to use for subsequent calls.\n/// @custom:member amount The amount to send to the delegate.\nstruct JBPayDelegateAllocation {\n IJBPayDelegate delegate;\n uint256 amount;\n}\n" + }, + "contracts/structs/JBPayParamsData.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\nimport {JBTokenAmount} from './JBTokenAmount.sol';\n\n/// @custom:member terminal The terminal that is facilitating the payment.\n/// @custom:member payer The address from which the payment originated.\n/// @custom:member amount The amount of the payment. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\n/// @custom:member projectId The ID of the project being paid.\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the payment is being made.\n/// @custom:member beneficiary The specified address that should be the beneficiary of anything that results from the payment.\n/// @custom:member weight The weight of the funding cycle during which the payment is being made.\n/// @custom:member reservedRate The reserved rate of the funding cycle during which the payment is being made.\n/// @custom:member memo The memo that was sent alongside the payment.\n/// @custom:member metadata Extra data provided by the payer.\nstruct JBPayParamsData {\n IJBPaymentTerminal terminal;\n address payer;\n JBTokenAmount amount;\n uint256 projectId;\n uint256 currentFundingCycleConfiguration;\n address beneficiary;\n uint256 weight;\n uint256 reservedRate;\n string memo;\n bytes metadata;\n}\n" + }, + "contracts/structs/JBRedeemParamsData.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\nimport {JBTokenAmount} from './JBTokenAmount.sol';\n\n/// @custom:member terminal The terminal that is facilitating the redemption.\n/// @custom:member holder The holder of the tokens being redeemed.\n/// @custom:member projectId The ID of the project whos tokens are being redeemed.\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the redemption is being made.\n/// @custom:member tokenCount The proposed number of tokens being redeemed, as a fixed point number with 18 decimals.\n/// @custom:member totalSupply The total supply of tokens used in the calculation, as a fixed point number with 18 decimals.\n/// @custom:member overflow The amount of overflow used in the reclaim amount calculation.\n/// @custom:member reclaimAmount The amount that should be reclaimed by the redeemer using the protocol's standard bonding curve redemption formula. Includes the token being reclaimed, the reclaim value, the number of decimals included, and the currency of the reclaim amount.\n/// @custom:member useTotalOverflow If overflow across all of a project's terminals is being used when making redemptions.\n/// @custom:member redemptionRate The redemption rate of the funding cycle during which the redemption is being made.\n/// @custom:member memo The proposed memo that is being emitted alongside the redemption.\n/// @custom:member metadata Extra data provided by the redeemer.\nstruct JBRedeemParamsData {\n IJBPaymentTerminal terminal;\n address holder;\n uint256 projectId;\n uint256 currentFundingCycleConfiguration;\n uint256 tokenCount;\n uint256 totalSupply;\n uint256 overflow;\n JBTokenAmount reclaimAmount;\n bool useTotalOverflow;\n uint256 redemptionRate;\n string memo;\n bytes metadata;\n}\n" + }, + "contracts/structs/JBRedemptionDelegateAllocation.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBRedemptionDelegate} from '../interfaces/IJBRedemptionDelegate.sol';\n\n/// @custom:member delegate A delegate contract to use for subsequent calls.\n/// @custom:member amount The amount to send to the delegate.\nstruct JBRedemptionDelegateAllocation {\n IJBRedemptionDelegate delegate;\n uint256 amount;\n}\n" + }, + "contracts/structs/JBTokenAmount.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @custom:member token The token the payment was made in.\n/// @custom:member value The amount of tokens that was paid, as a fixed point number.\n/// @custom:member decimals The number of decimals included in the value fixed point number.\n/// @custom:member currency The expected currency of the value.\nstruct JBTokenAmount {\n address token;\n uint256 value;\n uint256 decimals;\n uint256 currency;\n}\n" + }, + "contracts/interfaces/IJBPayDelegate.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBDidPayData} from './../structs/JBDidPayData.sol';\n\n/// @title Pay delegate\n/// @notice Delegate called after JBTerminal.pay(..) logic completion (if passed by the funding cycle datasource)\ninterface IJBPayDelegate is IERC165 {\n /// @notice This function is called by JBPaymentTerminal.pay(..), after the execution of its logic\n /// @dev Critical business logic should be protected by an appropriate access control\n /// @param data the data passed by the terminal, as a JBDidPayData struct:\n function didPay(JBDidPayData calldata data) external payable;\n}\n" + }, + "contracts/structs/JBDidPayData.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBTokenAmount} from './JBTokenAmount.sol';\n\n/// @custom:member payer The address from which the payment originated.\n/// @custom:member projectId The ID of the project for which the payment was made.\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the payment is being made.\n/// @custom:member amount The amount of the payment. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\n/// @custom:member forwardedAmount The amount of the payment that is being sent to the delegate. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\n/// @custom:member projectTokenCount The number of project tokens minted for the beneficiary.\n/// @custom:member beneficiary The address to which the tokens were minted.\n/// @custom:member preferClaimedTokens A flag indicating whether the request prefered to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract.\n/// @custom:member memo The memo that is being emitted alongside the payment.\n/// @custom:member metadata Extra data to send to the delegate.\nstruct JBDidPayData {\n address payer;\n uint256 projectId;\n uint256 currentFundingCycleConfiguration;\n JBTokenAmount amount;\n JBTokenAmount forwardedAmount;\n uint256 projectTokenCount;\n address beneficiary;\n bool preferClaimedTokens;\n string memo;\n bytes metadata;\n}\n" + }, + "contracts/interfaces/IJBRedemptionDelegate.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBDidRedeemData} from './../structs/JBDidRedeemData.sol';\n\n/// @title Redemption delegate\n/// @notice Delegate called after JBTerminal.redeemTokensOf(..) logic completion (if passed by the funding cycle datasource)\ninterface IJBRedemptionDelegate is IERC165 {\n /// @notice This function is called by JBPaymentTerminal.redeemTokensOf(..), after the execution of its logic\n /// @dev Critical business logic should be protected by an appropriate access control\n /// @param data the data passed by the terminal, as a JBDidRedeemData struct:\n function didRedeem(JBDidRedeemData calldata data) external payable;\n}\n" + }, + "contracts/structs/JBDidRedeemData.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBTokenAmount} from './JBTokenAmount.sol';\n\n/// @custom:member holder The holder of the tokens being redeemed.\n/// @custom:member projectId The ID of the project with which the redeemed tokens are associated.\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the redemption is being made.\n/// @custom:member projectTokenCount The number of project tokens being redeemed.\n/// @custom:member reclaimedAmount The amount reclaimed from the treasury. Includes the token being reclaimed, the value, the number of decimals included, and the currency of the amount.\n/// @custom:member forwardedAmount The amount of the payment that is being sent to the delegate. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\n/// @custom:member beneficiary The address to which the reclaimed amount will be sent.\n/// @custom:member memo The memo that is being emitted alongside the redemption.\n/// @custom:member metadata Extra data to send to the delegate.\nstruct JBDidRedeemData {\n address holder;\n uint256 projectId;\n uint256 currentFundingCycleConfiguration;\n uint256 projectTokenCount;\n JBTokenAmount reclaimedAmount;\n JBTokenAmount forwardedAmount;\n address payable beneficiary;\n string memo;\n bytes metadata;\n}\n" + }, + "contracts/interfaces/IJBPriceFeed.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBPriceFeed {\n function currentPrice(uint256 targetDecimals) external view returns (uint256);\n}\n" + }, + "contracts/JBSingleTokenPaymentTerminalStore3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {ReentrancyGuard} from '@openzeppelin/contracts/security/ReentrancyGuard.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {JBBallotState} from './enums/JBBallotState.sol';\nimport {IJBController3_1} from './interfaces/IJBController3_1.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBFundingCycleDataSource3_1_1} from './interfaces/IJBFundingCycleDataSource3_1_1.sol';\nimport {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol';\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\nimport {IJBSingleTokenPaymentTerminal} from './interfaces/IJBSingleTokenPaymentTerminal.sol';\nimport {IJBSingleTokenPaymentTerminalStore3_1_1} from './interfaces/IJBSingleTokenPaymentTerminalStore3_1_1.sol';\nimport {JBConstants} from './libraries/JBConstants.sol';\nimport {JBCurrencies} from './libraries/JBCurrencies.sol';\nimport {JBFixedPointNumber} from './libraries/JBFixedPointNumber.sol';\nimport {JBFundingCycleMetadataResolver} from './libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\nimport {JBPayDelegateAllocation3_1_1} from './structs/JBPayDelegateAllocation3_1_1.sol';\nimport {JBPayParamsData} from './structs/JBPayParamsData.sol';\nimport {JBRedeemParamsData} from './structs/JBRedeemParamsData.sol';\nimport {JBRedemptionDelegateAllocation3_1_1} from './structs/JBRedemptionDelegateAllocation3_1_1.sol';\nimport {JBTokenAmount} from './structs/JBTokenAmount.sol';\n\n/// @notice Manages all bookkeeping for inflows and outflows of funds from any ISingleTokenPaymentTerminal.\n/// @dev This Store expects a project's controller to be an IJBController3_1.\ncontract JBSingleTokenPaymentTerminalStore3_1_1 is\n ReentrancyGuard,\n IJBSingleTokenPaymentTerminalStore3_1_1\n{\n // A library that parses the packed funding cycle metadata into a friendlier format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error INVALID_AMOUNT_TO_SEND_DELEGATE();\n error CURRENCY_MISMATCH();\n error DISTRIBUTION_AMOUNT_LIMIT_REACHED();\n error FUNDING_CYCLE_PAYMENT_PAUSED();\n error FUNDING_CYCLE_DISTRIBUTION_PAUSED();\n error FUNDING_CYCLE_REDEEM_PAUSED();\n error INADEQUATE_CONTROLLER_ALLOWANCE();\n error INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n error INSUFFICIENT_TOKENS();\n error INVALID_FUNDING_CYCLE();\n error PAYMENT_TERMINAL_MIGRATION_NOT_ALLOWED();\n\n //*********************************************************************//\n // -------------------------- private constants ---------------------- //\n //*********************************************************************//\n\n /// @notice Ensures a maximum number of decimal points of persisted fidelity on mulDiv operations of fixed point numbers.\n uint256 private constant _MAX_FIXED_POINT_FIDELITY = 18;\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n /// @notice The contract storing all funding cycle configurations.\n IJBFundingCycleStore public immutable override fundingCycleStore;\n\n /// @notice The contract that exposes price feeds.\n IJBPrices public immutable override prices;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The amount of tokens that each project has for each terminal, in terms of the terminal's token.\n /// @dev The balance is represented as a fixed point number with the same amount of decimals as its relative terminal.\n /// @custom:param _terminal The terminal to which the balance applies.\n /// @custom:param _projectId The ID of the project to get the balance of.\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => uint256)) public override balanceOf;\n\n /// @notice The amount of funds that a project has distributed from its limit during the current funding cycle for each terminal, in terms of the distribution limit's currency.\n /// @dev Increases as projects use their preconfigured distribution limits.\n /// @dev The used distribution limit is represented as a fixed point number with the same amount of decimals as its relative terminal.\n /// @custom:param _terminal The terminal to which the used distribution limit applies.\n /// @custom:param _projectId The ID of the project to get the used distribution limit of.\n /// @custom:param _fundingCycleNumber The number of the funding cycle during which the distribution limit was used.\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => mapping(uint256 => uint256)))\n public\n override usedDistributionLimitOf;\n\n /// @notice The amount of funds that a project has used from its allowance during the current funding cycle configuration for each terminal, in terms of the overflow allowance's currency.\n /// @dev Increases as projects use their allowance.\n /// @dev The used allowance is represented as a fixed point number with the same amount of decimals as its relative terminal.\n /// @custom:param _terminal The terminal to which the overflow allowance applies.\n /// @custom:param _projectId The ID of the project to get the used overflow allowance of.\n /// @custom:param _configuration The configuration of the during which the allowance was used.\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => mapping(uint256 => uint256)))\n public\n override usedOverflowAllowanceOf;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Gets the current overflowed amount in a terminal for a specified project.\n /// @dev The current overflow is represented as a fixed point number with the same amount of decimals as the specified terminal.\n /// @param _terminal The terminal for which the overflow is being calculated.\n /// @param _projectId The ID of the project to get overflow for.\n /// @return The current amount of overflow that project has in the specified terminal.\n function currentOverflowOf(\n IJBSingleTokenPaymentTerminal _terminal,\n uint256 _projectId\n ) external view override returns (uint256) {\n // Return the overflow during the project's current funding cycle.\n return\n _overflowDuring(\n _terminal,\n _projectId,\n fundingCycleStore.currentOf(_projectId),\n _terminal.currency()\n );\n }\n\n /// @notice Gets the current overflowed amount for a specified project across all terminals.\n /// @param _projectId The ID of the project to get total overflow for.\n /// @param _decimals The number of decimals that the fixed point overflow should include.\n /// @param _currency The currency that the total overflow should be in terms of.\n /// @return The current total amount of overflow that project has across all terminals.\n function currentTotalOverflowOf(\n uint256 _projectId,\n uint256 _decimals,\n uint256 _currency\n ) external view override returns (uint256) {\n return _currentTotalOverflowOf(_projectId, _decimals, _currency);\n }\n\n /// @notice The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the total token supply and overflow in the ecosystem.\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\n /// @dev The current reclaimable overflow is returned in terms of the specified terminal's currency.\n /// @dev The reclaimable overflow is represented as a fixed point number with the same amount of decimals as the specified terminal.\n /// @param _terminal The terminal from which the reclaimable amount would come.\n /// @param _projectId The ID of the project to get the reclaimable overflow amount for.\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _useTotalOverflow A flag indicating whether the overflow used in the calculation should be summed from all of the project's terminals. If false, overflow should be limited to the amount in the specified `_terminal`.\n /// @return The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_terminal`.\n function currentReclaimableOverflowOf(\n IJBSingleTokenPaymentTerminal _terminal,\n uint256 _projectId,\n uint256 _tokenCount,\n bool _useTotalOverflow\n ) external view override returns (uint256) {\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Get the amount of current overflow.\n // Use the project's total overflow across all of its terminals if the flag species specifies so. Otherwise, use the overflow local to the specified terminal.\n uint256 _currentOverflow = _useTotalOverflow\n ? _currentTotalOverflowOf(_projectId, _terminal.decimals(), _terminal.currency())\n : _overflowDuring(_terminal, _projectId, _fundingCycle, _terminal.currency());\n\n // If there's no overflow, there's no reclaimable overflow.\n if (_currentOverflow == 0) return 0;\n\n // Get the number of outstanding tokens the project has.\n uint256 _totalSupply = IJBController3_1(directory.controllerOf(_projectId))\n .totalOutstandingTokensOf(_projectId);\n\n // Can't redeem more tokens that is in the supply.\n if (_tokenCount > _totalSupply) return 0;\n\n // Return the reclaimable overflow amount.\n return\n _reclaimableOverflowDuring(\n _projectId,\n _fundingCycle,\n _tokenCount,\n _totalSupply,\n _currentOverflow\n );\n }\n\n /// @notice The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the specified total token supply and overflow amounts.\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\n /// @param _projectId The ID of the project to get the reclaimable overflow amount for.\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _totalSupply The total number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _overflow The amount of overflow to make the calculation with, as a fixed point number.\n /// @return The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_overflow`.\n function currentReclaimableOverflowOf(\n uint256 _projectId,\n uint256 _tokenCount,\n uint256 _totalSupply,\n uint256 _overflow\n ) external view override returns (uint256) {\n // If there's no overflow, there's no reclaimable overflow.\n if (_overflow == 0) return 0;\n\n // Can't redeem more tokens that is in the supply.\n if (_tokenCount > _totalSupply) return 0;\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Return the reclaimable overflow amount.\n return\n _reclaimableOverflowDuring(_projectId, _fundingCycle, _tokenCount, _totalSupply, _overflow);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _fundingCycleStore A contract storing all funding cycle configurations.\n /// @param _prices A contract that exposes price feeds.\n constructor(IJBDirectory _directory, IJBFundingCycleStore _fundingCycleStore, IJBPrices _prices) {\n directory = _directory;\n fundingCycleStore = _fundingCycleStore;\n prices = _prices;\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Records newly contributed tokens to a project.\n /// @dev Mints the project's tokens according to values provided by a configured data source. If no data source is configured, mints tokens proportional to the amount of the contribution.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.sender's tokens.\n /// @param _payer The original address that sent the payment to the terminal.\n /// @param _amount The amount of tokens being paid. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\n /// @param _projectId The ID of the project being paid.\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _beneficiary The specified address that should be the beneficiary of anything that results from the payment.\n /// @param _memo A memo to pass along to the emitted event, and passed along to the funding cycle's data source.\n /// @param _metadata Bytes to send along to the data source, if one is provided.\n /// @return fundingCycle The project's funding cycle during which payment was made.\n /// @return tokenCount The number of project tokens that were minted, as a fixed point number with 18 decimals.\n /// @return delegateAllocations The amount to send to delegates instead of adding to the local balance.\n /// @return memo A memo that should be passed along to the emitted event.\n function recordPaymentFrom(\n address _payer,\n JBTokenAmount calldata _amount,\n uint256 _projectId,\n uint256 _baseWeightCurrency,\n address _beneficiary,\n string calldata _memo,\n bytes memory _metadata\n )\n external\n override\n nonReentrant\n returns (\n JBFundingCycle memory fundingCycle,\n uint256 tokenCount,\n JBPayDelegateAllocation3_1_1[] memory delegateAllocations,\n string memory memo\n )\n {\n // Get a reference to the current funding cycle for the project.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // The project must have a funding cycle configured.\n if (fundingCycle.number == 0) revert INVALID_FUNDING_CYCLE();\n\n // Must not be paused.\n if (fundingCycle.payPaused()) revert FUNDING_CYCLE_PAYMENT_PAUSED();\n\n // The weight according to which new token supply is to be minted, as a fixed point number with 18 decimals.\n uint256 _weight;\n\n // If the funding cycle has configured a data source, use it to derive a weight and memo.\n if (fundingCycle.useDataSourceForPay() && fundingCycle.dataSource() != address(0)) {\n // Create the params that'll be sent to the data source.\n JBPayParamsData memory _data = JBPayParamsData(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _payer,\n _amount,\n _projectId,\n fundingCycle.configuration,\n _beneficiary,\n fundingCycle.weight,\n fundingCycle.reservedRate(),\n _memo,\n _metadata\n );\n (_weight, memo, delegateAllocations) = IJBFundingCycleDataSource3_1_1(\n fundingCycle.dataSource()\n ).payParams(_data);\n }\n // Otherwise use the funding cycle's weight\n else {\n _weight = fundingCycle.weight;\n memo = _memo;\n }\n\n // Scoped section prevents stack too deep. `_balanceDiff` only used within scope.\n {\n // Keep a reference to the amount that should be added to the project's balance.\n uint256 _balanceDiff = _amount.value;\n\n // Validate all delegated amounts. This needs to be done before returning the delegate allocations to ensure valid delegated amounts.\n if (delegateAllocations.length != 0) {\n for (uint256 _i; _i < delegateAllocations.length; ) {\n // Get a reference to the amount to be delegated.\n uint256 _delegatedAmount = delegateAllocations[_i].amount;\n\n // Validate if non-zero.\n if (_delegatedAmount != 0) {\n // Can't delegate more than was paid.\n if (_delegatedAmount > _balanceDiff) revert INVALID_AMOUNT_TO_SEND_DELEGATE();\n\n // Decrement the total amount being added to the balance.\n _balanceDiff = _balanceDiff - _delegatedAmount;\n }\n\n unchecked {\n ++_i;\n }\n }\n }\n\n // If there's no amount being recorded, there's nothing left to do.\n if (_amount.value == 0) return (fundingCycle, 0, delegateAllocations, memo);\n\n // Add the correct balance difference to the token balance of the project.\n if (_balanceDiff != 0)\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] +\n _balanceDiff;\n }\n\n // If there's no weight, token count must be 0 so there's nothing left to do.\n if (_weight == 0) return (fundingCycle, 0, delegateAllocations, memo);\n\n // Get a reference to the number of decimals in the amount. (prevents stack too deep).\n uint256 _decimals = _amount.decimals;\n\n // If the terminal should base its weight on a different currency from the terminal's currency, determine the factor.\n // The weight is always a fixed point mumber with 18 decimals. To ensure this, the ratio should use the same number of decimals as the `_amount`.\n uint256 _weightRatio = _amount.currency == _baseWeightCurrency\n ? 10 ** _decimals\n : prices.priceFor(_amount.currency, _baseWeightCurrency, _decimals);\n\n // Find the number of tokens to mint, as a fixed point number with as many decimals as `weight` has.\n tokenCount = PRBMath.mulDiv(_amount.value, _weight, _weightRatio);\n }\n\n /// @notice Records newly redeemed tokens of a project.\n /// @dev Redeems the project's tokens according to values provided by a configured data source. If no data source is configured, redeems tokens along a redemption bonding curve that is a function of the number of tokens being burned.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.senders tokens.\n /// @param _holder The account that is having its tokens redeemed.\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\n /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the data source, if one is provided.\n /// @return fundingCycle The funding cycle during which the redemption was made.\n /// @return reclaimAmount The amount of terminal tokens reclaimed, as a fixed point number with 18 decimals.\n /// @return delegateAllocations The amount to send to delegates instead of sending to the beneficiary.\n /// @return memo A memo that should be passed along to the emitted event.\n function recordRedemptionFor(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n string memory _memo,\n bytes memory _metadata\n )\n external\n override\n nonReentrant\n returns (\n JBFundingCycle memory fundingCycle,\n uint256 reclaimAmount,\n JBRedemptionDelegateAllocation3_1_1[] memory delegateAllocations,\n string memory memo\n )\n {\n // Get a reference to the project's current funding cycle.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // The current funding cycle must not be paused.\n if (fundingCycle.redeemPaused()) revert FUNDING_CYCLE_REDEEM_PAUSED();\n\n // Scoped section prevents stack too deep. `_reclaimedTokenAmount`, `_currentOverflow`, and `_totalSupply` only used within scope.\n {\n // Get a reference to the reclaimed token amount struct, the current overflow, and the total token supply.\n JBTokenAmount memory _reclaimedTokenAmount;\n uint256 _currentOverflow;\n uint256 _totalSupply;\n\n // Another scoped section prevents stack too deep. `_token`, `_decimals`, and `_currency` only used within scope.\n {\n // Get a reference to the terminal's tokens.\n address _token = IJBSingleTokenPaymentTerminal(msg.sender).token();\n\n // Get a reference to the terminal's decimals.\n uint256 _decimals = IJBSingleTokenPaymentTerminal(msg.sender).decimals();\n\n // Get areference to the terminal's currency.\n uint256 _currency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\n\n // Get the amount of current overflow.\n // Use the local overflow if the funding cycle specifies that it should be used. Otherwise, use the project's total overflow across all of its terminals.\n _currentOverflow = fundingCycle.useTotalOverflowForRedemptions()\n ? _currentTotalOverflowOf(_projectId, _decimals, _currency)\n : _overflowDuring(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _projectId,\n fundingCycle,\n _currency\n );\n\n // Get the number of outstanding tokens the project has.\n _totalSupply = IJBController3_1(directory.controllerOf(_projectId))\n .totalOutstandingTokensOf(_projectId);\n\n // Can't redeem more tokens that is in the supply.\n if (_tokenCount > _totalSupply) revert INSUFFICIENT_TOKENS();\n\n if (_currentOverflow != 0)\n // Calculate reclaim amount using the current overflow amount.\n reclaimAmount = _reclaimableOverflowDuring(\n _projectId,\n fundingCycle,\n _tokenCount,\n _totalSupply,\n _currentOverflow\n );\n\n _reclaimedTokenAmount = JBTokenAmount(_token, reclaimAmount, _decimals, _currency);\n }\n\n // If the funding cycle has configured a data source, use it to derive a claim amount and memo.\n if (fundingCycle.useDataSourceForRedeem() && fundingCycle.dataSource() != address(0)) {\n // Yet another scoped section prevents stack too deep. `_state` only used within scope.\n {\n // Get a reference to the ballot state.\n JBBallotState _state = fundingCycleStore.currentBallotStateOf(_projectId);\n\n // Create the params that'll be sent to the data source.\n JBRedeemParamsData memory _data = JBRedeemParamsData(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _holder,\n _projectId,\n fundingCycle.configuration,\n _tokenCount,\n _totalSupply,\n _currentOverflow,\n _reclaimedTokenAmount,\n fundingCycle.useTotalOverflowForRedemptions(),\n _state == JBBallotState.Active\n ? fundingCycle.ballotRedemptionRate()\n : fundingCycle.redemptionRate(),\n _memo,\n _metadata\n );\n (reclaimAmount, memo, delegateAllocations) = IJBFundingCycleDataSource3_1_1(\n fundingCycle.dataSource()\n ).redeemParams(_data);\n }\n } else {\n memo = _memo;\n }\n }\n\n // Keep a reference to the amount that should be subtracted from the project's balance.\n uint256 _balanceDiff = reclaimAmount;\n\n if (delegateAllocations.length != 0) {\n // Validate all delegated amounts.\n for (uint256 _i; _i < delegateAllocations.length; ) {\n // Get a reference to the amount to be delegated.\n uint256 _delegatedAmount = delegateAllocations[_i].amount;\n\n // Validate if non-zero.\n if (_delegatedAmount != 0)\n // Increment the total amount being subtracted from the balance.\n _balanceDiff = _balanceDiff + _delegatedAmount;\n\n unchecked {\n ++_i;\n }\n }\n }\n\n // The amount being reclaimed must be within the project's balance.\n if (_balanceDiff > balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId])\n revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n\n // Remove the reclaimed funds from the project's balance.\n if (_balanceDiff != 0) {\n unchecked {\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\n _balanceDiff;\n }\n }\n }\n\n /// @notice Records newly distributed funds for a project.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\n /// @param _projectId The ID of the project that is having funds distributed.\n /// @param _amount The amount to use from the distribution limit, as a fixed point number.\n /// @param _currency The currency of the `_amount`. This must match the project's current funding cycle's currency.\n /// @return fundingCycle The funding cycle during which the distribution was made.\n /// @return distributedAmount The amount of terminal tokens distributed, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordDistributionFor(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency\n )\n external\n override\n nonReentrant\n returns (JBFundingCycle memory fundingCycle, uint256 distributedAmount)\n {\n // Get a reference to the project's current funding cycle.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // The funding cycle must not be configured to have distributions paused.\n if (fundingCycle.distributionsPaused()) revert FUNDING_CYCLE_DISTRIBUTION_PAUSED();\n\n // The new total amount that has been distributed during this funding cycle.\n uint256 _newUsedDistributionLimitOf = usedDistributionLimitOf[\n IJBSingleTokenPaymentTerminal(msg.sender)\n ][_projectId][fundingCycle.number] + _amount;\n\n // Amount must be within what is still distributable.\n (uint256 _distributionLimitOf, uint256 _distributionLimitCurrencyOf) = IJBController3_1(\n directory.controllerOf(_projectId)\n ).fundAccessConstraintsStore().distributionLimitOf(\n _projectId,\n fundingCycle.configuration,\n IJBSingleTokenPaymentTerminal(msg.sender),\n IJBSingleTokenPaymentTerminal(msg.sender).token()\n );\n\n // Make sure the new used amount is within the distribution limit.\n if (_newUsedDistributionLimitOf > _distributionLimitOf || _distributionLimitOf == 0)\n revert DISTRIBUTION_AMOUNT_LIMIT_REACHED();\n\n // Make sure the currencies match.\n if (_currency != _distributionLimitCurrencyOf) revert CURRENCY_MISMATCH();\n\n // Get a reference to the terminal's currency.\n uint256 _balanceCurrency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\n\n // Convert the amount to the balance's currency.\n distributedAmount = (_currency == _balanceCurrency)\n ? _amount\n : PRBMath.mulDiv(\n _amount,\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\n prices.priceFor(_currency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\n );\n\n // The amount being distributed must be available.\n if (distributedAmount > balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId])\n revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n\n // Store the new amount.\n usedDistributionLimitOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId][\n fundingCycle.number\n ] = _newUsedDistributionLimitOf;\n\n // Removed the distributed funds from the project's token balance.\n unchecked {\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\n distributedAmount;\n }\n }\n\n /// @notice Records newly used allowance funds of a project.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\n /// @param _projectId The ID of the project to use the allowance of.\n /// @param _amount The amount to use from the allowance, as a fixed point number.\n /// @param _currency The currency of the `_amount`. Must match the currency of the overflow allowance.\n /// @return fundingCycle The funding cycle during which the overflow allowance is being used.\n /// @return usedAmount The amount of terminal tokens used, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordUsedAllowanceOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency\n )\n external\n override\n nonReentrant\n returns (JBFundingCycle memory fundingCycle, uint256 usedAmount)\n {\n // Get a reference to the project's current funding cycle.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Get a reference to the new used overflow allowance for this funding cycle configuration.\n uint256 _newUsedOverflowAllowanceOf = usedOverflowAllowanceOf[\n IJBSingleTokenPaymentTerminal(msg.sender)\n ][_projectId][fundingCycle.configuration] + _amount;\n\n // There must be sufficient allowance available.\n (uint256 _overflowAllowanceOf, uint256 _overflowAllowanceCurrency) = IJBController3_1(\n directory.controllerOf(_projectId)\n ).fundAccessConstraintsStore().overflowAllowanceOf(\n _projectId,\n fundingCycle.configuration,\n IJBSingleTokenPaymentTerminal(msg.sender),\n IJBSingleTokenPaymentTerminal(msg.sender).token()\n );\n\n // Make sure the new used amount is within the allowance.\n if (_newUsedOverflowAllowanceOf > _overflowAllowanceOf || _overflowAllowanceOf == 0)\n revert INADEQUATE_CONTROLLER_ALLOWANCE();\n\n // Make sure the currencies match.\n if (_currency != _overflowAllowanceCurrency) revert CURRENCY_MISMATCH();\n\n // Get a reference to the terminal's currency.\n uint256 _balanceCurrency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\n\n // Convert the amount to this store's terminal's token.\n usedAmount = (_currency == _balanceCurrency)\n ? _amount\n : PRBMath.mulDiv(\n _amount,\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\n prices.priceFor(_currency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\n );\n\n // The amount being distributed must be available in the overflow.\n if (\n usedAmount >\n _overflowDuring(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _projectId,\n fundingCycle,\n _balanceCurrency\n )\n ) revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n\n // Store the incremented value.\n usedOverflowAllowanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId][\n fundingCycle.configuration\n ] = _newUsedOverflowAllowanceOf;\n\n // Update the project's balance.\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\n usedAmount;\n }\n\n /// @notice Records newly added funds for the project.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\n /// @param _projectId The ID of the project to which the funds being added belong.\n /// @param _amount The amount of terminal tokens added, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordAddedBalanceFor(uint256 _projectId, uint256 _amount) external override {\n // Increment the balance.\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] +\n _amount;\n }\n\n /// @notice Records the migration of funds from this store.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount returned is in terms of the msg.senders tokens.\n /// @param _projectId The ID of the project being migrated.\n /// @return balance The project's migrated balance, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordMigration(\n uint256 _projectId\n ) external override nonReentrant returns (uint256 balance) {\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Migration must be allowed.\n if (!_fundingCycle.terminalMigrationAllowed()) revert PAYMENT_TERMINAL_MIGRATION_NOT_ALLOWED();\n\n // Return the current balance.\n balance = balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId];\n\n // Set the balance to 0.\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] = 0;\n }\n\n //*********************************************************************//\n // --------------------- private helper functions -------------------- //\n //*********************************************************************//\n\n /// @notice The amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens when measured from the specified.\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\n /// @param _projectId The ID of the project to get the reclaimable overflow amount for.\n /// @param _fundingCycle The funding cycle during which reclaimable overflow is being calculated.\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _totalSupply The total supply of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _overflow The amount of overflow to make the calculation with.\n /// @return The amount of overflowed tokens that can be reclaimed.\n function _reclaimableOverflowDuring(\n uint256 _projectId,\n JBFundingCycle memory _fundingCycle,\n uint256 _tokenCount,\n uint256 _totalSupply,\n uint256 _overflow\n ) private view returns (uint256) {\n // If the amount being redeemed is the total supply, return the rest of the overflow.\n if (_tokenCount == _totalSupply) return _overflow;\n\n // Use the ballot redemption rate if the queued cycle is pending approval according to the previous funding cycle's ballot.\n uint256 _redemptionRate = fundingCycleStore.currentBallotStateOf(_projectId) ==\n JBBallotState.Active\n ? _fundingCycle.ballotRedemptionRate()\n : _fundingCycle.redemptionRate();\n\n // If the redemption rate is 0, nothing is claimable.\n if (_redemptionRate == 0) return 0;\n\n // Get a reference to the linear proportion.\n uint256 _base = PRBMath.mulDiv(_overflow, _tokenCount, _totalSupply);\n\n // These conditions are all part of the same curve. Edge conditions are separated because fewer operation are necessary.\n if (_redemptionRate == JBConstants.MAX_REDEMPTION_RATE) return _base;\n\n return\n PRBMath.mulDiv(\n _base,\n _redemptionRate +\n PRBMath.mulDiv(\n _tokenCount,\n JBConstants.MAX_REDEMPTION_RATE - _redemptionRate,\n _totalSupply\n ),\n JBConstants.MAX_REDEMPTION_RATE\n );\n }\n\n /// @notice Gets the amount that is overflowing when measured from the specified funding cycle.\n /// @dev This amount changes as the value of the balance changes in relation to the currency being used to measure the distribution limit.\n /// @param _terminal The terminal for which the overflow is being calculated.\n /// @param _projectId The ID of the project to get overflow for.\n /// @param _fundingCycle The ID of the funding cycle to base the overflow on.\n /// @param _balanceCurrency The currency that the stored balance is expected to be in terms of.\n /// @return overflow The overflow of funds, as a fixed point number with 18 decimals.\n function _overflowDuring(\n IJBSingleTokenPaymentTerminal _terminal,\n uint256 _projectId,\n JBFundingCycle memory _fundingCycle,\n uint256 _balanceCurrency\n ) private view returns (uint256) {\n // Get the current balance of the project.\n uint256 _balanceOf = balanceOf[_terminal][_projectId];\n\n // If there's no balance, there's no overflow.\n if (_balanceOf == 0) return 0;\n\n // Get a reference to the distribution limit during the funding cycle.\n (uint256 _distributionLimit, uint256 _distributionLimitCurrency) = IJBController3_1(\n directory.controllerOf(_projectId)\n ).fundAccessConstraintsStore().distributionLimitOf(\n _projectId,\n _fundingCycle.configuration,\n _terminal,\n _terminal.token()\n );\n\n // Get a reference to the amount still distributable during the funding cycle.\n uint256 _distributionLimitRemaining = _distributionLimit -\n usedDistributionLimitOf[_terminal][_projectId][_fundingCycle.number];\n\n // Convert the _distributionRemaining to be in terms of the provided currency.\n if (_distributionLimitRemaining != 0 && _distributionLimitCurrency != _balanceCurrency)\n _distributionLimitRemaining = PRBMath.mulDiv(\n _distributionLimitRemaining,\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\n prices.priceFor(_distributionLimitCurrency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\n );\n\n // Overflow is the balance of this project minus the amount that can still be distributed.\n unchecked {\n return\n _balanceOf > _distributionLimitRemaining ? _balanceOf - _distributionLimitRemaining : 0;\n }\n }\n\n /// @notice Gets the amount that is currently overflowing across all of a project's terminals.\n /// @dev This amount changes as the value of the balances changes in relation to the currency being used to measure the project's distribution limits.\n /// @param _projectId The ID of the project to get the total overflow for.\n /// @param _decimals The number of decimals that the fixed point overflow should include.\n /// @param _currency The currency that the overflow should be in terms of.\n /// @return overflow The total overflow of a project's funds.\n function _currentTotalOverflowOf(\n uint256 _projectId,\n uint256 _decimals,\n uint256 _currency\n ) private view returns (uint256) {\n // Get a reference to the project's terminals.\n IJBPaymentTerminal[] memory _terminals = directory.terminalsOf(_projectId);\n\n // Keep a reference to the ETH overflow across all terminals, as a fixed point number with 18 decimals.\n uint256 _ethOverflow;\n\n // Add the current ETH overflow for each terminal.\n for (uint256 _i; _i < _terminals.length; ) {\n _ethOverflow = _ethOverflow + _terminals[_i].currentEthOverflowOf(_projectId);\n unchecked {\n ++_i;\n }\n }\n\n // Convert the ETH overflow to the specified currency if needed, maintaining a fixed point number with 18 decimals.\n uint256 _totalOverflow18Decimal = _currency == JBCurrencies.ETH\n ? _ethOverflow\n : PRBMath.mulDiv(_ethOverflow, 10 ** 18, prices.priceFor(JBCurrencies.ETH, _currency, 18));\n\n // Adjust the decimals of the fixed point number if needed to match the target decimals.\n return\n (_decimals == 18)\n ? _totalOverflow18Decimal\n : JBFixedPointNumber.adjustDecimals(_totalOverflow18Decimal, 18, _decimals);\n }\n}\n" + }, + "contracts/interfaces/IJBFundingCycleDataSource3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBPayDelegateAllocation3_1_1} from './../structs/JBPayDelegateAllocation3_1_1.sol';\nimport {JBPayParamsData} from './../structs/JBPayParamsData.sol';\nimport {JBRedeemParamsData} from './../structs/JBRedeemParamsData.sol';\nimport {JBRedemptionDelegateAllocation3_1_1} from './../structs/JBRedemptionDelegateAllocation3_1_1.sol';\n\n/// @title Datasource\n/// @notice The datasource is called by JBPayoutRedemptionPaymentTerminals on pay and redemption, and provide an extra layer of logic to use a custom weight, a custom memo and/or a pay/redeem delegate\ninterface IJBFundingCycleDataSource3_1_1 is IERC165 {\n /// @notice The datasource implementation for JBPaymentTerminal.pay(..)\n /// @param data the data passed to the data source in terminal.pay(..), as a JBPayParamsData struct:\n /// @return weight the weight to use to override the funding cycle weight\n /// @return memo the memo to override the pay(..) memo\n /// @return delegateAllocations The amount to send to delegates instead of adding to the local balance.\n function payParams(\n JBPayParamsData calldata data\n )\n external\n returns (\n uint256 weight,\n string memory memo,\n JBPayDelegateAllocation3_1_1[] memory delegateAllocations\n );\n\n /// @notice The datasource implementation for JBPaymentTerminal.redeemTokensOf(..)\n /// @param data the data passed to the data source in terminal.redeemTokensOf(..), as a JBRedeemParamsData struct:\n /// @return reclaimAmount The amount to claim, overriding the terminal logic.\n /// @return memo The memo to override the redeemTokensOf(..) memo.\n /// @return delegateAllocations The amount to send to delegates instead of adding to the beneficiary.\n function redeemParams(\n JBRedeemParamsData calldata data\n )\n external\n returns (\n uint256 reclaimAmount,\n string memory memo,\n JBRedemptionDelegateAllocation3_1_1[] memory delegateAllocations\n );\n}\n" + }, + "contracts/interfaces/IJBSingleTokenPaymentTerminalStore3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\nimport {JBPayDelegateAllocation3_1_1} from './../structs/JBPayDelegateAllocation3_1_1.sol';\nimport {JBRedemptionDelegateAllocation3_1_1} from './../structs/JBRedemptionDelegateAllocation3_1_1.sol';\nimport {JBTokenAmount} from './../structs/JBTokenAmount.sol';\nimport {IJBDirectory} from './IJBDirectory.sol';\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\nimport {IJBPrices} from './IJBPrices.sol';\nimport {IJBSingleTokenPaymentTerminal} from './IJBSingleTokenPaymentTerminal.sol';\n\ninterface IJBSingleTokenPaymentTerminalStore3_1_1 {\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\n\n function directory() external view returns (IJBDirectory);\n\n function prices() external view returns (IJBPrices);\n\n function balanceOf(\n IJBSingleTokenPaymentTerminal terminal,\n uint256 projectId\n ) external view returns (uint256);\n\n function usedDistributionLimitOf(\n IJBSingleTokenPaymentTerminal terminal,\n uint256 projectId,\n uint256 fundingCycleNumber\n ) external view returns (uint256);\n\n function usedOverflowAllowanceOf(\n IJBSingleTokenPaymentTerminal terminal,\n uint256 projectId,\n uint256 fundingCycleConfiguration\n ) external view returns (uint256);\n\n function currentOverflowOf(\n IJBSingleTokenPaymentTerminal terminal,\n uint256 projectId\n ) external view returns (uint256);\n\n function currentTotalOverflowOf(\n uint256 projectId,\n uint256 decimals,\n uint256 currency\n ) external view returns (uint256);\n\n function currentReclaimableOverflowOf(\n IJBSingleTokenPaymentTerminal terminal,\n uint256 projectId,\n uint256 tokenCount,\n bool useTotalOverflow\n ) external view returns (uint256);\n\n function currentReclaimableOverflowOf(\n uint256 projectId,\n uint256 tokenCount,\n uint256 totalSupply,\n uint256 overflow\n ) external view returns (uint256);\n\n function recordPaymentFrom(\n address payer,\n JBTokenAmount memory amount,\n uint256 projectId,\n uint256 baseWeightCurrency,\n address beneficiary,\n string calldata inputMemo,\n bytes calldata metadata\n )\n external\n returns (\n JBFundingCycle memory fundingCycle,\n uint256 tokenCount,\n JBPayDelegateAllocation3_1_1[] memory delegateAllocations,\n string memory outputMemo\n );\n\n function recordRedemptionFor(\n address holder,\n uint256 projectId,\n uint256 tokenCount,\n string calldata inputMemo,\n bytes calldata metadata\n )\n external\n returns (\n JBFundingCycle memory fundingCycle,\n uint256 reclaimAmount,\n JBRedemptionDelegateAllocation3_1_1[] memory delegateAllocations,\n string memory outputMemo\n );\n\n function recordDistributionFor(\n uint256 projectId,\n uint256 amount,\n uint256 currency\n ) external returns (JBFundingCycle memory fundingCycle, uint256 distributedAmount);\n\n function recordUsedAllowanceOf(\n uint256 projectId,\n uint256 amount,\n uint256 currency\n ) external returns (JBFundingCycle memory fundingCycle, uint256 withdrawnAmount);\n\n function recordAddedBalanceFor(uint256 projectId, uint256 amount) external;\n\n function recordMigration(uint256 projectId) external returns (uint256 balance);\n}\n" + }, + "contracts/structs/JBPayDelegateAllocation3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBPayDelegate3_1_1} from '../interfaces/IJBPayDelegate3_1_1.sol';\n\n/// @custom:member delegate A delegate contract to use for subsequent calls.\n/// @custom:member amount The amount to send to the delegate.\n/// @custom:member metadata Metadata to pass the delegate.\nstruct JBPayDelegateAllocation3_1_1 {\n IJBPayDelegate3_1_1 delegate;\n uint256 amount;\n bytes metadata;\n}\n" + }, + "contracts/structs/JBRedemptionDelegateAllocation3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBRedemptionDelegate3_1_1} from '../interfaces/IJBRedemptionDelegate3_1_1.sol';\n\n/// @custom:member delegate A delegate contract to use for subsequent calls.\n/// @custom:member amount The amount to send to the delegate.\n/// @custom:member metadata Metadata to pass the delegate.\nstruct JBRedemptionDelegateAllocation3_1_1 {\n IJBRedemptionDelegate3_1_1 delegate;\n uint256 amount;\n bytes metadata;\n}\n" + }, + "contracts/interfaces/IJBPayDelegate3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBDidPayData3_1_1} from './../structs/JBDidPayData3_1_1.sol';\n\n/// @title Pay delegate\n/// @notice Delegate called after JBTerminal.pay(..) logic completion (if passed by the funding cycle datasource)\ninterface IJBPayDelegate3_1_1 is IERC165 {\n /// @notice This function is called by JBPaymentTerminal.pay(..), after the execution of its logic\n /// @dev Critical business logic should be protected by an appropriate access control\n /// @param data the data passed by the terminal, as a JBDidPayData3_1_1 struct:\n function didPay(JBDidPayData3_1_1 calldata data) external payable;\n}\n" + }, + "contracts/structs/JBDidPayData3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBTokenAmount} from './JBTokenAmount.sol';\n\n/// @custom:member payer The address from which the payment originated.\n/// @custom:member projectId The ID of the project for which the payment was made.\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the payment is being made.\n/// @custom:member amount The amount of the payment. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\n/// @custom:member forwardedAmount The amount of the payment that is being sent to the delegate. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\n/// @custom:member projectTokenCount The number of project tokens minted for the beneficiary.\n/// @custom:member beneficiary The address to which the tokens were minted.\n/// @custom:member preferClaimedTokens A flag indicating whether the request prefered to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract.\n/// @custom:member memo The memo that is being emitted alongside the payment.\n/// @custom:member dataSourceMetadata Extra data to send to the delegate sent by the data source.\n/// @custom:member payerMetadata Extra data to send to the delegate sent by the payer.\nstruct JBDidPayData3_1_1 {\n address payer;\n uint256 projectId;\n uint256 currentFundingCycleConfiguration;\n JBTokenAmount amount;\n JBTokenAmount forwardedAmount;\n uint256 projectTokenCount;\n address beneficiary;\n bool preferClaimedTokens;\n string memo;\n bytes dataSourceMetadata;\n bytes payerMetadata;\n}\n" + }, + "contracts/interfaces/IJBRedemptionDelegate3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBDidRedeemData3_1_1} from './../structs/JBDidRedeemData3_1_1.sol';\n\n/// @title Redemption delegate\n/// @notice Delegate called after JBTerminal.redeemTokensOf(..) logic completion (if passed by the funding cycle datasource)\ninterface IJBRedemptionDelegate3_1_1 is IERC165 {\n /// @notice This function is called by JBPaymentTerminal.redeemTokensOf(..), after the execution of its logic\n /// @dev Critical business logic should be protected by an appropriate access control\n /// @param data the data passed by the terminal, as a JBDidRedeemData struct:\n function didRedeem(JBDidRedeemData3_1_1 calldata data) external payable;\n}\n" + }, + "contracts/structs/JBDidRedeemData3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBTokenAmount} from './JBTokenAmount.sol';\n\n/// @custom:member holder The holder of the tokens being redeemed.\n/// @custom:member projectId The ID of the project with which the redeemed tokens are associated.\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the redemption is being made.\n/// @custom:member projectTokenCount The number of project tokens being redeemed.\n/// @custom:member reclaimedAmount The amount reclaimed from the treasury. Includes the token being reclaimed, the value, the number of decimals included, and the currency of the amount.\n/// @custom:member forwardedAmount The amount of the payment that is being sent to the delegate. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\n/// @custom:member beneficiary The address to which the reclaimed amount will be sent.\n/// @custom:member memo The memo that is being emitted alongside the redemption.\n/// @custom:member dataSourceMetadata Extra data to send to the delegate sent by the data source.\n/// @custom:member redeemerMetadata Extra data to send to the delegate sent by the redeemer.\nstruct JBDidRedeemData3_1_1 {\n address holder;\n uint256 projectId;\n uint256 currentFundingCycleConfiguration;\n uint256 projectTokenCount;\n JBTokenAmount reclaimedAmount;\n JBTokenAmount forwardedAmount;\n address payable beneficiary;\n string memo;\n bytes dataSourceMetadata;\n bytes redeemerMetadata;\n}\n" + }, + "contracts/JBSingleTokenPaymentTerminalStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {ReentrancyGuard} from '@openzeppelin/contracts/security/ReentrancyGuard.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {JBBallotState} from './enums/JBBallotState.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBController} from './interfaces/IJBController.sol';\nimport {IJBFundingCycleDataSource} from './interfaces/IJBFundingCycleDataSource.sol';\nimport {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol';\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\nimport {IJBSingleTokenPaymentTerminal} from './interfaces/IJBSingleTokenPaymentTerminal.sol';\nimport {IJBSingleTokenPaymentTerminalStore} from './interfaces/IJBSingleTokenPaymentTerminalStore.sol';\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\nimport {JBConstants} from './libraries/JBConstants.sol';\nimport {JBCurrencies} from './libraries/JBCurrencies.sol';\nimport {JBFixedPointNumber} from './libraries/JBFixedPointNumber.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\nimport {JBFundingCycleMetadataResolver} from './libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBPayDelegateAllocation} from './structs/JBPayDelegateAllocation.sol';\nimport {JBPayParamsData} from './structs/JBPayParamsData.sol';\nimport {JBRedeemParamsData} from './structs/JBRedeemParamsData.sol';\nimport {JBRedemptionDelegateAllocation} from './structs/JBRedemptionDelegateAllocation.sol';\nimport {JBTokenAmount} from './structs/JBTokenAmount.sol';\n\n/// @notice Manages all bookkeeping for inflows and outflows of funds from any ISingleTokenPaymentTerminal.\ncontract JBSingleTokenPaymentTerminalStore is ReentrancyGuard, IJBSingleTokenPaymentTerminalStore {\n // A library that parses the packed funding cycle metadata into a friendlier format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error INVALID_AMOUNT_TO_SEND_DELEGATE();\n error CURRENCY_MISMATCH();\n error DISTRIBUTION_AMOUNT_LIMIT_REACHED();\n error FUNDING_CYCLE_PAYMENT_PAUSED();\n error FUNDING_CYCLE_DISTRIBUTION_PAUSED();\n error FUNDING_CYCLE_REDEEM_PAUSED();\n error INADEQUATE_CONTROLLER_ALLOWANCE();\n error INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n error INSUFFICIENT_TOKENS();\n error INVALID_FUNDING_CYCLE();\n error PAYMENT_TERMINAL_MIGRATION_NOT_ALLOWED();\n\n //*********************************************************************//\n // -------------------------- private constants ---------------------- //\n //*********************************************************************//\n\n /// @notice Ensures a maximum number of decimal points of persisted fidelity on mulDiv operations of fixed point numbers.\n uint256 private constant _MAX_FIXED_POINT_FIDELITY = 18;\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n /// @notice The contract storing all funding cycle configurations.\n IJBFundingCycleStore public immutable override fundingCycleStore;\n\n /// @notice The contract that exposes price feeds.\n IJBPrices public immutable override prices;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The amount of tokens that each project has for each terminal, in terms of the terminal's token.\n /// @dev The used distribution limit is represented as a fixed point number with the same amount of decimals as its relative terminal.\n /// @custom:param _terminal The terminal to which the balance applies.\n /// @custom:param _projectId The ID of the project to get the balance of.\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => uint256)) public override balanceOf;\n\n /// @notice The amount of funds that a project has distributed from its limit during the current funding cycle for each terminal, in terms of the distribution limit's currency.\n /// @dev Increases as projects use their preconfigured distribution limits.\n /// @dev The used distribution limit is represented as a fixed point number with the same amount of decimals as its relative terminal.\n /// @custom:param _terminal The terminal to which the used distribution limit applies.\n /// @custom:param _projectId The ID of the project to get the used distribution limit of.\n /// @custom:param _fundingCycleNumber The number of the funding cycle during which the distribution limit was used.\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => mapping(uint256 => uint256)))\n public\n override usedDistributionLimitOf;\n\n /// @notice The amount of funds that a project has used from its allowance during the current funding cycle configuration for each terminal, in terms of the overflow allowance's currency.\n /// @dev Increases as projects use their allowance.\n /// @dev The used allowance is represented as a fixed point number with the same amount of decimals as its relative terminal.\n /// @custom:param _terminal The terminal to which the overflow allowance applies.\n /// @custom:param _projectId The ID of the project to get the used overflow allowance of.\n /// @custom:param _configuration The configuration of the during which the allowance was used.\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => mapping(uint256 => uint256)))\n public\n override usedOverflowAllowanceOf;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Gets the current overflowed amount in a terminal for a specified project.\n /// @dev The current overflow is represented as a fixed point number with the same amount of decimals as the specified terminal.\n /// @param _terminal The terminal for which the overflow is being calculated.\n /// @param _projectId The ID of the project to get overflow for.\n /// @return The current amount of overflow that project has in the specified terminal.\n function currentOverflowOf(\n IJBSingleTokenPaymentTerminal _terminal,\n uint256 _projectId\n ) external view override returns (uint256) {\n // Return the overflow during the project's current funding cycle.\n return\n _overflowDuring(\n _terminal,\n _projectId,\n fundingCycleStore.currentOf(_projectId),\n _terminal.currency()\n );\n }\n\n /// @notice Gets the current overflowed amount for a specified project across all terminals.\n /// @param _projectId The ID of the project to get total overflow for.\n /// @param _decimals The number of decimals that the fixed point overflow should include.\n /// @param _currency The currency that the total overflow should be in terms of.\n /// @return The current total amount of overflow that project has across all terminals.\n function currentTotalOverflowOf(\n uint256 _projectId,\n uint256 _decimals,\n uint256 _currency\n ) external view override returns (uint256) {\n return _currentTotalOverflowOf(_projectId, _decimals, _currency);\n }\n\n /// @notice The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the total token supply and overflow in the ecosystem.\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\n /// @dev The current reclaimable overflow is returned in terms of the specified terminal's currency.\n /// @dev The reclaimable overflow is represented as a fixed point number with the same amount of decimals as the specified terminal.\n /// @param _terminal The terminal from which the reclaimable amount would come.\n /// @param _projectId The ID of the project to get the reclaimable overflow amount for.\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _useTotalOverflow A flag indicating whether the overflow used in the calculation should be summed from all of the project's terminals. If false, overflow should be limited to the amount in the specified `_terminal`.\n /// @return The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_terminal`.\n function currentReclaimableOverflowOf(\n IJBSingleTokenPaymentTerminal _terminal,\n uint256 _projectId,\n uint256 _tokenCount,\n bool _useTotalOverflow\n ) external view override returns (uint256) {\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Get the amount of current overflow.\n // Use the project's total overflow across all of its terminals if the flag species specifies so. Otherwise, use the overflow local to the specified terminal.\n uint256 _currentOverflow = _useTotalOverflow\n ? _currentTotalOverflowOf(_projectId, _terminal.decimals(), _terminal.currency())\n : _overflowDuring(_terminal, _projectId, _fundingCycle, _terminal.currency());\n\n // If there's no overflow, there's no reclaimable overflow.\n if (_currentOverflow == 0) return 0;\n\n // Get the number of outstanding tokens the project has.\n uint256 _totalSupply = IJBController(directory.controllerOf(_projectId))\n .totalOutstandingTokensOf(_projectId, _fundingCycle.reservedRate());\n\n // Can't redeem more tokens that is in the supply.\n if (_tokenCount > _totalSupply) return 0;\n\n // Return the reclaimable overflow amount.\n return\n _reclaimableOverflowDuring(\n _projectId,\n _fundingCycle,\n _tokenCount,\n _totalSupply,\n _currentOverflow\n );\n }\n\n /// @notice The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the specified total token supply and overflow amounts.\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\n /// @param _projectId The ID of the project for which the reclaimable overflow applies.\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _totalSupply The total number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _overflow The amount of overflow to make the calculation with, as a fixed point number.\n /// @return The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_overflow`.\n function currentReclaimableOverflowOf(\n uint256 _projectId,\n uint256 _tokenCount,\n uint256 _totalSupply,\n uint256 _overflow\n ) external view override returns (uint256) {\n // If there's no overflow, there's no reclaimable overflow.\n if (_overflow == 0) return 0;\n\n // Can't redeem more tokens that is in the supply.\n if (_tokenCount > _totalSupply) return 0;\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Return the reclaimable overflow amount.\n return\n _reclaimableOverflowDuring(_projectId, _fundingCycle, _tokenCount, _totalSupply, _overflow);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _fundingCycleStore A contract storing all funding cycle configurations.\n /// @param _prices A contract that exposes price feeds.\n constructor(IJBDirectory _directory, IJBFundingCycleStore _fundingCycleStore, IJBPrices _prices) {\n directory = _directory;\n fundingCycleStore = _fundingCycleStore;\n prices = _prices;\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Records newly contributed tokens to a project.\n /// @dev Mints the project's tokens according to values provided by a configured data source. If no data source is configured, mints tokens proportional to the amount of the contribution.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.sender's tokens.\n /// @param _payer The original address that sent the payment to the terminal.\n /// @param _amount The amount of tokens being paid. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\n /// @param _projectId The ID of the project being paid.\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _beneficiary The specified address that should be the beneficiary of anything that results from the payment.\n /// @param _memo A memo to pass along to the emitted event, and passed along to the funding cycle's data source.\n /// @param _metadata Bytes to send along to the data source, if one is provided.\n /// @return fundingCycle The project's funding cycle during which payment was made.\n /// @return tokenCount The number of project tokens that were minted, as a fixed point number with 18 decimals.\n /// @return delegateAllocations The amount to send to delegates instead of adding to the local balance.\n /// @return memo A memo that should be passed along to the emitted event.\n function recordPaymentFrom(\n address _payer,\n JBTokenAmount calldata _amount,\n uint256 _projectId,\n uint256 _baseWeightCurrency,\n address _beneficiary,\n string calldata _memo,\n bytes memory _metadata\n )\n external\n override\n nonReentrant\n returns (\n JBFundingCycle memory fundingCycle,\n uint256 tokenCount,\n JBPayDelegateAllocation[] memory delegateAllocations,\n string memory memo\n )\n {\n // Get a reference to the current funding cycle for the project.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // The project must have a funding cycle configured.\n if (fundingCycle.number == 0) revert INVALID_FUNDING_CYCLE();\n\n // Must not be paused.\n if (fundingCycle.payPaused()) revert FUNDING_CYCLE_PAYMENT_PAUSED();\n\n // The weight according to which new token supply is to be minted, as a fixed point number with 18 decimals.\n uint256 _weight;\n\n // If the funding cycle has configured a data source, use it to derive a weight and memo.\n if (fundingCycle.useDataSourceForPay() && fundingCycle.dataSource() != address(0)) {\n // Create the params that'll be sent to the data source.\n JBPayParamsData memory _data = JBPayParamsData(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _payer,\n _amount,\n _projectId,\n fundingCycle.configuration,\n _beneficiary,\n fundingCycle.weight,\n fundingCycle.reservedRate(),\n _memo,\n _metadata\n );\n (_weight, memo, delegateAllocations) = IJBFundingCycleDataSource(fundingCycle.dataSource())\n .payParams(_data);\n }\n // Otherwise use the funding cycle's weight\n else {\n _weight = fundingCycle.weight;\n memo = _memo;\n }\n\n // Scoped section prevents stack too deep. `_balanceDiff` only used within scope.\n {\n // Keep a reference to the amount that should be added to the project's balance.\n uint256 _balanceDiff = _amount.value;\n\n // Validate all delegated amounts. This needs to be done before returning the delegate allocations to ensure valid delegated amounts.\n if (delegateAllocations.length != 0) {\n for (uint256 _i; _i < delegateAllocations.length; ) {\n // Get a reference to the amount to be delegated.\n uint256 _delegatedAmount = delegateAllocations[_i].amount;\n\n // Validate if non-zero.\n if (_delegatedAmount != 0) {\n // Can't delegate more than was paid.\n if (_delegatedAmount > _balanceDiff) revert INVALID_AMOUNT_TO_SEND_DELEGATE();\n\n // Decrement the total amount being added to the balance.\n _balanceDiff = _balanceDiff - _delegatedAmount;\n }\n\n unchecked {\n ++_i;\n }\n }\n }\n\n // If there's no amount being recorded, there's nothing left to do.\n if (_amount.value == 0) return (fundingCycle, 0, delegateAllocations, memo);\n\n // Add the correct balance difference to the token balance of the project.\n if (_balanceDiff != 0)\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] +\n _balanceDiff;\n }\n\n // If there's no weight, token count must be 0 so there's nothing left to do.\n if (_weight == 0) return (fundingCycle, 0, delegateAllocations, memo);\n\n // Get a reference to the number of decimals in the amount. (prevents stack too deep).\n uint256 _decimals = _amount.decimals;\n\n // If the terminal should base its weight on a different currency from the terminal's currency, determine the factor.\n // The weight is always a fixed point mumber with 18 decimals. To ensure this, the ratio should use the same number of decimals as the `_amount`.\n uint256 _weightRatio = _amount.currency == _baseWeightCurrency\n ? 10 ** _decimals\n : prices.priceFor(_amount.currency, _baseWeightCurrency, _decimals);\n\n // Find the number of tokens to mint, as a fixed point number with as many decimals as `weight` has.\n tokenCount = PRBMath.mulDiv(_amount.value, _weight, _weightRatio);\n }\n\n /// @notice Records newly redeemed tokens of a project.\n /// @dev Redeems the project's tokens according to values provided by a configured data source. If no data source is configured, redeems tokens along a redemption bonding curve that is a function of the number of tokens being burned.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.senders tokens.\n /// @param _holder The account that is having its tokens redeemed.\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\n /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the data source, if one is provided.\n /// @return fundingCycle The funding cycle during which the redemption was made.\n /// @return reclaimAmount The amount of terminal tokens reclaimed, as a fixed point number with 18 decimals.\n /// @return delegateAllocations The amount to send to delegates instead of sending to the beneficiary.\n /// @return memo A memo that should be passed along to the emitted event.\n function recordRedemptionFor(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n string memory _memo,\n bytes memory _metadata\n )\n external\n override\n nonReentrant\n returns (\n JBFundingCycle memory fundingCycle,\n uint256 reclaimAmount,\n JBRedemptionDelegateAllocation[] memory delegateAllocations,\n string memory memo\n )\n {\n // Get a reference to the project's current funding cycle.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // The current funding cycle must not be paused.\n if (fundingCycle.redeemPaused()) revert FUNDING_CYCLE_REDEEM_PAUSED();\n\n // Scoped section prevents stack too deep. `_reclaimedTokenAmount`, `_currentOverflow`, and `_totalSupply` only used within scope.\n {\n // Get a reference to the reclaimed token amount struct, the current overflow, and the total token supply.\n JBTokenAmount memory _reclaimedTokenAmount;\n uint256 _currentOverflow;\n uint256 _totalSupply;\n\n // Another scoped section prevents stack too deep. `_token`, `_decimals`, and `_currency` only used within scope.\n {\n // Get a reference to the terminal's tokens.\n address _token = IJBSingleTokenPaymentTerminal(msg.sender).token();\n\n // Get a reference to the terminal's decimals.\n uint256 _decimals = IJBSingleTokenPaymentTerminal(msg.sender).decimals();\n\n // Get areference to the terminal's currency.\n uint256 _currency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\n\n // Get the amount of current overflow.\n // Use the local overflow if the funding cycle specifies that it should be used. Otherwise, use the project's total overflow across all of its terminals.\n _currentOverflow = fundingCycle.useTotalOverflowForRedemptions()\n ? _currentTotalOverflowOf(_projectId, _decimals, _currency)\n : _overflowDuring(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _projectId,\n fundingCycle,\n _currency\n );\n\n // Get the number of outstanding tokens the project has.\n _totalSupply = IJBController(directory.controllerOf(_projectId)).totalOutstandingTokensOf(\n _projectId,\n fundingCycle.reservedRate()\n );\n\n // Can't redeem more tokens that is in the supply.\n if (_tokenCount > _totalSupply) revert INSUFFICIENT_TOKENS();\n\n if (_currentOverflow != 0)\n // Calculate reclaim amount using the current overflow amount.\n reclaimAmount = _reclaimableOverflowDuring(\n _projectId,\n fundingCycle,\n _tokenCount,\n _totalSupply,\n _currentOverflow\n );\n\n _reclaimedTokenAmount = JBTokenAmount(_token, reclaimAmount, _decimals, _currency);\n }\n\n // If the funding cycle has configured a data source, use it to derive a claim amount and memo.\n if (fundingCycle.useDataSourceForRedeem() && fundingCycle.dataSource() != address(0)) {\n // Yet another scoped section prevents stack too deep. `_state` only used within scope.\n {\n // Get a reference to the ballot state.\n JBBallotState _state = fundingCycleStore.currentBallotStateOf(_projectId);\n\n // Create the params that'll be sent to the data source.\n JBRedeemParamsData memory _data = JBRedeemParamsData(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _holder,\n _projectId,\n fundingCycle.configuration,\n _tokenCount,\n _totalSupply,\n _currentOverflow,\n _reclaimedTokenAmount,\n fundingCycle.useTotalOverflowForRedemptions(),\n _state == JBBallotState.Active\n ? fundingCycle.ballotRedemptionRate()\n : fundingCycle.redemptionRate(),\n _memo,\n _metadata\n );\n (reclaimAmount, memo, delegateAllocations) = IJBFundingCycleDataSource(\n fundingCycle.dataSource()\n ).redeemParams(_data);\n }\n } else {\n memo = _memo;\n }\n }\n\n // Keep a reference to the amount that should be subtracted from the project's balance.\n uint256 _balanceDiff = reclaimAmount;\n\n if (delegateAllocations.length != 0) {\n // Validate all delegated amounts.\n for (uint256 _i; _i < delegateAllocations.length; ) {\n // Get a reference to the amount to be delegated.\n uint256 _delegatedAmount = delegateAllocations[_i].amount;\n\n // Validate if non-zero.\n if (_delegatedAmount != 0)\n // Increment the total amount being subtracted from the balance.\n _balanceDiff = _balanceDiff + _delegatedAmount;\n\n unchecked {\n ++_i;\n }\n }\n }\n\n // The amount being reclaimed must be within the project's balance.\n if (_balanceDiff > balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId])\n revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n\n // Remove the reclaimed funds from the project's balance.\n if (_balanceDiff != 0) {\n unchecked {\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\n _balanceDiff;\n }\n }\n }\n\n /// @notice Records newly distributed funds for a project.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\n /// @param _projectId The ID of the project that is having funds distributed.\n /// @param _amount The amount to use from the distribution limit, as a fixed point number.\n /// @param _currency The currency of the `_amount`. This must match the project's current funding cycle's currency.\n /// @return fundingCycle The funding cycle during which the distribution was made.\n /// @return distributedAmount The amount of terminal tokens distributed, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordDistributionFor(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency\n )\n external\n override\n nonReentrant\n returns (JBFundingCycle memory fundingCycle, uint256 distributedAmount)\n {\n // Get a reference to the project's current funding cycle.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // The funding cycle must not be configured to have distributions paused.\n if (fundingCycle.distributionsPaused()) revert FUNDING_CYCLE_DISTRIBUTION_PAUSED();\n\n // The new total amount that has been distributed during this funding cycle.\n uint256 _newUsedDistributionLimitOf = usedDistributionLimitOf[\n IJBSingleTokenPaymentTerminal(msg.sender)\n ][_projectId][fundingCycle.number] + _amount;\n\n // Amount must be within what is still distributable.\n (uint256 _distributionLimitOf, uint256 _distributionLimitCurrencyOf) = IJBController(\n directory.controllerOf(_projectId)\n ).distributionLimitOf(\n _projectId,\n fundingCycle.configuration,\n IJBSingleTokenPaymentTerminal(msg.sender),\n IJBSingleTokenPaymentTerminal(msg.sender).token()\n );\n\n // Make sure the new used amount is within the distribution limit.\n if (_newUsedDistributionLimitOf > _distributionLimitOf || _distributionLimitOf == 0)\n revert DISTRIBUTION_AMOUNT_LIMIT_REACHED();\n\n // Make sure the currencies match.\n if (_currency != _distributionLimitCurrencyOf) revert CURRENCY_MISMATCH();\n\n // Get a reference to the terminal's currency.\n uint256 _balanceCurrency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\n\n // Convert the amount to the balance's currency.\n distributedAmount = (_currency == _balanceCurrency)\n ? _amount\n : PRBMath.mulDiv(\n _amount,\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\n prices.priceFor(_currency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\n );\n\n // The amount being distributed must be available.\n if (distributedAmount > balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId])\n revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n\n // Store the new amount.\n usedDistributionLimitOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId][\n fundingCycle.number\n ] = _newUsedDistributionLimitOf;\n\n // Removed the distributed funds from the project's token balance.\n unchecked {\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\n distributedAmount;\n }\n }\n\n /// @notice Records newly used allowance funds of a project.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\n /// @param _projectId The ID of the project to use the allowance of.\n /// @param _amount The amount to use from the allowance, as a fixed point number.\n /// @param _currency The currency of the `_amount`. Must match the currency of the overflow allowance.\n /// @return fundingCycle The funding cycle during which the overflow allowance is being used.\n /// @return usedAmount The amount of terminal tokens used, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordUsedAllowanceOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency\n )\n external\n override\n nonReentrant\n returns (JBFundingCycle memory fundingCycle, uint256 usedAmount)\n {\n // Get a reference to the project's current funding cycle.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Get a reference to the new used overflow allowance for this funding cycle configuration.\n uint256 _newUsedOverflowAllowanceOf = usedOverflowAllowanceOf[\n IJBSingleTokenPaymentTerminal(msg.sender)\n ][_projectId][fundingCycle.configuration] + _amount;\n\n // There must be sufficient allowance available.\n (uint256 _overflowAllowanceOf, uint256 _overflowAllowanceCurrency) = IJBController(\n directory.controllerOf(_projectId)\n ).overflowAllowanceOf(\n _projectId,\n fundingCycle.configuration,\n IJBSingleTokenPaymentTerminal(msg.sender),\n IJBSingleTokenPaymentTerminal(msg.sender).token()\n );\n\n // Make sure the new used amount is within the allowance.\n if (_newUsedOverflowAllowanceOf > _overflowAllowanceOf || _overflowAllowanceOf == 0)\n revert INADEQUATE_CONTROLLER_ALLOWANCE();\n\n // Make sure the currencies match.\n if (_currency != _overflowAllowanceCurrency) revert CURRENCY_MISMATCH();\n\n // Get a reference to the terminal's currency.\n uint256 _balanceCurrency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\n\n // Convert the amount to this store's terminal's token.\n usedAmount = (_currency == _balanceCurrency)\n ? _amount\n : PRBMath.mulDiv(\n _amount,\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\n prices.priceFor(_currency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\n );\n\n // The amount being distributed must be available in the overflow.\n if (\n usedAmount >\n _overflowDuring(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _projectId,\n fundingCycle,\n _balanceCurrency\n )\n ) revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n\n // Store the incremented value.\n usedOverflowAllowanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId][\n fundingCycle.configuration\n ] = _newUsedOverflowAllowanceOf;\n\n // Update the project's balance.\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\n usedAmount;\n }\n\n /// @notice Records newly added funds for the project.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\n /// @param _projectId The ID of the project to which the funds being added belong.\n /// @param _amount The amount of terminal tokens added, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordAddedBalanceFor(uint256 _projectId, uint256 _amount) external override {\n // Increment the balance.\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] +\n _amount;\n }\n\n /// @notice Records the migration of funds from this store.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount returned is in terms of the msg.senders tokens.\n /// @param _projectId The ID of the project being migrated.\n /// @return balance The project's migrated balance, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordMigration(\n uint256 _projectId\n ) external override nonReentrant returns (uint256 balance) {\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Migration must be allowed.\n if (!_fundingCycle.terminalMigrationAllowed()) revert PAYMENT_TERMINAL_MIGRATION_NOT_ALLOWED();\n\n // Return the current balance.\n balance = balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId];\n\n // Set the balance to 0.\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] = 0;\n }\n\n //*********************************************************************//\n // --------------------- private helper functions -------------------- //\n //*********************************************************************//\n\n /// @notice The amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens when measured from the specified.\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\n /// @param _projectId The ID of the project to get the reclaimable overflow amount for.\n /// @param _fundingCycle The funding cycle during which reclaimable overflow is being calculated.\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _totalSupply The total supply of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _overflow The amount of overflow to make the calculation with.\n /// @return The amount of overflowed tokens that can be reclaimed.\n function _reclaimableOverflowDuring(\n uint256 _projectId,\n JBFundingCycle memory _fundingCycle,\n uint256 _tokenCount,\n uint256 _totalSupply,\n uint256 _overflow\n ) private view returns (uint256) {\n // If the amount being redeemed is the total supply, return the rest of the overflow.\n if (_tokenCount == _totalSupply) return _overflow;\n\n // Use the ballot redemption rate if the queued cycle is pending approval according to the previous funding cycle's ballot.\n uint256 _redemptionRate = fundingCycleStore.currentBallotStateOf(_projectId) ==\n JBBallotState.Active\n ? _fundingCycle.ballotRedemptionRate()\n : _fundingCycle.redemptionRate();\n\n // If the redemption rate is 0, nothing is claimable.\n if (_redemptionRate == 0) return 0;\n\n // Get a reference to the linear proportion.\n uint256 _base = PRBMath.mulDiv(_overflow, _tokenCount, _totalSupply);\n\n // These conditions are all part of the same curve. Edge conditions are separated because fewer operation are necessary.\n if (_redemptionRate == JBConstants.MAX_REDEMPTION_RATE) return _base;\n\n return\n PRBMath.mulDiv(\n _base,\n _redemptionRate +\n PRBMath.mulDiv(\n _tokenCount,\n JBConstants.MAX_REDEMPTION_RATE - _redemptionRate,\n _totalSupply\n ),\n JBConstants.MAX_REDEMPTION_RATE\n );\n }\n\n /// @notice Gets the amount that is overflowing when measured from the specified funding cycle.\n /// @dev This amount changes as the value of the balance changes in relation to the currency being used to measure the distribution limit.\n /// @param _terminal The terminal for which the overflow is being calculated.\n /// @param _projectId The ID of the project to get overflow for.\n /// @param _fundingCycle The ID of the funding cycle to base the overflow on.\n /// @param _balanceCurrency The currency that the stored balance is expected to be in terms of.\n /// @return overflow The overflow of funds, as a fixed point number with 18 decimals.\n function _overflowDuring(\n IJBSingleTokenPaymentTerminal _terminal,\n uint256 _projectId,\n JBFundingCycle memory _fundingCycle,\n uint256 _balanceCurrency\n ) private view returns (uint256) {\n // Get the current balance of the project.\n uint256 _balanceOf = balanceOf[_terminal][_projectId];\n\n // If there's no balance, there's no overflow.\n if (_balanceOf == 0) return 0;\n\n // Get a reference to the distribution limit during the funding cycle.\n (uint256 _distributionLimit, uint256 _distributionLimitCurrency) = IJBController(\n directory.controllerOf(_projectId)\n ).distributionLimitOf(_projectId, _fundingCycle.configuration, _terminal, _terminal.token());\n\n // Get a reference to the amount still distributable during the funding cycle.\n uint256 _distributionLimitRemaining = _distributionLimit -\n usedDistributionLimitOf[_terminal][_projectId][_fundingCycle.number];\n\n // Convert the _distributionRemaining to be in terms of the provided currency.\n if (_distributionLimitRemaining != 0 && _distributionLimitCurrency != _balanceCurrency)\n _distributionLimitRemaining = PRBMath.mulDiv(\n _distributionLimitRemaining,\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\n prices.priceFor(_distributionLimitCurrency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\n );\n\n // Overflow is the balance of this project minus the amount that can still be distributed.\n unchecked {\n return\n _balanceOf > _distributionLimitRemaining ? _balanceOf - _distributionLimitRemaining : 0;\n }\n }\n\n /// @notice Gets the amount that is currently overflowing across all of a project's terminals.\n /// @dev This amount changes as the value of the balances changes in relation to the currency being used to measure the project's distribution limits.\n /// @param _projectId The ID of the project to get the total overflow for.\n /// @param _decimals The number of decimals that the fixed point overflow should include.\n /// @param _currency The currency that the overflow should be in terms of.\n /// @return overflow The total overflow of a project's funds.\n function _currentTotalOverflowOf(\n uint256 _projectId,\n uint256 _decimals,\n uint256 _currency\n ) private view returns (uint256) {\n // Get a reference to the project's terminals.\n IJBPaymentTerminal[] memory _terminals = directory.terminalsOf(_projectId);\n\n // Keep a reference to the ETH overflow across all terminals, as a fixed point number with 18 decimals.\n uint256 _ethOverflow;\n\n // Add the current ETH overflow for each terminal.\n for (uint256 _i; _i < _terminals.length; ) {\n _ethOverflow = _ethOverflow + _terminals[_i].currentEthOverflowOf(_projectId);\n unchecked {\n ++_i;\n }\n }\n\n // Convert the ETH overflow to the specified currency if needed, maintaining a fixed point number with 18 decimals.\n uint256 _totalOverflow18Decimal = _currency == JBCurrencies.ETH\n ? _ethOverflow\n : PRBMath.mulDiv(_ethOverflow, 10 ** 18, prices.priceFor(JBCurrencies.ETH, _currency, 18));\n\n // Adjust the decimals of the fixed point number if needed to match the target decimals.\n return\n (_decimals == 18)\n ? _totalOverflow18Decimal\n : JBFixedPointNumber.adjustDecimals(_totalOverflow18Decimal, 18, _decimals);\n }\n}\n" + }, + "contracts/JBMigrationOperator.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {IJBController} from './interfaces/IJBController.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBMigratable} from './interfaces/IJBMigratable.sol';\nimport {IJBPayoutRedemptionPaymentTerminal} from './interfaces/IJBPayoutRedemptionPaymentTerminal.sol';\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\n\n/// @notice Allows projects to migrate their controller & terminal to 3.1 version\ncontract JBMigrationOperator {\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error UNAUTHORIZED();\n\n //*********************************************************************//\n // --------------- public immutable stored properties ---------------- //\n //*********************************************************************//\n\n /// @notice directory instance which keeps a track of which controller is linked to which project.\n IJBDirectory public immutable directory;\n\n /// @notice The NFT granting ownership to a Juicebox project\n IJBProjects public immutable projects;\n\n //*********************************************************************//\n // ---------------------------- constructor -------------------------- //\n //*********************************************************************//\n\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n constructor(IJBDirectory _directory) {\n directory = _directory;\n projects = IJBProjects(_directory.projects());\n }\n\n //*********************************************************************//\n // --------------------- external transactions ----------------------- //\n //*********************************************************************//\n\n /// @notice Allows project owners to migrate the controller & terminal linked to their project to the latest version.\n /// @param _projectId The project id whose controller & terminal are to be migrated\n /// @param _newController Controller 3.1 address to migrate to.\n /// @param _newJbTerminal Terminal 3.1 address to migrate to.\n /// @param _oldJbTerminal Old terminal address to migrate from.\n function migrate(\n uint256 _projectId,\n IJBMigratable _newController,\n IJBPaymentTerminal _newJbTerminal,\n IJBPayoutRedemptionPaymentTerminal _oldJbTerminal\n ) external {\n // Only allow the project owner to migrate\n if (projects.ownerOf(_projectId) != msg.sender) revert UNAUTHORIZED();\n\n // controller migration\n address _oldController = directory.controllerOf(_projectId);\n\n // assuming the project owner has reconfigured the funding cycle with allowControllerMigration\n IJBController(_oldController).migrate(_projectId, _newController);\n\n // terminal migration\n IJBPaymentTerminal[] memory _newTerminals = new IJBPaymentTerminal[](1);\n _newTerminals[0] = IJBPaymentTerminal(address(_newJbTerminal));\n\n // assuming the project owner has reconfigured the funding cycle with allowTerminalMigration & global.allowSetTerminals\n directory.setTerminalsOf(_projectId, _newTerminals);\n _oldJbTerminal.migrate(_projectId, _newJbTerminal);\n }\n}\n" + }, + "contracts/interfaces/IJBPayoutRedemptionPaymentTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBFee} from './../structs/JBFee.sol';\nimport {IJBAllowanceTerminal} from './IJBAllowanceTerminal.sol';\nimport {IJBDirectory} from './IJBDirectory.sol';\nimport {IJBPayDelegate} from './IJBPayDelegate.sol';\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\nimport {IJBPayoutTerminal} from './IJBPayoutTerminal.sol';\nimport {IJBPrices} from './IJBPrices.sol';\nimport {IJBProjects} from './IJBProjects.sol';\nimport {IJBRedemptionDelegate} from './IJBRedemptionDelegate.sol';\nimport {IJBRedemptionTerminal} from './IJBRedemptionTerminal.sol';\nimport {IJBSplitsStore} from './IJBSplitsStore.sol';\nimport {JBDidPayData} from './../structs/JBDidPayData.sol';\nimport {JBDidRedeemData} from './../structs/JBDidRedeemData.sol';\nimport {JBSplit} from './../structs/JBSplit.sol';\n\ninterface IJBPayoutRedemptionPaymentTerminal is\n IJBPaymentTerminal,\n IJBPayoutTerminal,\n IJBAllowanceTerminal,\n IJBRedemptionTerminal\n{\n event AddToBalance(\n uint256 indexed projectId,\n uint256 amount,\n uint256 refundedFees,\n string memo,\n bytes metadata,\n address caller\n );\n\n event Migrate(\n uint256 indexed projectId,\n IJBPaymentTerminal indexed to,\n uint256 amount,\n address caller\n );\n\n event DistributePayouts(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n address beneficiary,\n uint256 amount,\n uint256 distributedAmount,\n uint256 fee,\n uint256 beneficiaryDistributionAmount,\n string memo,\n address caller\n );\n\n event UseAllowance(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n address beneficiary,\n uint256 amount,\n uint256 distributedAmount,\n uint256 netDistributedamount,\n string memo,\n address caller\n );\n\n event HoldFee(\n uint256 indexed projectId,\n uint256 indexed amount,\n uint256 indexed fee,\n uint256 feeDiscount,\n address beneficiary,\n address caller\n );\n\n event ProcessFee(\n uint256 indexed projectId,\n uint256 indexed amount,\n bool indexed wasHeld,\n address beneficiary,\n address caller\n );\n\n event RefundHeldFees(\n uint256 indexed projectId,\n uint256 indexed amount,\n uint256 indexed refundedFees,\n uint256 leftoverAmount,\n address caller\n );\n\n event Pay(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n address payer,\n address beneficiary,\n uint256 amount,\n uint256 beneficiaryTokenCount,\n string memo,\n bytes metadata,\n address caller\n );\n\n event DelegateDidPay(\n IJBPayDelegate indexed delegate,\n JBDidPayData data,\n uint256 delegatedAmount,\n address caller\n );\n\n event RedeemTokens(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n address holder,\n address beneficiary,\n uint256 tokenCount,\n uint256 reclaimedAmount,\n string memo,\n bytes metadata,\n address caller\n );\n\n event DelegateDidRedeem(\n IJBRedemptionDelegate indexed delegate,\n JBDidRedeemData data,\n uint256 delegatedAmount,\n address caller\n );\n\n event DistributeToPayoutSplit(\n uint256 indexed projectId,\n uint256 indexed domain,\n uint256 indexed group,\n JBSplit split,\n uint256 amount,\n address caller\n );\n\n event SetFee(uint256 fee, address caller);\n\n event SetFeeGauge(address indexed feeGauge, address caller);\n\n event SetFeelessAddress(address indexed addrs, bool indexed flag, address caller);\n\n function projects() external view returns (IJBProjects);\n\n function splitsStore() external view returns (IJBSplitsStore);\n\n function directory() external view returns (IJBDirectory);\n\n function prices() external view returns (IJBPrices);\n\n function store() external view returns (address);\n\n function baseWeightCurrency() external view returns (uint256);\n\n function payoutSplitsGroup() external view returns (uint256);\n\n function heldFeesOf(uint256 projectId) external view returns (JBFee[] memory);\n\n function fee() external view returns (uint256);\n\n function feeGauge() external view returns (address);\n\n function isFeelessAddress(address account) external view returns (bool);\n\n function migrate(uint256 projectId, IJBPaymentTerminal _to) external returns (uint256 balance);\n\n function processFees(uint256 projectId) external;\n\n function setFee(uint256 fee) external;\n\n function setFeeGauge(address feeGauge) external;\n\n function setFeelessAddress(address account, bool flag) external;\n}\n" + }, + "contracts/structs/JBFee.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @custom:member amount The total amount the fee was taken from, as a fixed point number with the same number of decimals as the terminal in which this struct was created.\n/// @custom:member fee The percent of the fee, out of MAX_FEE.\n/// @custom:member feeDiscount The discount of the fee.\n/// @custom:member beneficiary The address that will receive the tokens that are minted as a result of the fee payment.\nstruct JBFee {\n uint256 amount;\n uint32 fee;\n uint32 feeDiscount;\n address beneficiary;\n}\n" + }, + "contracts/interfaces/IJBAllowanceTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBAllowanceTerminal {\n function useAllowanceOf(\n uint256 projectId,\n uint256 amount,\n uint256 currency,\n address token,\n uint256 minReturnedTokens,\n address payable beneficiary,\n string calldata memo\n ) external returns (uint256 netDistributedAmount);\n}\n" + }, + "contracts/interfaces/IJBPayoutTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBPayoutTerminal {\n function distributePayoutsOf(\n uint256 projectId,\n uint256 amount,\n uint256 currency,\n address token,\n uint256 minReturnedTokens,\n string calldata memo\n ) external returns (uint256 netLeftoverDistributionAmount);\n}\n" + }, + "contracts/interfaces/IJBRedemptionTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBRedemptionTerminal {\n function redeemTokensOf(\n address holder,\n uint256 projectId,\n uint256 tokenCount,\n address token,\n uint256 minReturnedTokens,\n address payable beneficiary,\n string calldata memo,\n bytes calldata metadata\n ) external returns (uint256 reclaimAmount);\n}\n" + }, + "contracts/JBETHPaymentTerminal3_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Address} from '@openzeppelin/contracts/utils/Address.sol';\nimport {JBPayoutRedemptionPaymentTerminal3_1} from './abstract/JBPayoutRedemptionPaymentTerminal3_1.sol';\nimport {JBSplitsGroups} from './libraries/JBSplitsGroups.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {JBCurrencies} from './libraries/JBCurrencies.sol';\nimport {JBTokens} from './libraries/JBTokens.sol';\n\n/// @notice Manages all inflows and outflows of ETH funds into the protocol ecosystem.\ncontract JBETHPaymentTerminal3_1 is JBPayoutRedemptionPaymentTerminal3_1 {\n //*********************************************************************//\n // -------------------------- internal views ------------------------- //\n //*********************************************************************//\n\n /// @notice Checks the balance of tokens in this contract.\n /// @return The contract's balance, as a fixed point number with the same amount of decimals as this terminal.\n function _balance() internal view override returns (uint256) {\n return address(this).balance;\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _prices A contract that exposes price feeds.\n /// @param _store A contract that stores the terminal's data.\n /// @param _owner The address that will own this contract.\n constructor(\n uint256 _baseWeightCurrency,\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBSplitsStore _splitsStore,\n IJBPrices _prices,\n address _store,\n address _owner\n )\n JBPayoutRedemptionPaymentTerminal3_1(\n JBTokens.ETH,\n 18, // 18 decimals.\n JBCurrencies.ETH,\n _baseWeightCurrency,\n JBSplitsGroups.ETH_PAYOUT,\n _operatorStore,\n _projects,\n _directory,\n _splitsStore,\n _prices,\n _store,\n _owner\n )\n // solhint-disable-next-line no-empty-blocks\n {\n\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Transfers tokens.\n /// @param _from The address from which the transfer should originate.\n /// @param _to The address to which the transfer should go.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _transferFrom(address _from, address payable _to, uint256 _amount) internal override {\n _from; // Prevents unused var compiler and natspec complaints.\n\n Address.sendValue(_to, _amount);\n }\n}\n" + }, + "contracts/abstract/JBPayoutRedemptionPaymentTerminal3_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {ERC165Checker} from '@openzeppelin/contracts/utils/introspection/ERC165Checker.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {IJBAllowanceTerminal3_1} from './../interfaces/IJBAllowanceTerminal3_1.sol';\nimport {IJBController} from './../interfaces/IJBController.sol';\nimport {IJBDirectory} from './../interfaces/IJBDirectory.sol';\nimport {IJBFeeGauge} from './../interfaces/IJBFeeGauge.sol';\nimport {IJBPayoutRedemptionPaymentTerminal3_1} from './../interfaces/IJBPayoutRedemptionPaymentTerminal3_1.sol';\nimport {IJBSplitAllocator} from './../interfaces/IJBSplitAllocator.sol';\nimport {IJBOperatable} from './../interfaces/IJBOperatable.sol';\nimport {IJBOperatorStore} from './../interfaces/IJBOperatorStore.sol';\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\nimport {IJBPayoutTerminal3_1} from './../interfaces/IJBPayoutTerminal3_1.sol';\nimport {IJBPrices} from './../interfaces/IJBPrices.sol';\nimport {IJBProjects} from './../interfaces/IJBProjects.sol';\nimport {IJBRedemptionTerminal} from './../interfaces/IJBRedemptionTerminal.sol';\nimport {IJBSingleTokenPaymentTerminalStore} from './../interfaces/IJBSingleTokenPaymentTerminalStore.sol';\nimport {IJBSplitsStore} from './../interfaces/IJBSplitsStore.sol';\nimport {JBConstants} from './../libraries/JBConstants.sol';\nimport {JBCurrencies} from './../libraries/JBCurrencies.sol';\nimport {JBFixedPointNumber} from './../libraries/JBFixedPointNumber.sol';\nimport {JBFundingCycleMetadataResolver} from './../libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBOperations} from './../libraries/JBOperations.sol';\nimport {JBTokens} from './../libraries/JBTokens.sol';\nimport {JBDidPayData} from './../structs/JBDidPayData.sol';\nimport {JBDidRedeemData} from './../structs/JBDidRedeemData.sol';\nimport {JBFee} from './../structs/JBFee.sol';\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\nimport {JBPayDelegateAllocation} from './../structs/JBPayDelegateAllocation.sol';\nimport {JBTokenAmount} from './../structs/JBTokenAmount.sol';\nimport {JBRedemptionDelegateAllocation} from './../structs/JBRedemptionDelegateAllocation.sol';\nimport {JBSplit} from './../structs/JBSplit.sol';\nimport {JBSplitAllocationData} from './../structs/JBSplitAllocationData.sol';\nimport {JBOperatable} from './JBOperatable.sol';\nimport {JBSingleTokenPaymentTerminal} from './JBSingleTokenPaymentTerminal.sol';\n\n/// @notice Generic terminal managing all inflows and outflows of funds into the protocol ecosystem.\nabstract contract JBPayoutRedemptionPaymentTerminal3_1 is\n JBSingleTokenPaymentTerminal,\n JBOperatable,\n Ownable,\n IJBPayoutRedemptionPaymentTerminal3_1\n{\n // A library that parses the packed funding cycle metadata into a friendlier format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error FEE_TOO_HIGH();\n error INADEQUATE_DISTRIBUTION_AMOUNT();\n error INADEQUATE_RECLAIM_AMOUNT();\n error INADEQUATE_TOKEN_COUNT();\n error NO_MSG_VALUE_ALLOWED();\n error PAY_TO_ZERO_ADDRESS();\n error PROJECT_TERMINAL_MISMATCH();\n error REDEEM_TO_ZERO_ADDRESS();\n error TERMINAL_IN_SPLIT_ZERO_ADDRESS();\n error TERMINAL_TOKENS_INCOMPATIBLE();\n\n //*********************************************************************//\n // ---------------------------- modifiers ---------------------------- //\n //*********************************************************************//\n\n /// @notice A modifier that verifies this terminal is a terminal of provided project ID.\n modifier isTerminalOf(uint256 _projectId) {\n if (!directory.isTerminalOf(_projectId, this)) revert PROJECT_TERMINAL_MISMATCH();\n _;\n }\n\n //*********************************************************************//\n // --------------------- internal stored constants ------------------- //\n //*********************************************************************//\n\n /// @notice Maximum fee that can be set for a funding cycle configuration.\n /// @dev Out of MAX_FEE (50_000_000 / 1_000_000_000).\n uint256 internal constant _FEE_CAP = 50_000_000;\n\n /// @notice The fee beneficiary project ID is 1, as it should be the first project launched during the deployment process.\n uint256 internal constant _FEE_BENEFICIARY_PROJECT_ID = 1;\n\n //*********************************************************************//\n // --------------------- internal stored properties ------------------ //\n //*********************************************************************//\n\n /// @notice Fees that are being held to be processed later.\n /// @custom:param _projectId The ID of the project for which fees are being held.\n mapping(uint256 => JBFee[]) internal _heldFeesOf;\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice Mints ERC-721's that represent project ownership and transfers.\n IJBProjects public immutable override projects;\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n /// @notice The contract that stores splits for each project.\n IJBSplitsStore public immutable override splitsStore;\n\n /// @notice The contract that exposes price feeds.\n IJBPrices public immutable override prices;\n\n /// @notice The contract that stores and manages the terminal's data.\n address public immutable override store;\n\n /// @notice The currency to base token issuance on.\n /// @dev If this differs from `currency`, there must be a price feed available to convert `currency` to `baseWeightCurrency`.\n uint256 public immutable override baseWeightCurrency;\n\n /// @notice The group that payout splits coming from this terminal are identified by.\n uint256 public immutable override payoutSplitsGroup;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The platform fee percent.\n /// @dev Out of MAX_FEE (25_000_000 / 1_000_000_000)\n uint256 public override fee = 25_000_000; // 2.5%\n\n /// @notice The data source that returns a discount to apply to a project's fee.\n address public override feeGauge;\n\n /// @notice Addresses that can be paid towards from this terminal without incurring a fee.\n /// @dev Only addresses that are considered to be contained within the ecosystem can be feeless. Funds sent outside the ecosystem may incur fees despite being stored as feeless.\n /// @custom:param _address The address that can be paid toward.\n mapping(address => bool) public override isFeelessAddress;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Gets the current overflowed amount in this terminal for a specified project, in terms of ETH.\n /// @dev The current overflow is represented as a fixed point number with 18 decimals.\n /// @param _projectId The ID of the project to get overflow for.\n /// @return The current amount of ETH overflow that project has in this terminal, as a fixed point number with 18 decimals.\n function currentEthOverflowOf(\n uint256 _projectId\n ) external view virtual override returns (uint256) {\n // Get this terminal's current overflow.\n uint256 _overflow = IJBSingleTokenPaymentTerminalStore(store).currentOverflowOf(\n this,\n _projectId\n );\n\n // Adjust the decimals of the fixed point number if needed to have 18 decimals.\n uint256 _adjustedOverflow = (decimals == 18)\n ? _overflow\n : JBFixedPointNumber.adjustDecimals(_overflow, decimals, 18);\n\n // Return the amount converted to ETH.\n return\n (currency == JBCurrencies.ETH)\n ? _adjustedOverflow\n : PRBMath.mulDiv(\n _adjustedOverflow,\n 10 ** decimals,\n prices.priceFor(currency, JBCurrencies.ETH, decimals)\n );\n }\n\n /// @notice The fees that are currently being held to be processed later for each project.\n /// @param _projectId The ID of the project for which fees are being held.\n /// @return An array of fees that are being held.\n function heldFeesOf(uint256 _projectId) external view override returns (JBFee[] memory) {\n return _heldFeesOf[_projectId];\n }\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if the provided interface ID is supported.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(JBSingleTokenPaymentTerminal, IERC165) returns (bool) {\n return\n _interfaceId == type(IJBPayoutRedemptionPaymentTerminal3_1).interfaceId ||\n _interfaceId == type(IJBPayoutTerminal3_1).interfaceId ||\n _interfaceId == type(IJBAllowanceTerminal3_1).interfaceId ||\n _interfaceId == type(IJBRedemptionTerminal).interfaceId ||\n _interfaceId == type(IJBOperatable).interfaceId ||\n super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // -------------------------- internal views ------------------------- //\n //*********************************************************************//\n\n /// @notice Checks the balance of tokens in this contract.\n /// @return The contract's balance.\n function _balance() internal view virtual returns (uint256);\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _decimals The number of decimals the token fixed point amounts are expected to have.\n /// @param _currency The currency that this terminal's token adheres to for price feeds.\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _payoutSplitsGroup The group that denotes payout splits from this terminal in the splits store.\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _prices A contract that exposes price feeds.\n /// @param _store A contract that stores the terminal's data.\n /// @param _owner The address that will own this contract.\n constructor(\n // payable constructor save the gas used to check msg.value==0\n address _token,\n uint256 _decimals,\n uint256 _currency,\n uint256 _baseWeightCurrency,\n uint256 _payoutSplitsGroup,\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBSplitsStore _splitsStore,\n IJBPrices _prices,\n address _store,\n address _owner\n )\n payable\n JBSingleTokenPaymentTerminal(_token, _decimals, _currency)\n JBOperatable(_operatorStore)\n {\n baseWeightCurrency = _baseWeightCurrency;\n payoutSplitsGroup = _payoutSplitsGroup;\n projects = _projects;\n directory = _directory;\n splitsStore = _splitsStore;\n prices = _prices;\n store = _store;\n\n transferOwnership(_owner);\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Contribute tokens to a project.\n /// @param _projectId The ID of the project being paid.\n /// @param _amount The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place.\n /// @param _token The token being paid. This terminal ignores this property since it only manages one token.\n /// @param _beneficiary The address to mint tokens for and pass along to the funding cycle's data source and delegate.\n /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\n /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals.\n function pay(\n uint256 _projectId,\n uint256 _amount,\n address _token,\n address _beneficiary,\n uint256 _minReturnedTokens,\n bool _preferClaimedTokens,\n string calldata _memo,\n bytes calldata _metadata\n ) external payable virtual override isTerminalOf(_projectId) returns (uint256) {\n _token; // Prevents unused var compiler and natspec complaints.\n\n // ETH shouldn't be sent if this terminal's token isn't ETH.\n if (token != JBTokens.ETH) {\n if (msg.value > 0) revert NO_MSG_VALUE_ALLOWED();\n\n // Get a reference to the balance before receiving tokens.\n uint256 _balanceBefore = _balance();\n\n // Transfer tokens to this terminal from the msg sender.\n _transferFrom(msg.sender, payable(address(this)), _amount);\n\n // The amount should reflect the change in balance.\n _amount = _balance() - _balanceBefore;\n }\n // If this terminal's token is ETH, override _amount with msg.value.\n else _amount = msg.value;\n\n return\n _pay(\n _amount,\n msg.sender,\n _projectId,\n _beneficiary,\n _minReturnedTokens,\n _preferClaimedTokens,\n _memo,\n _metadata\n );\n }\n\n /// @notice Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source.\n /// @dev Only a token holder or a designated operator can redeem its tokens.\n /// @param _holder The account to redeem tokens for.\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\n /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals.\n /// @param _token The token being reclaimed. This terminal ignores this property since it only manages one token.\n /// @param _minReturnedTokens The minimum amount of terminal tokens expected in return, as a fixed point number with the same amount of decimals as the terminal.\n /// @param _beneficiary The address to send the terminal tokens to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return reclaimAmount The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals.\n function redeemTokensOf(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n address _token,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo,\n bytes memory _metadata\n )\n external\n virtual\n override\n requirePermission(_holder, _projectId, JBOperations.REDEEM)\n returns (uint256 reclaimAmount)\n {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return\n _redeemTokensOf(\n _holder,\n _projectId,\n _tokenCount,\n _minReturnedTokens,\n _beneficiary,\n _memo,\n _metadata\n );\n }\n\n /// @notice Distributes payouts for a project with the distribution limit of its current funding cycle.\n /// @dev Payouts are sent to the preprogrammed splits. Any leftover is sent to the project's owner.\n /// @dev 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.\n /// @dev All funds distributed outside of this contract or any feeless terminals incure the protocol fee.\n /// @param _projectId The ID of the project having its payouts distributed.\n /// @param _amount The amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency.\n /// @param _token The token being distributed. This terminal ignores this property since it only manages one token.\n /// @param _minReturnedTokens 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.\n /// @param _metadata Bytes to send along to the emitted event, if provided.\n /// @return netLeftoverDistributionAmount The amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal.\n function distributePayoutsOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n address _token,\n uint256 _minReturnedTokens,\n bytes calldata _metadata\n ) external virtual override returns (uint256 netLeftoverDistributionAmount) {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return _distributePayoutsOf(_projectId, _amount, _currency, _minReturnedTokens, _metadata);\n }\n\n /// @notice Only a project's owner or a designated operator can use its allowance.\n /// @dev Incurs the protocol fee.\n /// @param _projectId The ID of the project to use the allowance of.\n /// @param _amount The amount of terminal tokens to use from this project's current allowance, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's overflow allowance currency.\n /// @param _token The token being distributed. This terminal ignores this property since it only manages one token.\n /// @param _minReturnedTokens The minimum number of tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with 18 decimals.\n /// @param _beneficiary The address to send the funds to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the emitted event, if provided.\n /// @return netDistributedAmount The amount of tokens that was distributed to the beneficiary, as a fixed point number with the same amount of decimals as the terminal.\n function useAllowanceOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n address _token,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo,\n bytes calldata _metadata\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.USE_ALLOWANCE)\n returns (uint256 netDistributedAmount)\n {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return\n _useAllowanceOf(\n _projectId,\n _amount,\n _currency,\n _minReturnedTokens,\n _beneficiary,\n _memo,\n _metadata\n );\n }\n\n /// @notice Allows a project owner to migrate its funds and operations to a new terminal that accepts the same token type.\n /// @dev Only a project's owner or a designated operator can migrate it.\n /// @param _projectId The ID of the project being migrated.\n /// @param _to The terminal contract that will gain the project's funds.\n /// @return balance The amount of funds that were migrated, as a fixed point number with the same amount of decimals as this terminal.\n function migrate(\n uint256 _projectId,\n IJBPaymentTerminal _to\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.MIGRATE_TERMINAL)\n returns (uint256 balance)\n {\n // The terminal being migrated to must accept the same token as this terminal.\n if (!_to.acceptsToken(token, _projectId)) revert TERMINAL_TOKENS_INCOMPATIBLE();\n\n // Record the migration in the store.\n balance = IJBSingleTokenPaymentTerminalStore(store).recordMigration(_projectId);\n\n // Transfer the balance if needed.\n if (balance > 0) {\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_to), balance);\n\n // If this terminal's token is ETH, send it in msg.value.\n uint256 _payableValue = token == JBTokens.ETH ? balance : 0;\n\n // Withdraw the balance to transfer to the new terminal;\n _to.addToBalanceOf{value: _payableValue}(_projectId, balance, token, '', bytes(''));\n }\n\n emit Migrate(_projectId, _to, balance, msg.sender);\n }\n\n /// @notice Receives funds belonging to the specified project.\n /// @param _projectId The ID of the project to which the funds received belong.\n /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\n /// @param _token The token being paid. This terminal ignores this property since it only manages one currency.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the emitted event.\n function addToBalanceOf(\n uint256 _projectId,\n uint256 _amount,\n address _token,\n string calldata _memo,\n bytes calldata _metadata\n ) external payable virtual override isTerminalOf(_projectId) {\n // Do not refund held fees by default.\n addToBalanceOf(_projectId, _amount, _token, false, _memo, _metadata);\n }\n\n /// @notice Process any fees that are being held for the project.\n /// @dev Only a project owner, an operator, or the contract's owner can process held fees.\n /// @param _projectId The ID of the project whos held fees should be processed.\n function processFees(\n uint256 _projectId\n )\n external\n virtual\n override\n requirePermissionAllowingOverride(\n projects.ownerOf(_projectId),\n _projectId,\n JBOperations.PROCESS_FEES,\n msg.sender == owner()\n )\n {\n // Get a reference to the project's held fees.\n JBFee[] memory _heldFees = _heldFeesOf[_projectId];\n\n // Delete the held fees.\n delete _heldFeesOf[_projectId];\n\n // Push array length in stack\n uint256 _heldFeeLength = _heldFees.length;\n\n // Process each fee.\n for (uint256 _i; _i < _heldFeeLength; ) {\n // Get the fee amount.\n uint256 _amount = _feeAmount(\n _heldFees[_i].amount,\n _heldFees[_i].fee,\n _heldFees[_i].feeDiscount\n );\n\n // Process the fee.\n _processFee(_amount, _heldFees[_i].beneficiary, _projectId);\n\n emit ProcessFee(_projectId, _amount, true, _heldFees[_i].beneficiary, msg.sender);\n\n unchecked {\n ++_i;\n }\n }\n }\n\n /// @notice Allows the fee to be updated.\n /// @dev Only the owner of this contract can change the fee.\n /// @param _fee The new fee, out of MAX_FEE.\n function setFee(uint256 _fee) external virtual override onlyOwner {\n // The provided fee must be within the max.\n if (_fee > _FEE_CAP) revert FEE_TOO_HIGH();\n\n // Store the new fee.\n fee = _fee;\n\n emit SetFee(_fee, msg.sender);\n }\n\n /// @notice Allows the fee gauge to be updated.\n /// @dev Only the owner of this contract can change the fee gauge.\n /// @param _feeGauge The new fee gauge.\n function setFeeGauge(address _feeGauge) external virtual override onlyOwner {\n // Store the new fee gauge.\n feeGauge = _feeGauge;\n\n emit SetFeeGauge(_feeGauge, msg.sender);\n }\n\n /// @notice Sets whether projects operating on this terminal can pay towards the specified address without incurring a fee.\n /// @param _address The address that can be paid towards while still bypassing fees.\n /// @param _flag A flag indicating whether the terminal should be feeless or not.\n function setFeelessAddress(address _address, bool _flag) external virtual override onlyOwner {\n // Set the flag value.\n isFeelessAddress[_address] = _flag;\n\n emit SetFeelessAddress(_address, _flag, msg.sender);\n }\n\n //*********************************************************************//\n // ----------------------- public transactions ----------------------- //\n //*********************************************************************//\n\n /// @notice Receives funds belonging to the specified project.\n /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\n /// @param _token The token being paid. This terminal ignores this property since it only manages one currency.\n /// @param _shouldRefundHeldFees A flag indicating if held fees should be refunded based on the amount being added.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the emitted event.\n function addToBalanceOf(\n uint256 _projectId,\n uint256 _amount,\n address _token,\n bool _shouldRefundHeldFees,\n string calldata _memo,\n bytes calldata _metadata\n ) public payable virtual override isTerminalOf(_projectId) {\n _token; // Prevents unused var compiler and natspec complaints.\n\n // If this terminal's token isn't ETH, make sure no msg.value was sent, then transfer the tokens in from msg.sender.\n if (token != JBTokens.ETH) {\n // Amount must be greater than 0.\n if (msg.value > 0) revert NO_MSG_VALUE_ALLOWED();\n\n // Get a reference to the balance before receiving tokens.\n uint256 _balanceBefore = _balance();\n\n // Transfer tokens to this terminal from the msg sender.\n _transferFrom(msg.sender, payable(address(this)), _amount);\n\n // The amount should reflect the change in balance.\n _amount = _balance() - _balanceBefore;\n }\n // If the terminal's token is ETH, override `_amount` with msg.value.\n else _amount = msg.value;\n\n // Add to balance.\n _addToBalanceOf(_projectId, _amount, _shouldRefundHeldFees, _memo, _metadata);\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Transfers tokens.\n /// @param _from The address from which the transfer should originate.\n /// @param _to The address to which the transfer should go.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _transferFrom(address _from, address payable _to, uint256 _amount) internal virtual {\n _from; // Prevents unused var compiler and natspec complaints.\n _to; // Prevents unused var compiler and natspec complaints.\n _amount; // Prevents unused var compiler and natspec complaints.\n }\n\n /// @notice Logic to be triggered before transferring tokens from this terminal.\n /// @param _to The address to which the transfer is going.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _beforeTransferTo(address _to, uint256 _amount) internal virtual {\n _to; // Prevents unused var compiler and natspec complaints.\n _amount; // Prevents unused var compiler and natspec complaints.\n }\n\n /// @notice Logic to be triggered if a transfer should be undone\n /// @param _to The address to which the transfer went.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _cancelTransferTo(address _to, uint256 _amount) internal virtual {\n _to; // Prevents unused var compiler and natspec complaints.\n _amount; // Prevents unused var compiler and natspec complaints.\n }\n\n /// @notice Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source.\n /// @dev Only a token holder or a designated operator can redeem its tokens.\n /// @param _holder The account to redeem tokens for.\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\n /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals.\n /// @param _minReturnedTokens The minimum amount of terminal tokens expected in return, as a fixed point number with the same amount of decimals as the terminal.\n /// @param _beneficiary The address to send the terminal tokens to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return reclaimAmount The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals.\n function _redeemTokensOf(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo,\n bytes memory _metadata\n ) internal returns (uint256 reclaimAmount) {\n // Can't send reclaimed funds to the zero address.\n if (_beneficiary == address(0)) revert REDEEM_TO_ZERO_ADDRESS();\n\n // Define variables that will be needed outside the scoped section below.\n // Keep a reference to the funding cycle during which the redemption is being made.\n JBFundingCycle memory _fundingCycle;\n\n // Scoped section prevents stack too deep. `_delegateAllocations` only used within scope.\n {\n JBRedemptionDelegateAllocation[] memory _delegateAllocations;\n\n // Record the redemption.\n (\n _fundingCycle,\n reclaimAmount,\n _delegateAllocations,\n _memo\n ) = IJBSingleTokenPaymentTerminalStore(store).recordRedemptionFor(\n _holder,\n _projectId,\n _tokenCount,\n _memo,\n _metadata\n );\n\n // The amount being reclaimed must be at least as much as was expected.\n if (reclaimAmount < _minReturnedTokens) revert INADEQUATE_RECLAIM_AMOUNT();\n\n // Burn the project tokens.\n if (_tokenCount > 0)\n IJBController(directory.controllerOf(_projectId)).burnTokensOf(\n _holder,\n _projectId,\n _tokenCount,\n '',\n false\n );\n\n // If delegate allocations were specified by the data source, fulfill them.\n if (_delegateAllocations.length != 0) {\n // Keep a reference to the token amount being forwarded to the delegate.\n JBTokenAmount memory _forwardedAmount = JBTokenAmount(token, 0, decimals, currency);\n\n JBDidRedeemData memory _data = JBDidRedeemData(\n _holder,\n _projectId,\n _fundingCycle.configuration,\n _tokenCount,\n JBTokenAmount(token, reclaimAmount, decimals, currency),\n _forwardedAmount,\n _beneficiary,\n _memo,\n _metadata\n );\n\n uint256 _numDelegates = _delegateAllocations.length;\n\n for (uint256 _i; _i < _numDelegates; ) {\n // Get a reference to the delegate being iterated on.\n JBRedemptionDelegateAllocation memory _delegateAllocation = _delegateAllocations[_i];\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_delegateAllocation.delegate), _delegateAllocation.amount);\n\n // Keep track of the msg.value to use in the delegate call\n uint256 _payableValue;\n\n // If this terminal's token is ETH, send it in msg.value.\n if (token == JBTokens.ETH) _payableValue = _delegateAllocation.amount;\n\n // Pass the correct token forwardedAmount to the delegate\n _data.forwardedAmount.value = _delegateAllocation.amount;\n\n _delegateAllocation.delegate.didRedeem{value: _payableValue}(_data);\n\n emit DelegateDidRedeem(\n _delegateAllocation.delegate,\n _data,\n _delegateAllocation.amount,\n msg.sender\n );\n unchecked {\n ++_i;\n }\n }\n }\n }\n\n // Send the reclaimed funds to the beneficiary.\n if (reclaimAmount > 0) _transferFrom(address(this), _beneficiary, reclaimAmount);\n\n emit RedeemTokens(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _holder,\n _beneficiary,\n _tokenCount,\n reclaimAmount,\n _memo,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Distributes payouts for a project with the distribution limit of its current funding cycle.\n /// @dev Payouts are sent to the preprogrammed splits. Any leftover is sent to the project's owner.\n /// @dev 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.\n /// @dev All funds distributed outside of this contract or any feeless terminals incure the protocol fee.\n /// @param _projectId The ID of the project having its payouts distributed.\n /// @param _amount The amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency.\n /// @param _minReturnedTokens 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.\n /// @param _metadata Bytes to send along to the emitted event, if provided.\n /// @return netLeftoverDistributionAmount The amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal.\n function _distributePayoutsOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n uint256 _minReturnedTokens,\n bytes calldata _metadata\n ) internal returns (uint256 netLeftoverDistributionAmount) {\n // Record the distribution.\n (\n JBFundingCycle memory _fundingCycle,\n uint256 _distributedAmount\n ) = IJBSingleTokenPaymentTerminalStore(store).recordDistributionFor(\n _projectId,\n _amount,\n _currency\n );\n\n // The amount being distributed must be at least as much as was expected.\n if (_distributedAmount < _minReturnedTokens) revert INADEQUATE_DISTRIBUTION_AMOUNT();\n\n // Get a reference to the project owner, which will receive tokens from paying the platform fee\n // and receive any extra distributable funds not allocated to payout splits.\n address payable _projectOwner = payable(projects.ownerOf(_projectId));\n\n // Define variables that will be needed outside the scoped section below.\n // Keep a reference to the fee amount that was paid.\n uint256 _fee;\n\n // Scoped section prevents stack too deep. `_feeDiscount`, `_feeEligibleDistributionAmount`, and `_leftoverDistributionAmount` only used within scope.\n {\n // Get the amount of discount that should be applied to any fees taken.\n // If the fee is zero, set the discount to 100% for convenience.\n uint256 _feeDiscount = fee == 0\n ? JBConstants.MAX_FEE_DISCOUNT\n : _currentFeeDiscount(_projectId);\n\n // The amount distributed that is eligible for incurring fees.\n uint256 _feeEligibleDistributionAmount;\n\n // The amount leftover after distributing to the splits.\n uint256 _leftoverDistributionAmount;\n\n // Payout to splits and get a reference to the leftover transfer amount after all splits have been paid.\n // Also get a reference to the amount that was distributed to splits from which fees should be taken.\n (_leftoverDistributionAmount, _feeEligibleDistributionAmount) = _distributeToPayoutSplitsOf(\n _projectId,\n _fundingCycle.configuration,\n payoutSplitsGroup,\n _distributedAmount,\n _feeDiscount\n );\n\n if (_feeDiscount != JBConstants.MAX_FEE_DISCOUNT) {\n // Leftover distribution amount is also eligible for a fee since the funds are going out of the ecosystem to _beneficiary.\n unchecked {\n _feeEligibleDistributionAmount += _leftoverDistributionAmount;\n }\n }\n\n // Take the fee.\n _fee = _feeEligibleDistributionAmount != 0\n ? _takeFeeFrom(\n _projectId,\n _fundingCycle,\n _feeEligibleDistributionAmount,\n _projectOwner,\n _feeDiscount\n )\n : 0;\n\n // Transfer any remaining balance to the project owner and update returned leftover accordingly.\n if (_leftoverDistributionAmount != 0) {\n // Subtract the fee from the net leftover amount.\n netLeftoverDistributionAmount =\n _leftoverDistributionAmount -\n _feeAmount(_leftoverDistributionAmount, fee, _feeDiscount);\n\n // Transfer the amount to the project owner.\n _transferFrom(address(this), _projectOwner, netLeftoverDistributionAmount);\n }\n }\n\n emit DistributePayouts(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _projectOwner,\n _amount,\n _distributedAmount,\n _fee,\n netLeftoverDistributionAmount,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Allows a project to send funds from its overflow up to the preconfigured allowance.\n /// @dev Only a project's owner or a designated operator can use its allowance.\n /// @dev Incurs the protocol fee.\n /// @param _projectId The ID of the project to use the allowance of.\n /// @param _amount The amount of terminal tokens to use from this project's current allowance, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's overflow allowance currency.\n /// @param _minReturnedTokens The minimum number of tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with 18 decimals.\n /// @param _beneficiary The address to send the funds to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the emitted event, if provided.\n /// @return netDistributedAmount The amount of tokens that was distributed to the beneficiary, as a fixed point number with the same amount of decimals as the terminal.\n function _useAllowanceOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo,\n bytes calldata _metadata\n ) internal returns (uint256 netDistributedAmount) {\n // Record the use of the allowance.\n (\n JBFundingCycle memory _fundingCycle,\n uint256 _distributedAmount\n ) = IJBSingleTokenPaymentTerminalStore(store).recordUsedAllowanceOf(\n _projectId,\n _amount,\n _currency\n );\n\n // The amount being withdrawn must be at least as much as was expected.\n if (_distributedAmount < _minReturnedTokens) revert INADEQUATE_DISTRIBUTION_AMOUNT();\n\n // Scoped section prevents stack too deep. `_fee`, `_projectOwner`, `_feeDiscount`, and `_netAmount` only used within scope.\n {\n // Keep a reference to the fee amount that was paid.\n uint256 _fee;\n\n // Get a reference to the project owner, which will receive tokens from paying the platform fee.\n address _projectOwner = projects.ownerOf(_projectId);\n\n // Get the amount of discount that should be applied to any fees taken.\n // 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.\n uint256 _feeDiscount = fee == 0 || isFeelessAddress[msg.sender]\n ? JBConstants.MAX_FEE_DISCOUNT\n : _currentFeeDiscount(_projectId);\n\n // Take a fee from the `_distributedAmount`, if needed.\n _fee = _feeDiscount == JBConstants.MAX_FEE_DISCOUNT\n ? 0\n : _takeFeeFrom(_projectId, _fundingCycle, _distributedAmount, _projectOwner, _feeDiscount);\n\n unchecked {\n // The net amount is the withdrawn amount without the fee.\n netDistributedAmount = _distributedAmount - _fee;\n }\n\n // Transfer any remaining balance to the beneficiary.\n if (netDistributedAmount > 0)\n _transferFrom(address(this), _beneficiary, netDistributedAmount);\n }\n\n emit UseAllowance(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _beneficiary,\n _amount,\n _distributedAmount,\n netDistributedAmount,\n _memo,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Pays out splits for a project's funding cycle configuration.\n /// @param _projectId The ID of the project for which payout splits are being distributed.\n /// @param _domain The domain of the splits to distribute the payout between.\n /// @param _group The group of the splits to distribute the payout between.\n /// @param _amount The total amount being distributed, as a fixed point number with the same number of decimals as this terminal.\n /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE.\n /// @return leftoverAmount If the leftover amount if the splits don't add up to 100%.\n /// @return feeEligibleDistributionAmount The total amount of distributions that are eligible to have fees taken from.\n function _distributeToPayoutSplitsOf(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group,\n uint256 _amount,\n uint256 _feeDiscount\n ) internal returns (uint256 leftoverAmount, uint256 feeEligibleDistributionAmount) {\n // Set the leftover amount to the initial amount.\n leftoverAmount = _amount;\n // The total percentage available to split\n uint256 leftoverPercentage = JBConstants.SPLITS_TOTAL_PERCENT;\n\n // Get a reference to the project's payout splits.\n JBSplit[] memory _splits = splitsStore.splitsOf(_projectId, _domain, _group);\n\n // Transfer between all splits.\n for (uint256 _i; _i < _splits.length; ) {\n // Get a reference to the split being iterated on.\n JBSplit memory _split = _splits[_i];\n\n // The amount to send towards the split.\n uint256 _payoutAmount = _split.percent == leftoverPercentage\n ? leftoverAmount\n : PRBMath.mulDiv(_amount, _split.percent, JBConstants.SPLITS_TOTAL_PERCENT);\n\n // Decrement the leftover percentage.\n leftoverPercentage -= _split.percent;\n\n // The payout amount substracting any applicable incurred fees.\n uint256 _netPayoutAmount = _distributeToPayoutSplit(\n _split,\n _projectId,\n _group,\n _payoutAmount,\n _feeDiscount\n );\n\n // If the split allocator is set as feeless, this distribution is not eligible for a fee.\n if (_netPayoutAmount != 0 && _netPayoutAmount != _payoutAmount)\n feeEligibleDistributionAmount += _payoutAmount;\n\n if (_payoutAmount > 0) {\n // Subtract from the amount to be sent to the beneficiary.\n unchecked {\n leftoverAmount = leftoverAmount - _payoutAmount;\n }\n }\n\n emit DistributeToPayoutSplit(\n _projectId,\n _domain,\n _group,\n _split,\n _payoutAmount,\n _netPayoutAmount,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n\n /// @notice Pays out a split for a project's funding cycle configuration.\n /// @param _split The split to distribute payouts to.\n /// @param _amount The total amount being distributed to the split, as a fixed point number with the same number of decimals as this terminal.\n /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE.\n /// @return netPayoutAmount The amount sent to the split after subtracting fees.\n function _distributeToPayoutSplit(\n JBSplit memory _split,\n uint256 _projectId,\n uint256 _group,\n uint256 _amount,\n uint256 _feeDiscount\n ) internal returns (uint256 netPayoutAmount) {\n // If there's an allocator set, transfer to its `allocate` function.\n if (_split.allocator != IJBSplitAllocator(address(0))) {\n // If the split allocator is set as feeless, this distribution is not eligible for a fee.\n if (\n _feeDiscount == JBConstants.MAX_FEE_DISCOUNT || isFeelessAddress[address(_split.allocator)]\n )\n netPayoutAmount = _amount;\n // This distribution is eligible for a fee since the funds are leaving this contract and the allocator isn't listed as feeless.\n else {\n unchecked {\n netPayoutAmount = _amount - _feeAmount(_amount, fee, _feeDiscount);\n }\n }\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_split.allocator), netPayoutAmount);\n\n // Create the data to send to the allocator.\n JBSplitAllocationData memory _data = JBSplitAllocationData(\n token,\n netPayoutAmount,\n decimals,\n _projectId,\n _group,\n _split\n );\n\n // Trigger the allocator's `allocate` function.\n uint256 _error;\n bytes memory _reason;\n\n if (\n ERC165Checker.supportsInterface(\n address(_split.allocator),\n type(IJBSplitAllocator).interfaceId\n )\n )\n // If this terminal's token is ETH, send it in msg.value.\n try\n _split.allocator.allocate{value: token == JBTokens.ETH ? netPayoutAmount : 0}(_data)\n {} catch (bytes memory reason) {\n _reason = reason;\n _error = 1;\n }\n else _error = 2;\n\n if (_error != 0) {\n // Trigger any inhereted post-transfer cancelation logic.\n _cancelTransferTo(address(_split.allocator), netPayoutAmount);\n\n // Set the net payout amount to 0 to signal the reversion.\n netPayoutAmount = 0;\n\n // Add undistributed amount back to project's balance.\n IJBSingleTokenPaymentTerminalStore(store).recordAddedBalanceFor(_projectId, _amount);\n\n emit PayoutReverted(\n _projectId,\n _split,\n _amount,\n _error == 1 ? _reason : abi.encode('IERC165 fail'),\n msg.sender\n );\n }\n\n // Otherwise, if a project is specified, make a payment to it.\n } else if (_split.projectId != 0) {\n // Get a reference to the Juicebox terminal being used.\n IJBPaymentTerminal _terminal = directory.primaryTerminalOf(_split.projectId, token);\n\n // The project must have a terminal to send funds to.\n if (_terminal == IJBPaymentTerminal(address(0))) revert TERMINAL_IN_SPLIT_ZERO_ADDRESS();\n\n // If the terminal is set as feeless, this distribution is not eligible for a fee.\n if (\n _terminal == this ||\n _feeDiscount == JBConstants.MAX_FEE_DISCOUNT ||\n isFeelessAddress[address(_terminal)]\n )\n netPayoutAmount = _amount;\n // This distribution is eligible for a fee since the funds are leaving this contract and the terminal isn't listed as feeless.\n else {\n unchecked {\n netPayoutAmount = _amount - _feeAmount(_amount, fee, _feeDiscount);\n }\n }\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_terminal), netPayoutAmount);\n\n // Send the projectId in the metadata.\n bytes memory _projectMetadata = new bytes(32);\n _projectMetadata = bytes(abi.encodePacked(_projectId));\n\n // Add to balance if prefered.\n if (_split.preferAddToBalance)\n try\n _terminal.addToBalanceOf{value: token == JBTokens.ETH ? netPayoutAmount : 0}(\n _split.projectId,\n netPayoutAmount,\n token,\n '',\n _projectMetadata\n )\n {} catch (bytes memory reason) {\n // Trigger any inhereted post-transfer cancelation logic.\n _cancelTransferTo(address(_terminal), netPayoutAmount);\n\n // Set the net payout amount to 0 to signal the reversion.\n netPayoutAmount = 0;\n\n // Add undistributed amount back to project's balance.\n IJBSingleTokenPaymentTerminalStore(store).recordAddedBalanceFor(_projectId, _amount);\n\n emit PayoutReverted(_projectId, _split, _amount, reason, msg.sender);\n }\n else\n try\n _terminal.pay{value: token == JBTokens.ETH ? netPayoutAmount : 0}(\n _split.projectId,\n netPayoutAmount,\n token,\n _split.beneficiary != address(0) ? _split.beneficiary : msg.sender,\n 0,\n _split.preferClaimed,\n '',\n _projectMetadata\n )\n {} catch (bytes memory reason) {\n // Trigger any inhereted post-transfer cancelation logic.\n _cancelTransferTo(address(_terminal), netPayoutAmount);\n\n // Set the net payout amount to 0 to signal the reversion.\n netPayoutAmount = 0;\n\n // Add undistributed amount back to project's balance.\n IJBSingleTokenPaymentTerminalStore(store).recordAddedBalanceFor(_projectId, _amount);\n\n emit PayoutReverted(_projectId, _split, _amount, reason, msg.sender);\n }\n } else {\n // Keep a reference to the beneficiary.\n address payable _beneficiary = _split.beneficiary != address(0)\n ? _split.beneficiary\n : payable(msg.sender);\n\n // If there's a full discount, this distribution is not eligible for a fee.\n // Don't enforce feeless address for the beneficiary since the funds are leaving the ecosystem.\n if (_feeDiscount == JBConstants.MAX_FEE_DISCOUNT)\n netPayoutAmount = _amount;\n // This distribution is eligible for a fee since the funds are leaving this contract and the beneficiary isn't listed as feeless.\n else {\n unchecked {\n netPayoutAmount = _amount - _feeAmount(_amount, fee, _feeDiscount);\n }\n }\n\n // If there's a beneficiary, send the funds directly to the beneficiary. Otherwise send to the msg.sender.\n _transferFrom(address(this), _beneficiary, netPayoutAmount);\n }\n }\n\n /// @notice Takes a fee into the platform's project, which has an id of _FEE_BENEFICIARY_PROJECT_ID.\n /// @param _projectId The ID of the project having fees taken from.\n /// @param _fundingCycle The funding cycle during which the fee is being taken.\n /// @param _amount The amount of the fee to take, as a floating point number with 18 decimals.\n /// @param _beneficiary The address to mint the platforms tokens for.\n /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE.\n /// @return feeAmount The amount of the fee taken.\n function _takeFeeFrom(\n uint256 _projectId,\n JBFundingCycle memory _fundingCycle,\n uint256 _amount,\n address _beneficiary,\n uint256 _feeDiscount\n ) internal returns (uint256 feeAmount) {\n feeAmount = _feeAmount(_amount, fee, _feeDiscount);\n\n if (_fundingCycle.shouldHoldFees()) {\n // Store the held fee.\n _heldFeesOf[_projectId].push(JBFee(_amount, uint32(fee), uint32(_feeDiscount), _beneficiary));\n\n emit HoldFee(_projectId, _amount, fee, _feeDiscount, _beneficiary, msg.sender);\n } else {\n // Process the fee.\n _processFee(feeAmount, _beneficiary, _projectId); // Take the fee.\n\n emit ProcessFee(_projectId, feeAmount, false, _beneficiary, msg.sender);\n }\n }\n\n /// @notice Process a fee of the specified amount.\n /// @param _amount The fee amount, as a floating point number with 18 decimals.\n /// @param _beneficiary The address to mint the platform's tokens for.\n /// @param _from The project ID the fee is being paid from.\n function _processFee(uint256 _amount, address _beneficiary, uint256 _from) internal {\n // Get the terminal for the protocol project.\n IJBPaymentTerminal _terminal = directory.primaryTerminalOf(_FEE_BENEFICIARY_PROJECT_ID, token);\n\n // If this terminal's token is ETH, send it in msg.value.\n uint256 _payableValue = token == JBTokens.ETH ? _amount : 0;\n\n // Send the projectId in the metadata.\n bytes memory _projectMetadata = new bytes(32);\n _projectMetadata = bytes(abi.encodePacked(_from));\n\n // Trigger any inherited pre-transfer logic if funds will be transferred.\n if (address(_terminal) != address(this)) _beforeTransferTo(address(_terminal), _amount);\n\n try\n // Send the fee.\n _terminal.pay{value: _payableValue}(\n _FEE_BENEFICIARY_PROJECT_ID,\n _amount,\n token,\n _beneficiary,\n 0,\n false,\n '',\n _projectMetadata\n )\n {} catch (bytes memory reason) {\n // Trigger any inhereted post-transfer cancelation logic if the pre-transfer logic was triggered.\n if (address(_terminal) != address(this)) _cancelTransferTo(address(_terminal), _amount);\n\n // Add fee amount back to project's balance.\n IJBSingleTokenPaymentTerminalStore(store).recordAddedBalanceFor(_from, _amount);\n\n emit FeeReverted(_from, _FEE_BENEFICIARY_PROJECT_ID, _amount, reason, msg.sender);\n }\n }\n\n /// @notice Contribute tokens to a project.\n /// @param _amount The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place.\n /// @param _payer The address making the payment.\n /// @param _projectId The ID of the project being paid.\n /// @param _beneficiary The address to mint tokens for and pass along to the funding cycle's data source and delegate.\n /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\n /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return beneficiaryTokenCount The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals.\n function _pay(\n uint256 _amount,\n address _payer,\n uint256 _projectId,\n address _beneficiary,\n uint256 _minReturnedTokens,\n bool _preferClaimedTokens,\n string memory _memo,\n bytes memory _metadata\n ) internal returns (uint256 beneficiaryTokenCount) {\n // Cant send tokens to the zero address.\n if (_beneficiary == address(0)) revert PAY_TO_ZERO_ADDRESS();\n\n // Define variables that will be needed outside the scoped section below.\n // Keep a reference to the funding cycle during which the payment is being made.\n JBFundingCycle memory _fundingCycle;\n\n // Scoped section prevents stack too deep. `_delegateAllocations` and `_tokenCount` only used within scope.\n {\n JBPayDelegateAllocation[] memory _delegateAllocations;\n uint256 _tokenCount;\n\n // Bundle the amount info into a JBTokenAmount struct.\n JBTokenAmount memory _bundledAmount = JBTokenAmount(token, _amount, decimals, currency);\n\n // Record the payment.\n (\n _fundingCycle,\n _tokenCount,\n _delegateAllocations,\n _memo\n ) = IJBSingleTokenPaymentTerminalStore(store).recordPaymentFrom(\n _payer,\n _bundledAmount,\n _projectId,\n baseWeightCurrency,\n _beneficiary,\n _memo,\n _metadata\n );\n\n // Mint the tokens if needed.\n if (_tokenCount > 0)\n // Set token count to be the number of tokens minted for the beneficiary instead of the total amount.\n beneficiaryTokenCount = IJBController(directory.controllerOf(_projectId)).mintTokensOf(\n _projectId,\n _tokenCount,\n _beneficiary,\n '',\n _preferClaimedTokens,\n true\n );\n\n // The token count for the beneficiary must be greater than or equal to the minimum expected.\n if (beneficiaryTokenCount < _minReturnedTokens) revert INADEQUATE_TOKEN_COUNT();\n\n // If delegate allocations were specified by the data source, fulfill them.\n if (_delegateAllocations.length != 0) {\n // Keep a reference to the token amount being forwarded to the delegate.\n JBTokenAmount memory _forwardedAmount = JBTokenAmount(token, _amount, decimals, currency);\n\n JBDidPayData memory _data = JBDidPayData(\n _payer,\n _projectId,\n _fundingCycle.configuration,\n _bundledAmount,\n _forwardedAmount,\n beneficiaryTokenCount,\n _beneficiary,\n _preferClaimedTokens,\n _memo,\n _metadata\n );\n\n // Get a reference to the number of delegates to allocate to.\n uint256 _numDelegates = _delegateAllocations.length;\n\n for (uint256 _i; _i < _numDelegates; ) {\n // Get a reference to the delegate being iterated on.\n JBPayDelegateAllocation memory _delegateAllocation = _delegateAllocations[_i];\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_delegateAllocation.delegate), _delegateAllocation.amount);\n\n // Keep track of the msg.value to use in the delegate call\n uint256 _payableValue;\n\n // If this terminal's token is ETH, send it in msg.value.\n if (token == JBTokens.ETH) _payableValue = _delegateAllocation.amount;\n\n // Pass the correct token forwardedAmount to the delegate\n _data.forwardedAmount.value = _delegateAllocation.amount;\n\n _delegateAllocation.delegate.didPay{value: _payableValue}(_data);\n\n emit DelegateDidPay(\n _delegateAllocation.delegate,\n _data,\n _delegateAllocation.amount,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n }\n\n emit Pay(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _payer,\n _beneficiary,\n _amount,\n beneficiaryTokenCount,\n _memo,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Receives funds belonging to the specified project.\n /// @param _projectId The ID of the project to which the funds received belong.\n /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\n /// @param _shouldRefundHeldFees A flag indicating if held fees should be refunded based on the amount being added.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the emitted event.\n function _addToBalanceOf(\n uint256 _projectId,\n uint256 _amount,\n bool _shouldRefundHeldFees,\n string memory _memo,\n bytes memory _metadata\n ) internal {\n // Refund any held fees to make sure the project doesn't pay double for funds going in and out of the protocol.\n uint256 _refundedFees = _shouldRefundHeldFees ? _refundHeldFees(_projectId, _amount) : 0;\n\n // Record the added funds with any refunded fees.\n IJBSingleTokenPaymentTerminalStore(store).recordAddedBalanceFor(\n _projectId,\n _amount + _refundedFees\n );\n\n emit AddToBalance(_projectId, _amount, _refundedFees, _memo, _metadata, msg.sender);\n }\n\n /// @notice Refund fees based on the specified amount.\n /// @param _projectId The project for which fees are being refunded.\n /// @param _amount The amount to base the refund on, as a fixed point number with the same amount of decimals as this terminal.\n /// @return refundedFees How much fees were refunded, as a fixed point number with the same number of decimals as this terminal\n function _refundHeldFees(\n uint256 _projectId,\n uint256 _amount\n ) internal returns (uint256 refundedFees) {\n // Get a reference to the project's held fees.\n JBFee[] memory _heldFees = _heldFeesOf[_projectId];\n\n // Delete the current held fees.\n delete _heldFeesOf[_projectId];\n\n // Get a reference to the leftover amount once all fees have been settled.\n uint256 leftoverAmount = _amount;\n\n // Push length in stack\n uint256 _heldFeesLength = _heldFees.length;\n\n // Process each fee.\n for (uint256 _i; _i < _heldFeesLength; ) {\n if (leftoverAmount == 0) _heldFeesOf[_projectId].push(_heldFees[_i]);\n else if (leftoverAmount >= _heldFees[_i].amount) {\n unchecked {\n leftoverAmount = leftoverAmount - _heldFees[_i].amount;\n refundedFees += _feeAmount(\n _heldFees[_i].amount,\n _heldFees[_i].fee,\n _heldFees[_i].feeDiscount\n );\n }\n } else {\n unchecked {\n _heldFeesOf[_projectId].push(\n JBFee(\n _heldFees[_i].amount - leftoverAmount,\n _heldFees[_i].fee,\n _heldFees[_i].feeDiscount,\n _heldFees[_i].beneficiary\n )\n );\n refundedFees += _feeAmount(leftoverAmount, _heldFees[_i].fee, _heldFees[_i].feeDiscount);\n }\n leftoverAmount = 0;\n }\n\n unchecked {\n ++_i;\n }\n }\n\n emit RefundHeldFees(_projectId, _amount, refundedFees, leftoverAmount, msg.sender);\n }\n\n /// @notice Returns the fee amount based on the provided amount for the specified project.\n /// @param _amount The amount that the fee is based on, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _fee The percentage of the fee, out of MAX_FEE.\n /// @param _feeDiscount The percentage discount that should be applied out of the max amount, out of MAX_FEE_DISCOUNT.\n /// @return The amount of the fee, as a fixed point number with the same amount of decimals as this terminal.\n function _feeAmount(\n uint256 _amount,\n uint256 _fee,\n uint256 _feeDiscount\n ) internal pure returns (uint256) {\n // Calculate the discounted fee.\n uint256 _discountedFee = _fee -\n PRBMath.mulDiv(_fee, _feeDiscount, JBConstants.MAX_FEE_DISCOUNT);\n\n // The amount of tokens from the `_amount` to pay as a fee.\n return\n _amount - PRBMath.mulDiv(_amount, JBConstants.MAX_FEE, _discountedFee + JBConstants.MAX_FEE);\n }\n\n /// @notice Get the fee discount from the fee gauge for the specified project.\n /// @param _projectId The ID of the project to get a fee discount for.\n /// @return feeDiscount The fee discount, which should be interpreted as a percentage out MAX_FEE_DISCOUNT.\n function _currentFeeDiscount(uint256 _projectId) internal view returns (uint256) {\n // Can't take a fee if the protocol project doesn't have a terminal that accepts the token.\n if (\n directory.primaryTerminalOf(_FEE_BENEFICIARY_PROJECT_ID, token) ==\n IJBPaymentTerminal(address(0))\n ) return JBConstants.MAX_FEE_DISCOUNT;\n\n // Get the fee discount.\n if (feeGauge != address(0))\n // If the guage reverts, keep the discount at 0.\n try IJBFeeGauge(feeGauge).currentDiscountFor(_projectId) returns (uint256 discount) {\n // If the fee discount is greater than the max, we ignore the return value\n if (discount <= JBConstants.MAX_FEE_DISCOUNT) return discount;\n } catch {\n return 0;\n }\n\n return 0;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165Checker.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC165.sol\";\n\n/**\n * @dev Library used to query support of an interface declared via {IERC165}.\n *\n * Note that these functions return the actual result of the query: they do not\n * `revert` if an interface is not supported. It is up to the caller to decide\n * what to do in these cases.\n */\nlibrary ERC165Checker {\n // As per the EIP-165 spec, no interface should ever match 0xffffffff\n bytes4 private constant _INTERFACE_ID_INVALID = 0xffffffff;\n\n /**\n * @dev Returns true if `account` supports the {IERC165} interface,\n */\n function supportsERC165(address account) internal view returns (bool) {\n // Any contract that implements ERC165 must explicitly indicate support of\n // InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid\n return\n _supportsERC165Interface(account, type(IERC165).interfaceId) &&\n !_supportsERC165Interface(account, _INTERFACE_ID_INVALID);\n }\n\n /**\n * @dev Returns true if `account` supports the interface defined by\n * `interfaceId`. Support for {IERC165} itself is queried automatically.\n *\n * See {IERC165-supportsInterface}.\n */\n function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) {\n // query support of both ERC165 as per the spec and support of _interfaceId\n return supportsERC165(account) && _supportsERC165Interface(account, interfaceId);\n }\n\n /**\n * @dev Returns a boolean array where each value corresponds to the\n * interfaces passed in and whether they're supported or not. This allows\n * you to batch check interfaces for a contract where your expectation\n * is that some interfaces may not be supported.\n *\n * See {IERC165-supportsInterface}.\n *\n * _Available since v3.4._\n */\n function getSupportedInterfaces(address account, bytes4[] memory interfaceIds)\n internal\n view\n returns (bool[] memory)\n {\n // an array of booleans corresponding to interfaceIds and whether they're supported or not\n bool[] memory interfaceIdsSupported = new bool[](interfaceIds.length);\n\n // query support of ERC165 itself\n if (supportsERC165(account)) {\n // query support of each interface in interfaceIds\n for (uint256 i = 0; i < interfaceIds.length; i++) {\n interfaceIdsSupported[i] = _supportsERC165Interface(account, interfaceIds[i]);\n }\n }\n\n return interfaceIdsSupported;\n }\n\n /**\n * @dev Returns true if `account` supports all the interfaces defined in\n * `interfaceIds`. Support for {IERC165} itself is queried automatically.\n *\n * Batch-querying can lead to gas savings by skipping repeated checks for\n * {IERC165} support.\n *\n * See {IERC165-supportsInterface}.\n */\n function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) {\n // query support of ERC165 itself\n if (!supportsERC165(account)) {\n return false;\n }\n\n // query support of each interface in _interfaceIds\n for (uint256 i = 0; i < interfaceIds.length; i++) {\n if (!_supportsERC165Interface(account, interfaceIds[i])) {\n return false;\n }\n }\n\n // all interfaces supported\n return true;\n }\n\n /**\n * @notice Query if a contract implements an interface, does not check ERC165 support\n * @param account The address of the contract to query for support of an interface\n * @param interfaceId The interface identifier, as specified in ERC-165\n * @return true if the contract at account indicates support of the interface with\n * identifier interfaceId, false otherwise\n * @dev Assumes that account contains a contract that supports ERC165, otherwise\n * the behavior of this method is undefined. This precondition can be checked\n * with {supportsERC165}.\n * Interface identification is specified in ERC-165.\n */\n function _supportsERC165Interface(address account, bytes4 interfaceId) private view returns (bool) {\n bytes memory encodedParams = abi.encodeWithSelector(IERC165.supportsInterface.selector, interfaceId);\n (bool success, bytes memory result) = account.staticcall{gas: 30000}(encodedParams);\n if (result.length < 32) return false;\n return success && abi.decode(result, (bool));\n }\n}\n" + }, + "contracts/interfaces/IJBAllowanceTerminal3_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBAllowanceTerminal3_1 {\n function useAllowanceOf(\n uint256 projectId,\n uint256 amount,\n uint256 currency,\n address token,\n uint256 minReturnedTokens,\n address payable beneficiary,\n string calldata memo,\n bytes calldata metadata\n ) external returns (uint256 netDistributedAmount);\n}\n" + }, + "contracts/interfaces/IJBFeeGauge.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBFeeGauge {\n function currentDiscountFor(uint256 projectId) external view returns (uint256);\n}\n" + }, + "contracts/interfaces/IJBPayoutRedemptionPaymentTerminal3_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBFee} from './../structs/JBFee.sol';\nimport {IJBAllowanceTerminal3_1} from './IJBAllowanceTerminal3_1.sol';\nimport {IJBDirectory} from './IJBDirectory.sol';\nimport {IJBFeeHoldingTerminal} from './IJBFeeHoldingTerminal.sol';\nimport {IJBPayDelegate} from './IJBPayDelegate.sol';\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\nimport {IJBPayoutTerminal3_1} from './IJBPayoutTerminal3_1.sol';\nimport {IJBPrices} from './IJBPrices.sol';\nimport {IJBProjects} from './IJBProjects.sol';\nimport {IJBRedemptionDelegate} from './IJBRedemptionDelegate.sol';\nimport {IJBRedemptionTerminal} from './IJBRedemptionTerminal.sol';\nimport {IJBSplitsStore} from './IJBSplitsStore.sol';\nimport {JBDidPayData} from './../structs/JBDidPayData.sol';\nimport {JBDidRedeemData} from './../structs/JBDidRedeemData.sol';\nimport {JBSplit} from './../structs/JBSplit.sol';\n\ninterface IJBPayoutRedemptionPaymentTerminal3_1 is\n IJBPaymentTerminal,\n IJBPayoutTerminal3_1,\n IJBAllowanceTerminal3_1,\n IJBRedemptionTerminal,\n IJBFeeHoldingTerminal\n{\n event AddToBalance(\n uint256 indexed projectId,\n uint256 amount,\n uint256 refundedFees,\n string memo,\n bytes metadata,\n address caller\n );\n\n event Migrate(\n uint256 indexed projectId,\n IJBPaymentTerminal indexed to,\n uint256 amount,\n address caller\n );\n\n event DistributePayouts(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n address beneficiary,\n uint256 amount,\n uint256 distributedAmount,\n uint256 fee,\n uint256 beneficiaryDistributionAmount,\n bytes metadata,\n address caller\n );\n\n event UseAllowance(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n address beneficiary,\n uint256 amount,\n uint256 distributedAmount,\n uint256 netDistributedamount,\n string memo,\n bytes metadata,\n address caller\n );\n\n event HoldFee(\n uint256 indexed projectId,\n uint256 indexed amount,\n uint256 indexed fee,\n uint256 feeDiscount,\n address beneficiary,\n address caller\n );\n\n event ProcessFee(\n uint256 indexed projectId,\n uint256 indexed amount,\n bool indexed wasHeld,\n address beneficiary,\n address caller\n );\n\n event RefundHeldFees(\n uint256 indexed projectId,\n uint256 indexed amount,\n uint256 indexed refundedFees,\n uint256 leftoverAmount,\n address caller\n );\n\n event Pay(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n address payer,\n address beneficiary,\n uint256 amount,\n uint256 beneficiaryTokenCount,\n string memo,\n bytes metadata,\n address caller\n );\n\n event DelegateDidPay(\n IJBPayDelegate indexed delegate,\n JBDidPayData data,\n uint256 delegatedAmount,\n address caller\n );\n\n event RedeemTokens(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n address holder,\n address beneficiary,\n uint256 tokenCount,\n uint256 reclaimedAmount,\n string memo,\n bytes metadata,\n address caller\n );\n\n event DelegateDidRedeem(\n IJBRedemptionDelegate indexed delegate,\n JBDidRedeemData data,\n uint256 delegatedAmount,\n address caller\n );\n\n event DistributeToPayoutSplit(\n uint256 indexed projectId,\n uint256 indexed domain,\n uint256 indexed group,\n JBSplit split,\n uint256 amount,\n uint256 netAmount,\n address caller\n );\n\n event SetFee(uint256 fee, address caller);\n\n event SetFeeGauge(address indexed feeGauge, address caller);\n\n event SetFeelessAddress(address indexed addrs, bool indexed flag, address caller);\n\n event PayoutReverted(\n uint256 indexed projectId,\n JBSplit split,\n uint256 amount,\n bytes reason,\n address caller\n );\n\n event FeeReverted(\n uint256 indexed projectId,\n uint256 indexed feeProjectId,\n uint256 amount,\n bytes reason,\n address caller\n );\n\n function projects() external view returns (IJBProjects);\n\n function splitsStore() external view returns (IJBSplitsStore);\n\n function directory() external view returns (IJBDirectory);\n\n function prices() external view returns (IJBPrices);\n\n function store() external view returns (address);\n\n function baseWeightCurrency() external view returns (uint256);\n\n function payoutSplitsGroup() external view returns (uint256);\n\n function heldFeesOf(uint256 projectId) external view returns (JBFee[] memory);\n\n function fee() external view returns (uint256);\n\n function feeGauge() external view returns (address);\n\n function isFeelessAddress(address account) external view returns (bool);\n\n function migrate(uint256 projectId, IJBPaymentTerminal to) external returns (uint256 balance);\n\n function processFees(uint256 projectId) external;\n\n function setFee(uint256 fee) external;\n\n function setFeeGauge(address feeGauge) external;\n\n function setFeelessAddress(address account, bool flag) external;\n}\n" + }, + "contracts/interfaces/IJBPayoutTerminal3_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBPayoutTerminal3_1 {\n function distributePayoutsOf(\n uint256 projectId,\n uint256 amount,\n uint256 currency,\n address token,\n uint256 minReturnedTokens,\n bytes calldata metadata\n ) external returns (uint256 netLeftoverDistributionAmount);\n}\n" + }, + "contracts/abstract/JBSingleTokenPaymentTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {ERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol';\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\nimport {IJBSingleTokenPaymentTerminal} from './../interfaces/IJBSingleTokenPaymentTerminal.sol';\n\n/// @notice Generic terminal managing all inflows of funds into the protocol ecosystem for one token.\nabstract contract JBSingleTokenPaymentTerminal is ERC165, IJBSingleTokenPaymentTerminal {\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice The token that this terminal accepts.\n address public immutable override token;\n\n /// @notice The number of decimals the token fixed point amounts are expected to have.\n uint256 public immutable override decimals;\n\n /// @notice The currency to use when resolving price feeds for this terminal.\n uint256 public immutable override currency;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice A flag indicating if this terminal accepts the specified token.\n /// @param _token The token to check if this terminal accepts or not.\n /// @param _projectId The project ID to check for token acceptance.\n /// @return The flag.\n function acceptsToken(address _token, uint256 _projectId) external view override returns (bool) {\n _projectId; // Prevents unused var compiler and natspec complaints.\n\n return _token == token;\n }\n\n /// @notice The decimals that should be used in fixed number accounting for the specified token.\n /// @param _token The token to check for the decimals of.\n /// @return The number of decimals for the token.\n function decimalsForToken(address _token) external view override returns (uint256) {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return decimals;\n }\n\n /// @notice The currency that should be used for the specified token.\n /// @param _token The token to check for the currency of.\n /// @return The currency index.\n function currencyForToken(address _token) external view override returns (uint256) {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return currency;\n }\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if the provided interface ID is supported.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(ERC165, IERC165) returns (bool) {\n return\n _interfaceId == type(IJBPaymentTerminal).interfaceId ||\n _interfaceId == type(IJBSingleTokenPaymentTerminal).interfaceId ||\n super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _token The token that this terminal manages.\n /// @param _decimals The number of decimals the token fixed point amounts are expected to have.\n /// @param _currency The currency that this terminal's token adheres to for price feeds.\n constructor(address _token, uint256 _decimals, uint256 _currency) {\n token = _token;\n decimals = _decimals;\n currency = _currency;\n }\n}\n" + }, + "contracts/interfaces/IJBFeeHoldingTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBFeeHoldingTerminal {\n function addToBalanceOf(\n uint256 projectId,\n uint256 amount,\n address token,\n bool shouldRefundHeldFees,\n string calldata memo,\n bytes calldata metadata\n ) external payable;\n}\n" + }, + "contracts/JBETHPaymentTerminal3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Address} from '@openzeppelin/contracts/utils/Address.sol';\nimport {JBPayoutRedemptionPaymentTerminal3_1_1} from './abstract/JBPayoutRedemptionPaymentTerminal3_1_1.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\nimport {JBCurrencies} from './libraries/JBCurrencies.sol';\nimport {JBSplitsGroups} from './libraries/JBSplitsGroups.sol';\nimport {JBTokens} from './libraries/JBTokens.sol';\n\n/// @notice Manages all inflows and outflows of ETH funds into the protocol ecosystem.\ncontract JBETHPaymentTerminal3_1_1 is JBPayoutRedemptionPaymentTerminal3_1_1 {\n //*********************************************************************//\n // -------------------------- internal views ------------------------- //\n //*********************************************************************//\n\n /// @notice Checks the balance of tokens in this contract.\n /// @return The contract's balance, as a fixed point number with the same amount of decimals as this terminal.\n function _balance() internal view override returns (uint256) {\n return address(this).balance;\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _prices A contract that exposes price feeds.\n /// @param _store A contract that stores the terminal's data.\n /// @param _owner The address that will own this contract.\n constructor(\n uint256 _baseWeightCurrency,\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBSplitsStore _splitsStore,\n IJBPrices _prices,\n address _store,\n address _owner\n )\n JBPayoutRedemptionPaymentTerminal3_1_1(\n JBTokens.ETH,\n 18, // 18 decimals.\n JBCurrencies.ETH,\n _baseWeightCurrency,\n JBSplitsGroups.ETH_PAYOUT,\n _operatorStore,\n _projects,\n _directory,\n _splitsStore,\n _prices,\n _store,\n _owner\n )\n // solhint-disable-next-line no-empty-blocks\n {\n\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Transfers tokens.\n /// @param _from The address from which the transfer should originate.\n /// @param _to The address to which the transfer should go.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _transferFrom(address _from, address payable _to, uint256 _amount) internal override {\n _from; // Prevents unused var compiler and natspec complaints.\n\n Address.sendValue(_to, _amount);\n }\n}\n" + }, + "contracts/abstract/JBPayoutRedemptionPaymentTerminal3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {ERC165Checker} from '@openzeppelin/contracts/utils/introspection/ERC165Checker.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {JBFeeType} from './../enums/JBFeeType.sol';\nimport {IJBAllowanceTerminal3_1} from './../interfaces/IJBAllowanceTerminal3_1.sol';\nimport {IJBController} from './../interfaces/IJBController.sol';\nimport {IJBDirectory} from './../interfaces/IJBDirectory.sol';\nimport {IJBPayoutRedemptionPaymentTerminal3_1} from './../interfaces/IJBPayoutRedemptionPaymentTerminal3_1.sol';\nimport {IJBPayoutRedemptionPaymentTerminal3_1_1} from './../interfaces/IJBPayoutRedemptionPaymentTerminal3_1_1.sol';\nimport {IJBSplitsStore} from './../interfaces/IJBSplitsStore.sol';\nimport {IJBFeeGauge3_1} from './../interfaces/IJBFeeGauge3_1.sol';\nimport {IJBOperatable} from './../interfaces/IJBOperatable.sol';\nimport {IJBOperatorStore} from './../interfaces/IJBOperatorStore.sol';\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\nimport {IJBPayoutTerminal3_1} from './../interfaces/IJBPayoutTerminal3_1.sol';\nimport {IJBPrices} from './../interfaces/IJBPrices.sol';\nimport {IJBProjects} from './../interfaces/IJBProjects.sol';\nimport {IJBRedemptionTerminal} from './../interfaces/IJBRedemptionTerminal.sol';\nimport {IJBSingleTokenPaymentTerminalStore3_1_1} from './../interfaces/IJBSingleTokenPaymentTerminalStore3_1_1.sol';\nimport {IJBSplitAllocator} from './../interfaces/IJBSplitAllocator.sol';\nimport {JBConstants} from './../libraries/JBConstants.sol';\nimport {JBCurrencies} from './../libraries/JBCurrencies.sol';\nimport {JBFixedPointNumber} from './../libraries/JBFixedPointNumber.sol';\nimport {JBFundingCycleMetadataResolver} from './../libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBOperations} from './../libraries/JBOperations.sol';\nimport {JBTokens} from './../libraries/JBTokens.sol';\nimport {JBDidRedeemData3_1_1} from './../structs/JBDidRedeemData3_1_1.sol';\nimport {JBDidPayData3_1_1} from './../structs/JBDidPayData3_1_1.sol';\nimport {JBFee} from './../structs/JBFee.sol';\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\nimport {JBPayDelegateAllocation3_1_1} from './../structs/JBPayDelegateAllocation3_1_1.sol';\nimport {JBRedemptionDelegateAllocation3_1_1} from './../structs/JBRedemptionDelegateAllocation3_1_1.sol';\nimport {JBSplit} from './../structs/JBSplit.sol';\nimport {JBSplitAllocationData} from './../structs/JBSplitAllocationData.sol';\nimport {JBTokenAmount} from './../structs/JBTokenAmount.sol';\nimport {JBOperatable} from './JBOperatable.sol';\nimport {JBSingleTokenPaymentTerminal} from './JBSingleTokenPaymentTerminal.sol';\n\n/// @notice Generic terminal managing all inflows and outflows of funds into the protocol ecosystem.\nabstract contract JBPayoutRedemptionPaymentTerminal3_1_1 is\n JBSingleTokenPaymentTerminal,\n JBOperatable,\n Ownable,\n IJBPayoutRedemptionPaymentTerminal3_1,\n IJBPayoutRedemptionPaymentTerminal3_1_1\n{\n // A library that parses the packed funding cycle metadata into a friendlier format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error FEE_TOO_HIGH();\n error INADEQUATE_DISTRIBUTION_AMOUNT();\n error INADEQUATE_RECLAIM_AMOUNT();\n error INADEQUATE_TOKEN_COUNT();\n error NO_MSG_VALUE_ALLOWED();\n error PAY_TO_ZERO_ADDRESS();\n error PROJECT_TERMINAL_MISMATCH();\n error REDEEM_TO_ZERO_ADDRESS();\n error TERMINAL_TOKENS_INCOMPATIBLE();\n\n //*********************************************************************//\n // --------------------- internal stored constants ------------------- //\n //*********************************************************************//\n\n /// @notice Maximum fee that can be set for a funding cycle configuration.\n /// @dev Out of MAX_FEE (50_000_000 / 1_000_000_000).\n uint256 internal constant _FEE_CAP = 50_000_000;\n\n /// @notice The fee beneficiary project ID is 1, as it should be the first project launched during the deployment process.\n uint256 internal constant _FEE_BENEFICIARY_PROJECT_ID = 1;\n\n //*********************************************************************//\n // --------------------- internal stored properties ------------------ //\n //*********************************************************************//\n\n /// @notice Fees that are being held to be processed later.\n /// @custom:param _projectId The ID of the project for which fees are being held.\n mapping(uint256 => JBFee[]) internal _heldFeesOf;\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice Mints ERC-721's that represent project ownership and transfers.\n IJBProjects public immutable override projects;\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n /// @notice The contract that stores splits for each project.\n IJBSplitsStore public immutable override splitsStore;\n\n /// @notice The contract that exposes price feeds.\n IJBPrices public immutable override prices;\n\n /// @notice The contract that stores and manages the terminal's data.\n address public immutable override store;\n\n /// @notice The currency to base token issuance on.\n /// @dev If this differs from `currency`, there must be a price feed available to convert `currency` to `baseWeightCurrency`.\n uint256 public immutable override baseWeightCurrency;\n\n /// @notice The group that payout splits coming from this terminal are identified by.\n uint256 public immutable override payoutSplitsGroup;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The platform fee percent.\n /// @dev Out of MAX_FEE (25_000_000 / 1_000_000_000)\n uint256 public override fee = 25_000_000; // 2.5%\n\n /// @notice The data source that returns a discount to apply to a project's fee.\n address public override feeGauge;\n\n /// @notice Addresses that can be paid towards from this terminal without incurring a fee.\n /// @dev Only addresses that are considered to be contained within the ecosystem can be feeless. Funds sent outside the ecosystem may incur fees despite being stored as feeless.\n /// @custom:param _address The address that can be paid toward.\n mapping(address => bool) public override isFeelessAddress;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Gets the current overflowed amount in this terminal for a specified project, in terms of ETH.\n /// @dev The current overflow is represented as a fixed point number with 18 decimals.\n /// @param _projectId The ID of the project to get overflow for.\n /// @return The current amount of ETH overflow that project has in this terminal, as a fixed point number with 18 decimals.\n function currentEthOverflowOf(\n uint256 _projectId\n ) external view virtual override returns (uint256) {\n // Get this terminal's current overflow.\n uint256 _overflow = IJBSingleTokenPaymentTerminalStore3_1_1(store).currentOverflowOf(\n this,\n _projectId\n );\n\n // Adjust the decimals of the fixed point number if needed to have 18 decimals.\n uint256 _adjustedOverflow = (decimals == 18)\n ? _overflow\n : JBFixedPointNumber.adjustDecimals(_overflow, decimals, 18);\n\n // Return the amount converted to ETH.\n return\n (currency == JBCurrencies.ETH)\n ? _adjustedOverflow\n : PRBMath.mulDiv(\n _adjustedOverflow,\n 10 ** decimals,\n prices.priceFor(currency, JBCurrencies.ETH, decimals)\n );\n }\n\n /// @notice The fees that are currently being held to be processed later for each project.\n /// @param _projectId The ID of the project for which fees are being held.\n /// @return An array of fees that are being held.\n function heldFeesOf(uint256 _projectId) external view override returns (JBFee[] memory) {\n return _heldFeesOf[_projectId];\n }\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if the provided interface ID is supported.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(JBSingleTokenPaymentTerminal, IERC165) returns (bool) {\n return\n _interfaceId == type(IJBPayoutRedemptionPaymentTerminal3_1_1).interfaceId ||\n _interfaceId == type(IJBPayoutRedemptionPaymentTerminal3_1).interfaceId ||\n _interfaceId == type(IJBPayoutTerminal3_1).interfaceId ||\n _interfaceId == type(IJBAllowanceTerminal3_1).interfaceId ||\n _interfaceId == type(IJBRedemptionTerminal).interfaceId ||\n _interfaceId == type(IJBOperatable).interfaceId ||\n super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // -------------------------- internal views ------------------------- //\n //*********************************************************************//\n\n /// @notice Checks the balance of tokens in this contract.\n /// @return The contract's balance.\n function _balance() internal view virtual returns (uint256);\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _token The token that this terminal manages.\n /// @param _decimals The number of decimals the token fixed point amounts are expected to have.\n /// @param _currency The currency that this terminal's token adheres to for price feeds.\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _payoutSplitsGroup The group that denotes payout splits from this terminal in the splits store.\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _prices A contract that exposes price feeds.\n /// @param _store A contract that stores the terminal's data.\n /// @param _owner The address that will own this contract.\n constructor(\n // payable constructor save the gas used to check msg.value==0\n address _token,\n uint256 _decimals,\n uint256 _currency,\n uint256 _baseWeightCurrency,\n uint256 _payoutSplitsGroup,\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBSplitsStore _splitsStore,\n IJBPrices _prices,\n address _store,\n address _owner\n )\n payable\n JBSingleTokenPaymentTerminal(_token, _decimals, _currency)\n JBOperatable(_operatorStore)\n {\n baseWeightCurrency = _baseWeightCurrency;\n payoutSplitsGroup = _payoutSplitsGroup;\n projects = _projects;\n directory = _directory;\n splitsStore = _splitsStore;\n prices = _prices;\n store = _store;\n\n transferOwnership(_owner);\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Contribute tokens to a project.\n /// @param _projectId The ID of the project being paid.\n /// @param _amount The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place.\n /// @param _token The token being paid. This terminal ignores this property since it only manages one token.\n /// @param _beneficiary The address to mint tokens for and pass along to the funding cycle's data source and delegate.\n /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\n /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals.\n function pay(\n uint256 _projectId,\n uint256 _amount,\n address _token,\n address _beneficiary,\n uint256 _minReturnedTokens,\n bool _preferClaimedTokens,\n string calldata _memo,\n bytes calldata _metadata\n ) external payable virtual override returns (uint256) {\n _token; // Prevents unused var compiler and natspec complaints.\n\n // valid terminal check\n _isTerminalOf(_projectId);\n\n // ETH shouldn't be sent if this terminal's token isn't ETH.\n if (token != JBTokens.ETH) {\n if (msg.value != 0) revert NO_MSG_VALUE_ALLOWED();\n\n // Get a reference to the balance before receiving tokens.\n uint256 _balanceBefore = _balance();\n\n // Transfer tokens to this terminal from the msg sender.\n _transferFrom(msg.sender, payable(address(this)), _amount);\n\n // The amount should reflect the change in balance.\n _amount = _balance() - _balanceBefore;\n }\n // If this terminal's token is ETH, override _amount with msg.value.\n else _amount = msg.value;\n\n return\n _pay(\n _amount,\n msg.sender,\n _projectId,\n _beneficiary,\n _minReturnedTokens,\n _preferClaimedTokens,\n _memo,\n _metadata\n );\n }\n\n /// @notice Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source.\n /// @dev Only a token holder or a designated operator can redeem its tokens.\n /// @param _holder The account to redeem tokens for.\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\n /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals.\n /// @param _token The token being reclaimed. This terminal ignores this property since it only manages one token.\n /// @param _minReturnedTokens The minimum amount of terminal tokens expected in return, as a fixed point number with the same amount of decimals as the terminal.\n /// @param _beneficiary The address to send the terminal tokens to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return reclaimAmount The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals.\n function redeemTokensOf(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n address _token,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo,\n bytes memory _metadata\n )\n external\n virtual\n override\n requirePermission(_holder, _projectId, JBOperations.REDEEM)\n returns (uint256 reclaimAmount)\n {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return\n _redeemTokensOf(\n _holder,\n _projectId,\n _tokenCount,\n _minReturnedTokens,\n _beneficiary,\n _memo,\n _metadata\n );\n }\n\n /// @notice Distributes payouts for a project with the distribution limit of its current funding cycle.\n /// @dev Payouts are sent to the preprogrammed splits. Any leftover is sent to the project's owner.\n /// @dev 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.\n /// @dev All funds distributed outside of this contract or any feeless terminals incure the protocol fee.\n /// @param _projectId The ID of the project having its payouts distributed.\n /// @param _amount The amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency.\n /// @param _token The token being distributed. This terminal ignores this property since it only manages one token.\n /// @param _minReturnedTokens 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.\n /// @param _metadata Bytes to send along to the emitted event, if provided.\n /// @return netLeftoverDistributionAmount The amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal.\n function distributePayoutsOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n address _token,\n uint256 _minReturnedTokens,\n bytes calldata _metadata\n ) external virtual override returns (uint256 netLeftoverDistributionAmount) {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return _distributePayoutsOf(_projectId, _amount, _currency, _minReturnedTokens, _metadata);\n }\n\n /// @notice Allows a project to send funds from its overflow up to the preconfigured allowance.\n /// @dev Only a project's owner or a designated operator can use its allowance.\n /// @dev Incurs the protocol fee.\n /// @param _projectId The ID of the project to use the allowance of.\n /// @param _amount The amount of terminal tokens to use from this project's current allowance, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's overflow allowance currency.\n /// @param _token The token being distributed. This terminal ignores this property since it only manages one token.\n /// @param _minReturnedTokens The minimum number of tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with 18 decimals.\n /// @param _beneficiary The address to send the funds to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the emitted event, if provided.\n /// @return netDistributedAmount The amount of tokens that was distributed to the beneficiary, as a fixed point number with the same amount of decimals as the terminal.\n function useAllowanceOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n address _token,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo,\n bytes calldata _metadata\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.USE_ALLOWANCE)\n returns (uint256 netDistributedAmount)\n {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return\n _useAllowanceOf(\n _projectId,\n _amount,\n _currency,\n _minReturnedTokens,\n _beneficiary,\n _memo,\n _metadata\n );\n }\n\n /// @notice Allows a project owner to migrate its funds and operations to a new terminal that accepts the same token type.\n /// @dev Only a project's owner or a designated operator can migrate it.\n /// @param _projectId The ID of the project being migrated.\n /// @param _to The terminal contract that will gain the project's funds.\n /// @return balance The amount of funds that were migrated, as a fixed point number with the same amount of decimals as this terminal.\n function migrate(\n uint256 _projectId,\n IJBPaymentTerminal _to\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.MIGRATE_TERMINAL)\n returns (uint256 balance)\n {\n // The terminal being migrated to must accept the same token as this terminal.\n if (!_to.acceptsToken(token, _projectId)) revert TERMINAL_TOKENS_INCOMPATIBLE();\n\n // Record the migration in the store.\n balance = IJBSingleTokenPaymentTerminalStore3_1_1(store).recordMigration(_projectId);\n\n // Transfer the balance if needed.\n if (balance != 0) {\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_to), balance);\n\n // If this terminal's token is ETH, send it in msg.value.\n uint256 _payableValue = token == JBTokens.ETH ? balance : 0;\n\n // Withdraw the balance to transfer to the new terminal;\n _to.addToBalanceOf{value: _payableValue}(_projectId, balance, token, '', bytes(''));\n }\n\n emit Migrate(_projectId, _to, balance, msg.sender);\n }\n\n /// @notice Receives funds belonging to the specified project.\n /// @param _projectId The ID of the project to which the funds received belong.\n /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\n /// @param _token The token being paid. This terminal ignores this property since it only manages one currency.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the emitted event.\n function addToBalanceOf(\n uint256 _projectId,\n uint256 _amount,\n address _token,\n string calldata _memo,\n bytes calldata _metadata\n ) external payable virtual override {\n // valid terminal check\n _isTerminalOf(_projectId);\n\n // Do not refund held fees by default.\n addToBalanceOf(_projectId, _amount, _token, false, _memo, _metadata);\n }\n\n /// @notice Process any fees that are being held for the project.\n /// @dev Only a project owner, an operator, or the contract's owner can process held fees.\n /// @param _projectId The ID of the project whos held fees should be processed.\n function processFees(\n uint256 _projectId\n )\n external\n virtual\n override\n requirePermissionAllowingOverride(\n projects.ownerOf(_projectId),\n _projectId,\n JBOperations.PROCESS_FEES,\n msg.sender == owner()\n )\n {\n // Get a reference to the project's held fees.\n JBFee[] memory _heldFees = _heldFeesOf[_projectId];\n\n // Delete the held fees.\n delete _heldFeesOf[_projectId];\n\n // Push array length in stack\n uint256 _heldFeeLength = _heldFees.length;\n\n // Keep a reference to the amount.\n uint256 _amount;\n\n // Process each fee.\n for (uint256 _i; _i < _heldFeeLength; ) {\n // Get the fee amount.\n _amount = (\n _heldFees[_i].fee == 0 || _heldFees[_i].feeDiscount == JBConstants.MAX_FEE_DISCOUNT\n ? 0\n : _feeAmount(_heldFees[_i].amount, _heldFees[_i].fee, _heldFees[_i].feeDiscount)\n );\n\n // Process the fee.\n _processFee(_amount, _heldFees[_i].beneficiary, _projectId);\n\n emit ProcessFee(_projectId, _amount, true, _heldFees[_i].beneficiary, msg.sender);\n\n unchecked {\n ++_i;\n }\n }\n }\n\n /// @notice Allows the fee to be updated.\n /// @dev Only the owner of this contract can change the fee.\n /// @param _fee The new fee, out of MAX_FEE.\n function setFee(uint256 _fee) external virtual override onlyOwner {\n // The provided fee must be within the max.\n if (_fee > _FEE_CAP) revert FEE_TOO_HIGH();\n\n // Store the new fee.\n fee = _fee;\n\n emit SetFee(_fee, msg.sender);\n }\n\n /// @notice Allows the fee gauge to be updated.\n /// @dev Only the owner of this contract can change the fee gauge.\n /// @param _feeGauge The new fee gauge.\n function setFeeGauge(address _feeGauge) external virtual override onlyOwner {\n // Store the new fee gauge.\n feeGauge = _feeGauge;\n\n emit SetFeeGauge(_feeGauge, msg.sender);\n }\n\n /// @notice Sets whether projects operating on this terminal can pay towards the specified address without incurring a fee.\n /// @dev Only the owner of this contract can set addresses as feeless.\n /// @param _address The address that can be paid towards while still bypassing fees.\n /// @param _flag A flag indicating whether the terminal should be feeless or not.\n function setFeelessAddress(address _address, bool _flag) external virtual override onlyOwner {\n // Set the flag value.\n isFeelessAddress[_address] = _flag;\n\n emit SetFeelessAddress(_address, _flag, msg.sender);\n }\n\n //*********************************************************************//\n // ----------------------- public transactions ----------------------- //\n //*********************************************************************//\n\n /// @notice Receives funds belonging to the specified project.\n /// @param _projectId The ID of the project to which the funds received belong.\n /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\n /// @param _token The token being paid. This terminal ignores this property since it only manages one currency.\n /// @param _shouldRefundHeldFees A flag indicating if held fees should be refunded based on the amount being added.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the emitted event.\n function addToBalanceOf(\n uint256 _projectId,\n uint256 _amount,\n address _token,\n bool _shouldRefundHeldFees,\n string calldata _memo,\n bytes calldata _metadata\n ) public payable virtual override {\n // valid terminal check\n _isTerminalOf(_projectId);\n\n _token; // Prevents unused var compiler and natspec complaints.\n\n // If this terminal's token isn't ETH, make sure no msg.value was sent, then transfer the tokens in from msg.sender.\n if (token != JBTokens.ETH) {\n // Amount must be greater than 0.\n if (msg.value != 0) revert NO_MSG_VALUE_ALLOWED();\n\n // Get a reference to the balance before receiving tokens.\n uint256 _balanceBefore = _balance();\n\n // Transfer tokens to this terminal from the msg sender.\n _transferFrom(msg.sender, payable(address(this)), _amount);\n\n // The amount should reflect the change in balance.\n _amount = _balance() - _balanceBefore;\n }\n // If the terminal's token is ETH, override `_amount` with msg.value.\n else _amount = msg.value;\n\n // Add to balance.\n _addToBalanceOf(_projectId, _amount, _shouldRefundHeldFees, _memo, _metadata);\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Transfers tokens.\n /// @param _from The address from which the transfer should originate.\n /// @param _to The address to which the transfer should go.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _transferFrom(address _from, address payable _to, uint256 _amount) internal virtual {\n _from; // Prevents unused var compiler and natspec complaints.\n _to; // Prevents unused var compiler and natspec complaints.\n _amount; // Prevents unused var compiler and natspec complaints.\n }\n\n /// @notice Logic to be triggered before transferring tokens from this terminal.\n /// @param _to The address to which the transfer is going.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _beforeTransferTo(address _to, uint256 _amount) internal virtual {\n _to; // Prevents unused var compiler and natspec complaints.\n _amount; // Prevents unused var compiler and natspec complaints.\n }\n\n /// @notice Logic to be triggered if a transfer should be undone\n /// @param _to The address to which the transfer went.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _cancelTransferTo(address _to, uint256 _amount) internal virtual {\n _to; // Prevents unused var compiler and natspec complaints.\n _amount; // Prevents unused var compiler and natspec complaints.\n }\n\n /// @notice Verifies this terminal is a terminal of provided project ID.\n /// @param _projectId The ID of the project to check if this contract is a terminal of.\n function _isTerminalOf(uint256 _projectId) internal view {\n if (!directory.isTerminalOf(_projectId, this)) revert PROJECT_TERMINAL_MISMATCH();\n }\n\n /// @notice Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source.\n /// @dev Only a token holder or a designated operator can redeem its tokens.\n /// @param _holder The account to redeem tokens for.\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\n /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals.\n /// @param _minReturnedTokens The minimum amount of terminal tokens expected in return, as a fixed point number with the same amount of decimals as the terminal.\n /// @param _beneficiary The address to send the terminal tokens to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return reclaimAmount The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals.\n function _redeemTokensOf(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo,\n bytes memory _metadata\n ) internal returns (uint256 reclaimAmount) {\n // Can't send reclaimed funds to the zero address.\n if (_beneficiary == address(0)) revert REDEEM_TO_ZERO_ADDRESS();\n\n // Define variables that will be needed outside the scoped section below.\n // Keep a reference to the funding cycle during which the redemption is being made.\n JBFundingCycle memory _fundingCycle;\n\n // Scoped section prevents stack too deep. `_feeEligibleDistributionAmount`, `_feeDiscount` and `_feePercent` only used within scope.\n {\n // Keep a reference to the amount being reclaimed that should have fees withheld from.\n uint256 _feeEligibleDistributionAmount;\n\n // Keep a reference to the amount of discount to apply to the fee.\n uint256 _feeDiscount;\n\n // Keep a reference to the fee.\n uint256 _feePercent = fee;\n\n // Scoped section prevents stack too deep. `_delegateAllocations` only used within scope.\n {\n JBRedemptionDelegateAllocation3_1_1[] memory _delegateAllocations;\n\n // Record the redemption.\n (\n _fundingCycle,\n reclaimAmount,\n _delegateAllocations,\n _memo\n ) = IJBSingleTokenPaymentTerminalStore3_1_1(store).recordRedemptionFor(\n _holder,\n _projectId,\n _tokenCount,\n _memo,\n _metadata\n );\n\n // Set the reference to the fee discount to apply. No fee if the beneficiary is feeless or if the redemption rate is at its max.\n _feeDiscount = isFeelessAddress[_beneficiary] ||\n (_fundingCycle.redemptionRate() == JBConstants.MAX_REDEMPTION_RATE &&\n _fundingCycle.ballotRedemptionRate() == JBConstants.MAX_REDEMPTION_RATE) ||\n _feePercent == 0\n ? JBConstants.MAX_FEE_DISCOUNT\n : _currentFeeDiscount(_projectId, JBFeeType.REDEMPTION);\n\n // The amount being reclaimed must be at least as much as was expected.\n if (reclaimAmount < _minReturnedTokens) revert INADEQUATE_RECLAIM_AMOUNT();\n\n // Burn the project tokens.\n if (_tokenCount != 0)\n IJBController(directory.controllerOf(_projectId)).burnTokensOf(\n _holder,\n _projectId,\n _tokenCount,\n '',\n false\n );\n\n // If delegate allocations were specified by the data source, fulfill them.\n if (_delegateAllocations.length != 0) {\n JBDidRedeemData3_1_1 memory _data = JBDidRedeemData3_1_1(\n _holder,\n _projectId,\n _fundingCycle.configuration,\n _tokenCount,\n JBTokenAmount(token, reclaimAmount, decimals, currency),\n JBTokenAmount(token, 0, decimals, currency),\n _beneficiary,\n _memo,\n bytes(''),\n _metadata\n );\n\n // Keep a reference to the allocation.\n JBRedemptionDelegateAllocation3_1_1 memory _delegateAllocation;\n\n // Keep a reference to the fee.\n uint256 _delegatedAmountFee;\n\n // Keep a reference to the number of allocations.\n uint256 _numDelegates = _delegateAllocations.length;\n\n for (uint256 _i; _i < _numDelegates; ) {\n // Get a reference to the delegate being iterated on.\n _delegateAllocation = _delegateAllocations[_i];\n\n // Get the fee for the delegated amount.\n _delegatedAmountFee = _feePercent == 0\n ? 0\n : _feeAmount(_delegateAllocation.amount, _feePercent, _feeDiscount);\n\n // Add the delegated amount to the amount eligible for having a fee taken.\n if (_delegatedAmountFee != 0) {\n _feeEligibleDistributionAmount += _delegateAllocation.amount;\n _delegateAllocation.amount -= _delegatedAmountFee;\n }\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_delegateAllocation.delegate), _delegateAllocation.amount);\n\n // Pass the correct token forwardedAmount to the delegate\n _data.forwardedAmount.value = _delegateAllocation.amount;\n\n // Pass the correct metadata from the data source.\n _data.dataSourceMetadata = _delegateAllocation.metadata;\n\n _delegateAllocation.delegate.didRedeem{\n value: token == JBTokens.ETH ? _delegateAllocation.amount : 0\n }(_data);\n\n emit DelegateDidRedeem(\n _delegateAllocation.delegate,\n _data,\n _delegateAllocation.amount,\n _delegatedAmountFee,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n }\n\n // Send the reclaimed funds to the beneficiary.\n if (reclaimAmount != 0) {\n // Get the fee for the reclaimed amount.\n uint256 _reclaimAmountFee = _feeDiscount == JBConstants.MAX_FEE_DISCOUNT\n ? 0\n : _feeAmount(reclaimAmount, _feePercent, _feeDiscount);\n\n if (_reclaimAmountFee != 0) {\n _feeEligibleDistributionAmount += reclaimAmount;\n reclaimAmount -= _reclaimAmountFee;\n }\n\n // Subtract the fee from the reclaim amount.\n if (reclaimAmount != 0) _transferFrom(address(this), _beneficiary, reclaimAmount);\n }\n\n // Take the fee from all outbound reclaimations.\n _feeEligibleDistributionAmount != 0\n ? _takeFeeFrom(\n _projectId,\n false,\n _feeEligibleDistributionAmount,\n _feePercent,\n _beneficiary,\n _feeDiscount\n )\n : 0;\n }\n\n emit RedeemTokens(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _holder,\n _beneficiary,\n _tokenCount,\n reclaimAmount,\n _memo,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Distributes payouts for a project with the distribution limit of its current funding cycle.\n /// @dev Payouts are sent to the preprogrammed splits. Any leftover is sent to the project's owner.\n /// @dev 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.\n /// @dev All funds distributed outside of this contract or any feeless terminals incure the protocol fee.\n /// @param _projectId The ID of the project having its payouts distributed.\n /// @param _amount The amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency.\n /// @param _minReturnedTokens 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.\n /// @param _metadata Bytes to send along to the emitted event, if provided.\n /// @return netLeftoverDistributionAmount The amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal.\n function _distributePayoutsOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n uint256 _minReturnedTokens,\n bytes calldata _metadata\n ) internal returns (uint256 netLeftoverDistributionAmount) {\n // Record the distribution.\n (\n JBFundingCycle memory _fundingCycle,\n uint256 _distributedAmount\n ) = IJBSingleTokenPaymentTerminalStore3_1_1(store).recordDistributionFor(\n _projectId,\n _amount,\n _currency\n );\n\n // The amount being distributed must be at least as much as was expected.\n if (_distributedAmount < _minReturnedTokens) revert INADEQUATE_DISTRIBUTION_AMOUNT();\n\n // Get a reference to the project owner, which will receive tokens from paying the platform fee\n // and receive any extra distributable funds not allocated to payout splits.\n address payable _projectOwner = payable(projects.ownerOf(_projectId));\n\n // Define variables that will be needed outside the scoped section below.\n // Keep a reference to the fee amount that was paid.\n uint256 _feeTaken;\n\n // Scoped section prevents stack too deep. `_feePercent`, `_feeDiscount`, `_feeEligibleDistributionAmount`, and `_leftoverDistributionAmount` only used within scope.\n {\n // Keep a reference to the fee.\n uint256 _feePercent = fee;\n\n // Get the amount of discount that should be applied to any fees taken.\n // If the fee is zero, set the discount to 100% for convenience.\n uint256 _feeDiscount = _feePercent == 0\n ? JBConstants.MAX_FEE_DISCOUNT\n : _currentFeeDiscount(_projectId, JBFeeType.PAYOUT);\n\n // The amount distributed that is eligible for incurring fees.\n uint256 _feeEligibleDistributionAmount;\n\n // The amount leftover after distributing to the splits.\n uint256 _leftoverDistributionAmount;\n\n // Payout to splits and get a reference to the leftover transfer amount after all splits have been paid.\n // Also get a reference to the amount that was distributed to splits from which fees should be taken.\n (_leftoverDistributionAmount, _feeEligibleDistributionAmount) = _distributeToPayoutSplitsOf(\n _projectId,\n _fundingCycle.configuration,\n payoutSplitsGroup,\n _distributedAmount,\n _feePercent,\n _feeDiscount\n );\n\n if (_feeDiscount != JBConstants.MAX_FEE_DISCOUNT) {\n // Leftover distribution amount is also eligible for a fee since the funds are going out of the ecosystem to _beneficiary.\n unchecked {\n _feeEligibleDistributionAmount += _leftoverDistributionAmount;\n }\n }\n\n // Take the fee.\n _feeTaken = _feeEligibleDistributionAmount != 0\n ? _takeFeeFrom(\n _projectId,\n _fundingCycle.shouldHoldFees(),\n _feeEligibleDistributionAmount,\n _feePercent,\n _projectOwner,\n _feeDiscount\n )\n : 0;\n\n // Transfer any remaining balance to the project owner and update returned leftover accordingly.\n if (_leftoverDistributionAmount != 0) {\n // Subtract the fee from the net leftover amount.\n netLeftoverDistributionAmount =\n _leftoverDistributionAmount -\n (\n _feeDiscount == JBConstants.MAX_FEE_DISCOUNT\n ? 0\n : _feeAmount(_leftoverDistributionAmount, _feePercent, _feeDiscount)\n );\n\n // Transfer the amount to the project owner.\n _transferFrom(address(this), _projectOwner, netLeftoverDistributionAmount);\n }\n }\n\n emit DistributePayouts(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _projectOwner,\n _amount,\n _distributedAmount,\n _feeTaken,\n netLeftoverDistributionAmount,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Allows a project to send funds from its overflow up to the preconfigured allowance.\n /// @dev Only a project's owner or a designated operator can use its allowance.\n /// @dev Incurs the protocol fee.\n /// @param _projectId The ID of the project to use the allowance of.\n /// @param _amount The amount of terminal tokens to use from this project's current allowance, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's overflow allowance currency.\n /// @param _minReturnedTokens The minimum number of tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with 18 decimals.\n /// @param _beneficiary The address to send the funds to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the emitted event, if provided.\n /// @return netDistributedAmount The amount of tokens that was distributed to the beneficiary, as a fixed point number with the same amount of decimals as the terminal.\n function _useAllowanceOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo,\n bytes calldata _metadata\n ) internal returns (uint256 netDistributedAmount) {\n // Record the use of the allowance.\n (\n JBFundingCycle memory _fundingCycle,\n uint256 _distributedAmount\n ) = IJBSingleTokenPaymentTerminalStore3_1_1(store).recordUsedAllowanceOf(\n _projectId,\n _amount,\n _currency\n );\n\n // The amount being withdrawn must be at least as much as was expected.\n if (_distributedAmount < _minReturnedTokens) revert INADEQUATE_DISTRIBUTION_AMOUNT();\n\n // Scoped section prevents stack too deep. `_fee`, `_projectOwner`, `_feeDiscount`, and `_netAmount` only used within scope.\n {\n // Keep a reference to the fee amount that was paid.\n uint256 _feeTaken;\n\n // Keep a reference to the fee.\n uint256 _feePercent = fee;\n\n // Get a reference to the project owner, which will receive tokens from paying the platform fee.\n address _projectOwner = projects.ownerOf(_projectId);\n\n // Get the amount of discount that should be applied to any fees taken.\n // 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.\n uint256 _feeDiscount = _feePercent == 0 || isFeelessAddress[msg.sender]\n ? JBConstants.MAX_FEE_DISCOUNT\n : _currentFeeDiscount(_projectId, JBFeeType.ALLOWANCE);\n\n // Take a fee from the `_distributedAmount`, if needed.\n _feeTaken = _feeDiscount == JBConstants.MAX_FEE_DISCOUNT\n ? 0\n : _takeFeeFrom(\n _projectId,\n _fundingCycle.shouldHoldFees(),\n _distributedAmount,\n _feePercent,\n _projectOwner,\n _feeDiscount\n );\n\n unchecked {\n // The net amount is the withdrawn amount without the fee.\n netDistributedAmount = _distributedAmount - _feeTaken;\n }\n\n // Transfer any remaining balance to the beneficiary.\n if (netDistributedAmount != 0)\n _transferFrom(address(this), _beneficiary, netDistributedAmount);\n }\n\n emit UseAllowance(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _beneficiary,\n _amount,\n _distributedAmount,\n netDistributedAmount,\n _memo,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Pays out splits for a project's funding cycle configuration.\n /// @param _projectId The ID of the project for which payout splits are being distributed.\n /// @param _domain The domain of the splits to distribute the payout between.\n /// @param _group The group of the splits to distribute the payout between.\n /// @param _amount The total amount being distributed, as a fixed point number with the same number of decimals as this terminal.\n /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE.\n /// @param _feePercent The percent of fees to take, out of MAX_FEE.\n /// @return If the leftover amount if the splits don't add up to 100%.\n /// @return feeEligibleDistributionAmount The total amount of distributions that are eligible to have fees taken from.\n function _distributeToPayoutSplitsOf(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group,\n uint256 _amount,\n uint256 _feePercent,\n uint256 _feeDiscount\n ) internal returns (uint256, uint256 feeEligibleDistributionAmount) {\n // The total percentage available to split\n uint256 _leftoverPercentage = JBConstants.SPLITS_TOTAL_PERCENT;\n\n // Get a reference to the project's payout splits.\n JBSplit[] memory _splits = splitsStore.splitsOf(_projectId, _domain, _group);\n\n // Keep a reference to the split being iterated on.\n JBSplit memory _split;\n\n // Transfer between all splits.\n for (uint256 _i; _i < _splits.length; ) {\n // Get a reference to the split being iterated on.\n _split = _splits[_i];\n\n // The amount to send towards the split.\n uint256 _payoutAmount = PRBMath.mulDiv(_amount, _split.percent, _leftoverPercentage);\n\n // The payout amount substracting any applicable incurred fees.\n uint256 _netPayoutAmount = _distributeToPayoutSplit(\n _split,\n _projectId,\n _group,\n _payoutAmount,\n _feePercent,\n _feeDiscount\n );\n\n // If the split allocator is set as feeless, this distribution is not eligible for a fee.\n if (_netPayoutAmount != 0 && _netPayoutAmount != _payoutAmount)\n feeEligibleDistributionAmount += _payoutAmount;\n\n if (_payoutAmount != 0) {\n // Subtract from the amount to be sent to the beneficiary.\n unchecked {\n _amount -= _payoutAmount;\n }\n }\n\n unchecked {\n // Decrement the leftover percentage.\n _leftoverPercentage -= _split.percent;\n }\n\n emit DistributeToPayoutSplit(\n _projectId,\n _domain,\n _group,\n _split,\n _payoutAmount,\n _netPayoutAmount,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n\n return (_amount, feeEligibleDistributionAmount);\n }\n\n /// @notice Pays out a split for a project's funding cycle configuration.\n /// @param _split The split to distribute payouts to.\n /// @param _amount The total amount being distributed to the split, as a fixed point number with the same number of decimals as this terminal.\n /// @param _feePercent The percent of fees to take, out of MAX_FEE.\n /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE.\n /// @return netPayoutAmount The amount sent to the split after subtracting fees.\n function _distributeToPayoutSplit(\n JBSplit memory _split,\n uint256 _projectId,\n uint256 _group,\n uint256 _amount,\n uint256 _feePercent,\n uint256 _feeDiscount\n ) internal returns (uint256 netPayoutAmount) {\n // By default, the net payout amount is the full amount. This will be adjusted if fees are taken.\n netPayoutAmount = _amount;\n\n // If there's an allocator set, transfer to its `allocate` function.\n if (_split.allocator != IJBSplitAllocator(address(0))) {\n // This distribution is eligible for a fee since the funds are leaving this contract and the allocator isn't listed as feeless.\n if (\n _feeDiscount != JBConstants.MAX_FEE_DISCOUNT && !isFeelessAddress[address(_split.allocator)]\n ) {\n unchecked {\n netPayoutAmount -= _feeAmount(_amount, _feePercent, _feeDiscount);\n }\n }\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_split.allocator), netPayoutAmount);\n\n // Create the data to send to the allocator.\n JBSplitAllocationData memory _data = JBSplitAllocationData(\n token,\n netPayoutAmount,\n decimals,\n _projectId,\n _group,\n _split\n );\n\n // Trigger the allocator's `allocate` function.\n bytes memory _reason;\n\n if (\n ERC165Checker.supportsInterface(\n address(_split.allocator),\n type(IJBSplitAllocator).interfaceId\n )\n )\n // If this terminal's token is ETH, send it in msg.value.\n try\n _split.allocator.allocate{value: token == JBTokens.ETH ? netPayoutAmount : 0}(_data)\n {} catch (bytes memory __reason) {\n _reason = __reason.length == 0 ? abi.encode('Allocate fail') : __reason;\n }\n else {\n _reason = abi.encode('IERC165 fail');\n }\n\n if (_reason.length != 0) {\n // Revert the payout.\n _revertTransferFrom(_projectId, address(_split.allocator), netPayoutAmount, _amount);\n\n // Set the net payout amount to 0 to signal the reversion.\n netPayoutAmount = 0;\n\n emit PayoutReverted(_projectId, _split, _amount, _reason, msg.sender);\n }\n\n // Otherwise, if a project is specified, make a payment to it.\n } else if (_split.projectId != 0) {\n // Get a reference to the Juicebox terminal being used.\n IJBPaymentTerminal _terminal = directory.primaryTerminalOf(_split.projectId, token);\n\n // The project must have a terminal to send funds to.\n if (_terminal == IJBPaymentTerminal(address(0))) {\n // Set the net payout amount to 0 to signal the reversion.\n netPayoutAmount = 0;\n\n // Revert the payout.\n _revertTransferFrom(_projectId, address(0), 0, _amount);\n\n emit PayoutReverted(_projectId, _split, _amount, 'Terminal not found', msg.sender);\n } else {\n // This distribution is eligible for a fee since the funds are leaving this contract and the terminal isn't listed as feeless.\n if (\n _terminal != this &&\n _feeDiscount != JBConstants.MAX_FEE_DISCOUNT &&\n !isFeelessAddress[address(_terminal)]\n ) {\n unchecked {\n netPayoutAmount -= _feeAmount(_amount, _feePercent, _feeDiscount);\n }\n }\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_terminal), netPayoutAmount);\n\n // Add to balance if prefered.\n if (_split.preferAddToBalance)\n try\n _terminal.addToBalanceOf{value: token == JBTokens.ETH ? netPayoutAmount : 0}(\n _split.projectId,\n netPayoutAmount,\n token,\n '',\n // Send the projectId in the metadata as a referral.\n bytes(abi.encodePacked(_projectId))\n )\n {} catch (bytes memory _reason) {\n // Revert the payout.\n _revertTransferFrom(_projectId, address(_terminal), netPayoutAmount, _amount);\n\n // Set the net payout amount to 0 to signal the reversion.\n netPayoutAmount = 0;\n\n emit PayoutReverted(_projectId, _split, _amount, _reason, msg.sender);\n }\n else\n try\n _terminal.pay{value: token == JBTokens.ETH ? netPayoutAmount : 0}(\n _split.projectId,\n netPayoutAmount,\n token,\n _split.beneficiary != address(0) ? _split.beneficiary : msg.sender,\n 0,\n _split.preferClaimed,\n '',\n // Send the projectId in the metadata as a referral.\n bytes(abi.encodePacked(_projectId))\n )\n {} catch (bytes memory _reason) {\n // Revert the payout.\n _revertTransferFrom(_projectId, address(_terminal), netPayoutAmount, _amount);\n\n // Set the net payout amount to 0 to signal the reversion.\n netPayoutAmount = 0;\n\n emit PayoutReverted(_projectId, _split, _amount, _reason, msg.sender);\n }\n }\n } else {\n // This distribution is eligible for a fee since the funds are leaving this contract and the beneficiary isn't listed as feeless.\n // Don't enforce feeless address for the beneficiary since the funds are leaving the ecosystem.\n if (_feeDiscount != JBConstants.MAX_FEE_DISCOUNT) {\n unchecked {\n netPayoutAmount -= _feeAmount(_amount, _feePercent, _feeDiscount);\n }\n }\n\n // If there's a beneficiary, send the funds directly to the beneficiary. Otherwise send to the msg.sender.\n _transferFrom(\n address(this),\n _split.beneficiary != address(0) ? _split.beneficiary : payable(msg.sender),\n netPayoutAmount\n );\n }\n }\n\n /// @notice Takes a fee into the platform's project, which has an id of _FEE_BENEFICIARY_PROJECT_ID.\n /// @param _projectId The ID of the project having fees taken from.\n /// @param _shouldHoldFees If fees should be tracked and held back.\n /// @param _feePercent The percent of fees to take, out of MAX_FEE.\n /// @param _amount The amount of the fee to take, as a floating point number with 18 decimals.\n /// @param _beneficiary The address to mint the platforms tokens for.\n /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE.\n /// @return feeAmount The amount of the fee taken.\n function _takeFeeFrom(\n uint256 _projectId,\n bool _shouldHoldFees,\n uint256 _amount,\n uint256 _feePercent,\n address _beneficiary,\n uint256 _feeDiscount\n ) internal returns (uint256 feeAmount) {\n feeAmount = _feeAmount(_amount, _feePercent, _feeDiscount);\n\n if (_shouldHoldFees) {\n // Store the held fee.\n _heldFeesOf[_projectId].push(\n JBFee(_amount, uint32(_feePercent), uint32(_feeDiscount), _beneficiary)\n );\n\n emit HoldFee(_projectId, _amount, _feePercent, _feeDiscount, _beneficiary, msg.sender);\n } else {\n // Process the fee.\n _processFee(feeAmount, _beneficiary, _projectId); // Take the fee.\n\n emit ProcessFee(_projectId, feeAmount, false, _beneficiary, msg.sender);\n }\n }\n\n /// @notice Process a fee of the specified amount.\n /// @param _amount The fee amount, as a floating point number with 18 decimals.\n /// @param _beneficiary The address to mint the platform's tokens for.\n /// @param _from The project ID the fee is being paid from.\n function _processFee(uint256 _amount, address _beneficiary, uint256 _from) internal {\n // Get the terminal for the protocol project.\n IJBPaymentTerminal _terminal = directory.primaryTerminalOf(_FEE_BENEFICIARY_PROJECT_ID, token);\n\n // Trigger any inherited pre-transfer logic if funds will be transferred.\n if (address(_terminal) != address(this)) _beforeTransferTo(address(_terminal), _amount);\n\n try\n // Send the fee.\n // If this terminal's token is ETH, send it in msg.value.\n _terminal.pay{value: token == JBTokens.ETH ? _amount : 0}(\n _FEE_BENEFICIARY_PROJECT_ID,\n _amount,\n token,\n _beneficiary,\n 0,\n false,\n '',\n // Send the projectId in the metadata.\n bytes(abi.encodePacked(_from))\n )\n {} catch (bytes memory _reason) {\n _revertTransferFrom(\n _from,\n address(_terminal) != address(this) ? address(_terminal) : address(0),\n address(_terminal) != address(this) ? _amount : 0,\n _amount\n );\n emit FeeReverted(_from, _FEE_BENEFICIARY_PROJECT_ID, _amount, _reason, msg.sender);\n }\n }\n\n /// @notice Reverts an expected payout.\n /// @param _projectId The ID of the project having paying out.\n /// @param _expectedDestination The address the payout was expected to go to.\n /// @param _allowanceAmount The amount that the destination has been allowed to use.\n /// @param _depositAmount The amount of the payout as debited from the project's balance.\n function _revertTransferFrom(\n uint256 _projectId,\n address _expectedDestination,\n uint256 _allowanceAmount,\n uint256 _depositAmount\n ) internal {\n // Cancel allowance if needed.\n if (_allowanceAmount != 0) _cancelTransferTo(_expectedDestination, _allowanceAmount);\n\n // Add undistributed amount back to project's balance.\n IJBSingleTokenPaymentTerminalStore3_1_1(store).recordAddedBalanceFor(\n _projectId,\n _depositAmount\n );\n }\n\n /// @notice Contribute tokens to a project.\n /// @param _amount The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place.\n /// @param _payer The address making the payment.\n /// @param _projectId The ID of the project being paid.\n /// @param _beneficiary The address to mint tokens for and pass along to the funding cycle's data source and delegate.\n /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\n /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return beneficiaryTokenCount The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals.\n function _pay(\n uint256 _amount,\n address _payer,\n uint256 _projectId,\n address _beneficiary,\n uint256 _minReturnedTokens,\n bool _preferClaimedTokens,\n string memory _memo,\n bytes memory _metadata\n ) internal returns (uint256 beneficiaryTokenCount) {\n // Cant send tokens to the zero address.\n if (_beneficiary == address(0)) revert PAY_TO_ZERO_ADDRESS();\n\n // Define variables that will be needed outside the scoped section below.\n // Keep a reference to the funding cycle during which the payment is being made.\n JBFundingCycle memory _fundingCycle;\n\n // Scoped section prevents stack too deep. `_delegateAllocations` and `_tokenCount` only used within scope.\n {\n JBPayDelegateAllocation3_1_1[] memory _delegateAllocations;\n uint256 _tokenCount;\n\n // Bundle the amount info into a JBTokenAmount struct.\n JBTokenAmount memory _bundledAmount = JBTokenAmount(token, _amount, decimals, currency);\n\n // Record the payment.\n (\n _fundingCycle,\n _tokenCount,\n _delegateAllocations,\n _memo\n ) = IJBSingleTokenPaymentTerminalStore3_1_1(store).recordPaymentFrom(\n _payer,\n _bundledAmount,\n _projectId,\n baseWeightCurrency,\n _beneficiary,\n _memo,\n _metadata\n );\n\n // Mint the tokens if needed.\n if (_tokenCount != 0)\n // Set token count to be the number of tokens minted for the beneficiary instead of the total amount.\n beneficiaryTokenCount = IJBController(directory.controllerOf(_projectId)).mintTokensOf(\n _projectId,\n _tokenCount,\n _beneficiary,\n '',\n _preferClaimedTokens,\n true\n );\n\n // The token count for the beneficiary must be greater than or equal to the minimum expected.\n if (beneficiaryTokenCount < _minReturnedTokens) revert INADEQUATE_TOKEN_COUNT();\n\n // If delegate allocations were specified by the data source, fulfill them.\n if (_delegateAllocations.length != 0) {\n JBDidPayData3_1_1 memory _data = JBDidPayData3_1_1(\n _payer,\n _projectId,\n _fundingCycle.configuration,\n _bundledAmount,\n JBTokenAmount(token, 0, decimals, currency),\n beneficiaryTokenCount,\n _beneficiary,\n _preferClaimedTokens,\n _memo,\n bytes(''),\n _metadata\n );\n\n // Get a reference to the number of delegates to allocate to.\n uint256 _numDelegates = _delegateAllocations.length;\n\n // Keep a reference to the allocation.\n JBPayDelegateAllocation3_1_1 memory _delegateAllocation;\n\n for (uint256 _i; _i < _numDelegates; ) {\n // Get a reference to the delegate being iterated on.\n _delegateAllocation = _delegateAllocations[_i];\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_delegateAllocation.delegate), _delegateAllocation.amount);\n\n // Pass the correct token forwardedAmount to the delegate\n _data.forwardedAmount.value = _delegateAllocation.amount;\n\n // Pass the correct metadata from the data source.\n _data.dataSourceMetadata = _delegateAllocation.metadata;\n\n _delegateAllocation.delegate.didPay{\n value: token == JBTokens.ETH ? _delegateAllocation.amount : 0\n }(_data);\n\n emit DelegateDidPay(\n _delegateAllocation.delegate,\n _data,\n _delegateAllocation.amount,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n }\n\n emit Pay(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _payer,\n _beneficiary,\n _amount,\n beneficiaryTokenCount,\n _memo,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Receives funds belonging to the specified project.\n /// @param _projectId The ID of the project to which the funds received belong.\n /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\n /// @param _shouldRefundHeldFees A flag indicating if held fees should be refunded based on the amount being added.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the emitted event.\n function _addToBalanceOf(\n uint256 _projectId,\n uint256 _amount,\n bool _shouldRefundHeldFees,\n string memory _memo,\n bytes memory _metadata\n ) internal {\n // Refund any held fees to make sure the project doesn't pay double for funds going in and out of the protocol.\n uint256 _refundedFees = _shouldRefundHeldFees ? _refundHeldFees(_projectId, _amount) : 0;\n\n // Record the added funds with any refunded fees.\n IJBSingleTokenPaymentTerminalStore3_1_1(store).recordAddedBalanceFor(\n _projectId,\n _amount + _refundedFees\n );\n\n emit AddToBalance(_projectId, _amount, _refundedFees, _memo, _metadata, msg.sender);\n }\n\n /// @notice Refund fees based on the specified amount.\n /// @param _projectId The project for which fees are being refunded.\n /// @param _amount The amount to base the refund on, as a fixed point number with the same amount of decimals as this terminal.\n /// @return refundedFees How much fees were refunded, as a fixed point number with the same number of decimals as this terminal\n function _refundHeldFees(\n uint256 _projectId,\n uint256 _amount\n ) internal returns (uint256 refundedFees) {\n // Get a reference to the project's held fees.\n JBFee[] memory _heldFees = _heldFeesOf[_projectId];\n\n // Delete the current held fees.\n delete _heldFeesOf[_projectId];\n\n // Get a reference to the leftover amount once all fees have been settled.\n uint256 leftoverAmount = _amount;\n\n // Push length in stack\n uint256 _heldFeesLength = _heldFees.length;\n\n // Process each fee.\n for (uint256 _i; _i < _heldFeesLength; ) {\n if (leftoverAmount == 0) _heldFeesOf[_projectId].push(_heldFees[_i]);\n else if (leftoverAmount >= _heldFees[_i].amount) {\n unchecked {\n leftoverAmount = leftoverAmount - _heldFees[_i].amount;\n refundedFees += (\n _heldFees[_i].fee == 0 || _heldFees[_i].feeDiscount == JBConstants.MAX_FEE_DISCOUNT\n ? 0\n : _feeAmount(_heldFees[_i].amount, _heldFees[_i].fee, _heldFees[_i].feeDiscount)\n );\n }\n } else {\n unchecked {\n _heldFeesOf[_projectId].push(\n JBFee(\n _heldFees[_i].amount - leftoverAmount,\n _heldFees[_i].fee,\n _heldFees[_i].feeDiscount,\n _heldFees[_i].beneficiary\n )\n );\n refundedFees += (\n _heldFees[_i].fee == 0 || _heldFees[_i].feeDiscount == JBConstants.MAX_FEE_DISCOUNT\n ? 0\n : _feeAmount(leftoverAmount, _heldFees[_i].fee, _heldFees[_i].feeDiscount)\n );\n }\n leftoverAmount = 0;\n }\n\n unchecked {\n ++_i;\n }\n }\n\n emit RefundHeldFees(_projectId, _amount, refundedFees, leftoverAmount, msg.sender);\n }\n\n /// @notice Returns the fee amount based on the provided amount for the specified project.\n /// @param _amount The amount that the fee is based on, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _fee The percentage of the fee, out of MAX_FEE.\n /// @param _feeDiscount The percentage discount that should be applied out of the max amount, out of MAX_FEE_DISCOUNT.\n /// @return The amount of the fee, as a fixed point number with the same amount of decimals as this terminal.\n function _feeAmount(\n uint256 _amount,\n uint256 _fee,\n uint256 _feeDiscount\n ) internal pure returns (uint256) {\n // Calculate the discounted fee.\n uint256 _discountedFee = _fee -\n PRBMath.mulDiv(_fee, _feeDiscount, JBConstants.MAX_FEE_DISCOUNT);\n\n // The amount of tokens from the `_amount` to pay as a fee.\n return\n _amount - PRBMath.mulDiv(_amount, JBConstants.MAX_FEE, _discountedFee + JBConstants.MAX_FEE);\n }\n\n /// @notice Get the fee discount from the fee gauge for the specified project.\n /// @param _projectId The ID of the project to get a fee discount for.\n /// @param _feeType The type of fee the discount is being applied to.\n /// @return feeDiscount The fee discount, which should be interpreted as a percentage out MAX_FEE_DISCOUNT.\n function _currentFeeDiscount(\n uint256 _projectId,\n JBFeeType _feeType\n ) internal view returns (uint256) {\n // Can't take a fee if the protocol project doesn't have a terminal that accepts the token.\n if (\n directory.primaryTerminalOf(_FEE_BENEFICIARY_PROJECT_ID, token) ==\n IJBPaymentTerminal(address(0))\n ) return JBConstants.MAX_FEE_DISCOUNT;\n\n // Get the fee discount.\n if (feeGauge != address(0))\n // If the guage reverts, keep the discount at 0.\n try IJBFeeGauge3_1(feeGauge).currentDiscountFor(_projectId, _feeType) returns (\n uint256 discount\n ) {\n // If the fee discount is greater than the max, we ignore the return value\n if (discount <= JBConstants.MAX_FEE_DISCOUNT) return discount;\n } catch {\n return 0;\n }\n\n return 0;\n }\n}\n" + }, + "contracts/enums/JBFeeType.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nenum JBFeeType {\n PAYOUT,\n ALLOWANCE,\n REDEMPTION\n}\n" + }, + "contracts/interfaces/IJBPayoutRedemptionPaymentTerminal3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBFee} from './../structs/JBFee.sol';\nimport {JBDidRedeemData3_1_1} from './../structs/JBDidRedeemData3_1_1.sol';\nimport {JBDidPayData3_1_1} from './../structs/JBDidPayData3_1_1.sol';\nimport {IJBPayDelegate3_1_1} from './IJBPayDelegate3_1_1.sol';\nimport {IJBRedemptionDelegate3_1_1} from './IJBRedemptionDelegate3_1_1.sol';\n\ninterface IJBPayoutRedemptionPaymentTerminal3_1_1 {\n event DelegateDidRedeem(\n IJBRedemptionDelegate3_1_1 indexed delegate,\n JBDidRedeemData3_1_1 data,\n uint256 delegatedAmount,\n uint256 fee,\n address caller\n );\n\n event DelegateDidPay(\n IJBPayDelegate3_1_1 indexed delegate,\n JBDidPayData3_1_1 data,\n uint256 delegatedAmount,\n address caller\n );\n}\n" + }, + "contracts/interfaces/IJBFeeGauge3_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBFeeType} from './../enums/JBFeeType.sol';\n\ninterface IJBFeeGauge3_1 {\n function currentDiscountFor(uint256 projectId, JBFeeType feeType) external view returns (uint256);\n}\n" + }, + "contracts/JBETHPaymentTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Address} from '@openzeppelin/contracts/utils/Address.sol';\nimport {JBPayoutRedemptionPaymentTerminal} from './abstract/JBPayoutRedemptionPaymentTerminal.sol';\nimport {JBSplitsGroups} from './libraries/JBSplitsGroups.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {JBCurrencies} from './libraries/JBCurrencies.sol';\nimport {JBTokens} from './libraries/JBTokens.sol';\n\n/// @notice Manages all inflows and outflows of ETH funds into the protocol ecosystem.\ncontract JBETHPaymentTerminal is JBPayoutRedemptionPaymentTerminal {\n //*********************************************************************//\n // -------------------------- internal views ------------------------- //\n //*********************************************************************//\n\n /// @notice Checks the balance of tokens in this contract.\n /// @return The contract's balance, as a fixed point number with the same amount of decimals as this terminal.\n function _balance() internal view override returns (uint256) {\n return address(this).balance;\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _prices A contract that exposes price feeds.\n /// @param _store A contract that stores the terminal's data.\n /// @param _owner The address that will own this contract.\n constructor(\n uint256 _baseWeightCurrency,\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBSplitsStore _splitsStore,\n IJBPrices _prices,\n address _store,\n address _owner\n )\n JBPayoutRedemptionPaymentTerminal(\n JBTokens.ETH,\n 18, // 18 decimals.\n JBCurrencies.ETH,\n _baseWeightCurrency,\n JBSplitsGroups.ETH_PAYOUT,\n _operatorStore,\n _projects,\n _directory,\n _splitsStore,\n _prices,\n _store,\n _owner\n )\n // solhint-disable-next-line no-empty-blocks\n {\n\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Transfers tokens.\n /// @param _from The address from which the transfer should originate.\n /// @param _to The address to which the transfer should go.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _transferFrom(address _from, address payable _to, uint256 _amount) internal override {\n _from; // Prevents unused var compiler and natspec complaints.\n\n Address.sendValue(_to, _amount);\n }\n}\n" + }, + "contracts/abstract/JBPayoutRedemptionPaymentTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {IJBAllowanceTerminal} from './../interfaces/IJBAllowanceTerminal.sol';\nimport {IJBController} from './../interfaces/IJBController.sol';\nimport {IJBDirectory} from './../interfaces/IJBDirectory.sol';\nimport {IJBPayoutRedemptionPaymentTerminal} from './../interfaces/IJBPayoutRedemptionPaymentTerminal.sol';\nimport {IJBSplitAllocator} from './../interfaces/IJBSplitAllocator.sol';\nimport {IJBFeeGauge} from './../interfaces/IJBFeeGauge.sol';\nimport {IJBOperatable} from './../interfaces/IJBOperatable.sol';\nimport {IJBOperatorStore} from './../interfaces/IJBOperatorStore.sol';\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\nimport {IJBPayoutTerminal} from './../interfaces/IJBPayoutTerminal.sol';\nimport {IJBPrices} from './../interfaces/IJBPrices.sol';\nimport {IJBProjects} from './../interfaces/IJBProjects.sol';\nimport {IJBRedemptionTerminal} from './../interfaces/IJBRedemptionTerminal.sol';\nimport {IJBSingleTokenPaymentTerminalStore} from './../interfaces/IJBSingleTokenPaymentTerminalStore.sol';\nimport {IJBSplitsStore} from './../interfaces/IJBSplitsStore.sol';\nimport {JBConstants} from './../libraries/JBConstants.sol';\nimport {JBCurrencies} from './../libraries/JBCurrencies.sol';\nimport {JBFixedPointNumber} from './../libraries/JBFixedPointNumber.sol';\nimport {JBFundingCycleMetadataResolver} from './../libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBOperations} from './../libraries/JBOperations.sol';\nimport {JBTokens} from './../libraries/JBTokens.sol';\nimport {JBDidPayData} from './../structs/JBDidPayData.sol';\nimport {JBDidRedeemData} from './../structs/JBDidRedeemData.sol';\nimport {JBFee} from './../structs/JBFee.sol';\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\nimport {JBPayDelegateAllocation} from './../structs/JBPayDelegateAllocation.sol';\nimport {JBTokenAmount} from './../structs/JBTokenAmount.sol';\nimport {JBRedemptionDelegateAllocation} from './../structs/JBRedemptionDelegateAllocation.sol';\nimport {JBSplit} from './../structs/JBSplit.sol';\nimport {JBSplitAllocationData} from './../structs/JBSplitAllocationData.sol';\nimport {JBOperatable} from './JBOperatable.sol';\nimport {JBSingleTokenPaymentTerminal} from './JBSingleTokenPaymentTerminal.sol';\n\n/// @notice Generic terminal managing all inflows and outflows of funds into the protocol ecosystem.\n/// A project can transfer its funds, along with the power to reconfigure and mint/burn their tokens, from this contract to another allowed terminal of the same token type contract at any time.\nabstract contract JBPayoutRedemptionPaymentTerminal is\n JBSingleTokenPaymentTerminal,\n JBOperatable,\n Ownable,\n IJBPayoutRedemptionPaymentTerminal\n{\n // A library that parses the packed funding cycle metadata into a friendlier format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error FEE_TOO_HIGH();\n error INADEQUATE_DISTRIBUTION_AMOUNT();\n error INADEQUATE_RECLAIM_AMOUNT();\n error INADEQUATE_TOKEN_COUNT();\n error NO_MSG_VALUE_ALLOWED();\n error PAY_TO_ZERO_ADDRESS();\n error PROJECT_TERMINAL_MISMATCH();\n error REDEEM_TO_ZERO_ADDRESS();\n error TERMINAL_IN_SPLIT_ZERO_ADDRESS();\n error TERMINAL_TOKENS_INCOMPATIBLE();\n\n //*********************************************************************//\n // ---------------------------- modifiers ---------------------------- //\n //*********************************************************************//\n\n /// @notice A modifier that verifies this terminal is a terminal of provided project ID.\n modifier isTerminalOf(uint256 _projectId) {\n if (!directory.isTerminalOf(_projectId, this)) revert PROJECT_TERMINAL_MISMATCH();\n _;\n }\n\n //*********************************************************************//\n // --------------------- internal stored constants ------------------- //\n //*********************************************************************//\n\n /// @notice Maximum fee that can be set for a funding cycle configuration.\n /// @dev Out of MAX_FEE (50_000_000 / 1_000_000_000).\n uint256 internal constant _FEE_CAP = 50_000_000;\n\n /// @notice The fee beneficiary project ID is 1, as it should be the first project launched during the deployment process.\n uint256 internal constant _FEE_BENEFICIARY_PROJECT_ID = 1;\n\n //*********************************************************************//\n // --------------------- internal stored properties ------------------ //\n //*********************************************************************//\n\n /// @notice Fees that are being held to be processed later.\n /// @custom:param _projectId The ID of the project for which fees are being held.\n mapping(uint256 => JBFee[]) internal _heldFeesOf;\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice Mints ERC-721's that represent project ownership and transfers.\n IJBProjects public immutable override projects;\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n /// @notice The contract that stores splits for each project.\n IJBSplitsStore public immutable override splitsStore;\n\n /// @notice The contract that exposes price feeds.\n IJBPrices public immutable override prices;\n\n /// @notice The contract that stores and manages the terminal's data.\n address public immutable override store;\n\n /// @notice The currency to base token issuance on.\n /// @dev If this differs from `currency`, there must be a price feed available to convert `currency` to `baseWeightCurrency`.\n uint256 public immutable override baseWeightCurrency;\n\n /// @notice The group that payout splits coming from this terminal are identified by.\n uint256 public immutable override payoutSplitsGroup;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The platform fee percent.\n /// @dev Out of MAX_FEE (25_000_000 / 1_000_000_000)\n uint256 public override fee = 25_000_000; // 2.5%\n\n /// @notice The data source that returns a discount to apply to a project's fee.\n address public override feeGauge;\n\n /// @notice Addresses that can be paid towards from this terminal without incurring a fee.\n /// @dev Only addresses that are considered to be contained within the ecosystem can be feeless. Funds sent outside the ecosystem may incur fees despite being stored as feeless.\n /// @custom:param _address The address that can be paid toward.\n mapping(address => bool) public override isFeelessAddress;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Gets the current overflowed amount in this terminal for a specified project, in terms of ETH.\n /// @dev The current overflow is represented as a fixed point number with 18 decimals.\n /// @param _projectId The ID of the project to get overflow for.\n /// @return The current amount of ETH overflow that project has in this terminal, as a fixed point number with 18 decimals.\n function currentEthOverflowOf(\n uint256 _projectId\n ) external view virtual override returns (uint256) {\n // Get this terminal's current overflow.\n uint256 _overflow = IJBSingleTokenPaymentTerminalStore(store).currentOverflowOf(\n this,\n _projectId\n );\n\n // Adjust the decimals of the fixed point number if needed to have 18 decimals.\n uint256 _adjustedOverflow = (decimals == 18)\n ? _overflow\n : JBFixedPointNumber.adjustDecimals(_overflow, decimals, 18);\n\n // Return the amount converted to ETH.\n return\n (currency == JBCurrencies.ETH)\n ? _adjustedOverflow\n : PRBMath.mulDiv(\n _adjustedOverflow,\n 10 ** decimals,\n prices.priceFor(currency, JBCurrencies.ETH, decimals)\n );\n }\n\n /// @notice The fees that are currently being held to be processed later for each project.\n /// @param _projectId The ID of the project for which fees are being held.\n /// @return An array of fees that are being held.\n function heldFeesOf(uint256 _projectId) external view override returns (JBFee[] memory) {\n return _heldFeesOf[_projectId];\n }\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if the provided interface ID is supported.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(JBSingleTokenPaymentTerminal, IERC165) returns (bool) {\n return\n _interfaceId == type(IJBPayoutRedemptionPaymentTerminal).interfaceId ||\n _interfaceId == type(IJBPayoutTerminal).interfaceId ||\n _interfaceId == type(IJBAllowanceTerminal).interfaceId ||\n _interfaceId == type(IJBRedemptionTerminal).interfaceId ||\n _interfaceId == type(IJBOperatable).interfaceId ||\n super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // -------------------------- internal views ------------------------- //\n //*********************************************************************//\n\n /// @notice Checks the balance of tokens in this contract.\n /// @return The contract's balance.\n function _balance() internal view virtual returns (uint256);\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _token The token that this terminal manages.\n /// @param _decimals The number of decimals the token fixed point amounts are expected to have.\n /// @param _currency The currency that this terminal's token adheres to for price feeds.\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _payoutSplitsGroup The group that denotes payout splits from this terminal in the splits store.\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _prices A contract that exposes price feeds.\n /// @param _store A contract that stores the terminal's data.\n /// @param _owner The address that will own this contract.\n constructor(\n // payable constructor save the gas used to check msg.value==0\n address _token,\n uint256 _decimals,\n uint256 _currency,\n uint256 _baseWeightCurrency,\n uint256 _payoutSplitsGroup,\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBSplitsStore _splitsStore,\n IJBPrices _prices,\n address _store,\n address _owner\n )\n payable\n JBSingleTokenPaymentTerminal(_token, _decimals, _currency)\n JBOperatable(_operatorStore)\n {\n baseWeightCurrency = _baseWeightCurrency;\n payoutSplitsGroup = _payoutSplitsGroup;\n projects = _projects;\n directory = _directory;\n splitsStore = _splitsStore;\n prices = _prices;\n store = _store;\n\n transferOwnership(_owner);\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Contribute tokens to a project.\n /// @param _projectId The ID of the project being paid.\n /// @param _amount The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place.\n /// @param _token The token being paid. This terminal ignores this property since it only manages one token.\n /// @param _beneficiary The address to mint tokens for and pass along to the funding cycle's data source and delegate.\n /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\n /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals.\n function pay(\n uint256 _projectId,\n uint256 _amount,\n address _token,\n address _beneficiary,\n uint256 _minReturnedTokens,\n bool _preferClaimedTokens,\n string calldata _memo,\n bytes calldata _metadata\n ) external payable virtual override isTerminalOf(_projectId) returns (uint256) {\n _token; // Prevents unused var compiler and natspec complaints.\n\n // ETH shouldn't be sent if this terminal's token isn't ETH.\n if (token != JBTokens.ETH) {\n if (msg.value > 0) revert NO_MSG_VALUE_ALLOWED();\n\n // Get a reference to the balance before receiving tokens.\n uint256 _balanceBefore = _balance();\n\n // Transfer tokens to this terminal from the msg sender.\n _transferFrom(msg.sender, payable(address(this)), _amount);\n\n // The amount should reflect the change in balance.\n _amount = _balance() - _balanceBefore;\n }\n // If this terminal's token is ETH, override _amount with msg.value.\n else _amount = msg.value;\n\n return\n _pay(\n _amount,\n msg.sender,\n _projectId,\n _beneficiary,\n _minReturnedTokens,\n _preferClaimedTokens,\n _memo,\n _metadata\n );\n }\n\n /// @notice Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source.\n /// @dev Only a token holder or a designated operator can redeem its tokens.\n /// @param _holder The account to redeem tokens for.\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\n /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals.\n /// @param _token The token being reclaimed. This terminal ignores this property since it only manages one token.\n /// @param _minReturnedTokens The minimum amount of terminal tokens expected in return, as a fixed point number with the same amount of decimals as the terminal.\n /// @param _beneficiary The address to send the terminal tokens to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return reclaimAmount The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals.\n function redeemTokensOf(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n address _token,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo,\n bytes memory _metadata\n )\n external\n virtual\n override\n requirePermission(_holder, _projectId, JBOperations.REDEEM)\n returns (uint256 reclaimAmount)\n {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return\n _redeemTokensOf(\n _holder,\n _projectId,\n _tokenCount,\n _minReturnedTokens,\n _beneficiary,\n _memo,\n _metadata\n );\n }\n\n /// @notice Distributes payouts for a project with the distribution limit of its current funding cycle.\n /// @dev Payouts are sent to the preprogrammed splits. Any leftover is sent to the project's owner.\n /// @dev 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.\n /// @dev All funds distributed outside of this contract or any feeless terminals incure the protocol fee.\n /// @param _projectId The ID of the project having its payouts distributed.\n /// @param _amount The amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency.\n /// @param _token The token being distributed. This terminal ignores this property since it only manages one token.\n /// @param _minReturnedTokens 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.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return netLeftoverDistributionAmount The amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal.\n function distributePayoutsOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n address _token,\n uint256 _minReturnedTokens,\n string calldata _memo\n ) external virtual override returns (uint256 netLeftoverDistributionAmount) {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return _distributePayoutsOf(_projectId, _amount, _currency, _minReturnedTokens, _memo);\n }\n\n /// @notice Allows a project to send funds from its overflow up to the preconfigured allowance.\n /// @dev Only a project's owner or a designated operator can use its allowance.\n /// @dev Incurs the protocol fee.\n /// @param _projectId The ID of the project to use the allowance of.\n /// @param _amount The amount of terminal tokens to use from this project's current allowance, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's overflow allowance currency.\n /// @param _token The token being distributed. This terminal ignores this property since it only manages one token.\n /// @param _minReturnedTokens The minimum number of tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with 18 decimals.\n /// @param _beneficiary The address to send the funds to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return netDistributedAmount The amount of tokens that was distributed to the beneficiary, as a fixed point number with the same amount of decimals as the terminal.\n function useAllowanceOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n address _token,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.USE_ALLOWANCE)\n returns (uint256 netDistributedAmount)\n {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return _useAllowanceOf(_projectId, _amount, _currency, _minReturnedTokens, _beneficiary, _memo);\n }\n\n /// @notice Allows a project owner to migrate its funds and operations to a new terminal that accepts the same token type.\n /// @dev Only a project's owner or a designated operator can migrate it.\n /// @param _projectId The ID of the project being migrated.\n /// @param _to The terminal contract that will gain the project's funds.\n /// @return balance The amount of funds that were migrated, as a fixed point number with the same amount of decimals as this terminal.\n function migrate(\n uint256 _projectId,\n IJBPaymentTerminal _to\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.MIGRATE_TERMINAL)\n returns (uint256 balance)\n {\n // The terminal being migrated to must accept the same token as this terminal.\n if (!_to.acceptsToken(token, _projectId)) revert TERMINAL_TOKENS_INCOMPATIBLE();\n\n // Record the migration in the store.\n balance = IJBSingleTokenPaymentTerminalStore(store).recordMigration(_projectId);\n\n // Transfer the balance if needed.\n if (balance > 0) {\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_to), balance);\n\n // If this terminal's token is ETH, send it in msg.value.\n uint256 _payableValue = token == JBTokens.ETH ? balance : 0;\n\n // Withdraw the balance to transfer to the new terminal;\n _to.addToBalanceOf{value: _payableValue}(_projectId, balance, token, '', bytes(''));\n }\n\n emit Migrate(_projectId, _to, balance, msg.sender);\n }\n\n /// @notice Receives funds belonging to the specified project.\n /// @param _projectId The ID of the project to which the funds received belong.\n /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\n /// @param _token The token being paid. This terminal ignores this property since it only manages one currency.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the emitted event.\n function addToBalanceOf(\n uint256 _projectId,\n uint256 _amount,\n address _token,\n string calldata _memo,\n bytes calldata _metadata\n ) external payable virtual override isTerminalOf(_projectId) {\n _token; // Prevents unused var compiler and natspec complaints.\n\n // If this terminal's token isn't ETH, make sure no msg.value was sent, then transfer the tokens in from msg.sender.\n if (token != JBTokens.ETH) {\n // Amount must be greater than 0.\n if (msg.value > 0) revert NO_MSG_VALUE_ALLOWED();\n\n // Get a reference to the balance before receiving tokens.\n uint256 _balanceBefore = _balance();\n\n // Transfer tokens to this terminal from the msg sender.\n _transferFrom(msg.sender, payable(address(this)), _amount);\n\n // The amount should reflect the change in balance.\n _amount = _balance() - _balanceBefore;\n }\n // If the terminal's token is ETH, override `_amount` with msg.value.\n else _amount = msg.value;\n\n // Add to balance while only refunding held fees if the funds aren't originating from a feeless terminal.\n _addToBalanceOf(_projectId, _amount, !isFeelessAddress[msg.sender], _memo, _metadata);\n }\n\n /// @notice Process any fees that are being held for the project.\n /// @dev Only a project owner, an operator, or the contract's owner can process held fees.\n /// @param _projectId The ID of the project whos held fees should be processed.\n function processFees(\n uint256 _projectId\n )\n external\n virtual\n override\n requirePermissionAllowingOverride(\n projects.ownerOf(_projectId),\n _projectId,\n JBOperations.PROCESS_FEES,\n msg.sender == owner()\n )\n {\n // Get a reference to the project's held fees.\n JBFee[] memory _heldFees = _heldFeesOf[_projectId];\n\n // Delete the held fees.\n delete _heldFeesOf[_projectId];\n\n // Push array length in stack\n uint256 _heldFeeLength = _heldFees.length;\n\n // Process each fee.\n for (uint256 _i; _i < _heldFeeLength; ) {\n // Get the fee amount.\n uint256 _amount = _feeAmount(\n _heldFees[_i].amount,\n _heldFees[_i].fee,\n _heldFees[_i].feeDiscount\n );\n\n // Process the fee.\n _processFee(_amount, _heldFees[_i].beneficiary);\n\n emit ProcessFee(_projectId, _amount, true, _heldFees[_i].beneficiary, msg.sender);\n\n unchecked {\n ++_i;\n }\n }\n }\n\n /// @notice Allows the fee to be updated.\n /// @dev Only the owner of this contract can change the fee.\n /// @param _fee The new fee, out of MAX_FEE.\n function setFee(uint256 _fee) external virtual override onlyOwner {\n // The provided fee must be within the max.\n if (_fee > _FEE_CAP) revert FEE_TOO_HIGH();\n\n // Store the new fee.\n fee = _fee;\n\n emit SetFee(_fee, msg.sender);\n }\n\n /// @notice Allows the fee gauge to be updated.\n /// @dev Only the owner of this contract can change the fee gauge.\n /// @param _feeGauge The new fee gauge.\n function setFeeGauge(address _feeGauge) external virtual override onlyOwner {\n // Store the new fee gauge.\n feeGauge = _feeGauge;\n\n emit SetFeeGauge(_feeGauge, msg.sender);\n }\n\n /// @notice Sets whether projects operating on this terminal can pay towards the specified address without incurring a fee.\n /// @dev Only the owner of this contract can set addresses as feeless.\n /// @param _address The address that can be paid towards while still bypassing fees.\n /// @param _flag A flag indicating whether the terminal should be feeless or not.\n function setFeelessAddress(address _address, bool _flag) external virtual override onlyOwner {\n // Set the flag value.\n isFeelessAddress[_address] = _flag;\n\n emit SetFeelessAddress(_address, _flag, msg.sender);\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Transfers tokens.\n /// @param _from The address from which the transfer should originate.\n /// @param _to The address to which the transfer should go.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _transferFrom(address _from, address payable _to, uint256 _amount) internal virtual {\n _from; // Prevents unused var compiler and natspec complaints.\n _to; // Prevents unused var compiler and natspec complaints.\n _amount; // Prevents unused var compiler and natspec complaints.\n }\n\n /// @notice Logic to be triggered before transferring tokens from this terminal.\n /// @param _to The address to which the transfer is going.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _beforeTransferTo(address _to, uint256 _amount) internal virtual {\n _to; // Prevents unused var compiler and natspec complaints.\n _amount; // Prevents unused var compiler and natspec complaints.\n }\n\n /// @notice Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source.\n /// @dev Only a token holder or a designated operator can redeem its tokens.\n /// @param _holder The account to redeem tokens for.\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\n /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals.\n /// @param _minReturnedTokens The minimum amount of terminal tokens expected in return, as a fixed point number with the same amount of decimals as the terminal.\n /// @param _beneficiary The address to send the terminal tokens to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return reclaimAmount The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals.\n function _redeemTokensOf(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo,\n bytes memory _metadata\n ) internal returns (uint256 reclaimAmount) {\n // Can't send reclaimed funds to the zero address.\n if (_beneficiary == address(0)) revert REDEEM_TO_ZERO_ADDRESS();\n\n // Define variables that will be needed outside the scoped section below.\n // Keep a reference to the funding cycle during which the redemption is being made.\n JBFundingCycle memory _fundingCycle;\n\n // Scoped section prevents stack too deep. `_delegateAllocations` only used within scope.\n {\n JBRedemptionDelegateAllocation[] memory _delegateAllocations;\n\n // Record the redemption.\n (\n _fundingCycle,\n reclaimAmount,\n _delegateAllocations,\n _memo\n ) = IJBSingleTokenPaymentTerminalStore(store).recordRedemptionFor(\n _holder,\n _projectId,\n _tokenCount,\n _memo,\n _metadata\n );\n\n // The amount being reclaimed must be at least as much as was expected.\n if (reclaimAmount < _minReturnedTokens) revert INADEQUATE_RECLAIM_AMOUNT();\n\n // Burn the project tokens.\n if (_tokenCount > 0)\n IJBController(directory.controllerOf(_projectId)).burnTokensOf(\n _holder,\n _projectId,\n _tokenCount,\n '',\n false\n );\n\n // If delegate allocations were specified by the data source, fulfill them.\n if (_delegateAllocations.length != 0) {\n // Keep a reference to the token amount being forwarded to the delegate.\n JBTokenAmount memory _forwardedAmount = JBTokenAmount(token, 0, decimals, currency);\n\n JBDidRedeemData memory _data = JBDidRedeemData(\n _holder,\n _projectId,\n _fundingCycle.configuration,\n _tokenCount,\n JBTokenAmount(token, reclaimAmount, decimals, currency),\n _forwardedAmount,\n _beneficiary,\n _memo,\n _metadata\n );\n\n uint256 _numDelegates = _delegateAllocations.length;\n\n for (uint256 _i; _i < _numDelegates; ) {\n // Get a reference to the delegate being iterated on.\n JBRedemptionDelegateAllocation memory _delegateAllocation = _delegateAllocations[_i];\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_delegateAllocation.delegate), _delegateAllocation.amount);\n\n // Keep track of the msg.value to use in the delegate call\n uint256 _payableValue;\n\n // If this terminal's token is ETH, send it in msg.value.\n if (token == JBTokens.ETH) _payableValue = _delegateAllocation.amount;\n\n // Pass the correct token forwardedAmount to the delegate\n _data.forwardedAmount.value = _delegateAllocation.amount;\n\n _delegateAllocation.delegate.didRedeem{value: _payableValue}(_data);\n\n emit DelegateDidRedeem(\n _delegateAllocation.delegate,\n _data,\n _delegateAllocation.amount,\n msg.sender\n );\n unchecked {\n ++_i;\n }\n }\n }\n }\n\n // Send the reclaimed funds to the beneficiary.\n if (reclaimAmount > 0) _transferFrom(address(this), _beneficiary, reclaimAmount);\n\n emit RedeemTokens(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _holder,\n _beneficiary,\n _tokenCount,\n reclaimAmount,\n _memo,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Distributes payouts for a project with the distribution limit of its current funding cycle.\n /// @dev Payouts are sent to the preprogrammed splits. Any leftover is sent to the project's owner.\n /// @dev 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.\n /// @dev All funds distributed outside of this contract or any feeless terminals incure the protocol fee.\n /// @param _projectId The ID of the project having its payouts distributed.\n /// @param _amount The amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency.\n /// @param _minReturnedTokens 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.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return netLeftoverDistributionAmount The amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal.\n function _distributePayoutsOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n uint256 _minReturnedTokens,\n string calldata _memo\n ) internal returns (uint256 netLeftoverDistributionAmount) {\n // Record the distribution.\n (\n JBFundingCycle memory _fundingCycle,\n uint256 _distributedAmount\n ) = IJBSingleTokenPaymentTerminalStore(store).recordDistributionFor(\n _projectId,\n _amount,\n _currency\n );\n\n // The amount being distributed must be at least as much as was expected.\n if (_distributedAmount < _minReturnedTokens) revert INADEQUATE_DISTRIBUTION_AMOUNT();\n\n // Get a reference to the project owner, which will receive tokens from paying the platform fee\n // and receive any extra distributable funds not allocated to payout splits.\n address payable _projectOwner = payable(projects.ownerOf(_projectId));\n\n // Define variables that will be needed outside the scoped section below.\n // Keep a reference to the fee amount that was paid.\n uint256 _fee;\n\n // Scoped section prevents stack too deep. `_feeDiscount`, `_feeEligibleDistributionAmount`, and `_leftoverDistributionAmount` only used within scope.\n {\n // Get the amount of discount that should be applied to any fees taken.\n // If the fee is zero, set the discount to 100% for convenience.\n uint256 _feeDiscount = fee == 0\n ? JBConstants.MAX_FEE_DISCOUNT\n : _currentFeeDiscount(_projectId);\n\n // The amount distributed that is eligible for incurring fees.\n uint256 _feeEligibleDistributionAmount;\n\n // The amount leftover after distributing to the splits.\n uint256 _leftoverDistributionAmount;\n\n // Payout to splits and get a reference to the leftover transfer amount after all splits have been paid.\n // Also get a reference to the amount that was distributed to splits from which fees should be taken.\n (_leftoverDistributionAmount, _feeEligibleDistributionAmount) = _distributeToPayoutSplitsOf(\n _projectId,\n _fundingCycle.configuration,\n payoutSplitsGroup,\n _distributedAmount,\n _feeDiscount\n );\n\n if (_feeDiscount != JBConstants.MAX_FEE_DISCOUNT) {\n // Leftover distribution amount is also eligible for a fee since the funds are going out of the ecosystem to _beneficiary.\n unchecked {\n _feeEligibleDistributionAmount += _leftoverDistributionAmount;\n }\n }\n\n // Take the fee.\n _fee = _feeEligibleDistributionAmount != 0\n ? _takeFeeFrom(\n _projectId,\n _fundingCycle,\n _feeEligibleDistributionAmount,\n _projectOwner,\n _feeDiscount\n )\n : 0;\n\n // Transfer any remaining balance to the project owner and update returned leftover accordingly.\n if (_leftoverDistributionAmount != 0) {\n // Subtract the fee from the net leftover amount.\n netLeftoverDistributionAmount =\n _leftoverDistributionAmount -\n _feeAmount(_leftoverDistributionAmount, fee, _feeDiscount);\n\n // Transfer the amount to the project owner.\n _transferFrom(address(this), _projectOwner, netLeftoverDistributionAmount);\n }\n }\n\n emit DistributePayouts(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _projectOwner,\n _amount,\n _distributedAmount,\n _fee,\n netLeftoverDistributionAmount,\n _memo,\n msg.sender\n );\n }\n\n /// @notice Allows a project to send funds from its overflow up to the preconfigured allowance.\n /// @dev Only a project's owner or a designated operator can use its allowance.\n /// @dev Incurs the protocol fee.\n /// @param _projectId The ID of the project to use the allowance of.\n /// @param _amount The amount of terminal tokens to use from this project's current allowance, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's overflow allowance currency.\n /// @param _minReturnedTokens The minimum number of tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with 18 decimals.\n /// @param _beneficiary The address to send the funds to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return netDistributedAmount The amount of tokens that was distributed to the beneficiary, as a fixed point number with the same amount of decimals as the terminal.\n function _useAllowanceOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo\n ) internal returns (uint256 netDistributedAmount) {\n // Record the use of the allowance.\n (\n JBFundingCycle memory _fundingCycle,\n uint256 _distributedAmount\n ) = IJBSingleTokenPaymentTerminalStore(store).recordUsedAllowanceOf(\n _projectId,\n _amount,\n _currency\n );\n\n // The amount being withdrawn must be at least as much as was expected.\n if (_distributedAmount < _minReturnedTokens) revert INADEQUATE_DISTRIBUTION_AMOUNT();\n\n // Scoped section prevents stack too deep. `_fee`, `_projectOwner`, `_feeDiscount`, and `_netAmount` only used within scope.\n {\n // Keep a reference to the fee amount that was paid.\n uint256 _fee;\n\n // Get a reference to the project owner, which will receive tokens from paying the platform fee.\n address _projectOwner = projects.ownerOf(_projectId);\n\n // Get the amount of discount that should be applied to any fees taken.\n // 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.\n uint256 _feeDiscount = fee == 0 || isFeelessAddress[msg.sender]\n ? JBConstants.MAX_FEE_DISCOUNT\n : _currentFeeDiscount(_projectId);\n\n // Take a fee from the `_distributedAmount`, if needed.\n _fee = _feeDiscount == JBConstants.MAX_FEE_DISCOUNT\n ? 0\n : _takeFeeFrom(_projectId, _fundingCycle, _distributedAmount, _projectOwner, _feeDiscount);\n\n unchecked {\n // The net amount is the withdrawn amount without the fee.\n netDistributedAmount = _distributedAmount - _fee;\n }\n\n // Transfer any remaining balance to the beneficiary.\n if (netDistributedAmount > 0)\n _transferFrom(address(this), _beneficiary, netDistributedAmount);\n }\n\n emit UseAllowance(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _beneficiary,\n _amount,\n _distributedAmount,\n netDistributedAmount,\n _memo,\n msg.sender\n );\n }\n\n /// @notice Pays out splits for a project's funding cycle configuration.\n /// @param _projectId The ID of the project for which payout splits are being distributed.\n /// @param _domain The domain of the splits to distribute the payout between.\n /// @param _group The group of the splits to distribute the payout between.\n /// @param _amount The total amount being distributed, as a fixed point number with the same number of decimals as this terminal.\n /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE.\n /// @return leftoverAmount If the leftover amount if the splits don't add up to 100%.\n /// @return feeEligibleDistributionAmount The total amount of distributions that are eligible to have fees taken from.\n function _distributeToPayoutSplitsOf(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group,\n uint256 _amount,\n uint256 _feeDiscount\n ) internal returns (uint256 leftoverAmount, uint256 feeEligibleDistributionAmount) {\n // Set the leftover amount to the initial amount.\n leftoverAmount = _amount;\n // The total percentage available to split\n uint256 leftoverPercentage = JBConstants.SPLITS_TOTAL_PERCENT;\n\n // Get a reference to the project's payout splits.\n JBSplit[] memory _splits = splitsStore.splitsOf(_projectId, _domain, _group);\n\n // Transfer between all splits.\n for (uint256 _i; _i < _splits.length; ) {\n // Get a reference to the split being iterated on.\n JBSplit memory _split = _splits[_i];\n\n // The amount to send towards the split.\n uint256 _payoutAmount = _split.percent == leftoverPercentage\n ? leftoverAmount\n : PRBMath.mulDiv(_amount, _split.percent, JBConstants.SPLITS_TOTAL_PERCENT);\n\n // Decrement the leftover percentage.\n leftoverPercentage -= _split.percent;\n\n // The payout amount substracting any applicable incurred fees.\n uint256 _netPayoutAmount;\n\n if (_payoutAmount > 0) {\n // Transfer tokens to the split.\n // If there's an allocator set, transfer to its `allocate` function.\n if (_split.allocator != IJBSplitAllocator(address(0))) {\n // If the split allocator is set as feeless, this distribution is not eligible for a fee.\n if (\n _feeDiscount == JBConstants.MAX_FEE_DISCOUNT ||\n isFeelessAddress[address(_split.allocator)]\n )\n _netPayoutAmount = _payoutAmount;\n // This distribution is eligible for a fee since the funds are leaving this contract and the allocator isn't listed as feeless.\n else {\n unchecked {\n _netPayoutAmount = _payoutAmount - _feeAmount(_payoutAmount, fee, _feeDiscount);\n }\n\n // This distribution is eligible for a fee since the funds are leaving the ecosystem.\n feeEligibleDistributionAmount += _payoutAmount;\n }\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_split.allocator), _netPayoutAmount);\n\n // Create the data to send to the allocator.\n JBSplitAllocationData memory _data = JBSplitAllocationData(\n token,\n _netPayoutAmount,\n decimals,\n _projectId,\n _group,\n _split\n );\n\n // Trigger the allocator's `allocate` function.\n // If this terminal's token is ETH, send it in msg.value.\n _split.allocator.allocate{value: token == JBTokens.ETH ? _netPayoutAmount : 0}(_data);\n\n // Otherwise, if a project is specified, make a payment to it.\n } else if (_split.projectId != 0) {\n // Get a reference to the Juicebox terminal being used.\n IJBPaymentTerminal _terminal = directory.primaryTerminalOf(_split.projectId, token);\n\n // The project must have a terminal to send funds to.\n if (_terminal == IJBPaymentTerminal(address(0))) revert TERMINAL_IN_SPLIT_ZERO_ADDRESS();\n\n // Save gas if this contract is being used as the terminal.\n if (_terminal == this) {\n // This distribution does not incur a fee.\n _netPayoutAmount = _payoutAmount;\n\n // Send the projectId in the metadata.\n bytes memory _projectMetadata = new bytes(32);\n _projectMetadata = bytes(abi.encodePacked(_projectId));\n\n // Add to balance if prefered.\n if (_split.preferAddToBalance)\n _addToBalanceOf(_split.projectId, _netPayoutAmount, false, '', _projectMetadata);\n else\n _pay(\n _netPayoutAmount,\n address(this),\n _split.projectId,\n (_split.beneficiary != address(0)) ? _split.beneficiary : msg.sender,\n 0,\n _split.preferClaimed,\n '',\n _projectMetadata\n );\n } else {\n // If the terminal is set as feeless, this distribution is not eligible for a fee.\n if (\n _feeDiscount == JBConstants.MAX_FEE_DISCOUNT || isFeelessAddress[address(_terminal)]\n )\n _netPayoutAmount = _payoutAmount;\n // This distribution is eligible for a fee since the funds are leaving this contract and the terminal isn't listed as feeless.\n else {\n unchecked {\n _netPayoutAmount = _payoutAmount - _feeAmount(_payoutAmount, fee, _feeDiscount);\n }\n\n feeEligibleDistributionAmount += _payoutAmount;\n }\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_terminal), _netPayoutAmount);\n\n // If this terminal's token is ETH, send it in msg.value.\n uint256 _payableValue = token == JBTokens.ETH ? _netPayoutAmount : 0;\n\n // Send the projectId in the metadata.\n bytes memory _projectMetadata = new bytes(32);\n _projectMetadata = bytes(abi.encodePacked(_projectId));\n\n // Add to balance if prefered.\n if (_split.preferAddToBalance)\n _terminal.addToBalanceOf{value: _payableValue}(\n _split.projectId,\n _netPayoutAmount,\n token,\n '',\n _projectMetadata\n );\n else\n _terminal.pay{value: _payableValue}(\n _split.projectId,\n _netPayoutAmount,\n token,\n _split.beneficiary != address(0) ? _split.beneficiary : msg.sender,\n 0,\n _split.preferClaimed,\n '',\n _projectMetadata\n );\n }\n } else {\n // Keep a reference to the beneficiary.\n address payable _beneficiary = _split.beneficiary != address(0)\n ? _split.beneficiary\n : payable(msg.sender);\n\n // If there's a full discount, this distribution is not eligible for a fee.\n // Don't enforce feeless address for the beneficiary since the funds are leaving the ecosystem.\n if (_feeDiscount == JBConstants.MAX_FEE_DISCOUNT)\n _netPayoutAmount = _payoutAmount;\n // This distribution is eligible for a fee since the funds are leaving this contract and the beneficiary isn't listed as feeless.\n else {\n unchecked {\n _netPayoutAmount = _payoutAmount - _feeAmount(_payoutAmount, fee, _feeDiscount);\n }\n\n feeEligibleDistributionAmount += _payoutAmount;\n }\n\n // If there's a beneficiary, send the funds directly to the beneficiary. Otherwise send to the msg.sender.\n _transferFrom(address(this), _beneficiary, _netPayoutAmount);\n }\n\n // Subtract from the amount to be sent to the beneficiary.\n unchecked {\n leftoverAmount = leftoverAmount - _payoutAmount;\n }\n }\n\n emit DistributeToPayoutSplit(\n _projectId,\n _domain,\n _group,\n _split,\n _netPayoutAmount,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n\n /// @notice Takes a fee into the platform's project, which has an id of _FEE_BENEFICIARY_PROJECT_ID.\n /// @param _projectId The ID of the project having fees taken from.\n /// @param _fundingCycle The funding cycle during which the fee is being taken.\n /// @param _amount The amount of the fee to take, as a floating point number with 18 decimals.\n /// @param _beneficiary The address to mint the platforms tokens for.\n /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE.\n /// @return feeAmount The amount of the fee taken.\n function _takeFeeFrom(\n uint256 _projectId,\n JBFundingCycle memory _fundingCycle,\n uint256 _amount,\n address _beneficiary,\n uint256 _feeDiscount\n ) internal returns (uint256 feeAmount) {\n feeAmount = _feeAmount(_amount, fee, _feeDiscount);\n\n if (_fundingCycle.shouldHoldFees()) {\n // Store the held fee.\n _heldFeesOf[_projectId].push(JBFee(_amount, uint32(fee), uint32(_feeDiscount), _beneficiary));\n\n emit HoldFee(_projectId, _amount, fee, _feeDiscount, _beneficiary, msg.sender);\n } else {\n // Process the fee.\n _processFee(feeAmount, _beneficiary); // Take the fee.\n\n emit ProcessFee(_projectId, feeAmount, false, _beneficiary, msg.sender);\n }\n }\n\n /// @notice Process a fee of the specified amount.\n /// @param _amount The fee amount, as a floating point number with 18 decimals.\n /// @param _beneficiary The address to mint the platform's tokens for.\n function _processFee(uint256 _amount, address _beneficiary) internal {\n // Get the terminal for the protocol project.\n IJBPaymentTerminal _terminal = directory.primaryTerminalOf(_FEE_BENEFICIARY_PROJECT_ID, token);\n\n // When processing the admin fee, save gas if the admin is using this contract as its terminal.\n if (_terminal == this)\n _pay(\n _amount,\n address(this),\n _FEE_BENEFICIARY_PROJECT_ID,\n _beneficiary,\n 0,\n false,\n '',\n bytes('')\n ); // Use the local pay call.\n else {\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_terminal), _amount);\n\n // If this terminal's token is ETH, send it in msg.value.\n uint256 _payableValue = token == JBTokens.ETH ? _amount : 0;\n\n // Send the payment.\n _terminal.pay{value: _payableValue}(\n _FEE_BENEFICIARY_PROJECT_ID,\n _amount,\n token,\n _beneficiary,\n 0,\n false,\n '',\n bytes('')\n ); // Use the external pay call of the correct terminal.\n }\n }\n\n /// @notice Contribute tokens to a project.\n /// @param _amount The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place.\n /// @param _payer The address making the payment.\n /// @param _projectId The ID of the project being paid.\n /// @param _beneficiary The address to mint tokens for and pass along to the funding cycle's data source and delegate.\n /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\n /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return beneficiaryTokenCount The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals.\n function _pay(\n uint256 _amount,\n address _payer,\n uint256 _projectId,\n address _beneficiary,\n uint256 _minReturnedTokens,\n bool _preferClaimedTokens,\n string memory _memo,\n bytes memory _metadata\n ) internal returns (uint256 beneficiaryTokenCount) {\n // Cant send tokens to the zero address.\n if (_beneficiary == address(0)) revert PAY_TO_ZERO_ADDRESS();\n\n // Define variables that will be needed outside the scoped section below.\n // Keep a reference to the funding cycle during which the payment is being made.\n JBFundingCycle memory _fundingCycle;\n\n // Scoped section prevents stack too deep. `_delegateAllocations` and `_tokenCount` only used within scope.\n {\n JBPayDelegateAllocation[] memory _delegateAllocations;\n uint256 _tokenCount;\n\n // Bundle the amount info into a JBTokenAmount struct.\n JBTokenAmount memory _bundledAmount = JBTokenAmount(token, _amount, decimals, currency);\n\n // Record the payment.\n (\n _fundingCycle,\n _tokenCount,\n _delegateAllocations,\n _memo\n ) = IJBSingleTokenPaymentTerminalStore(store).recordPaymentFrom(\n _payer,\n _bundledAmount,\n _projectId,\n baseWeightCurrency,\n _beneficiary,\n _memo,\n _metadata\n );\n\n // Mint the tokens if needed.\n if (_tokenCount > 0)\n // Set token count to be the number of tokens minted for the beneficiary instead of the total amount.\n beneficiaryTokenCount = IJBController(directory.controllerOf(_projectId)).mintTokensOf(\n _projectId,\n _tokenCount,\n _beneficiary,\n '',\n _preferClaimedTokens,\n true\n );\n\n // The token count for the beneficiary must be greater than or equal to the minimum expected.\n if (beneficiaryTokenCount < _minReturnedTokens) revert INADEQUATE_TOKEN_COUNT();\n\n // If delegate allocations were specified by the data source, fulfill them.\n if (_delegateAllocations.length != 0) {\n // Keep a reference to the token amount being forwarded to the delegate.\n JBTokenAmount memory _forwardedAmount = JBTokenAmount(token, _amount, decimals, currency);\n\n JBDidPayData memory _data = JBDidPayData(\n _payer,\n _projectId,\n _fundingCycle.configuration,\n _bundledAmount,\n _forwardedAmount,\n beneficiaryTokenCount,\n _beneficiary,\n _preferClaimedTokens,\n _memo,\n _metadata\n );\n\n // Get a reference to the number of delegates to allocate to.\n uint256 _numDelegates = _delegateAllocations.length;\n\n for (uint256 _i; _i < _numDelegates; ) {\n // Get a reference to the delegate being iterated on.\n JBPayDelegateAllocation memory _delegateAllocation = _delegateAllocations[_i];\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_delegateAllocation.delegate), _delegateAllocation.amount);\n\n // Keep track of the msg.value to use in the delegate call\n uint256 _payableValue;\n\n // If this terminal's token is ETH, send it in msg.value.\n if (token == JBTokens.ETH) _payableValue = _delegateAllocation.amount;\n\n // Pass the correct token forwardedAmount to the delegate\n _data.forwardedAmount.value = _delegateAllocation.amount;\n\n _delegateAllocation.delegate.didPay{value: _payableValue}(_data);\n\n emit DelegateDidPay(\n _delegateAllocation.delegate,\n _data,\n _delegateAllocation.amount,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n }\n\n emit Pay(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _payer,\n _beneficiary,\n _amount,\n beneficiaryTokenCount,\n _memo,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Receives funds belonging to the specified project.\n /// @param _projectId The ID of the project to which the funds received belong.\n /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\n /// @param _shouldRefundHeldFees A flag indicating if held fees should be refunded based on the amount being added.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the emitted event.\n function _addToBalanceOf(\n uint256 _projectId,\n uint256 _amount,\n bool _shouldRefundHeldFees,\n string memory _memo,\n bytes memory _metadata\n ) internal {\n // Refund any held fees to make sure the project doesn't pay double for funds going in and out of the protocol.\n uint256 _refundedFees = _shouldRefundHeldFees ? _refundHeldFees(_projectId, _amount) : 0;\n\n // Record the added funds with any refunded fees.\n IJBSingleTokenPaymentTerminalStore(store).recordAddedBalanceFor(\n _projectId,\n _amount + _refundedFees\n );\n\n emit AddToBalance(_projectId, _amount, _refundedFees, _memo, _metadata, msg.sender);\n }\n\n /// @notice Refund fees based on the specified amount.\n /// @param _projectId The project for which fees are being refunded.\n /// @param _amount The amount to base the refund on, as a fixed point number with the same amount of decimals as this terminal.\n /// @return refundedFees How much fees were refunded, as a fixed point number with the same number of decimals as this terminal\n function _refundHeldFees(\n uint256 _projectId,\n uint256 _amount\n ) internal returns (uint256 refundedFees) {\n // Get a reference to the project's held fees.\n JBFee[] memory _heldFees = _heldFeesOf[_projectId];\n\n // Delete the current held fees.\n delete _heldFeesOf[_projectId];\n\n // Get a reference to the leftover amount once all fees have been settled.\n uint256 leftoverAmount = _amount;\n\n // Push length in stack\n uint256 _heldFeesLength = _heldFees.length;\n\n // Process each fee.\n for (uint256 _i; _i < _heldFeesLength; ) {\n if (leftoverAmount == 0) _heldFeesOf[_projectId].push(_heldFees[_i]);\n else if (leftoverAmount >= _heldFees[_i].amount) {\n unchecked {\n leftoverAmount = leftoverAmount - _heldFees[_i].amount;\n refundedFees += _feeAmount(\n _heldFees[_i].amount,\n _heldFees[_i].fee,\n _heldFees[_i].feeDiscount\n );\n }\n } else {\n unchecked {\n _heldFeesOf[_projectId].push(\n JBFee(\n _heldFees[_i].amount - leftoverAmount,\n _heldFees[_i].fee,\n _heldFees[_i].feeDiscount,\n _heldFees[_i].beneficiary\n )\n );\n refundedFees += _feeAmount(leftoverAmount, _heldFees[_i].fee, _heldFees[_i].feeDiscount);\n }\n leftoverAmount = 0;\n }\n\n unchecked {\n ++_i;\n }\n }\n\n emit RefundHeldFees(_projectId, _amount, refundedFees, leftoverAmount, msg.sender);\n }\n\n /// @notice Returns the fee amount based on the provided amount for the specified project.\n /// @param _amount The amount that the fee is based on, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _fee The percentage of the fee, out of MAX_FEE.\n /// @param _feeDiscount The percentage discount that should be applied out of the max amount, out of MAX_FEE_DISCOUNT.\n /// @return The amount of the fee, as a fixed point number with the same amount of decimals as this terminal.\n function _feeAmount(\n uint256 _amount,\n uint256 _fee,\n uint256 _feeDiscount\n ) internal pure returns (uint256) {\n // Calculate the discounted fee.\n uint256 _discountedFee = _fee -\n PRBMath.mulDiv(_fee, _feeDiscount, JBConstants.MAX_FEE_DISCOUNT);\n\n // The amount of tokens from the `_amount` to pay as a fee.\n return\n _amount - PRBMath.mulDiv(_amount, JBConstants.MAX_FEE, _discountedFee + JBConstants.MAX_FEE);\n }\n\n /// @notice Get the fee discount from the fee gauge for the specified project.\n /// @param _projectId The ID of the project to get a fee discount for.\n /// @return feeDiscount The fee discount, which should be interpreted as a percentage out MAX_FEE_DISCOUNT.\n function _currentFeeDiscount(uint256 _projectId) internal view returns (uint256) {\n // Can't take a fee if the protocol project doesn't have a terminal that accepts the token.\n if (\n directory.primaryTerminalOf(_FEE_BENEFICIARY_PROJECT_ID, token) ==\n IJBPaymentTerminal(address(0))\n ) return JBConstants.MAX_FEE_DISCOUNT;\n\n // Get the fee discount.\n if (feeGauge != address(0))\n // If the guage reverts, keep the discount at 0.\n try IJBFeeGauge(feeGauge).currentDiscountFor(_projectId) returns (uint256 discount) {\n // If the fee discount is greater than the max, we ignore the return value\n if (discount <= JBConstants.MAX_FEE_DISCOUNT) return discount;\n } catch {\n return 0;\n }\n\n return 0;\n }\n}\n" + }, + "contracts/JBERC20PaymentTerminal3_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';\nimport {IERC20Metadata} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol';\nimport {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';\nimport {JBPayoutRedemptionPaymentTerminal3_1} from './abstract/JBPayoutRedemptionPaymentTerminal3_1.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\n\n/// @notice Manages the inflows and outflows of an ERC-20 token.\ncontract JBERC20PaymentTerminal3_1 is JBPayoutRedemptionPaymentTerminal3_1 {\n using SafeERC20 for IERC20;\n\n //*********************************************************************//\n // -------------------------- internal views ------------------------- //\n //*********************************************************************//\n\n /// @notice Checks the balance of tokens in this contract.\n /// @return The contract's balance, as a fixed point number with the same amount of decimals as this terminal.\n function _balance() internal view override returns (uint256) {\n return IERC20(token).balanceOf(address(this));\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _token The token that this terminal manages.\n /// @param _currency The currency that this terminal's token adheres to for price feeds.\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _payoutSplitsGroup The group that denotes payout splits from this terminal in the splits store.\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _prices A contract that exposes price feeds.\n /// @param _store A contract that stores the terminal's data.\n /// @param _owner The address that will own this contract.\n constructor(\n IERC20Metadata _token,\n uint256 _currency,\n uint256 _baseWeightCurrency,\n uint256 _payoutSplitsGroup,\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBSplitsStore _splitsStore,\n IJBPrices _prices,\n address _store,\n address _owner\n )\n JBPayoutRedemptionPaymentTerminal3_1(\n address(_token),\n _token.decimals(),\n _currency,\n _baseWeightCurrency,\n _payoutSplitsGroup,\n _operatorStore,\n _projects,\n _directory,\n _splitsStore,\n _prices,\n _store,\n _owner\n )\n // solhint-disable-next-line no-empty-blocks\n {\n\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Transfers tokens.\n /// @param _from The address from which the transfer should originate.\n /// @param _to The address to which the transfer should go.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _transferFrom(address _from, address payable _to, uint256 _amount) internal override {\n _from == address(this)\n ? IERC20(token).safeTransfer(_to, _amount)\n : IERC20(token).safeTransferFrom(_from, _to, _amount);\n }\n\n /// @notice Logic to be triggered before transferring tokens from this terminal.\n /// @param _to The address to which the transfer is going.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _beforeTransferTo(address _to, uint256 _amount) internal override {\n IERC20(token).safeIncreaseAllowance(_to, _amount);\n }\n\n /// @notice Logic to be triggered if a transfer should be undone\n /// @param _to The address to which the transfer went.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _cancelTransferTo(address _to, uint256 _amount) internal override {\n IERC20(token).safeDecreaseAllowance(_to, _amount);\n }\n}\n" + }, + "contracts/JBPrices.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {IJBPriceFeed} from './interfaces/IJBPriceFeed.sol';\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\n\n/// @notice Manages and normalizes price feeds.\ncontract JBPrices is Ownable, IJBPrices {\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error PRICE_FEED_ALREADY_EXISTS();\n error PRICE_FEED_NOT_FOUND();\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The available price feeds.\n /// @dev The feed returns the number of `_currency` units that can be converted to 1 `_base` unit.\n /// @custom:param _currency The currency units the feed's resulting price is in terms of.\n /// @custom:param _base The base currency unit being priced by the feed.\n mapping(uint256 => mapping(uint256 => IJBPriceFeed)) public override feedFor;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Gets the number of `_currency` units that can be converted to 1 `_base` unit.\n /// @param _currency The currency units the resulting price is in terms of.\n /// @param _base The base currency unit being priced.\n /// @param _decimals The number of decimals the returned fixed point price should include.\n /// @return The price of the currency in terms of the base, as a fixed point number with the specified number of decimals.\n function priceFor(\n uint256 _currency,\n uint256 _base,\n uint256 _decimals\n ) external view override returns (uint256) {\n // If the currency is the base, return 1 since they are priced the same. Include the desired number of decimals.\n if (_currency == _base) return 10 ** _decimals;\n\n // Get a reference to the feed.\n IJBPriceFeed _feed = feedFor[_currency][_base];\n\n // If it exists, return the price.\n if (_feed != IJBPriceFeed(address(0))) return _feed.currentPrice(_decimals);\n\n // Get the inverse feed.\n _feed = feedFor[_base][_currency];\n\n // If it exists, return the inverse price.\n if (_feed != IJBPriceFeed(address(0)))\n return PRBMath.mulDiv(10 ** _decimals, 10 ** _decimals, _feed.currentPrice(_decimals));\n\n // No price feed available, revert.\n revert PRICE_FEED_NOT_FOUND();\n }\n\n //*********************************************************************//\n // ---------------------------- constructor -------------------------- //\n //*********************************************************************//\n\n /// @param _owner The address that will own the contract.\n constructor(address _owner) {\n // Transfer the ownership.\n transferOwnership(_owner);\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Add a price feed for a currency in terms of the provided base currency.\n /// @dev Current feeds can't be modified.\n /// @param _currency The currency units the feed's resulting price is in terms of.\n /// @param _base The base currency unit being priced by the feed.\n /// @param _feed The price feed being added.\n function addFeedFor(\n uint256 _currency,\n uint256 _base,\n IJBPriceFeed _feed\n ) external override onlyOwner {\n // There can't already be a feed for the specified currency.\n if (\n feedFor[_currency][_base] != IJBPriceFeed(address(0)) ||\n feedFor[_base][_currency] != IJBPriceFeed(address(0))\n ) revert PRICE_FEED_ALREADY_EXISTS();\n\n // Store the feed.\n feedFor[_currency][_base] = _feed;\n\n emit AddFeed(_currency, _base, _feed);\n }\n}\n" + }, + "contracts/JBChainlinkV3PriceFeed.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {AggregatorV3Interface} from '@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol';\nimport {IJBPriceFeed} from './interfaces/IJBPriceFeed.sol';\nimport {JBFixedPointNumber} from './libraries/JBFixedPointNumber.sol';\n\n/// @notice A generalized price feed for the Chainlink AggregatorV3Interface.\ncontract JBChainlinkV3PriceFeed is IJBPriceFeed {\n // A library that provides utility for fixed point numbers.\n using JBFixedPointNumber for uint256;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error STALE_PRICE();\n error INCOMPLETE_ROUND();\n error NEGATIVE_PRICE();\n\n //*********************************************************************//\n // ---------------- public stored immutable properties --------------- //\n //*********************************************************************//\n\n /// @notice The feed that prices are reported from.\n AggregatorV3Interface public immutable feed;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Gets the current price from the feed, normalized to the specified number of decimals.\n /// @param _decimals The number of decimals the returned fixed point price should include.\n /// @return The current price of the feed, as a fixed point number with the specified number of decimals.\n function currentPrice(uint256 _decimals) external view override returns (uint256) {\n // Get the latest round information.\n (uint80 roundId, int256 _price, , uint256 updatedAt, uint80 answeredInRound) = feed\n .latestRoundData();\n\n // Make sure the price isn't stale.\n if (answeredInRound < roundId) revert STALE_PRICE();\n\n // Make sure the round is finished.\n if (updatedAt == 0) revert INCOMPLETE_ROUND();\n\n // Make sure the price is positive.\n if (_price < 0) revert NEGATIVE_PRICE();\n\n // Get a reference to the number of decimals the feed uses.\n uint256 _feedDecimals = feed.decimals();\n\n // Return the price, adjusted to the target decimals.\n return uint256(_price).adjustDecimals(_feedDecimals, _decimals);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _feed The feed to report prices from.\n constructor(AggregatorV3Interface _feed) {\n feed = _feed;\n }\n}\n" + }, + "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface AggregatorV3Interface {\n\n function decimals()\n external\n view\n returns (\n uint8\n );\n\n function description()\n external\n view\n returns (\n string memory\n );\n\n function version()\n external\n view\n returns (\n uint256\n );\n\n // getRoundData and latestRoundData should both raise \"No data present\"\n // if they do not have data to report, instead of returning unset values\n // which could be misinterpreted as actual reported values.\n function getRoundData(\n uint80 _roundId\n )\n external\n view\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n );\n\n function latestRoundData()\n external\n view\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n );\n\n}\n" + }, + "contracts/JBERC20PaymentTerminal3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';\nimport {IERC20Metadata} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol';\nimport {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';\nimport {JBPayoutRedemptionPaymentTerminal3_1_1} from './abstract/JBPayoutRedemptionPaymentTerminal3_1_1.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\n\n/// @notice Manages the inflows and outflows of an ERC-20 token.\ncontract JBERC20PaymentTerminal3_1_1 is JBPayoutRedemptionPaymentTerminal3_1_1 {\n using SafeERC20 for IERC20;\n\n //*********************************************************************//\n // -------------------------- internal views ------------------------- //\n //*********************************************************************//\n\n /// @notice Checks the balance of tokens in this contract.\n /// @return The contract's balance, as a fixed point number with the same amount of decimals as this terminal.\n function _balance() internal view override returns (uint256) {\n return IERC20(token).balanceOf(address(this));\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _token The token that this terminal manages.\n /// @param _currency The currency that this terminal's token adheres to for price feeds.\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _payoutSplitsGroup The group that denotes payout splits from this terminal in the splits store.\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _prices A contract that exposes price feeds.\n /// @param _store A contract that stores the terminal's data.\n /// @param _owner The address that will own this contract.\n constructor(\n IERC20Metadata _token,\n uint256 _currency,\n uint256 _baseWeightCurrency,\n uint256 _payoutSplitsGroup,\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBSplitsStore _splitsStore,\n IJBPrices _prices,\n address _store,\n address _owner\n )\n JBPayoutRedemptionPaymentTerminal3_1_1(\n address(_token),\n _token.decimals(),\n _currency,\n _baseWeightCurrency,\n _payoutSplitsGroup,\n _operatorStore,\n _projects,\n _directory,\n _splitsStore,\n _prices,\n _store,\n _owner\n )\n // solhint-disable-next-line no-empty-blocks\n {\n\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Transfers tokens.\n /// @param _from The address from which the transfer should originate.\n /// @param _to The address to which the transfer should go.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _transferFrom(address _from, address payable _to, uint256 _amount) internal override {\n _from == address(this)\n ? IERC20(token).safeTransfer(_to, _amount)\n : IERC20(token).safeTransferFrom(_from, _to, _amount);\n }\n\n /// @notice Logic to be triggered before transferring tokens from this terminal.\n /// @param _to The address to which the transfer is going.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _beforeTransferTo(address _to, uint256 _amount) internal override {\n IERC20(token).safeIncreaseAllowance(_to, _amount);\n }\n\n /// @notice Logic to be triggered if a transfer should be undone\n /// @param _to The address to which the transfer went.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _cancelTransferTo(address _to, uint256 _amount) internal override {\n IERC20(token).safeDecreaseAllowance(_to, _amount);\n }\n}\n" + }, + "contracts/JBERC20PaymentTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';\nimport {IERC20Metadata} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol';\nimport {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';\nimport {JBPayoutRedemptionPaymentTerminal} from './abstract/JBPayoutRedemptionPaymentTerminal.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\n\n/// @notice Manages the inflows and outflows of an ERC-20 token.\ncontract JBERC20PaymentTerminal is JBPayoutRedemptionPaymentTerminal {\n using SafeERC20 for IERC20;\n\n //*********************************************************************//\n // -------------------------- internal views ------------------------- //\n //*********************************************************************//\n\n /// @notice Checks the balance of tokens in this contract.\n /// @return The contract's balance, as a fixed point number with the same amount of decimals as this terminal.\n function _balance() internal view override returns (uint256) {\n return IERC20(token).balanceOf(address(this));\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _token The token that this terminal manages.\n /// @param _currency The currency that this terminal's token adheres to for price feeds.\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _payoutSplitsGroup The group that denotes payout splits from this terminal in the splits store.\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _prices A contract that exposes price feeds.\n /// @param _store A contract that stores the terminal's data.\n /// @param _owner The address that will own this contract.\n constructor(\n IERC20Metadata _token,\n uint256 _currency,\n uint256 _baseWeightCurrency,\n uint256 _payoutSplitsGroup,\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBSplitsStore _splitsStore,\n IJBPrices _prices,\n address _store,\n address _owner\n )\n JBPayoutRedemptionPaymentTerminal(\n address(_token),\n _token.decimals(),\n _currency,\n _baseWeightCurrency,\n _payoutSplitsGroup,\n _operatorStore,\n _projects,\n _directory,\n _splitsStore,\n _prices,\n _store,\n _owner\n )\n // solhint-disable-next-line no-empty-blocks\n {\n\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Transfers tokens.\n /// @param _from The address from which the transfer should originate.\n /// @param _to The address to which the transfer should go.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _transferFrom(address _from, address payable _to, uint256 _amount) internal override {\n _from == address(this)\n ? IERC20(token).safeTransfer(_to, _amount)\n : IERC20(token).safeTransferFrom(_from, _to, _amount);\n }\n\n /// @notice Logic to be triggered before transferring tokens from this terminal.\n /// @param _to The address to which the transfer is going.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _beforeTransferTo(address _to, uint256 _amount) internal override {\n IERC20(token).safeApprove(_to, _amount);\n }\n}\n" + }, + "contracts/JBFundingCycleStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {JBControllerUtility} from './abstract/JBControllerUtility.sol';\nimport {JBBallotState} from './enums/JBBallotState.sol';\nimport {JBConstants} from './libraries/JBConstants.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBFundingCycleBallot} from './interfaces/IJBFundingCycleBallot.sol';\nimport {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\nimport {JBFundingCycleData} from './structs/JBFundingCycleData.sol';\n\n/// @notice Manages funding cycle configurations and scheduling.\ncontract JBFundingCycleStore is JBControllerUtility, IJBFundingCycleStore {\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error INVALID_BALLOT();\n error INVALID_DISCOUNT_RATE();\n error INVALID_DURATION();\n error INVALID_TIMEFRAME();\n error INVALID_WEIGHT();\n error NO_SAME_BLOCK_RECONFIGURATION();\n\n //*********************************************************************//\n // --------------------- private stored properties ------------------- //\n //*********************************************************************//\n\n /// @notice Stores the user defined properties of each funding cycle, packed into one storage slot.\n /// @custom:param _projectId The ID of the project to get properties of.\n /// @custom:param _configuration The funding cycle configuration to get properties of.\n mapping(uint256 => mapping(uint256 => uint256)) private _packedUserPropertiesOf;\n\n /// @notice Stores the properties added by the mechanism to manage and schedule each funding cycle, packed into one storage slot.\n /// @custom:param _projectId The ID of the project to get instrinsic properties of.\n /// @custom:param _configuration The funding cycle configuration to get properties of.\n mapping(uint256 => mapping(uint256 => uint256)) private _packedIntrinsicPropertiesOf;\n\n /// @notice Stores the metadata for each funding cycle configuration, packed into one storage slot.\n /// @custom:param _projectId The ID of the project to get metadata of.\n /// @custom:param _configuration The funding cycle configuration to get metadata of.\n mapping(uint256 => mapping(uint256 => uint256)) private _metadataOf;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The latest funding cycle configuration for each project.\n /// @custom:param _projectId The ID of the project to get the latest funding cycle configuration of.\n mapping(uint256 => uint256) public override latestConfigurationOf;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Get the funding cycle with the given configuration for the specified project.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @param _configuration The configuration of the funding cycle to get.\n /// @return fundingCycle The funding cycle.\n function get(\n uint256 _projectId,\n uint256 _configuration\n ) external view override returns (JBFundingCycle memory fundingCycle) {\n return _getStructFor(_projectId, _configuration);\n }\n\n /// @notice The latest funding cycle to be configured for the specified project, and its current ballot state.\n /// @param _projectId The ID of the project to get the latest configured funding cycle of.\n /// @return fundingCycle The project's queued funding cycle.\n /// @return ballotState The state of the ballot for the reconfiguration.\n function latestConfiguredOf(\n uint256 _projectId\n ) external view override returns (JBFundingCycle memory fundingCycle, JBBallotState ballotState) {\n // Get a reference to the latest funding cycle configuration.\n uint256 _fundingCycleConfiguration = latestConfigurationOf[_projectId];\n\n // Resolve the funding cycle for the latest configuration.\n fundingCycle = _getStructFor(_projectId, _fundingCycleConfiguration);\n\n // Resolve the ballot state.\n ballotState = _ballotStateOf(\n _projectId,\n fundingCycle.configuration,\n fundingCycle.start,\n fundingCycle.basedOn\n );\n }\n\n /// @notice The funding cycle that's next up for the specified project.\n /// @dev If a queued funding cycle of the project is not found, returns an empty funding cycle with all properties set to 0.\n /// @param _projectId The ID of the project to get the queued funding cycle of.\n /// @return fundingCycle The project's queued funding cycle.\n function queuedOf(\n uint256 _projectId\n ) external view override returns (JBFundingCycle memory fundingCycle) {\n // If the project does not have a funding cycle, return an empty struct.\n if (latestConfigurationOf[_projectId] == 0) return _getStructFor(0, 0);\n\n // Get a reference to the configuration of the standby funding cycle.\n uint256 _standbyFundingCycleConfiguration = _standbyOf(_projectId);\n\n // If it exists, return its funding cycle if it is approved.\n if (_standbyFundingCycleConfiguration > 0) {\n fundingCycle = _getStructFor(_projectId, _standbyFundingCycleConfiguration);\n\n if (_isApproved(_projectId, fundingCycle)) return fundingCycle;\n\n // Resolve the funding cycle for the latest configured funding cycle.\n fundingCycle = _getStructFor(_projectId, fundingCycle.basedOn);\n } else {\n // Resolve the funding cycle for the latest configured funding cycle.\n fundingCycle = _getStructFor(_projectId, latestConfigurationOf[_projectId]);\n\n // If the latest funding cycle starts in the future, it must start in the distant future\n // since its not in standby. In this case base the queued cycles on the base cycle.\n if (fundingCycle.start > block.timestamp)\n fundingCycle = _getStructFor(_projectId, fundingCycle.basedOn);\n }\n\n // There's no queued if the current has a duration of 0.\n if (fundingCycle.duration == 0) return _getStructFor(0, 0);\n\n // Check to see if this funding cycle's ballot is approved.\n // If so, return a funding cycle based on it.\n if (_isApproved(_projectId, fundingCycle)) return _mockFundingCycleBasedOn(fundingCycle, false);\n\n // Get the funding cycle of its base funding cycle, which carries the last approved configuration.\n fundingCycle = _getStructFor(_projectId, fundingCycle.basedOn);\n\n // There's no queued if the base, which must still be the current, has a duration of 0.\n if (fundingCycle.duration == 0) return _getStructFor(0, 0);\n\n // Return a mock of the next up funding cycle.\n return _mockFundingCycleBasedOn(fundingCycle, false);\n }\n\n /// @notice The funding cycle that is currently active for the specified project.\n /// @dev If a current funding cycle of the project is not found, returns an empty funding cycle with all properties set to 0.\n /// @param _projectId The ID of the project to get the current funding cycle of.\n /// @return fundingCycle The project's current funding cycle.\n function currentOf(\n uint256 _projectId\n ) external view override returns (JBFundingCycle memory fundingCycle) {\n // If the project does not have a funding cycle, return an empty struct.\n if (latestConfigurationOf[_projectId] == 0) return _getStructFor(0, 0);\n\n // Get a reference to the configuration of the eligible funding cycle.\n uint256 _fundingCycleConfiguration = _eligibleOf(_projectId);\n\n // Keep a reference to the eligible funding cycle.\n JBFundingCycle memory _fundingCycle;\n\n // If an eligible funding cycle exists...\n if (_fundingCycleConfiguration > 0) {\n // Resolve the funding cycle for the eligible configuration.\n _fundingCycle = _getStructFor(_projectId, _fundingCycleConfiguration);\n\n // Check to see if this funding cycle's ballot is approved.\n // If so, return it.\n if (_isApproved(_projectId, _fundingCycle)) return _fundingCycle;\n\n // If it hasn't been approved, set the funding cycle configuration to be the configuration of the funding cycle that it's based on,\n // which carries the last approved configuration.\n _fundingCycleConfiguration = _fundingCycle.basedOn;\n } else {\n // No upcoming funding cycle found that is eligible to become active,\n // so use the last configuration.\n _fundingCycleConfiguration = latestConfigurationOf[_projectId];\n\n // Get the funding cycle for the latest ID.\n _fundingCycle = _getStructFor(_projectId, _fundingCycleConfiguration);\n\n // If it's not approved or if it hasn't yet started, get a reference to the funding cycle that the latest is based on, which has the latest approved configuration.\n if (!_isApproved(_projectId, _fundingCycle) || block.timestamp < _fundingCycle.start)\n _fundingCycleConfiguration = _fundingCycle.basedOn;\n }\n\n // If there is not funding cycle to base the current one on, there can't be a current one.\n if (_fundingCycleConfiguration == 0) return _getStructFor(0, 0);\n\n // The funding cycle to base a current one on.\n _fundingCycle = _getStructFor(_projectId, _fundingCycleConfiguration);\n\n // If the base has no duration, it's still the current one.\n if (_fundingCycle.duration == 0) return _fundingCycle;\n\n // Return a mock of the current funding cycle.\n return _mockFundingCycleBasedOn(_fundingCycle, true);\n }\n\n /// @notice The current ballot state of the project.\n /// @param _projectId The ID of the project to check the ballot state of.\n /// @return The project's current ballot's state.\n function currentBallotStateOf(uint256 _projectId) external view override returns (JBBallotState) {\n // Get a reference to the latest funding cycle configuration.\n uint256 _fundingCycleConfiguration = latestConfigurationOf[_projectId];\n\n // Resolve the funding cycle for the latest configuration.\n JBFundingCycle memory _fundingCycle = _getStructFor(_projectId, _fundingCycleConfiguration);\n\n return\n _ballotStateOf(\n _projectId,\n _fundingCycle.configuration,\n _fundingCycle.start,\n _fundingCycle.basedOn\n );\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n // solhint-disable-next-line no-empty-blocks\n constructor(IJBDirectory _directory) JBControllerUtility(_directory) {}\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Configures the next eligible funding cycle for the specified project.\n /// @dev Only a project's current controller can configure its funding cycles.\n /// @param _projectId The ID of the project being configured.\n /// @param _data The funding cycle configuration data.\n /// @param _metadata Arbitrary extra data to associate with this funding cycle configuration that's not used within.\n /// @param _mustStartAtOrAfter The time before which the initialized funding cycle cannot start.\n /// @return The funding cycle that the configuration will take effect during.\n function configureFor(\n uint256 _projectId,\n JBFundingCycleData calldata _data,\n uint256 _metadata,\n uint256 _mustStartAtOrAfter\n ) external override onlyController(_projectId) returns (JBFundingCycle memory) {\n // Duration must fit in a uint32.\n if (_data.duration > type(uint32).max) revert INVALID_DURATION();\n\n // Discount rate must be less than or equal to 100%.\n if (_data.discountRate > JBConstants.MAX_DISCOUNT_RATE) revert INVALID_DISCOUNT_RATE();\n\n // Weight must fit into a uint88.\n if (_data.weight > type(uint88).max) revert INVALID_WEIGHT();\n\n // If the start date is in the past, set it to be the current timestamp.\n if (_mustStartAtOrAfter < block.timestamp) _mustStartAtOrAfter = block.timestamp;\n\n // Make sure the min start date fits in a uint56, and that the start date of an upcoming cycle also starts within the max.\n if (_mustStartAtOrAfter + _data.duration > type(uint56).max) revert INVALID_TIMEFRAME();\n\n // Ballot should be a valid contract, supporting the correct interface\n if (_data.ballot != IJBFundingCycleBallot(address(0))) {\n address _ballot = address(_data.ballot);\n\n // No contract at the address ?\n if (_ballot.code.length == 0) revert INVALID_BALLOT();\n\n // Make sure the ballot supports the expected interface.\n try _data.ballot.supportsInterface(type(IJBFundingCycleBallot).interfaceId) returns (\n bool _supports\n ) {\n if (!_supports) revert INVALID_BALLOT(); // Contract exists at the address but with the wrong interface\n } catch {\n revert INVALID_BALLOT(); // No ERC165 support\n }\n }\n\n // The configuration timestamp is now.\n uint256 _configuration = block.timestamp;\n\n // Set up a reconfiguration by configuring intrinsic properties.\n _configureIntrinsicPropertiesFor(_projectId, _configuration, _data.weight, _mustStartAtOrAfter);\n\n // Efficiently stores a funding cycles provided user defined properties.\n // If all user config properties are zero, no need to store anything as the default value will have the same outcome.\n if (\n _data.ballot != IJBFundingCycleBallot(address(0)) ||\n _data.duration > 0 ||\n _data.discountRate > 0\n ) {\n // ballot in bits 0-159 bytes.\n uint256 packed = uint160(address(_data.ballot));\n\n // duration in bits 160-191 bytes.\n packed |= _data.duration << 160;\n\n // discountRate in bits 192-223 bytes.\n packed |= _data.discountRate << 192;\n\n // Set in storage.\n _packedUserPropertiesOf[_projectId][_configuration] = packed;\n }\n\n // Set the metadata if needed.\n if (_metadata > 0) _metadataOf[_projectId][_configuration] = _metadata;\n\n emit Configure(_configuration, _projectId, _data, _metadata, _mustStartAtOrAfter, msg.sender);\n\n // Return the funding cycle for the new configuration.\n return _getStructFor(_projectId, _configuration);\n }\n\n //*********************************************************************//\n // --------------------- private helper functions -------------------- //\n //*********************************************************************//\n\n /// @notice Updates the configurable funding cycle for this project if it exists, otherwise creates one.\n /// @param _projectId The ID of the project to find a configurable funding cycle for.\n /// @param _configuration The time at which the funding cycle was configured.\n /// @param _weight The weight to store in the configured funding cycle.\n /// @param _mustStartAtOrAfter The time before which the initialized funding cycle can't start.\n function _configureIntrinsicPropertiesFor(\n uint256 _projectId,\n uint256 _configuration,\n uint256 _weight,\n uint256 _mustStartAtOrAfter\n ) private {\n // If there's not yet a funding cycle for the project, initialize one.\n if (latestConfigurationOf[_projectId] == 0)\n // Use an empty funding cycle as the base.\n return\n _initFor(_projectId, _getStructFor(0, 0), _configuration, _mustStartAtOrAfter, _weight);\n\n // Get the active funding cycle's configuration.\n uint256 _currentConfiguration = _eligibleOf(_projectId);\n\n // If an eligible funding cycle does not exist, get a reference to the latest funding cycle configuration for the project.\n if (_currentConfiguration == 0)\n // Get the latest funding cycle's configuration.\n _currentConfiguration = latestConfigurationOf[_projectId];\n\n // Get a reference to the funding cycle.\n JBFundingCycle memory _baseFundingCycle = _getStructFor(_projectId, _currentConfiguration);\n\n if (!_isApproved(_projectId, _baseFundingCycle) || block.timestamp < _baseFundingCycle.start)\n // If it hasn't been approved or hasn't yet started, set the ID to be the funding cycle it's based on,\n // which carries the latest approved configuration.\n _baseFundingCycle = _getStructFor(_projectId, _baseFundingCycle.basedOn);\n\n // The configuration can't be the same as the base configuration.\n if (_baseFundingCycle.configuration == _configuration) revert NO_SAME_BLOCK_RECONFIGURATION();\n\n // The time after the ballot of the provided funding cycle has expired.\n // If the provided funding cycle has no ballot, return the current timestamp.\n uint256 _timestampAfterBallot = _baseFundingCycle.ballot == IJBFundingCycleBallot(address(0))\n ? 0\n : _configuration + _baseFundingCycle.ballot.duration();\n\n _initFor(\n _projectId,\n _baseFundingCycle,\n _configuration,\n // Can only start after the ballot.\n _timestampAfterBallot > _mustStartAtOrAfter ? _timestampAfterBallot : _mustStartAtOrAfter,\n _weight\n );\n }\n\n /// @notice Initializes a funding cycle with the specified properties.\n /// @param _projectId The ID of the project to which the funding cycle being initialized belongs.\n /// @param _baseFundingCycle The funding cycle to base the initialized one on.\n /// @param _configuration The configuration of the funding cycle being initialized.\n /// @param _mustStartAtOrAfter The time before which the initialized funding cycle cannot start.\n /// @param _weight The weight to give the newly initialized funding cycle.\n function _initFor(\n uint256 _projectId,\n JBFundingCycle memory _baseFundingCycle,\n uint256 _configuration,\n uint256 _mustStartAtOrAfter,\n uint256 _weight\n ) private {\n // If there is no base, initialize a first cycle.\n if (_baseFundingCycle.number == 0) {\n // The first number is 1.\n uint256 _number = 1;\n\n // Set fresh intrinsic properties.\n _packAndStoreIntrinsicPropertiesOf(\n _configuration,\n _projectId,\n _number,\n _weight,\n _baseFundingCycle.configuration,\n _mustStartAtOrAfter\n );\n } else {\n // Derive the correct next start time from the base.\n uint256 _start = _deriveStartFrom(_baseFundingCycle, _mustStartAtOrAfter);\n\n // A weight of 1 is treated as a weight of 0.\n // This is to allow a weight of 0 (default) to represent inheriting the discounted weight of the previous funding cycle.\n _weight = _weight > 0\n ? (_weight == 1 ? 0 : _weight)\n : _deriveWeightFrom(_baseFundingCycle, _start);\n\n // Derive the correct number.\n uint256 _number = _deriveNumberFrom(_baseFundingCycle, _start);\n\n // Update the intrinsic properties.\n _packAndStoreIntrinsicPropertiesOf(\n _configuration,\n _projectId,\n _number,\n _weight,\n _baseFundingCycle.configuration,\n _start\n );\n }\n\n // Set the project's latest funding cycle configuration.\n latestConfigurationOf[_projectId] = _configuration;\n\n emit Init(_configuration, _projectId, _baseFundingCycle.configuration);\n }\n\n /// @notice Efficiently stores a funding cycle's provided intrinsic properties.\n /// @param _configuration The configuration of the funding cycle to pack and store.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @param _number The number of the funding cycle.\n /// @param _weight The weight of the funding cycle.\n /// @param _basedOn The configuration of the base funding cycle.\n /// @param _start The start time of this funding cycle.\n function _packAndStoreIntrinsicPropertiesOf(\n uint256 _configuration,\n uint256 _projectId,\n uint256 _number,\n uint256 _weight,\n uint256 _basedOn,\n uint256 _start\n ) private {\n // weight in bits 0-87.\n uint256 packed = _weight;\n\n // basedOn in bits 88-143.\n packed |= _basedOn << 88;\n\n // start in bits 144-199.\n packed |= _start << 144;\n\n // number in bits 200-255.\n packed |= _number << 200;\n\n // Store the packed value.\n _packedIntrinsicPropertiesOf[_projectId][_configuration] = packed;\n }\n\n /// @notice The project's stored funding cycle that hasn't yet started and should be used next, if one exists.\n /// @dev A value of 0 is returned if no funding cycle was found.\n /// @dev Assumes the project has a latest configuration.\n /// @param _projectId The ID of a project to look through for a standby cycle.\n /// @return configuration The configuration of the standby funding cycle if one exists, or 0 if one doesn't exist.\n function _standbyOf(uint256 _projectId) private view returns (uint256 configuration) {\n // Get a reference to the project's latest funding cycle.\n configuration = latestConfigurationOf[_projectId];\n\n // Get the necessary properties for the latest funding cycle.\n JBFundingCycle memory _fundingCycle = _getStructFor(_projectId, configuration);\n\n // There is no upcoming funding cycle if the latest funding cycle has already started.\n if (block.timestamp >= _fundingCycle.start) return 0;\n\n // If this is the first funding cycle, it is queued.\n if (_fundingCycle.number == 1) return configuration;\n\n // Get the necessary properties for the base funding cycle.\n JBFundingCycle memory _baseFundingCycle = _getStructFor(_projectId, _fundingCycle.basedOn);\n\n // If the latest configuration doesn't start until after another base cycle, return 0.\n if (\n _baseFundingCycle.duration > 0 &&\n block.timestamp < _fundingCycle.start - _baseFundingCycle.duration\n ) return 0;\n }\n\n /// @notice The project's stored funding cycle that has started and hasn't yet expired.\n /// @dev A value of 0 is returned if no funding cycle was found.\n /// @dev Assumes the project has a latest configuration.\n /// @param _projectId The ID of the project to look through.\n /// @return configuration The configuration of an eligible funding cycle if one exists, or 0 if one doesn't exist.\n function _eligibleOf(uint256 _projectId) private view returns (uint256 configuration) {\n // Get a reference to the project's latest funding cycle.\n configuration = latestConfigurationOf[_projectId];\n\n // Get the latest funding cycle.\n JBFundingCycle memory _fundingCycle = _getStructFor(_projectId, configuration);\n\n // If the latest is expired, return an empty funding cycle.\n // A duration of 0 cannot be expired.\n if (\n _fundingCycle.duration > 0 && block.timestamp >= _fundingCycle.start + _fundingCycle.duration\n ) return 0;\n\n // Return the funding cycle's configuration if it has started.\n if (block.timestamp >= _fundingCycle.start) return _fundingCycle.configuration;\n\n // Get a reference to the cycle's base configuration.\n JBFundingCycle memory _baseFundingCycle = _getStructFor(_projectId, _fundingCycle.basedOn);\n\n // If the base cycle isn't eligible, the project has no eligible cycle.\n // A duration of 0 is always eligible.\n if (\n _baseFundingCycle.duration > 0 &&\n block.timestamp >= _baseFundingCycle.start + _baseFundingCycle.duration\n ) return 0;\n\n // Return the configuration that the latest funding cycle is based on.\n configuration = _fundingCycle.basedOn;\n }\n\n /// @notice A view of the funding cycle that would be created based on the provided one if the project doesn't make a reconfiguration.\n /// @dev Returns an empty funding cycle if there can't be a mock funding cycle based on the provided one.\n /// @dev Assumes a funding cycle with a duration of 0 will never be asked to be the base of a mock.\n /// @param _baseFundingCycle The funding cycle that the resulting funding cycle should follow.\n /// @param _allowMidCycle A flag indicating if the mocked funding cycle is allowed to already be mid cycle.\n /// @return A mock of what the next funding cycle will be.\n function _mockFundingCycleBasedOn(\n JBFundingCycle memory _baseFundingCycle,\n bool _allowMidCycle\n ) private view returns (JBFundingCycle memory) {\n // Get the distance of the current time to the start of the next possible funding cycle.\n // If the returned mock cycle must not yet have started, the start time of the mock must be in the future.\n uint256 _mustStartAtOrAfter = !_allowMidCycle\n ? block.timestamp + 1\n : block.timestamp - _baseFundingCycle.duration + 1;\n\n // Derive what the start time should be.\n uint256 _start = _deriveStartFrom(_baseFundingCycle, _mustStartAtOrAfter);\n\n // Derive what the number should be.\n uint256 _number = _deriveNumberFrom(_baseFundingCycle, _start);\n\n return\n JBFundingCycle(\n _number,\n _baseFundingCycle.configuration,\n _baseFundingCycle.basedOn,\n _start,\n _baseFundingCycle.duration,\n _deriveWeightFrom(_baseFundingCycle, _start),\n _baseFundingCycle.discountRate,\n _baseFundingCycle.ballot,\n _baseFundingCycle.metadata\n );\n }\n\n /// @notice The date that is the nearest multiple of the specified funding cycle's duration from its end.\n /// @param _baseFundingCycle The funding cycle to base the calculation on.\n /// @param _mustStartAtOrAfter A date that the derived start must be on or come after.\n /// @return start The next start time.\n function _deriveStartFrom(\n JBFundingCycle memory _baseFundingCycle,\n uint256 _mustStartAtOrAfter\n ) private pure returns (uint256 start) {\n // A subsequent cycle to one with a duration of 0 should start as soon as possible.\n if (_baseFundingCycle.duration == 0) return _mustStartAtOrAfter;\n\n // The time when the funding cycle immediately after the specified funding cycle starts.\n uint256 _nextImmediateStart = _baseFundingCycle.start + _baseFundingCycle.duration;\n\n // If the next immediate start is now or in the future, return it.\n if (_nextImmediateStart >= _mustStartAtOrAfter) return _nextImmediateStart;\n\n // The amount of seconds since the `_mustStartAtOrAfter` time which results in a start time that might satisfy the specified constraints.\n uint256 _timeFromImmediateStartMultiple = (_mustStartAtOrAfter - _nextImmediateStart) %\n _baseFundingCycle.duration;\n\n // A reference to the first possible start timestamp.\n start = _mustStartAtOrAfter - _timeFromImmediateStartMultiple;\n\n // Add increments of duration as necessary to satisfy the threshold.\n while (_mustStartAtOrAfter > start) start = start + _baseFundingCycle.duration;\n }\n\n /// @notice The accumulated weight change since the specified funding cycle.\n /// @param _baseFundingCycle The funding cycle to base the calculation on.\n /// @param _start The start time of the funding cycle to derive a number for.\n /// @return weight The derived weight, as a fixed point number with 18 decimals.\n function _deriveWeightFrom(\n JBFundingCycle memory _baseFundingCycle,\n uint256 _start\n ) private pure returns (uint256 weight) {\n // A subsequent cycle to one with a duration of 0 should have the next possible weight.\n if (_baseFundingCycle.duration == 0)\n return\n PRBMath.mulDiv(\n _baseFundingCycle.weight,\n JBConstants.MAX_DISCOUNT_RATE - _baseFundingCycle.discountRate,\n JBConstants.MAX_DISCOUNT_RATE\n );\n\n // The weight should be based off the base funding cycle's weight.\n weight = _baseFundingCycle.weight;\n\n // If the discount is 0, the weight doesn't change.\n if (_baseFundingCycle.discountRate == 0) return weight;\n\n // The difference between the start of the base funding cycle and the proposed start.\n uint256 _startDistance = _start - _baseFundingCycle.start;\n\n // Apply the base funding cycle's discount rate for each cycle that has passed.\n uint256 _discountMultiple;\n unchecked {\n _discountMultiple = _startDistance / _baseFundingCycle.duration; // Non-null duration is excluded above\n }\n\n for (uint256 _i; _i < _discountMultiple; ) {\n // The number of times to apply the discount rate.\n // Base the new weight on the specified funding cycle's weight.\n weight = PRBMath.mulDiv(\n weight,\n JBConstants.MAX_DISCOUNT_RATE - _baseFundingCycle.discountRate,\n JBConstants.MAX_DISCOUNT_RATE\n );\n\n // The calculation doesn't need to continue if the weight is 0.\n if (weight == 0) break;\n\n unchecked {\n ++_i;\n }\n }\n }\n\n /// @notice The number of the next funding cycle given the specified funding cycle.\n /// @param _baseFundingCycle The funding cycle to base the calculation on.\n /// @param _start The start time of the funding cycle to derive a number for.\n /// @return The funding cycle number.\n function _deriveNumberFrom(\n JBFundingCycle memory _baseFundingCycle,\n uint256 _start\n ) private pure returns (uint256) {\n // A subsequent cycle to one with a duration of 0 should be the next number.\n if (_baseFundingCycle.duration == 0) return _baseFundingCycle.number + 1;\n\n // The difference between the start of the base funding cycle and the proposed start.\n uint256 _startDistance = _start - _baseFundingCycle.start;\n\n // Find the number of base cycles that fit in the start distance.\n return _baseFundingCycle.number + (_startDistance / _baseFundingCycle.duration);\n }\n\n /// @notice Checks to see if the provided funding cycle is approved according to the correct ballot.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @param _fundingCycle The funding cycle to get an approval flag for.\n /// @return The approval flag.\n function _isApproved(\n uint256 _projectId,\n JBFundingCycle memory _fundingCycle\n ) private view returns (bool) {\n return\n _ballotStateOf(\n _projectId,\n _fundingCycle.configuration,\n _fundingCycle.start,\n _fundingCycle.basedOn\n ) == JBBallotState.Approved;\n }\n\n /// @notice A project's latest funding cycle configuration approval status.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @param _configuration The funding cycle configuration to get the ballot state of.\n /// @param _start The start time of the funding cycle configuration to get the ballot state of.\n /// @param _ballotFundingCycleConfiguration The configuration of the funding cycle which is configured with the ballot that should be used.\n /// @return The ballot state of the project.\n function _ballotStateOf(\n uint256 _projectId,\n uint256 _configuration,\n uint256 _start,\n uint256 _ballotFundingCycleConfiguration\n ) private view returns (JBBallotState) {\n // If there is no ballot funding cycle, implicitly approve.\n if (_ballotFundingCycleConfiguration == 0) return JBBallotState.Approved;\n\n // Get the ballot funding cycle.\n JBFundingCycle memory _ballotFundingCycle = _getStructFor(\n _projectId,\n _ballotFundingCycleConfiguration\n );\n\n // If there is no ballot, the ID is auto approved.\n if (_ballotFundingCycle.ballot == IJBFundingCycleBallot(address(0)))\n return JBBallotState.Approved;\n\n // Return the ballot's state\n return _ballotFundingCycle.ballot.stateOf(_projectId, _configuration, _start);\n }\n\n /// @notice Unpack a funding cycle's packed stored values into an easy-to-work-with funding cycle struct.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @param _configuration The funding cycle configuration to get the full struct for.\n /// @return fundingCycle A funding cycle struct.\n function _getStructFor(\n uint256 _projectId,\n uint256 _configuration\n ) private view returns (JBFundingCycle memory fundingCycle) {\n // Return an empty funding cycle if the configuration specified is 0.\n if (_configuration == 0) return fundingCycle;\n\n fundingCycle.configuration = _configuration;\n\n uint256 _packedIntrinsicProperties = _packedIntrinsicPropertiesOf[_projectId][_configuration];\n\n // weight in bits 0-87 bits.\n fundingCycle.weight = uint256(uint88(_packedIntrinsicProperties));\n // basedOn in bits 88-143 bits.\n fundingCycle.basedOn = uint256(uint56(_packedIntrinsicProperties >> 88));\n // start in bits 144-199 bits.\n fundingCycle.start = uint256(uint56(_packedIntrinsicProperties >> 144));\n // number in bits 200-255 bits.\n fundingCycle.number = uint256(uint56(_packedIntrinsicProperties >> 200));\n\n uint256 _packedUserProperties = _packedUserPropertiesOf[_projectId][_configuration];\n\n // ballot in bits 0-159 bits.\n fundingCycle.ballot = IJBFundingCycleBallot(address(uint160(_packedUserProperties)));\n // duration in bits 160-191 bits.\n fundingCycle.duration = uint256(uint32(_packedUserProperties >> 160));\n // discountRate in bits 192-223 bits.\n fundingCycle.discountRate = uint256(uint32(_packedUserProperties >> 192));\n\n fundingCycle.metadata = _metadataOf[_projectId][_configuration];\n }\n}\n" + }, + "contracts/JBController.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {ERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {SafeCast} from '@openzeppelin/contracts/utils/math/SafeCast.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {JBOperatable} from './abstract/JBOperatable.sol';\nimport {JBBallotState} from './enums/JBBallotState.sol';\nimport {IJBController} from './interfaces/IJBController.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol';\nimport {IJBMigratable} from './interfaces/IJBMigratable.sol';\nimport {IJBOperatable} from './interfaces/IJBOperatable.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {IJBSplitAllocator} from './interfaces/IJBSplitAllocator.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {IJBTokenStore} from './interfaces/IJBTokenStore.sol';\nimport {JBConstants} from './libraries/JBConstants.sol';\nimport {JBFundingCycleMetadataResolver} from './libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBOperations} from './libraries/JBOperations.sol';\nimport {JBSplitsGroups} from './libraries/JBSplitsGroups.sol';\nimport {JBSplitAllocationData} from './structs/JBSplitAllocationData.sol';\nimport {JBFundAccessConstraints} from './structs/JBFundAccessConstraints.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\nimport {JBFundingCycleData} from './structs/JBFundingCycleData.sol';\nimport {JBFundingCycleMetadata} from './structs/JBFundingCycleMetadata.sol';\nimport {JBGroupedSplits} from './structs/JBGroupedSplits.sol';\nimport {JBProjectMetadata} from './structs/JBProjectMetadata.sol';\nimport {JBSplit} from './structs/JBSplit.sol';\n\n/// @notice Stitches together funding cycles and project tokens, making sure all activity is accounted for and correct.\ncontract JBController is JBOperatable, ERC165, IJBController, IJBMigratable {\n // A library that parses the packed funding cycle metadata into a more friendly format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error BURN_PAUSED_AND_SENDER_NOT_VALID_TERMINAL_DELEGATE();\n error CANT_MIGRATE_TO_CURRENT_CONTROLLER();\n error FUNDING_CYCLE_ALREADY_LAUNCHED();\n error INVALID_BALLOT_REDEMPTION_RATE();\n error INVALID_DISTRIBUTION_LIMIT();\n error INVALID_DISTRIBUTION_LIMIT_CURRENCY();\n error INVALID_OVERFLOW_ALLOWANCE();\n error INVALID_OVERFLOW_ALLOWANCE_CURRENCY();\n error INVALID_REDEMPTION_RATE();\n error INVALID_RESERVED_RATE();\n error MIGRATION_NOT_ALLOWED();\n error MINT_NOT_ALLOWED_AND_NOT_TERMINAL_DELEGATE();\n error NO_BURNABLE_TOKENS();\n error NOT_CURRENT_CONTROLLER();\n error ZERO_TOKENS_TO_MINT();\n\n //*********************************************************************//\n // --------------------- internal stored properties ------------------ //\n //*********************************************************************//\n\n /// @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.\n /// @custom:param _projectId The ID of the project to get the tracker of.\n mapping(uint256 => int256) internal _processedTokenTrackerOf;\n\n /// @notice Data regarding the distribution limit of a project during a configuration.\n /// @dev bits 0-231: The amount of token that a project can distribute per funding cycle.\n /// @dev bits 232-255: The currency of amount that a project can distribute.\n /// @custom:param _projectId The ID of the project to get the packed distribution limit data of.\n /// @custom:param _configuration The configuration during which the packed distribution limit data applies.\n /// @custom:param _terminal The terminal from which distributions are being limited.\n /// @custom:param _token The token for which distributions are being limited.\n mapping(uint256 => mapping(uint256 => mapping(IJBPaymentTerminal => mapping(address => uint256))))\n internal _packedDistributionLimitDataOf;\n\n /// @notice Data regarding the overflow allowance of a project during a configuration.\n /// @dev bits 0-231: The amount of overflow that a project is allowed to tap into on-demand throughout the configuration.\n /// @dev bits 232-255: The currency of the amount of overflow that a project is allowed to tap.\n /// @custom:param _projectId The ID of the project to get the packed overflow allowance data of.\n /// @custom:param _configuration The configuration during which the packed overflow allowance data applies.\n /// @custom:param _terminal The terminal managing the overflow.\n /// @custom:param _token The token for which overflow is being allowed.\n mapping(uint256 => mapping(uint256 => mapping(IJBPaymentTerminal => mapping(address => uint256))))\n internal _packedOverflowAllowanceDataOf;\n\n //*********************************************************************//\n // --------------- public immutable stored properties ---------------- //\n //*********************************************************************//\n\n /// @notice Mints ERC-721's that represent project ownership.\n IJBProjects public immutable override projects;\n\n /// @notice The contract storing all funding cycle configurations.\n IJBFundingCycleStore public immutable override fundingCycleStore;\n\n /// @notice The contract that manages token minting and burning.\n IJBTokenStore public immutable override tokenStore;\n\n /// @notice The contract that stores splits for each project.\n IJBSplitsStore public immutable override splitsStore;\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice The amount of token that a project can distribute per funding cycle, and the currency it's in terms of.\n /// @dev The number of decimals in the returned fixed point amount is the same as that of the specified terminal.\n /// @param _projectId The ID of the project to get the distribution limit of.\n /// @param _configuration The configuration during which the distribution limit applies.\n /// @param _terminal The terminal from which distributions are being limited.\n /// @param _token The token for which the distribution limit applies.\n /// @return The distribution limit, as a fixed point number with the same number of decimals as the provided terminal.\n /// @return The currency of the distribution limit.\n function distributionLimitOf(\n uint256 _projectId,\n uint256 _configuration,\n IJBPaymentTerminal _terminal,\n address _token\n ) external view override returns (uint256, uint256) {\n // Get a reference to the packed data.\n uint256 _data = _packedDistributionLimitDataOf[_projectId][_configuration][_terminal][_token];\n\n // The limit is in bits 0-231. The currency is in bits 232-255.\n return (uint256(uint232(_data)), _data >> 232);\n }\n\n /// @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.\n /// @dev The number of decimals in the returned fixed point amount is the same as that of the specified terminal.\n /// @param _projectId The ID of the project to get the overflow allowance of.\n /// @param _configuration The configuration of the during which the allowance applies.\n /// @param _terminal The terminal managing the overflow.\n /// @param _token The token for which the overflow allowance applies.\n /// @return The overflow allowance, as a fixed point number with the same number of decimals as the provided terminal.\n /// @return The currency of the overflow allowance.\n function overflowAllowanceOf(\n uint256 _projectId,\n uint256 _configuration,\n IJBPaymentTerminal _terminal,\n address _token\n ) external view override returns (uint256, uint256) {\n // Get a reference to the packed data.\n uint256 _data = _packedOverflowAllowanceDataOf[_projectId][_configuration][_terminal][_token];\n\n // The allowance is in bits 0-231. The currency is in bits 232-255.\n return (uint256(uint232(_data)), _data >> 232);\n }\n\n /// @notice Gets the amount of reserved tokens that a project has available to distribute.\n /// @param _projectId The ID of the project to get a reserved token balance of.\n /// @param _reservedRate The reserved rate to use when making the calculation.\n /// @return The current amount of reserved tokens.\n function reservedTokenBalanceOf(\n uint256 _projectId,\n uint256 _reservedRate\n ) external view override returns (uint256) {\n return\n _reservedTokenAmountFrom(\n _processedTokenTrackerOf[_projectId],\n _reservedRate,\n tokenStore.totalSupplyOf(_projectId)\n );\n }\n\n /// @notice Gets the current total amount of outstanding tokens for a project, given a reserved rate.\n /// @param _projectId The ID of the project to get total outstanding tokens of.\n /// @param _reservedRate The reserved rate to use when making the calculation.\n /// @return The current total amount of outstanding tokens for the project.\n function totalOutstandingTokensOf(\n uint256 _projectId,\n uint256 _reservedRate\n ) external view override returns (uint256) {\n // Get the total number of tokens in circulation.\n uint256 _totalSupply = tokenStore.totalSupplyOf(_projectId);\n\n // Get the number of reserved tokens the project has.\n uint256 _reservedTokenAmount = _reservedTokenAmountFrom(\n _processedTokenTrackerOf[_projectId],\n _reservedRate,\n _totalSupply\n );\n\n // Add the reserved tokens to the total supply.\n return _totalSupply + _reservedTokenAmount;\n }\n\n /// @notice A project's funding cycle for the specified configuration along with its metadata.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The funding cycle.\n /// @return metadata The funding cycle's metadata.\n function getFundingCycleOf(\n uint256 _projectId,\n uint256 _configuration\n )\n external\n view\n override\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata)\n {\n fundingCycle = fundingCycleStore.get(_projectId, _configuration);\n metadata = fundingCycle.expandMetadata();\n }\n\n /// @notice A project's latest configured funding cycle along with its metadata and the ballot state of the configuration.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The latest configured funding cycle.\n /// @return metadata The latest configured funding cycle's metadata.\n /// @return ballotState The state of the configuration.\n function latestConfiguredFundingCycleOf(\n uint256 _projectId\n )\n external\n view\n override\n returns (\n JBFundingCycle memory fundingCycle,\n JBFundingCycleMetadata memory metadata,\n JBBallotState ballotState\n )\n {\n (fundingCycle, ballotState) = fundingCycleStore.latestConfiguredOf(_projectId);\n metadata = fundingCycle.expandMetadata();\n }\n\n /// @notice A project's current funding cycle along with its metadata.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The current funding cycle.\n /// @return metadata The current funding cycle's metadata.\n function currentFundingCycleOf(\n uint256 _projectId\n )\n external\n view\n override\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata)\n {\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n metadata = fundingCycle.expandMetadata();\n }\n\n /// @notice A project's queued funding cycle along with its metadata.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The queued funding cycle.\n /// @return metadata The queued funding cycle's metadata.\n function queuedFundingCycleOf(\n uint256 _projectId\n )\n external\n view\n override\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata)\n {\n fundingCycle = fundingCycleStore.queuedOf(_projectId);\n metadata = fundingCycle.expandMetadata();\n }\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if the provided interface ID is supported.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(ERC165, IERC165) returns (bool) {\n return\n _interfaceId == type(IJBController).interfaceId ||\n _interfaceId == type(IJBMigratable).interfaceId ||\n _interfaceId == type(IJBOperatable).interfaceId ||\n super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // ---------------------------- constructor -------------------------- //\n //*********************************************************************//\n\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _fundingCycleStore A contract storing all funding cycle configurations.\n /// @param _tokenStore A contract that manages token minting and burning.\n /// @param _splitsStore A contract that stores splits for each project.\n constructor(\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBFundingCycleStore _fundingCycleStore,\n IJBTokenStore _tokenStore,\n IJBSplitsStore _splitsStore\n ) JBOperatable(_operatorStore) {\n projects = _projects;\n directory = _directory;\n fundingCycleStore = _fundingCycleStore;\n tokenStore = _tokenStore;\n splitsStore = _splitsStore;\n }\n\n //*********************************************************************//\n // --------------------- external transactions ----------------------- //\n //*********************************************************************//\n\n /// @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.\n /// @dev Each operation within this transaction can be done in sequence separately.\n /// @dev Anyone can deploy a project on an owner's behalf.\n /// @param _owner The address to set as the owner of the project. The project ERC-721 will be owned by this address.\n /// @param _projectMetadata Metadata to associate with the project within a particular domain. This can be updated any time by the owner of the project.\n /// @param _data Data that defines the project's first funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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`.\n /// @param _terminals Payment terminals to add for the project.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return projectId The ID of the project.\n function launchProjectFor(\n address _owner,\n JBProjectMetadata calldata _projectMetadata,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] calldata _groupedSplits,\n JBFundAccessConstraints[] calldata _fundAccessConstraints,\n IJBPaymentTerminal[] memory _terminals,\n string memory _memo\n ) external virtual override returns (uint256 projectId) {\n // Keep a reference to the directory.\n IJBDirectory _directory = directory;\n\n // Mint the project into the wallet of the owner.\n projectId = projects.createFor(_owner, _projectMetadata);\n\n // Set this contract as the project's controller in the directory.\n _directory.setControllerOf(projectId, address(this));\n\n // Configure the first funding cycle.\n uint256 _configuration = _configure(\n projectId,\n _data,\n _metadata,\n _mustStartAtOrAfter,\n _groupedSplits,\n _fundAccessConstraints\n );\n\n // Add the provided terminals to the list of terminals.\n if (_terminals.length > 0) _directory.setTerminalsOf(projectId, _terminals);\n\n emit LaunchProject(_configuration, projectId, _memo, msg.sender);\n }\n\n /// @notice Creates a funding cycle for an already existing project ERC-721.\n /// @dev Each operation within this transaction can be done in sequence separately.\n /// @dev Only a project owner or operator can launch its funding cycles.\n /// @param _projectId The ID of the project to launch funding cycles for.\n /// @param _data Data that defines the project's first funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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`.\n /// @param _terminals Payment terminals to add for the project.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return configuration The configuration of the funding cycle that was successfully created.\n function launchFundingCyclesFor(\n uint256 _projectId,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] calldata _groupedSplits,\n JBFundAccessConstraints[] memory _fundAccessConstraints,\n IJBPaymentTerminal[] memory _terminals,\n string memory _memo\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.RECONFIGURE)\n returns (uint256 configuration)\n {\n // If there is a previous configuration, reconfigureFundingCyclesOf should be called instead\n if (fundingCycleStore.latestConfigurationOf(_projectId) > 0)\n revert FUNDING_CYCLE_ALREADY_LAUNCHED();\n\n // Set this contract as the project's controller in the directory.\n directory.setControllerOf(_projectId, address(this));\n\n // Configure the first funding cycle.\n configuration = _configure(\n _projectId,\n _data,\n _metadata,\n _mustStartAtOrAfter,\n _groupedSplits,\n _fundAccessConstraints\n );\n\n // Add the provided terminals to the list of terminals.\n if (_terminals.length > 0) directory.setTerminalsOf(_projectId, _terminals);\n\n emit LaunchFundingCycles(configuration, _projectId, _memo, msg.sender);\n }\n\n /// @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.\n /// @dev Only a project's owner or a designated operator can configure its funding cycles.\n /// @param _projectId The ID of the project whose funding cycles are being reconfigured.\n /// @param _data Data that defines the funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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`.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return configuration The configuration of the funding cycle that was successfully reconfigured.\n function reconfigureFundingCyclesOf(\n uint256 _projectId,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] calldata _groupedSplits,\n JBFundAccessConstraints[] calldata _fundAccessConstraints,\n string calldata _memo\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.RECONFIGURE)\n returns (uint256 configuration)\n {\n // Configure the next funding cycle.\n configuration = _configure(\n _projectId,\n _data,\n _metadata,\n _mustStartAtOrAfter,\n _groupedSplits,\n _fundAccessConstraints\n );\n\n emit ReconfigureFundingCycles(configuration, _projectId, _memo, msg.sender);\n }\n\n /// @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.\n /// @dev Only a project's owner, a designated operator, one of its terminals, or the current data source can mint its tokens.\n /// @param _projectId The ID of the project to which the tokens being minted belong.\n /// @param _tokenCount The amount of tokens to mint in total, counting however many should be reserved.\n /// @param _beneficiary The account that the tokens are being minted for.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _preferClaimedTokens A flag indicating whether a project's attached token contract should be minted if they have been issued.\n /// @param _useReservedRate Whether to use the current funding cycle's reserved rate in the mint calculation.\n /// @return beneficiaryTokenCount The amount of tokens minted for the beneficiary.\n function mintTokensOf(\n uint256 _projectId,\n uint256 _tokenCount,\n address _beneficiary,\n string calldata _memo,\n bool _preferClaimedTokens,\n bool _useReservedRate\n ) external virtual override returns (uint256 beneficiaryTokenCount) {\n // There should be tokens to mint.\n if (_tokenCount == 0) revert ZERO_TOKENS_TO_MINT();\n\n // Define variables that will be needed outside scoped section below.\n // Keep a reference to the reserved rate to use\n uint256 _reservedRate;\n\n // Scoped section prevents stack too deep. `_fundingCycle` only used within scope.\n {\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Minting limited to: project owner, authorized callers, project terminal and current funding cycle data source\n _requirePermissionAllowingOverride(\n projects.ownerOf(_projectId),\n _projectId,\n JBOperations.MINT,\n directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender)) ||\n msg.sender == address(_fundingCycle.dataSource())\n );\n\n // If the message sender is not a terminal or a datasource, the current funding cycle must allow minting.\n if (\n !_fundingCycle.mintingAllowed() &&\n !directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender)) &&\n msg.sender != address(_fundingCycle.dataSource())\n ) revert MINT_NOT_ALLOWED_AND_NOT_TERMINAL_DELEGATE();\n\n // Determine the reserved rate to use.\n _reservedRate = _useReservedRate ? _fundingCycle.reservedRate() : 0;\n\n // Override the claimed token preference with the funding cycle value.\n _preferClaimedTokens = _preferClaimedTokens == true\n ? _preferClaimedTokens\n : _fundingCycle.preferClaimedTokenOverride();\n }\n\n if (_reservedRate == JBConstants.MAX_RESERVED_RATE)\n // Subtract the total weighted amount from the tracker so the full reserved token amount can be printed later.\n _processedTokenTrackerOf[_projectId] =\n _processedTokenTrackerOf[_projectId] -\n SafeCast.toInt256(_tokenCount);\n else {\n // The unreserved token count that will be minted for the beneficiary.\n beneficiaryTokenCount = PRBMath.mulDiv(\n _tokenCount,\n JBConstants.MAX_RESERVED_RATE - _reservedRate,\n JBConstants.MAX_RESERVED_RATE\n );\n\n if (_reservedRate == 0)\n // If there's no reserved rate, increment the tracker with the newly minted tokens.\n _processedTokenTrackerOf[_projectId] =\n _processedTokenTrackerOf[_projectId] +\n SafeCast.toInt256(beneficiaryTokenCount);\n\n // Mint the tokens.\n tokenStore.mintFor(_beneficiary, _projectId, beneficiaryTokenCount, _preferClaimedTokens);\n }\n\n emit MintTokens(\n _beneficiary,\n _projectId,\n _tokenCount,\n beneficiaryTokenCount,\n _memo,\n _reservedRate,\n msg.sender\n );\n }\n\n /// @notice Burns a token holder's supply.\n /// @dev Only a token's holder, a designated operator, or a project's terminal can burn it.\n /// @param _holder The account that is having its tokens burned.\n /// @param _projectId The ID of the project to which the tokens being burned belong.\n /// @param _tokenCount The number of tokens to burn.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _preferClaimedTokens A flag indicating whether a project's attached token contract should be burned first if they have been issued.\n function burnTokensOf(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n string calldata _memo,\n bool _preferClaimedTokens\n )\n external\n virtual\n override\n requirePermissionAllowingOverride(\n _holder,\n _projectId,\n JBOperations.BURN,\n directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender))\n )\n {\n // There should be tokens to burn\n if (_tokenCount == 0) revert NO_BURNABLE_TOKENS();\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // If the message sender is a terminal, the current funding cycle must not be paused.\n if (\n _fundingCycle.burnPaused() &&\n !directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender))\n ) revert BURN_PAUSED_AND_SENDER_NOT_VALID_TERMINAL_DELEGATE();\n\n // Update the token tracker so that reserved tokens will still be correctly mintable.\n _processedTokenTrackerOf[_projectId] =\n _processedTokenTrackerOf[_projectId] -\n SafeCast.toInt256(_tokenCount);\n\n // Burn the tokens.\n tokenStore.burnFrom(_holder, _projectId, _tokenCount, _preferClaimedTokens);\n\n emit BurnTokens(_holder, _projectId, _tokenCount, _memo, msg.sender);\n }\n\n /// @notice Distributes all outstanding reserved tokens for a project.\n /// @param _projectId The ID of the project to which the reserved tokens belong.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return The amount of minted reserved tokens.\n function distributeReservedTokensOf(\n uint256 _projectId,\n string calldata _memo\n ) external virtual override returns (uint256) {\n return _distributeReservedTokensOf(_projectId, _memo);\n }\n\n /// @notice Allows other controllers to signal to this one that a migration is expected for the specified project.\n /// @dev This controller should not yet be the project's controller.\n /// @param _projectId The ID of the project that will be migrated to this controller.\n /// @param _from The controller being migrated from.\n function prepForMigrationOf(uint256 _projectId, address _from) external virtual override {\n // This controller must not be the project's current controller.\n if (directory.controllerOf(_projectId) == address(this))\n revert CANT_MIGRATE_TO_CURRENT_CONTROLLER();\n\n // Set the tracker as the total supply.\n _processedTokenTrackerOf[_projectId] = SafeCast.toInt256(tokenStore.totalSupplyOf(_projectId));\n\n emit PrepMigration(_projectId, _from, msg.sender);\n }\n\n /// @notice Allows a project to migrate from this controller to another.\n /// @dev Only a project's owner or a designated operator can migrate it.\n /// @param _projectId The ID of the project that will be migrated from this controller.\n /// @param _to The controller to which the project is migrating.\n function migrate(\n uint256 _projectId,\n IJBMigratable _to\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.MIGRATE_CONTROLLER)\n {\n // Keep a reference to the directory.\n IJBDirectory _directory = directory;\n\n // This controller must be the project's current controller.\n if (_directory.controllerOf(_projectId) != address(this)) revert NOT_CURRENT_CONTROLLER();\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Migration must be allowed.\n if (!_fundingCycle.controllerMigrationAllowed()) revert MIGRATION_NOT_ALLOWED();\n\n // All reserved tokens must be minted before migrating.\n if (\n _processedTokenTrackerOf[_projectId] < 0 ||\n uint256(_processedTokenTrackerOf[_projectId]) != tokenStore.totalSupplyOf(_projectId)\n ) _distributeReservedTokensOf(_projectId, '');\n\n // Make sure the new controller is prepped for the migration.\n _to.prepForMigrationOf(_projectId, address(this));\n\n // Set the new controller.\n _directory.setControllerOf(_projectId, address(_to));\n\n emit Migrate(_projectId, _to, msg.sender);\n }\n\n //*********************************************************************//\n // ------------------------ internal functions ----------------------- //\n //*********************************************************************//\n\n /// @notice Distributes all outstanding reserved tokens for a project.\n /// @param _projectId The ID of the project to which the reserved tokens belong.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return tokenCount The amount of minted reserved tokens.\n function _distributeReservedTokensOf(\n uint256 _projectId,\n string memory _memo\n ) internal returns (uint256 tokenCount) {\n // Keep a reference to the token store.\n IJBTokenStore _tokenStore = tokenStore;\n\n // Get the current funding cycle to read the reserved rate from.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Get a reference to new total supply of tokens before minting reserved tokens.\n uint256 _totalTokens = _tokenStore.totalSupplyOf(_projectId);\n\n // Get a reference to the number of tokens that need to be minted.\n tokenCount = _reservedTokenAmountFrom(\n _processedTokenTrackerOf[_projectId],\n _fundingCycle.reservedRate(),\n _totalTokens\n );\n\n // Set the tracker to be the new total supply.\n _processedTokenTrackerOf[_projectId] = SafeCast.toInt256(_totalTokens + tokenCount);\n\n // Get a reference to the project owner.\n address _owner = projects.ownerOf(_projectId);\n\n // Distribute tokens to splits and get a reference to the leftover amount to mint after all splits have gotten their share.\n uint256 _leftoverTokenCount = tokenCount == 0\n ? 0\n : _distributeToReservedTokenSplitsOf(\n _projectId,\n _fundingCycle.configuration,\n JBSplitsGroups.RESERVED_TOKENS,\n tokenCount\n );\n\n // Mint any leftover tokens to the project owner.\n if (_leftoverTokenCount > 0)\n _tokenStore.mintFor(_owner, _projectId, _leftoverTokenCount, false);\n\n emit DistributeReservedTokens(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _owner,\n tokenCount,\n _leftoverTokenCount,\n _memo,\n msg.sender\n );\n }\n\n /// @notice Distribute tokens to the splits according to the specified funding cycle configuration.\n /// @param _projectId The ID of the project for which reserved token splits are being distributed.\n /// @param _domain The domain of the splits to distribute the reserved tokens between.\n /// @param _group The group of the splits to distribute the reserved tokens between.\n /// @param _amount The total amount of tokens to mint.\n /// @return leftoverAmount If the splits percents dont add up to 100%, the leftover amount is returned.\n function _distributeToReservedTokenSplitsOf(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group,\n uint256 _amount\n ) internal returns (uint256 leftoverAmount) {\n // Keep a reference to the token store.\n IJBTokenStore _tokenStore = tokenStore;\n\n // Set the leftover amount to the initial amount.\n leftoverAmount = _amount;\n\n // Get a reference to the project's reserved token splits.\n JBSplit[] memory _splits = splitsStore.splitsOf(_projectId, _domain, _group);\n\n //Transfer between all splits.\n for (uint256 _i; _i < _splits.length; ) {\n // Get a reference to the split being iterated on.\n JBSplit memory _split = _splits[_i];\n\n // The amount to send towards the split.\n uint256 _tokenCount = PRBMath.mulDiv(\n _amount,\n _split.percent,\n JBConstants.SPLITS_TOTAL_PERCENT\n );\n\n // Mints tokens for the split if needed.\n if (_tokenCount > 0) {\n _tokenStore.mintFor(\n // If an allocator is set in the splits, set it as the beneficiary.\n // Otherwise if a projectId is set in the split, set the project's owner as the beneficiary.\n // If the split has a beneficiary send to the split's beneficiary. Otherwise send to the msg.sender.\n _split.allocator != IJBSplitAllocator(address(0))\n ? address(_split.allocator)\n : _split.projectId != 0\n ? projects.ownerOf(_split.projectId)\n : _split.beneficiary != address(0)\n ? _split.beneficiary\n : msg.sender,\n _projectId,\n _tokenCount,\n _split.preferClaimed\n );\n\n // If there's an allocator set, trigger its `allocate` function.\n if (_split.allocator != IJBSplitAllocator(address(0)))\n _split.allocator.allocate(\n JBSplitAllocationData(\n address(_tokenStore.tokenOf(_projectId)),\n _tokenCount,\n 18,\n _projectId,\n _group,\n _split\n )\n );\n\n // Subtract from the amount to be sent to the beneficiary.\n leftoverAmount = leftoverAmount - _tokenCount;\n }\n\n emit DistributeToReservedTokenSplit(\n _projectId,\n _domain,\n _group,\n _split,\n _tokenCount,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n\n /// @notice Configures a funding cycle and stores information pertinent to the configuration.\n /// @param _projectId The ID of the project whose funding cycles are being reconfigured.\n /// @param _data Data that defines the funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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.\n /// @return configuration The configuration of the funding cycle that was successfully reconfigured.\n function _configure(\n uint256 _projectId,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] memory _groupedSplits,\n JBFundAccessConstraints[] memory _fundAccessConstraints\n ) internal returns (uint256) {\n // Make sure the provided reserved rate is valid.\n if (_metadata.reservedRate > JBConstants.MAX_RESERVED_RATE) revert INVALID_RESERVED_RATE();\n\n // Make sure the provided redemption rate is valid.\n if (_metadata.redemptionRate > JBConstants.MAX_REDEMPTION_RATE)\n revert INVALID_REDEMPTION_RATE();\n\n // Make sure the provided ballot redemption rate is valid.\n if (_metadata.ballotRedemptionRate > JBConstants.MAX_REDEMPTION_RATE)\n revert INVALID_BALLOT_REDEMPTION_RATE();\n\n // Configure the funding cycle's properties.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.configureFor(\n _projectId,\n _data,\n JBFundingCycleMetadataResolver.packFundingCycleMetadata(_metadata),\n _mustStartAtOrAfter\n );\n\n // Set splits for the group.\n splitsStore.set(_projectId, _fundingCycle.configuration, _groupedSplits);\n\n // Set distribution limits if there are any.\n for (uint256 _i; _i < _fundAccessConstraints.length; ) {\n JBFundAccessConstraints memory _constraints = _fundAccessConstraints[_i];\n\n // If distribution limit value is larger than 232 bits, revert.\n if (_constraints.distributionLimit > type(uint232).max) revert INVALID_DISTRIBUTION_LIMIT();\n\n // If distribution limit currency value is larger than 24 bits, revert.\n if (_constraints.distributionLimitCurrency > type(uint24).max)\n revert INVALID_DISTRIBUTION_LIMIT_CURRENCY();\n\n // If overflow allowance value is larger than 232 bits, revert.\n if (_constraints.overflowAllowance > type(uint232).max) revert INVALID_OVERFLOW_ALLOWANCE();\n\n // If overflow allowance currency value is larger than 24 bits, revert.\n if (_constraints.overflowAllowanceCurrency > type(uint24).max)\n revert INVALID_OVERFLOW_ALLOWANCE_CURRENCY();\n\n // Set the distribution limit if there is one.\n if (_constraints.distributionLimit > 0)\n _packedDistributionLimitDataOf[_projectId][_fundingCycle.configuration][\n _constraints.terminal\n ][_constraints.token] =\n _constraints.distributionLimit |\n (_constraints.distributionLimitCurrency << 232);\n\n // Set the overflow allowance if there is one.\n if (_constraints.overflowAllowance > 0)\n _packedOverflowAllowanceDataOf[_projectId][_fundingCycle.configuration][\n _constraints.terminal\n ][_constraints.token] =\n _constraints.overflowAllowance |\n (_constraints.overflowAllowanceCurrency << 232);\n\n emit SetFundAccessConstraints(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _constraints,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n\n return _fundingCycle.configuration;\n }\n\n /// @notice Gets the amount of reserved tokens currently tracked for a project given a reserved rate.\n /// @param _processedTokenTracker The tracker to make the calculation with.\n /// @param _reservedRate The reserved rate to use to make the calculation.\n /// @param _totalEligibleTokens The total amount to make the calculation with.\n /// @return amount reserved token amount.\n function _reservedTokenAmountFrom(\n int256 _processedTokenTracker,\n uint256 _reservedRate,\n uint256 _totalEligibleTokens\n ) internal pure returns (uint256) {\n // Get a reference to the amount of tokens that are unprocessed.\n uint256 _unprocessedTokenBalanceOf = _processedTokenTracker >= 0\n ? _totalEligibleTokens - uint256(_processedTokenTracker)\n : _totalEligibleTokens + uint256(-_processedTokenTracker);\n\n // If there are no unprocessed tokens, return.\n if (_unprocessedTokenBalanceOf == 0) return 0;\n\n // If all tokens are reserved, return the full unprocessed amount.\n if (_reservedRate == JBConstants.MAX_RESERVED_RATE) return _unprocessedTokenBalanceOf;\n\n return\n PRBMath.mulDiv(\n _unprocessedTokenBalanceOf,\n JBConstants.MAX_RESERVED_RATE,\n JBConstants.MAX_RESERVED_RATE - _reservedRate\n ) - _unprocessedTokenBalanceOf;\n }\n}\n" + }, + "contracts/JBReconfigurationBufferBallot.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {ERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBBallotState} from './enums/JBBallotState.sol';\nimport {IJBFundingCycleBallot} from './interfaces/IJBFundingCycleBallot.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\n\n/// @notice Manages approving funding cycle reconfigurations automatically after a buffer period.\ncontract JBReconfigurationBufferBallot is ERC165, IJBFundingCycleBallot {\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice The number of seconds that must pass for a funding cycle reconfiguration to become either `Approved` or `Failed`.\n uint256 public immutable override duration;\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice The approval state of a particular funding cycle.\n /// @param _projectId The ID of the project to which the funding cycle being checked belongs.\n /// @param _configured The configuration of the funding cycle to check the state of.\n /// @param _start The start timestamp of the funding cycle to check the state of.\n /// @return The state of the provided ballot.\n function stateOf(\n uint256 _projectId,\n uint256 _configured,\n uint256 _start\n ) public view override returns (JBBallotState) {\n _projectId; // Prevents unused var compiler and natspec complaints.\n\n // If the provided configured timestamp is after the start timestamp, the ballot is Failed.\n if (_configured > _start) return JBBallotState.Failed;\n\n unchecked {\n // If there was sufficient time between configuration and the start of the cycle, it is approved. Otherwise, it is failed.\n return (_start - _configured < duration) ? JBBallotState.Failed : JBBallotState.Approved;\n }\n }\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if this contract adheres to the specified interface.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(ERC165, IERC165) returns (bool) {\n return\n _interfaceId == type(IJBFundingCycleBallot).interfaceId ||\n super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _duration The number of seconds to wait until a reconfiguration can be either `Approved` or `Failed`.\n constructor(uint256 _duration) {\n duration = _duration;\n }\n}\n" + }, + "contracts/JBETHERC20ProjectPayerDeployer.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Clones} from '@openzeppelin/contracts/proxy/Clones.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBProjectPayer} from './interfaces/IJBProjectPayer.sol';\nimport {IJBETHERC20ProjectPayerDeployer} from './interfaces/IJBETHERC20ProjectPayerDeployer.sol';\nimport {JBETHERC20ProjectPayer} from './JBETHERC20ProjectPayer.sol';\n\n/// @notice Deploys project payer contracts.\ncontract JBETHERC20ProjectPayerDeployer is IJBETHERC20ProjectPayerDeployer {\n //*********************************************************************//\n // --------------- public immutable stored properties ---------------- //\n //*********************************************************************//\n\n /// @notice The implementation contract on which Clones will be based.\n address immutable implementation;\n\n /// @notice directory instance which keeps a track of which controller is linked to which project.\n IJBDirectory immutable directory;\n\n //*********************************************************************//\n // ---------------------------- constructor -------------------------- //\n //*********************************************************************//\n\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n constructor(IJBDirectory _directory) {\n implementation = address(new JBETHERC20ProjectPayer(_directory));\n directory = _directory;\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Allows anyone to deploy a new project payer contract.\n /// @param _defaultProjectId The ID of the project whose treasury should be forwarded the project payer contract's received payments.\n /// @param _defaultBeneficiary The address that'll receive the project's tokens when the project payer receives payments.\n /// @param _defaultPreferClaimedTokens A flag indicating whether issued tokens from the project payer's received payments should be automatically claimed into the beneficiary's wallet.\n /// @param _defaultMemo The memo that'll be forwarded with the project payer's received payments.\n /// @param _defaultMetadata The metadata that'll be forwarded with the project payer's received payments.\n /// @param _defaultPreferAddToBalance A flag indicating if received payments should call the `pay` function or the `addToBalance` function of a project.\n /// @param _owner The address that will own the project payer.\n /// @return projectPayer The project payer contract.\n function deployProjectPayer(\n uint256 _defaultProjectId,\n address payable _defaultBeneficiary,\n bool _defaultPreferClaimedTokens,\n string memory _defaultMemo,\n bytes memory _defaultMetadata,\n bool _defaultPreferAddToBalance,\n address _owner\n ) external override returns (IJBProjectPayer projectPayer) {\n // Deploy the project payer.\n projectPayer = IJBProjectPayer(payable(Clones.clone(implementation)));\n\n // Initialize the project payer.\n projectPayer.initialize(\n _defaultProjectId,\n _defaultBeneficiary,\n _defaultPreferClaimedTokens,\n _defaultMemo,\n _defaultMetadata,\n _defaultPreferAddToBalance,\n _owner\n );\n\n emit DeployProjectPayer(\n projectPayer,\n _defaultProjectId,\n _defaultBeneficiary,\n _defaultPreferClaimedTokens,\n _defaultMemo,\n _defaultMetadata,\n _defaultPreferAddToBalance,\n directory,\n _owner,\n msg.sender\n );\n }\n}\n" + }, + "contracts/interfaces/IJBETHERC20ProjectPayerDeployer.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBDirectory} from './IJBDirectory.sol';\nimport {IJBProjectPayer} from './IJBProjectPayer.sol';\n\ninterface IJBETHERC20ProjectPayerDeployer {\n event DeployProjectPayer(\n IJBProjectPayer indexed projectPayer,\n uint256 defaultProjectId,\n address defaultBeneficiary,\n bool defaultPreferClaimedTokens,\n string defaultMemo,\n bytes defaultMetadata,\n bool preferAddToBalance,\n IJBDirectory directory,\n address owner,\n address caller\n );\n\n function deployProjectPayer(\n uint256 defaultProjectId,\n address payable defaultBeneficiary,\n bool defaultPreferClaimedTokens,\n string memory defaultMemo,\n bytes memory defaultMetadata,\n bool preferAddToBalance,\n address owner\n ) external returns (IJBProjectPayer projectPayer);\n}\n" + }, + "contracts/JBOperatorStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {JBOperatorData} from './structs/JBOperatorData.sol';\n\n/// @notice Stores operator permissions for all addresses. Addresses can give permissions to any other address to take specific indexed actions on their behalf.\ncontract JBOperatorStore is IJBOperatorStore {\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error PERMISSION_INDEX_OUT_OF_BOUNDS();\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The permissions that an operator has been given to operate on a specific domain.\n /// @dev An account can give an operator permissions that only pertain to a specific domain namespace.\n /// @dev There is no domain with a value of 0 – accounts can use the 0 domain to give an operator permissions to all domains on their behalf.\n /// @dev Permissions are stored in a packed `uint256`. Each 256 bits represents the on/off state of a permission. Applications can specify the significance of each index.\n /// @custom:param _operator The address of the operator.\n /// @custom:param _account The address of the account being operated.\n /// @custom:param _domain The domain within which the permissions apply. Applications can use the domain namespace as they wish.\n mapping(address => mapping(address => mapping(uint256 => uint256))) public override permissionsOf;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Whether or not an operator has the permission to take a certain action pertaining to the specified domain.\n /// @param _operator The operator to check.\n /// @param _account The account that has given out permissions to the operator.\n /// @param _domain The domain that the operator has been given permissions to operate.\n /// @param _permissionIndex The permission index to check for.\n /// @return A flag indicating whether the operator has the specified permission.\n function hasPermission(\n address _operator,\n address _account,\n uint256 _domain,\n uint256 _permissionIndex\n ) external view override returns (bool) {\n if (_permissionIndex > 255) revert PERMISSION_INDEX_OUT_OF_BOUNDS();\n\n return (((permissionsOf[_operator][_account][_domain] >> _permissionIndex) & 1) == 1);\n }\n\n /// @notice Whether or not an operator has the permission to take certain actions pertaining to the specified domain.\n /// @param _operator The operator to check.\n /// @param _account The account that has given out permissions to the operator.\n /// @param _domain The domain that the operator has been given permissions to operate.\n /// @param _permissionIndexes An array of permission indexes to check for.\n /// @return A flag indicating whether the operator has all specified permissions.\n function hasPermissions(\n address _operator,\n address _account,\n uint256 _domain,\n uint256[] calldata _permissionIndexes\n ) external view override returns (bool) {\n for (uint256 _i; _i < _permissionIndexes.length; ) {\n uint256 _permissionIndex = _permissionIndexes[_i];\n\n if (_permissionIndex > 255) revert PERMISSION_INDEX_OUT_OF_BOUNDS();\n\n if (((permissionsOf[_operator][_account][_domain] >> _permissionIndex) & 1) == 0)\n return false;\n\n unchecked {\n ++_i;\n }\n }\n return true;\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Sets permissions for an operators.\n /// @dev Only an address can set its own operators.\n /// @param _operatorData The data that specifies the params for the operator being set.\n function setOperator(JBOperatorData calldata _operatorData) external override {\n // Pack the indexes into a uint256.\n uint256 _packed = _packedPermissions(_operatorData.permissionIndexes);\n\n // Store the new value.\n permissionsOf[_operatorData.operator][msg.sender][_operatorData.domain] = _packed;\n\n emit SetOperator(\n _operatorData.operator,\n msg.sender,\n _operatorData.domain,\n _operatorData.permissionIndexes,\n _packed\n );\n }\n\n /// @notice Sets permissions for many operators.\n /// @dev Only an address can set its own operators.\n /// @param _operatorData The data that specify the params for each operator being set.\n function setOperators(JBOperatorData[] calldata _operatorData) external override {\n for (uint256 _i; _i < _operatorData.length; ) {\n // Pack the indexes into a uint256.\n uint256 _packed = _packedPermissions(_operatorData[_i].permissionIndexes);\n\n // Store the new value.\n permissionsOf[_operatorData[_i].operator][msg.sender][_operatorData[_i].domain] = _packed;\n\n emit SetOperator(\n _operatorData[_i].operator,\n msg.sender,\n _operatorData[_i].domain,\n _operatorData[_i].permissionIndexes,\n _packed\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n\n //*********************************************************************//\n // --------------------- private helper functions -------------------- //\n //*********************************************************************//\n\n /// @notice Converts an array of permission indexes to a packed `uint256`.\n /// @param _indexes The indexes of the permissions to pack.\n /// @return packed The packed value.\n function _packedPermissions(uint256[] calldata _indexes) private pure returns (uint256 packed) {\n for (uint256 _i; _i < _indexes.length; ) {\n uint256 _index = _indexes[_i];\n\n if (_index > 255) revert PERMISSION_INDEX_OUT_OF_BOUNDS();\n\n // Turn the bit at the index on.\n packed |= 1 << _index;\n\n unchecked {\n ++_i;\n }\n }\n }\n}\n" + }, + "contracts/JBFundAccessConstraintsStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {ERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol';\nimport {JBControllerUtility} from './abstract/JBControllerUtility.sol';\nimport {IJBFundAccessConstraintsStore} from './interfaces/IJBFundAccessConstraintsStore.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\nimport {JBFundAccessConstraints} from './structs/JBFundAccessConstraints.sol';\n\n/// @notice Information pertaining to how much funds can be accessed by a project from each payment terminal.\ncontract JBFundAccessConstraintsStore is\n JBControllerUtility,\n ERC165,\n IJBFundAccessConstraintsStore\n{\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n\n error INVALID_DISTRIBUTION_LIMIT();\n error INVALID_DISTRIBUTION_LIMIT_CURRENCY();\n error INVALID_OVERFLOW_ALLOWANCE();\n error INVALID_OVERFLOW_ALLOWANCE_CURRENCY();\n\n //*********************************************************************//\n // --------------------- internal stored properties ------------------ //\n //*********************************************************************//\n\n /// @notice Data regarding the distribution limit of a project during a configuration.\n /// @dev bits 0-231: The amount of token that a project can distribute per funding cycle.\n /// @dev bits 232-255: The currency of amount that a project can distribute.\n /// @custom:param _projectId The ID of the project to get the packed distribution limit data of.\n /// @custom:param _configuration The configuration during which the packed distribution limit data applies.\n /// @custom:param _terminal The terminal from which distributions are being limited.\n /// @custom:param _token The token for which distributions are being limited.\n mapping(uint256 => mapping(uint256 => mapping(IJBPaymentTerminal => mapping(address => uint256))))\n internal _packedDistributionLimitDataOf;\n\n /// @notice Data regarding the overflow allowance of a project during a configuration.\n /// @dev bits 0-231: The amount of overflow that a project is allowed to tap into on-demand throughout the configuration.\n /// @dev bits 232-255: The currency of the amount of overflow that a project is allowed to tap.\n /// @custom:param _projectId The ID of the project to get the packed overflow allowance data of.\n /// @custom:param _configuration The configuration during which the packed overflow allowance data applies.\n /// @custom:param _terminal The terminal managing the overflow.\n /// @custom:param _token The token for which overflow is being allowed.\n mapping(uint256 => mapping(uint256 => mapping(IJBPaymentTerminal => mapping(address => uint256))))\n internal _packedOverflowAllowanceDataOf;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice The amount of token that a project can distribute per funding cycle, and the currency it's in terms of.\n /// @dev The number of decimals in the returned fixed point amount is the same as that of the specified terminal.\n /// @param _projectId The ID of the project to get the distribution limit of.\n /// @param _configuration The configuration during which the distribution limit applies.\n /// @param _terminal The terminal from which distributions are being limited.\n /// @param _token The token for which the distribution limit applies.\n /// @return The distribution limit, as a fixed point number with the same number of decimals as the provided terminal.\n /// @return The currency of the distribution limit.\n function distributionLimitOf(\n uint256 _projectId,\n uint256 _configuration,\n IJBPaymentTerminal _terminal,\n address _token\n ) external view override returns (uint256, uint256) {\n // Get a reference to the packed data.\n uint256 _data = _packedDistributionLimitDataOf[_projectId][_configuration][_terminal][_token];\n\n // The limit is in bits 0-231. The currency is in bits 232-255.\n return (uint256(uint232(_data)), _data >> 232);\n }\n\n /// @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.\n /// @dev The number of decimals in the returned fixed point amount is the same as that of the specified terminal.\n /// @param _projectId The ID of the project to get the overflow allowance of.\n /// @param _configuration The configuration of the during which the allowance applies.\n /// @param _terminal The terminal managing the overflow.\n /// @param _token The token for which the overflow allowance applies.\n /// @return The overflow allowance, as a fixed point number with the same number of decimals as the provided terminal.\n /// @return The currency of the overflow allowance.\n function overflowAllowanceOf(\n uint256 _projectId,\n uint256 _configuration,\n IJBPaymentTerminal _terminal,\n address _token\n ) external view override returns (uint256, uint256) {\n // Get a reference to the packed data.\n uint256 _data = _packedOverflowAllowanceDataOf[_projectId][_configuration][_terminal][_token];\n\n // The allowance is in bits 0-231. The currency is in bits 232-255.\n return (uint256(uint232(_data)), _data >> 232);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n // solhint-disable-next-line no-empty-blocks\n constructor(IJBDirectory _directory) JBControllerUtility(_directory) {}\n\n //*********************************************************************//\n // --------------------- external transactions ----------------------- //\n //*********************************************************************//\n\n /// @notice Sets a project's constraints for accessing treasury funds.\n /// @dev Only a project's current controller can set its fund access constraints.\n /// @param _projectId The ID of the project whose fund access constraints are being set.\n /// @param _configuration The funding cycle configuration the constraints apply within.\n /// @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`.\n function setFor(\n uint256 _projectId,\n uint256 _configuration,\n JBFundAccessConstraints[] calldata _fundAccessConstraints\n ) external override onlyController(_projectId) {\n // Save the number of constraints.\n uint256 _numberOfFundAccessConstraints = _fundAccessConstraints.length;\n\n // Set distribution limits if there are any.\n for (uint256 _i; _i < _numberOfFundAccessConstraints; ) {\n // If distribution limit value is larger than 232 bits, revert.\n if (_fundAccessConstraints[_i].distributionLimit > type(uint232).max)\n revert INVALID_DISTRIBUTION_LIMIT();\n\n // If distribution limit currency value is larger than 24 bits, revert.\n if (_fundAccessConstraints[_i].distributionLimitCurrency > type(uint24).max)\n revert INVALID_DISTRIBUTION_LIMIT_CURRENCY();\n\n // If overflow allowance value is larger than 232 bits, revert.\n if (_fundAccessConstraints[_i].overflowAllowance > type(uint232).max)\n revert INVALID_OVERFLOW_ALLOWANCE();\n\n // If overflow allowance currency value is larger than 24 bits, revert.\n if (_fundAccessConstraints[_i].overflowAllowanceCurrency > type(uint24).max)\n revert INVALID_OVERFLOW_ALLOWANCE_CURRENCY();\n\n // Set the distribution limit if there is one.\n if (_fundAccessConstraints[_i].distributionLimit > 0)\n _packedDistributionLimitDataOf[_projectId][_configuration][\n _fundAccessConstraints[_i].terminal\n ][_fundAccessConstraints[_i].token] =\n _fundAccessConstraints[_i].distributionLimit |\n (_fundAccessConstraints[_i].distributionLimitCurrency << 232);\n\n // Set the overflow allowance if there is one.\n if (_fundAccessConstraints[_i].overflowAllowance > 0)\n _packedOverflowAllowanceDataOf[_projectId][_configuration][\n _fundAccessConstraints[_i].terminal\n ][_fundAccessConstraints[_i].token] =\n _fundAccessConstraints[_i].overflowAllowance |\n (_fundAccessConstraints[_i].overflowAllowanceCurrency << 232);\n\n emit SetFundAccessConstraints(\n _configuration,\n _projectId,\n _fundAccessConstraints[_i],\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n}\n" + }, + "contracts/interfaces/IJBTerminalUtility.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBDirectory} from './IJBDirectory.sol';\n\ninterface IJBPaymentTerminalUtility {\n function directory() external view returns (IJBDirectory);\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": [ + "ast" + ] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} \ No newline at end of file diff --git a/deployments/goerli/solcInputs/f58e5b1a8ab27311c5c442a686fda095.json b/deployments/goerli/solcInputs/f58e5b1a8ab27311c5c442a686fda095.json new file mode 100644 index 000000000..6a8aad861 --- /dev/null +++ b/deployments/goerli/solcInputs/f58e5b1a8ab27311c5c442a686fda095.json @@ -0,0 +1,461 @@ +{ + "language": "Solidity", + "sources": { + "contracts/abstract/JBControllerUtility.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {IJBControllerUtility} from './../interfaces/IJBControllerUtility.sol';\nimport {IJBDirectory} from './../interfaces/IJBDirectory.sol';\n\n/// @notice Provides tools for contracts with functionality that can only be accessed by a project's controller.\nabstract contract JBControllerUtility is IJBControllerUtility {\n //*********************************************************************//\n // --------------------------- custom errors -------------------------- //\n //*********************************************************************//\n error CONTROLLER_UNAUTHORIZED();\n\n //*********************************************************************//\n // ---------------------------- modifiers ---------------------------- //\n //*********************************************************************//\n\n /// @notice Only allows the controller of the specified project to proceed.\n /// @param _projectId The ID of the project.\n modifier onlyController(uint256 _projectId) {\n if (address(directory.controllerOf(_projectId)) != msg.sender) revert CONTROLLER_UNAUTHORIZED();\n _;\n }\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n constructor(IJBDirectory _directory) {\n directory = _directory;\n }\n}\n" + }, + "contracts/interfaces/IJBControllerUtility.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBDirectory} from './IJBDirectory.sol';\n\ninterface IJBControllerUtility {\n function directory() external view returns (IJBDirectory);\n}\n" + }, + "contracts/interfaces/IJBDirectory.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\nimport {IJBProjects} from './IJBProjects.sol';\n\ninterface IJBDirectory {\n event SetController(uint256 indexed projectId, address indexed controller, address caller);\n\n event AddTerminal(uint256 indexed projectId, IJBPaymentTerminal indexed terminal, address caller);\n\n event SetTerminals(uint256 indexed projectId, IJBPaymentTerminal[] terminals, address caller);\n\n event SetPrimaryTerminal(\n uint256 indexed projectId,\n address indexed token,\n IJBPaymentTerminal indexed terminal,\n address caller\n );\n\n event SetIsAllowedToSetFirstController(address indexed addr, bool indexed flag, address caller);\n\n function projects() external view returns (IJBProjects);\n\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\n\n function controllerOf(uint256 projectId) external view returns (address);\n\n function isAllowedToSetFirstController(address account) external view returns (bool);\n\n function terminalsOf(uint256 projectId) external view returns (IJBPaymentTerminal[] memory);\n\n function isTerminalOf(\n uint256 projectId,\n IJBPaymentTerminal terminal\n ) external view returns (bool);\n\n function primaryTerminalOf(\n uint256 projectId,\n address token\n ) external view returns (IJBPaymentTerminal);\n\n function setControllerOf(uint256 projectId, address controller) external;\n\n function setTerminalsOf(uint256 projectId, IJBPaymentTerminal[] calldata terminals) external;\n\n function setPrimaryTerminalOf(\n uint256 projectId,\n address token,\n IJBPaymentTerminal terminal\n ) external;\n\n function setIsAllowedToSetFirstController(address account, bool flag) external;\n}\n" + }, + "contracts/interfaces/IJBFundingCycleStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBBallotState} from './../enums/JBBallotState.sol';\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\nimport {JBFundingCycleData} from './../structs/JBFundingCycleData.sol';\n\ninterface IJBFundingCycleStore {\n event Configure(\n uint256 indexed configuration,\n uint256 indexed projectId,\n JBFundingCycleData data,\n uint256 metadata,\n uint256 mustStartAtOrAfter,\n address caller\n );\n\n event Init(uint256 indexed configuration, uint256 indexed projectId, uint256 indexed basedOn);\n\n function latestConfigurationOf(uint256 projectId) external view returns (uint256);\n\n function get(\n uint256 projectId,\n uint256 configuration\n ) external view returns (JBFundingCycle memory);\n\n function latestConfiguredOf(\n uint256 projectId\n ) external view returns (JBFundingCycle memory fundingCycle, JBBallotState ballotState);\n\n function queuedOf(uint256 projectId) external view returns (JBFundingCycle memory fundingCycle);\n\n function currentOf(uint256 projectId) external view returns (JBFundingCycle memory fundingCycle);\n\n function currentBallotStateOf(uint256 projectId) external view returns (JBBallotState);\n\n function configureFor(\n uint256 projectId,\n JBFundingCycleData calldata data,\n uint256 metadata,\n uint256 mustStartAtOrAfter\n ) external returns (JBFundingCycle memory fundingCycle);\n}\n" + }, + "contracts/interfaces/IJBPaymentTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\n\ninterface IJBPaymentTerminal is IERC165 {\n function acceptsToken(address token, uint256 projectId) external view returns (bool);\n\n function currencyForToken(address token) external view returns (uint256);\n\n function decimalsForToken(address token) external view returns (uint256);\n\n // Return value must be a fixed point number with 18 decimals.\n function currentEthOverflowOf(uint256 projectId) external view returns (uint256);\n\n function pay(\n uint256 projectId,\n uint256 amount,\n address token,\n address beneficiary,\n uint256 minReturnedTokens,\n bool preferClaimedTokens,\n string calldata memo,\n bytes calldata metadata\n ) external payable returns (uint256 beneficiaryTokenCount);\n\n function addToBalanceOf(\n uint256 projectId,\n uint256 amount,\n address token,\n string calldata memo,\n bytes calldata metadata\n ) external payable;\n}\n" + }, + "contracts/interfaces/IJBProjects.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC721} from '@openzeppelin/contracts/token/ERC721/IERC721.sol';\nimport {JBProjectMetadata} from './../structs/JBProjectMetadata.sol';\nimport {IJBTokenUriResolver} from './IJBTokenUriResolver.sol';\n\ninterface IJBProjects is IERC721 {\n event Create(\n uint256 indexed projectId,\n address indexed owner,\n JBProjectMetadata metadata,\n address caller\n );\n\n event SetMetadata(uint256 indexed projectId, JBProjectMetadata metadata, address caller);\n\n event SetTokenUriResolver(IJBTokenUriResolver indexed resolver, address caller);\n\n function count() external view returns (uint256);\n\n function metadataContentOf(\n uint256 projectId,\n uint256 domain\n ) external view returns (string memory);\n\n function tokenUriResolver() external view returns (IJBTokenUriResolver);\n\n function createFor(\n address owner,\n JBProjectMetadata calldata metadata\n ) external returns (uint256 projectId);\n\n function setMetadataOf(uint256 projectId, JBProjectMetadata calldata metadata) external;\n\n function setTokenUriResolver(IJBTokenUriResolver newResolver) external;\n}\n" + }, + "contracts/enums/JBBallotState.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nenum JBBallotState {\n Active,\n Approved,\n Failed\n}\n" + }, + "contracts/structs/JBFundingCycle.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBFundingCycleBallot} from './../interfaces/IJBFundingCycleBallot.sol';\n\n/// @custom:member number The funding cycle number for the cycle's project. Each funding cycle has a number that is an increment of the cycle that directly preceded it. Each project's first funding cycle has a number of 1.\n/// @custom:member configuration The timestamp when the parameters for this funding cycle were configured. This value will stay the same for subsequent funding cycles that roll over from an originally configured cycle.\n/// @custom:member basedOn The `configuration` of the funding cycle that was active when this cycle was created.\n/// @custom:member start The timestamp marking the moment from which the funding cycle is considered active. It is a unix timestamp measured in seconds.\n/// @custom:member duration The number of seconds the funding cycle lasts for, after which a new funding cycle will start. A duration of 0 means that the funding cycle will stay active until the project owner explicitly issues a reconfiguration, at which point a new funding cycle will immediately start with the updated properties. If the duration is greater than 0, a project owner cannot make changes to a funding cycle's parameters while it is active – any proposed changes will apply to the subsequent cycle. If no changes are proposed, a funding cycle rolls over to another one with the same properties but new `start` timestamp and a discounted `weight`.\n/// @custom:member weight A fixed point number with 18 decimals that contracts can use to base arbitrary calculations on. For example, payment terminals can use this to determine how many tokens should be minted when a payment is received.\n/// @custom:member discountRate A percent by how much the `weight` of the subsequent funding cycle should be reduced, if the project owner hasn't configured the subsequent funding cycle with an explicit `weight`. If it's 0, each funding cycle will have equal weight. If the number is 90%, the next funding cycle will have a 10% smaller weight. This weight is out of `JBConstants.MAX_DISCOUNT_RATE`.\n/// @custom:member ballot An address of a contract that says whether a proposed reconfiguration should be accepted or rejected. It can be used to create rules around how a project owner can change funding cycle parameters over time.\n/// @custom:member metadata Extra data that can be associated with a funding cycle.\nstruct JBFundingCycle {\n uint256 number;\n uint256 configuration;\n uint256 basedOn;\n uint256 start;\n uint256 duration;\n uint256 weight;\n uint256 discountRate;\n IJBFundingCycleBallot ballot;\n uint256 metadata;\n}\n" + }, + "contracts/structs/JBFundingCycleData.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBFundingCycleBallot} from './../interfaces/IJBFundingCycleBallot.sol';\n\n/// @custom:member duration The number of seconds the funding cycle lasts for, after which a new funding cycle will start. A duration of 0 means that the funding cycle will stay active until the project owner explicitly issues a reconfiguration, at which point a new funding cycle will immediately start with the updated properties. If the duration is greater than 0, a project owner cannot make changes to a funding cycle's parameters while it is active – any proposed changes will apply to the subsequent cycle. If no changes are proposed, a funding cycle rolls over to another one with the same properties but new `start` timestamp and a discounted `weight`.\n/// @custom:member weight A fixed point number with 18 decimals that contracts can use to base arbitrary calculations on. For example, payment terminals can use this to determine how many tokens should be minted when a payment is received.\n/// @custom:member discountRate A percent by how much the `weight` of the subsequent funding cycle should be reduced, if the project owner hasn't configured the subsequent funding cycle with an explicit `weight`. If it's 0, each funding cycle will have equal weight. If the number is 90%, the next funding cycle will have a 10% smaller weight. This weight is out of `JBConstants.MAX_DISCOUNT_RATE`.\n/// @custom:member ballot An address of a contract that says whether a proposed reconfiguration should be accepted or rejected. It can be used to create rules around how a project owner can change funding cycle parameters over time.\nstruct JBFundingCycleData {\n uint256 duration;\n uint256 weight;\n uint256 discountRate;\n IJBFundingCycleBallot ballot;\n}\n" + }, + "contracts/interfaces/IJBFundingCycleBallot.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBBallotState} from './../enums/JBBallotState.sol';\n\ninterface IJBFundingCycleBallot is IERC165 {\n function duration() external view returns (uint256);\n\n function stateOf(\n uint256 projectId,\n uint256 configuration,\n uint256 start\n ) external view returns (JBBallotState);\n}\n" + }, + "@openzeppelin/contracts/utils/introspection/IERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n" + }, + "@openzeppelin/contracts/token/ERC721/IERC721.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../../utils/introspection/IERC165.sol\";\n\n/**\n * @dev Required interface of an ERC721 compliant contract.\n */\ninterface IERC721 is IERC165 {\n /**\n * @dev Emitted when `tokenId` token is transferred from `from` to `to`.\n */\n event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);\n\n /**\n * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.\n */\n event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);\n\n /**\n * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.\n */\n event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n /**\n * @dev Returns the number of tokens in ``owner``'s account.\n */\n function balanceOf(address owner) external view returns (uint256 balance);\n\n /**\n * @dev Returns the owner of the `tokenId` token.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n */\n function ownerOf(uint256 tokenId) external view returns (address owner);\n\n /**\n * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\n * are aware of the ERC721 protocol to prevent tokens from being forever locked.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must exist and be owned by `from`.\n * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId\n ) external;\n\n /**\n * @dev Transfers `tokenId` token from `from` to `to`.\n *\n * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must be owned by `from`.\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 tokenId\n ) external;\n\n /**\n * @dev Gives permission to `to` to transfer `tokenId` token to another account.\n * The approval is cleared when the token is transferred.\n *\n * Only a single account can be approved at a time, so approving the zero address clears previous approvals.\n *\n * Requirements:\n *\n * - The caller must own the token or be an approved operator.\n * - `tokenId` must exist.\n *\n * Emits an {Approval} event.\n */\n function approve(address to, uint256 tokenId) external;\n\n /**\n * @dev Returns the account approved for `tokenId` token.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n */\n function getApproved(uint256 tokenId) external view returns (address operator);\n\n /**\n * @dev Approve or remove `operator` as an operator for the caller.\n * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.\n *\n * Requirements:\n *\n * - The `operator` cannot be the caller.\n *\n * Emits an {ApprovalForAll} event.\n */\n function setApprovalForAll(address operator, bool _approved) external;\n\n /**\n * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.\n *\n * See {setApprovalForAll}\n */\n function isApprovedForAll(address owner, address operator) external view returns (bool);\n\n /**\n * @dev Safely transfers `tokenId` token from `from` to `to`.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must exist and be owned by `from`.\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId,\n bytes calldata data\n ) external;\n}\n" + }, + "contracts/structs/JBProjectMetadata.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @custom:member content The metadata content.\n/// @custom:member domain The domain within which the metadata applies.\nstruct JBProjectMetadata {\n string content;\n uint256 domain;\n}\n" + }, + "contracts/interfaces/IJBTokenUriResolver.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBTokenUriResolver {\n function getUri(uint256 projectId) external view returns (string memory tokenUri);\n}\n" + }, + "contracts/JBTokenStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {JBControllerUtility} from './abstract/JBControllerUtility.sol';\nimport {JBOperatable} from './abstract/JBOperatable.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {IJBToken} from './interfaces/IJBToken.sol';\nimport {IJBTokenStore} from './interfaces/IJBTokenStore.sol';\nimport {JBFundingCycleMetadataResolver} from './libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBOperations} from './libraries/JBOperations.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\nimport {JBToken} from './JBToken.sol';\n\n/// @notice Manage token minting, burning, and account balances.\n/// @dev Token balances can be either represented internally or claimed as ERC-20s into wallets. This contract manages these two representations and allows claiming.\n/// @dev The total supply of a project's tokens and the balance of each account are calculated in this contract.\n/// @dev Each project can bring their own token if they prefer, and swap between tokens at any time.\ncontract JBTokenStore is JBControllerUtility, JBOperatable, IJBTokenStore {\n // A library that parses the packed funding cycle metadata into a friendlier format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error ALREADY_SET();\n error EMPTY_NAME();\n error EMPTY_SYMBOL();\n error EMPTY_TOKEN();\n error INSUFFICIENT_FUNDS();\n error INSUFFICIENT_UNCLAIMED_TOKENS();\n error PROJECT_ALREADY_HAS_TOKEN();\n error RECIPIENT_ZERO_ADDRESS();\n error TOKEN_NOT_FOUND();\n error TOKENS_MUST_HAVE_18_DECIMALS();\n error TRANSFERS_PAUSED();\n error OVERFLOW_ALERT();\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice Mints ERC-721's that represent project ownership and transfers. \n IJBProjects public immutable override projects;\n\n /// @notice The contract storing all funding cycle configurations. \n IJBFundingCycleStore public immutable override fundingCycleStore;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice Each project's attached token contract.\n /// @custom:param _projectId The ID of the project to which the token belongs. \n mapping(uint256 => IJBToken) public override tokenOf;\n\n /// @notice The total supply of unclaimed tokens for each project.\n /// @custom:param _projectId The ID of the project to which the token belongs. \n mapping(uint256 => uint256) public override unclaimedTotalSupplyOf;\n\n /// @notice Each holder's balance of unclaimed tokens for each project.\n /// @custom:param _holder The holder of balance.\n /// @custom:param _projectId The ID of the project to which the token belongs.\n mapping(address => mapping(uint256 => uint256)) public override unclaimedBalanceOf;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice The total balance of tokens a holder has for a specified project, including claimed and unclaimed tokens.\n /// @param _holder The token holder to get a balance for.\n /// @param _projectId The project to get the `_holder`s balance of.\n /// @return balance The project token balance of the `_holder \n function balanceOf(address _holder, uint256 _projectId)\n external\n view\n override\n returns (uint256 balance)\n {\n // Get a reference to the holder's unclaimed balance for the project.\n balance = unclaimedBalanceOf[_holder][_projectId];\n\n // Get a reference to the project's current token.\n IJBToken _token = tokenOf[_projectId];\n\n // If the project has a current token, add the holder's balance to the total.\n if (_token != IJBToken(address(0))) balance = balance + _token.balanceOf(_holder, _projectId);\n }\n\n //*********************************************************************//\n // --------------------------- public views -------------------------- //\n //*********************************************************************//\n\n /// @notice The total supply of tokens for each project, including claimed and unclaimed tokens.\n /// @param _projectId The ID of the project to get the total token supply of.\n /// @return totalSupply The total supply of the project's tokens.\n function totalSupplyOf(uint256 _projectId) public view override returns (uint256 totalSupply) {\n // Get a reference to the total supply of the project's unclaimed tokens.\n totalSupply = unclaimedTotalSupplyOf[_projectId];\n\n // Get a reference to the project's current token.\n IJBToken _token = tokenOf[_projectId];\n\n // If the project has a current token, add its total supply to the total.\n if (_token != IJBToken(address(0))) totalSupply = totalSupply + _token.totalSupply(_projectId);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _fundingCycleStore A contract storing all funding cycle configurations.\n constructor(\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBFundingCycleStore _fundingCycleStore\n ) JBOperatable(_operatorStore) JBControllerUtility(_directory) {\n projects = _projects;\n fundingCycleStore = _fundingCycleStore;\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Issues a project's ERC-20 tokens that'll be used when claiming tokens.\n /// @dev Deploys a project's ERC-20 token contract.\n /// @dev Only a project's owner or operator can issue its token.\n /// @param _projectId The ID of the project being issued tokens.\n /// @param _name The ERC-20's name.\n /// @param _symbol The ERC-20's symbol.\n /// @return token The token that was issued.\n function issueFor(\n uint256 _projectId,\n string calldata _name,\n string calldata _symbol\n )\n external\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.ISSUE)\n returns (IJBToken token)\n {\n // There must be a name.\n if (bytes(_name).length == 0) revert EMPTY_NAME();\n\n // There must be a symbol.\n if (bytes(_symbol).length == 0) revert EMPTY_SYMBOL();\n \n // The project shouldn't already have a token.\n if (tokenOf[_projectId] != IJBToken(address(0))) revert PROJECT_ALREADY_HAS_TOKEN();\n\n // Deploy the token contract.\n token = new JBToken(_name, _symbol, _projectId);\n\n // Store the token contract.\n tokenOf[_projectId] = token;\n\n emit Issue(_projectId, token, _name, _symbol, msg.sender);\n }\n\n /// @notice Set a project's token if not already set.\n /// @dev Only a project's owner or operator can set its token.\n /// @param _projectId The ID of the project to which the set token belongs.\n /// @param _token The new token. \n function setFor(uint256 _projectId, IJBToken _token)\n external\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.SET_TOKEN)\n {\n // Can't set to the zero address.\n if (_token == IJBToken(address(0))) revert EMPTY_TOKEN();\n\n // Can't set token if already set.\n if (tokenOf[_projectId] != IJBToken(address(0))) revert ALREADY_SET();\n\n // Can't change to a token that doesn't use 18 decimals.\n if (_token.decimals() != 18) revert TOKENS_MUST_HAVE_18_DECIMALS();\n\n // Store the new token.\n tokenOf[_projectId] = _token;\n\n emit Set(_projectId, _token, msg.sender);\n }\n\n /// @notice Mint new project tokens.\n /// @dev Only a project's current controller can mint its tokens.\n /// @param _holder The address receiving the new tokens.\n /// @param _projectId The ID of the project to which the tokens belong.\n /// @param _amount The amount of tokens to mint.\n /// @param _preferClaimedTokens A flag indicating whether there's a preference for minted tokens to be claimed automatically into the `_holder`s wallet if the project currently has a token contract attached.\n function mintFor(\n address _holder,\n uint256 _projectId,\n uint256 _amount,\n bool _preferClaimedTokens\n ) external override onlyController(_projectId) {\n // Get a reference to the project's current token.\n IJBToken _token = tokenOf[_projectId];\n\n // Save a reference to whether there exists a token and the caller prefers these claimed tokens.\n bool _shouldClaimTokens = _preferClaimedTokens && _token != IJBToken(address(0));\n\n if (_shouldClaimTokens)\n // If tokens should be claimed, mint tokens into the holder's wallet.\n _token.mint(_projectId, _holder, _amount);\n else {\n // Otherwise, add the tokens to the unclaimed balance and total supply.\n unclaimedBalanceOf[_holder][_projectId] = unclaimedBalanceOf[_holder][_projectId] + _amount;\n unclaimedTotalSupplyOf[_projectId] = unclaimedTotalSupplyOf[_projectId] + _amount;\n }\n\n // The total supply can't exceed the maximum value storable in a uint224.\n if (totalSupplyOf(_projectId) > type(uint224).max) revert OVERFLOW_ALERT();\n\n emit Mint(_holder, _projectId, _amount, _shouldClaimTokens, _preferClaimedTokens, msg.sender);\n }\n\n /// @notice Burns a project's tokens.\n /// @dev Only a project's current controller can burn its tokens.\n /// @param _holder The address that owns the tokens being burned.\n /// @param _projectId The ID of the project to which the burned tokens belong.\n /// @param _amount The amount of tokens to burn.\n /// @param _preferClaimedTokens A flag indicating whether there's a preference for tokens to burned from the `_holder`s wallet if the project currently has a token contract attached.\n function burnFrom(\n address _holder,\n uint256 _projectId,\n uint256 _amount,\n bool _preferClaimedTokens\n ) external override onlyController(_projectId) {\n // Get a reference to the project's current token.\n IJBToken _token = tokenOf[_projectId];\n\n // Get a reference to the amount of unclaimed project tokens the holder has.\n uint256 _unclaimedBalance = unclaimedBalanceOf[_holder][_projectId];\n\n // Get a reference to the amount of the project's current token the holder has in their wallet.\n uint256 _claimedBalance = _token == IJBToken(address(0))\n ? 0\n : _token.balanceOf(_holder, _projectId);\n\n // There must be adequate tokens to burn across the holder's claimed and unclaimed balance.\n if (_amount > _claimedBalance + _unclaimedBalance) revert INSUFFICIENT_FUNDS();\n\n // The amount of tokens to burn.\n uint256 _claimedTokensToBurn;\n\n // Get a reference to how many claimed tokens should be burned\n if (_claimedBalance != 0)\n if (_preferClaimedTokens)\n // If prefer converted, burn the claimed tokens before the unclaimed.\n _claimedTokensToBurn = _claimedBalance < _amount ? _claimedBalance : _amount;\n // Otherwise, burn unclaimed tokens before claimed tokens.\n else {\n unchecked {\n _claimedTokensToBurn = _unclaimedBalance < _amount ? _amount - _unclaimedBalance : 0;\n }\n }\n\n // The amount of unclaimed tokens to burn.\n uint256 _unclaimedTokensToBurn;\n unchecked {\n _unclaimedTokensToBurn = _amount - _claimedTokensToBurn;\n }\n\n // Subtract the tokens from the unclaimed balance and total supply.\n if (_unclaimedTokensToBurn > 0) {\n // Reduce the holders balance and the total supply.\n unclaimedBalanceOf[_holder][_projectId] =\n unclaimedBalanceOf[_holder][_projectId] -\n _unclaimedTokensToBurn;\n unclaimedTotalSupplyOf[_projectId] =\n unclaimedTotalSupplyOf[_projectId] -\n _unclaimedTokensToBurn;\n }\n\n // Burn the claimed tokens.\n if (_claimedTokensToBurn > 0) _token.burn(_projectId, _holder, _claimedTokensToBurn);\n\n emit Burn(\n _holder,\n _projectId,\n _amount,\n _unclaimedBalance,\n _claimedBalance,\n _preferClaimedTokens,\n msg.sender\n );\n }\n\n /// @notice Claims internally accounted for tokens into a holder's wallet.\n /// @dev Only a token holder or an operator specified by the token holder can claim its unclaimed tokens.\n /// @param _holder The owner of the tokens being claimed.\n /// @param _projectId The ID of the project whose tokens are being claimed.\n /// @param _amount The amount of tokens to claim.\n function claimFor(\n address _holder,\n uint256 _projectId,\n uint256 _amount\n ) external override requirePermission(_holder, _projectId, JBOperations.CLAIM) {\n // Get a reference to the project's current token.\n IJBToken _token = tokenOf[_projectId];\n\n // The project must have a token contract attached.\n if (_token == IJBToken(address(0))) revert TOKEN_NOT_FOUND();\n\n // Get a reference to the amount of unclaimed project tokens the holder has.\n uint256 _unclaimedBalance = unclaimedBalanceOf[_holder][_projectId];\n\n // There must be enough unclaimed tokens to claim.\n if (_unclaimedBalance < _amount) revert INSUFFICIENT_UNCLAIMED_TOKENS();\n\n unchecked {\n // Subtract the claim amount from the holder's unclaimed project token balance.\n unclaimedBalanceOf[_holder][_projectId] = _unclaimedBalance - _amount;\n\n // Subtract the claim amount from the project's unclaimed total supply.\n unclaimedTotalSupplyOf[_projectId] = unclaimedTotalSupplyOf[_projectId] - _amount;\n }\n\n // Mint the equivalent amount of the project's token for the holder.\n _token.mint(_projectId, _holder, _amount);\n\n emit Claim(_holder, _projectId, _unclaimedBalance, _amount, msg.sender);\n }\n\n /// @notice Allows a holder to transfer unclaimed tokens to another account.\n /// @dev Only a token holder or an operator can transfer its unclaimed tokens.\n /// @param _holder The address to transfer tokens from.\n /// @param _projectId The ID of the project whose tokens are being transferred.\n /// @param _recipient The recipient of the tokens.\n /// @param _amount The amount of tokens to transfer.\n function transferFrom(\n address _holder,\n uint256 _projectId,\n address _recipient,\n uint256 _amount\n ) external override requirePermission(_holder, _projectId, JBOperations.TRANSFER) {\n // Get a reference to the current funding cycle for the project.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Must not be paused.\n if (_fundingCycle.global().pauseTransfers) revert TRANSFERS_PAUSED();\n\n // Can't transfer to the zero address.\n if (_recipient == address(0)) revert RECIPIENT_ZERO_ADDRESS();\n\n // Get a reference to the holder's unclaimed project token balance.\n uint256 _unclaimedBalance = unclaimedBalanceOf[_holder][_projectId];\n\n // The holder must have enough unclaimed tokens to transfer.\n if (_amount > _unclaimedBalance) revert INSUFFICIENT_UNCLAIMED_TOKENS();\n\n // Subtract from the holder's unclaimed token balance.\n unchecked {\n unclaimedBalanceOf[_holder][_projectId] = _unclaimedBalance - _amount;\n }\n\n // Add the unclaimed project tokens to the recipient's balance.\n unclaimedBalanceOf[_recipient][_projectId] =\n unclaimedBalanceOf[_recipient][_projectId] +\n _amount;\n\n emit Transfer(_holder, _projectId, _recipient, _amount, msg.sender);\n }\n}\n" + }, + "contracts/abstract/JBOperatable.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {IJBOperatable} from './../interfaces/IJBOperatable.sol';\nimport {IJBOperatorStore} from './../interfaces/IJBOperatorStore.sol';\n\n/// @notice Modifiers to allow access to functions based on the message sender's operator status.\nabstract contract JBOperatable is IJBOperatable {\n //*********************************************************************//\n // --------------------------- custom errors -------------------------- //\n //*********************************************************************//\n error UNAUTHORIZED();\n\n //*********************************************************************//\n // ---------------------------- modifiers ---------------------------- //\n //*********************************************************************//\n\n /// @notice Only allows the speficied account or an operator of the account to proceed.\n /// @param _account The account to check for.\n /// @param _domain The domain namespace to look for an operator within.\n /// @param _permissionIndex The index of the permission to check for.\n modifier requirePermission(\n address _account,\n uint256 _domain,\n uint256 _permissionIndex\n ) {\n _requirePermission(_account, _domain, _permissionIndex);\n _;\n }\n\n /// @notice Only allows the speficied account, an operator of the account to proceed, or a truthy override flag.\n /// @param _account The account to check for.\n /// @param _domain The domain namespace to look for an operator within.\n /// @param _permissionIndex The index of the permission to check for.\n /// @param _override A condition to force allowance for.\n modifier requirePermissionAllowingOverride(\n address _account,\n uint256 _domain,\n uint256 _permissionIndex,\n bool _override\n ) {\n _requirePermissionAllowingOverride(_account, _domain, _permissionIndex, _override);\n _;\n }\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice A contract storing operator assignments.\n IJBOperatorStore public immutable override operatorStore;\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _operatorStore A contract storing operator assignments.\n constructor(IJBOperatorStore _operatorStore) {\n operatorStore = _operatorStore;\n }\n\n //*********************************************************************//\n // -------------------------- internal views ------------------------- //\n //*********************************************************************//\n\n /// @notice Require the message sender is either the account or has the specified permission.\n /// @param _account The account to allow.\n /// @param _domain The domain namespace within which the permission index will be checked.\n /// @param _permissionIndex The permission index that an operator must have within the specified domain to be allowed.\n function _requirePermission(\n address _account,\n uint256 _domain,\n uint256 _permissionIndex\n ) internal view {\n if (\n msg.sender != _account &&\n !operatorStore.hasPermission(msg.sender, _account, _domain, _permissionIndex) &&\n !operatorStore.hasPermission(msg.sender, _account, 0, _permissionIndex)\n ) revert UNAUTHORIZED();\n }\n\n /// @notice Require the message sender is either the account, has the specified permission, or the override condition is true.\n /// @param _account The account to allow.\n /// @param _domain The domain namespace within which the permission index will be checked.\n /// @param _domain The permission index that an operator must have within the specified domain to be allowed.\n /// @param _override The override condition to allow.\n function _requirePermissionAllowingOverride(\n address _account,\n uint256 _domain,\n uint256 _permissionIndex,\n bool _override\n ) internal view {\n if (\n !_override &&\n msg.sender != _account &&\n !operatorStore.hasPermission(msg.sender, _account, _domain, _permissionIndex) &&\n !operatorStore.hasPermission(msg.sender, _account, 0, _permissionIndex)\n ) revert UNAUTHORIZED();\n }\n}\n" + }, + "contracts/interfaces/IJBOperatorStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBOperatorData} from './../structs/JBOperatorData.sol';\n\ninterface IJBOperatorStore {\n event SetOperator(\n address indexed operator,\n address indexed account,\n uint256 indexed domain,\n uint256[] permissionIndexes,\n uint256 packed\n );\n\n function permissionsOf(\n address operator,\n address account,\n uint256 domain\n ) external view returns (uint256);\n\n function hasPermission(\n address operator,\n address account,\n uint256 domain,\n uint256 permissionIndex\n ) external view returns (bool);\n\n function hasPermissions(\n address operator,\n address account,\n uint256 domain,\n uint256[] calldata permissionIndexes\n ) external view returns (bool);\n\n function setOperator(JBOperatorData calldata operatorData) external;\n\n function setOperators(JBOperatorData[] calldata operatorData) external;\n}\n" + }, + "contracts/interfaces/IJBToken.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBToken {\n function projectId() external view returns (uint256);\n\n function decimals() external view returns (uint8);\n\n function totalSupply(uint256 projectId) external view returns (uint256);\n\n function balanceOf(address account, uint256 projectId) external view returns (uint256);\n\n function mint(uint256 projectId, address account, uint256 amount) external;\n\n function burn(uint256 projectId, address account, uint256 amount) external;\n\n function approve(uint256, address spender, uint256 amount) external;\n\n function transfer(uint256 projectId, address to, uint256 amount) external;\n\n function transferFrom(uint256 projectId, address from, address to, uint256 amount) external;\n}\n" + }, + "contracts/interfaces/IJBTokenStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\nimport {IJBProjects} from './IJBProjects.sol';\nimport {IJBToken} from './IJBToken.sol';\n\ninterface IJBTokenStore {\n event Issue(\n uint256 indexed projectId,\n IJBToken indexed token,\n string name,\n string symbol,\n address caller\n );\n\n event Mint(\n address indexed holder,\n uint256 indexed projectId,\n uint256 amount,\n bool tokensWereClaimed,\n bool preferClaimedTokens,\n address caller\n );\n\n event Burn(\n address indexed holder,\n uint256 indexed projectId,\n uint256 amount,\n uint256 initialUnclaimedBalance,\n uint256 initialClaimedBalance,\n bool preferClaimedTokens,\n address caller\n );\n\n event Claim(\n address indexed holder,\n uint256 indexed projectId,\n uint256 initialUnclaimedBalance,\n uint256 amount,\n address caller\n );\n\n event Set(uint256 indexed projectId, IJBToken indexed newToken, address caller);\n\n event Transfer(\n address indexed holder,\n uint256 indexed projectId,\n address indexed recipient,\n uint256 amount,\n address caller\n );\n\n function tokenOf(uint256 projectId) external view returns (IJBToken);\n\n function projects() external view returns (IJBProjects);\n\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\n\n function unclaimedBalanceOf(address holder, uint256 projectId) external view returns (uint256);\n\n function unclaimedTotalSupplyOf(uint256 projectId) external view returns (uint256);\n\n function totalSupplyOf(uint256 projectId) external view returns (uint256);\n\n function balanceOf(address holder, uint256 projectId) external view returns (uint256 result);\n\n function issueFor(\n uint256 projectId,\n string calldata name,\n string calldata symbol\n ) external returns (IJBToken token);\n\n function setFor(uint256 projectId, IJBToken token) external;\n\n function burnFrom(\n address holder,\n uint256 projectId,\n uint256 amount,\n bool preferClaimedTokens\n ) external;\n\n function mintFor(\n address holder,\n uint256 projectId,\n uint256 amount,\n bool preferClaimedTokens\n ) external;\n\n function claimFor(address holder, uint256 projectId, uint256 amount) external;\n\n function transferFrom(\n address holder,\n uint256 projectId,\n address recipient,\n uint256 amount\n ) external;\n}\n" + }, + "contracts/libraries/JBFundingCycleMetadataResolver.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\nimport {JBFundingCycleMetadata} from './../structs/JBFundingCycleMetadata.sol';\nimport {JBGlobalFundingCycleMetadata} from './../structs/JBGlobalFundingCycleMetadata.sol';\nimport {JBConstants} from './JBConstants.sol';\nimport {JBGlobalFundingCycleMetadataResolver} from './JBGlobalFundingCycleMetadataResolver.sol';\n\nlibrary JBFundingCycleMetadataResolver {\n function global(JBFundingCycle memory _fundingCycle)\n internal\n pure\n returns (JBGlobalFundingCycleMetadata memory)\n {\n return JBGlobalFundingCycleMetadataResolver.expandMetadata(uint8(_fundingCycle.metadata >> 8));\n }\n\n function reservedRate(JBFundingCycle memory _fundingCycle) internal pure returns (uint256) {\n return uint256(uint16(_fundingCycle.metadata >> 24));\n }\n\n function redemptionRate(JBFundingCycle memory _fundingCycle) internal pure returns (uint256) {\n // Redemption rate is a number 0-10000. It's inverse was stored so the most common case of 100% results in no storage needs.\n return JBConstants.MAX_REDEMPTION_RATE - uint256(uint16(_fundingCycle.metadata >> 40));\n }\n\n function ballotRedemptionRate(JBFundingCycle memory _fundingCycle)\n internal\n pure\n returns (uint256)\n {\n // Redemption rate is a number 0-10000. It's inverse was stored so the most common case of 100% results in no storage needs.\n return JBConstants.MAX_REDEMPTION_RATE - uint256(uint16(_fundingCycle.metadata >> 56));\n }\n\n function payPaused(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\n return ((_fundingCycle.metadata >> 72) & 1) == 1;\n }\n\n function distributionsPaused(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\n return ((_fundingCycle.metadata >> 73) & 1) == 1;\n }\n\n function redeemPaused(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\n return ((_fundingCycle.metadata >> 74) & 1) == 1;\n }\n\n function burnPaused(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\n return ((_fundingCycle.metadata >> 75) & 1) == 1;\n }\n\n function mintingAllowed(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\n return ((_fundingCycle.metadata >> 76) & 1) == 1;\n }\n\n function terminalMigrationAllowed(JBFundingCycle memory _fundingCycle)\n internal\n pure\n returns (bool)\n {\n return ((_fundingCycle.metadata >> 77) & 1) == 1;\n }\n\n function controllerMigrationAllowed(JBFundingCycle memory _fundingCycle)\n internal\n pure\n returns (bool)\n {\n return ((_fundingCycle.metadata >> 78) & 1) == 1;\n }\n\n function shouldHoldFees(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\n return ((_fundingCycle.metadata >> 79) & 1) == 1;\n }\n\n function preferClaimedTokenOverride(JBFundingCycle memory _fundingCycle)\n internal\n pure\n returns (bool)\n {\n return ((_fundingCycle.metadata >> 80) & 1) == 1;\n }\n\n function useTotalOverflowForRedemptions(JBFundingCycle memory _fundingCycle)\n internal\n pure\n returns (bool)\n {\n return ((_fundingCycle.metadata >> 81) & 1) == 1;\n }\n\n function useDataSourceForPay(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\n return (_fundingCycle.metadata >> 82) & 1 == 1;\n }\n\n function useDataSourceForRedeem(JBFundingCycle memory _fundingCycle)\n internal\n pure\n returns (bool)\n {\n return (_fundingCycle.metadata >> 83) & 1 == 1;\n }\n\n function dataSource(JBFundingCycle memory _fundingCycle) internal pure returns (address) {\n return address(uint160(_fundingCycle.metadata >> 84));\n }\n\n function metadata(JBFundingCycle memory _fundingCycle) internal pure returns (uint256) {\n return uint256(uint8(_fundingCycle.metadata >> 244));\n }\n\n /// @notice Pack the funding cycle metadata.\n /// @param _metadata The metadata to validate and pack.\n /// @return packed The packed uint256 of all metadata params. The first 8 bits specify the version. \n function packFundingCycleMetadata(JBFundingCycleMetadata memory _metadata)\n internal\n pure\n returns (uint256 packed)\n {\n // version 1 in the bits 0-7 (8 bits).\n packed = 1;\n // global metadta in bits 8-23 (16 bits).\n packed |=\n JBGlobalFundingCycleMetadataResolver.packFundingCycleGlobalMetadata(_metadata.global) <<\n 8;\n // reserved rate in bits 24-39 (16 bits).\n packed |= _metadata.reservedRate << 24;\n // redemption rate in bits 40-55 (16 bits).\n // redemption rate is a number 0-10000. Store the reverse so the most common case of 100% results in no storage needs.\n packed |= (JBConstants.MAX_REDEMPTION_RATE - _metadata.redemptionRate) << 40;\n // ballot redemption rate rate in bits 56-71 (16 bits).\n // ballot redemption rate is a number 0-10000. Store the reverse so the most common case of 100% results in no storage needs.\n packed |= (JBConstants.MAX_REDEMPTION_RATE - _metadata.ballotRedemptionRate) << 56;\n // pause pay in bit 72.\n if (_metadata.pausePay) packed |= 1 << 72;\n // pause tap in bit 73.\n if (_metadata.pauseDistributions) packed |= 1 << 73;\n // pause redeem in bit 74.\n if (_metadata.pauseRedeem) packed |= 1 << 74;\n // pause burn in bit 75.\n if (_metadata.pauseBurn) packed |= 1 << 75;\n // allow minting in bit 76.\n if (_metadata.allowMinting) packed |= 1 << 76;\n // allow terminal migration in bit 77.\n if (_metadata.allowTerminalMigration) packed |= 1 << 77;\n // allow controller migration in bit 78.\n if (_metadata.allowControllerMigration) packed |= 1 << 78;\n // hold fees in bit 79.\n if (_metadata.holdFees) packed |= 1 << 79;\n // prefer claimed token override in bit 80.\n if (_metadata.preferClaimedTokenOverride) packed |= 1 << 80;\n // useTotalOverflowForRedemptions in bit 81.\n if (_metadata.useTotalOverflowForRedemptions) packed |= 1 << 81;\n // use pay data source in bit 82.\n if (_metadata.useDataSourceForPay) packed |= 1 << 82;\n // use redeem data source in bit 83.\n if (_metadata.useDataSourceForRedeem) packed |= 1 << 83;\n // data source address in bits 84-243.\n packed |= uint256(uint160(address(_metadata.dataSource))) << 84;\n // metadata in bits 244-252 (8 bits).\n packed |= _metadata.metadata << 244;\n }\n\n /// @notice Expand the funding cycle metadata.\n /// @param _fundingCycle The funding cycle having its metadata expanded.\n /// @return metadata The metadata object. \n function expandMetadata(JBFundingCycle memory _fundingCycle)\n internal\n pure\n returns (JBFundingCycleMetadata memory)\n {\n return\n JBFundingCycleMetadata(\n global(_fundingCycle),\n reservedRate(_fundingCycle),\n redemptionRate(_fundingCycle),\n ballotRedemptionRate(_fundingCycle),\n payPaused(_fundingCycle),\n distributionsPaused(_fundingCycle),\n redeemPaused(_fundingCycle),\n burnPaused(_fundingCycle),\n mintingAllowed(_fundingCycle),\n terminalMigrationAllowed(_fundingCycle),\n controllerMigrationAllowed(_fundingCycle),\n shouldHoldFees(_fundingCycle),\n preferClaimedTokenOverride(_fundingCycle),\n useTotalOverflowForRedemptions(_fundingCycle),\n useDataSourceForPay(_fundingCycle),\n useDataSourceForRedeem(_fundingCycle),\n dataSource(_fundingCycle),\n metadata(_fundingCycle)\n );\n }\n}\n" + }, + "contracts/libraries/JBOperations.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nlibrary JBOperations {\n uint256 public constant RECONFIGURE = 1;\n uint256 public constant REDEEM = 2;\n uint256 public constant MIGRATE_CONTROLLER = 3;\n uint256 public constant MIGRATE_TERMINAL = 4;\n uint256 public constant PROCESS_FEES = 5;\n uint256 public constant SET_METADATA = 6;\n uint256 public constant ISSUE = 7;\n uint256 public constant SET_TOKEN = 8;\n uint256 public constant MINT = 9;\n uint256 public constant BURN = 10;\n uint256 public constant CLAIM = 11;\n uint256 public constant TRANSFER = 12;\n uint256 public constant REQUIRE_CLAIM = 13; // unused in v3\n uint256 public constant SET_CONTROLLER = 14;\n uint256 public constant SET_TERMINALS = 15;\n uint256 public constant SET_PRIMARY_TERMINAL = 16;\n uint256 public constant USE_ALLOWANCE = 17;\n uint256 public constant SET_SPLITS = 18;\n}\n" + }, + "contracts/JBToken.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';\nimport {ERC20Votes, ERC20, ERC20Permit} from '@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.sol';\nimport {IJBToken} from './interfaces/IJBToken.sol';\n\n/// @notice An ERC-20 token that can be used by a project in the `JBTokenStore`.\ncontract JBToken is ERC20Votes, Ownable, IJBToken {\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error BAD_PROJECT();\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The ID of the project that this token should be exclusively used for. Send 0 to support any project.\n uint256 public immutable override projectId;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice The total supply of this ERC20.\n /// @param _projectId the ID of the project to which the token belongs. This is ignored.\n /// @return The total supply of this ERC20, as a fixed point number.\n function totalSupply(uint256 _projectId) external view override returns (uint256) {\n _projectId; // Prevents unused var compiler and natspec complaints.\n\n return super.totalSupply();\n }\n\n /// @notice An account's balance of this ERC20.\n /// @param _account The account to get a balance of.\n /// @param _projectId is the ID of the project to which the token belongs. This is ignored.\n /// @return The balance of the `_account` of this ERC20, as a fixed point number with 18 decimals.\n function balanceOf(\n address _account,\n uint256 _projectId\n ) external view override returns (uint256) {\n _account; // Prevents unused var compiler and natspec complaints.\n _projectId; // Prevents unused var compiler and natspec complaints.\n\n return super.balanceOf(_account);\n }\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice The number of decimals included in the fixed point accounting of this token.\n /// @return The number of decimals.\n function decimals() public view override(ERC20, IJBToken) returns (uint8) {\n return super.decimals();\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _name The name of the token.\n /// @param _symbol The symbol that the token should be represented by.\n /// @param _projectId The ID of the project that this token should be exclusively used for. Send 0 to support any project.\n constructor(\n string memory _name,\n string memory _symbol,\n uint256 _projectId\n ) ERC20(_name, _symbol) ERC20Permit(_name) {\n projectId = _projectId;\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Mints more of the token.\n /// @dev Only the owner of this contract cant mint more of it.\n /// @param _projectId The ID of the project to which the token belongs.\n /// @param _account The account to mint the tokens for.\n /// @param _amount The amount of tokens to mint, as a fixed point number with 18 decimals.\n function mint(uint256 _projectId, address _account, uint256 _amount) external override onlyOwner {\n // Can't mint for a wrong project.\n if (projectId != 0 && _projectId != projectId) revert BAD_PROJECT();\n\n return _mint(_account, _amount);\n }\n\n /// @notice Burn some outstanding tokens.\n /// @dev Only the owner of this contract cant burn some of its supply.\n /// @param _projectId The ID of the project to which the token belongs.\n /// @param _account The account to burn tokens from.\n /// @param _amount The amount of tokens to burn, as a fixed point number with 18 decimals.\n function burn(uint256 _projectId, address _account, uint256 _amount) external override onlyOwner {\n // Can't burn for a wrong project.\n if (projectId != 0 && _projectId != projectId) revert BAD_PROJECT();\n\n return _burn(_account, _amount);\n }\n\n /// @notice Approves an account to spend tokens on the `msg.sender`s behalf.\n /// @param _projectId the ID of the project to which the token belongs.\n /// @param _spender The address that will be spending tokens on the `msg.sender`s behalf.\n /// @param _amount The amount the `_spender` is allowed to spend.\n function approve(uint256 _projectId, address _spender, uint256 _amount) external override {\n // Can't approve for a wrong project.\n if (projectId != 0 && _projectId != projectId) revert BAD_PROJECT();\n\n approve(_spender, _amount);\n }\n\n /// @notice Transfer tokens to an account.\n /// @param _projectId The ID of the project to which the token belongs.\n /// @param _to The destination address.\n /// @param _amount The amount of the transfer, as a fixed point number with 18 decimals.\n function transfer(uint256 _projectId, address _to, uint256 _amount) external override {\n // Can't transfer for a wrong project.\n if (projectId != 0 && _projectId != projectId) revert BAD_PROJECT();\n\n transfer(_to, _amount);\n }\n\n /// @notice Transfer tokens between accounts.\n /// @param _projectId The ID of the project to which the token belongs.\n /// @param _from The originating address.\n /// @param _to The destination address.\n /// @param _amount The amount of the transfer, as a fixed point number with 18 decimals.\n function transferFrom(\n uint256 _projectId,\n address _from,\n address _to,\n uint256 _amount\n ) external override {\n // Can't transfer for a wrong project.\n if (projectId != 0 && _projectId != projectId) revert BAD_PROJECT();\n\n transferFrom(_from, _to, _amount);\n }\n}\n" + }, + "contracts/interfaces/IJBOperatable.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBOperatorStore} from './IJBOperatorStore.sol';\n\ninterface IJBOperatable {\n function operatorStore() external view returns (IJBOperatorStore);\n}\n" + }, + "contracts/structs/JBOperatorData.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @custom:member operator The address of the operator.\n/// @custom:member domain The domain within which the operator is being given permissions. A domain of 0 is a wildcard domain, which gives an operator access to all domains.\n/// @custom:member permissionIndexes The indexes of the permissions the operator is being given.\nstruct JBOperatorData {\n address operator;\n uint256 domain;\n uint256[] permissionIndexes;\n}\n" + }, + "contracts/structs/JBFundingCycleMetadata.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBGlobalFundingCycleMetadata} from './JBGlobalFundingCycleMetadata.sol';\n\n/// @custom:member global Data used globally in non-migratable ecosystem contracts.\n/// @custom:member reservedRate The reserved rate of the funding cycle. This number is a percentage calculated out of `JBConstants.MAX_RESERVED_RATE`.\n/// @custom:member redemptionRate The redemption rate of the funding cycle. This number is a percentage calculated out of `JBConstants.MAX_REDEMPTION_RATE`.\n/// @custom:member ballotRedemptionRate The redemption rate to use during an active ballot of the funding cycle. This number is a percentage calculated out of `JBConstants.MAX_REDEMPTION_RATE`.\n/// @custom:member pausePay A flag indicating if the pay functionality should be paused during the funding cycle.\n/// @custom:member pauseDistributions A flag indicating if the distribute functionality should be paused during the funding cycle.\n/// @custom:member pauseRedeem A flag indicating if the redeem functionality should be paused during the funding cycle.\n/// @custom:member pauseBurn A flag indicating if the burn functionality should be paused during the funding cycle.\n/// @custom:member allowMinting A flag indicating if minting tokens should be allowed during this funding cycle.\n/// @custom:member allowTerminalMigration A flag indicating if migrating terminals should be allowed during this funding cycle.\n/// @custom:member allowControllerMigration A flag indicating if migrating controllers should be allowed during this funding cycle.\n/// @custom:member holdFees A flag indicating if fees should be held during this funding cycle.\n/// @custom:member preferClaimedTokenOverride A flag indicating if claimed tokens should always be prefered to unclaimed tokens when minting.\n/// @custom:member useTotalOverflowForRedemptions A flag indicating if redemptions should use the project's balance held in all terminals instead of the project's local terminal balance from which the redemption is being fulfilled.\n/// @custom:member useDataSourceForPay A flag indicating if the data source should be used for pay transactions during this funding cycle.\n/// @custom:member useDataSourceForRedeem A flag indicating if the data source should be used for redeem transactions during this funding cycle.\n/// @custom:member dataSource The data source to use during this funding cycle.\n/// @custom:member metadata Metadata of the metadata, up to uint8 in size.\nstruct JBFundingCycleMetadata {\n JBGlobalFundingCycleMetadata global;\n uint256 reservedRate;\n uint256 redemptionRate;\n uint256 ballotRedemptionRate;\n bool pausePay;\n bool pauseDistributions;\n bool pauseRedeem;\n bool pauseBurn;\n bool allowMinting;\n bool allowTerminalMigration;\n bool allowControllerMigration;\n bool holdFees;\n bool preferClaimedTokenOverride;\n bool useTotalOverflowForRedemptions;\n bool useDataSourceForPay;\n bool useDataSourceForRedeem;\n address dataSource;\n uint256 metadata;\n}\n" + }, + "contracts/structs/JBGlobalFundingCycleMetadata.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @custom:member allowSetTerminals A flag indicating if setting terminals should be allowed during this funding cycle.\n/// @custom:member allowSetController A flag indicating if setting a new controller should be allowed during this funding cycle.\n/// @custom:member pauseTransfers A flag indicating if the project token transfer functionality should be paused during the funding cycle.\nstruct JBGlobalFundingCycleMetadata {\n bool allowSetTerminals;\n bool allowSetController;\n bool pauseTransfers;\n}\n" + }, + "contracts/libraries/JBConstants.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @notice Global constants used across Juicebox contracts.\nlibrary JBConstants {\n uint256 public constant MAX_RESERVED_RATE = 10_000;\n uint256 public constant MAX_REDEMPTION_RATE = 10_000;\n uint256 public constant MAX_DISCOUNT_RATE = 1_000_000_000;\n uint256 public constant SPLITS_TOTAL_PERCENT = 1_000_000_000;\n uint256 public constant MAX_FEE = 1_000_000_000;\n uint256 public constant MAX_FEE_DISCOUNT = 1_000_000_000;\n}\n" + }, + "contracts/libraries/JBGlobalFundingCycleMetadataResolver.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {JBFundingCycleMetadata} from './../structs/JBFundingCycleMetadata.sol';\nimport {JBGlobalFundingCycleMetadata} from './../structs/JBGlobalFundingCycleMetadata.sol';\n\nlibrary JBGlobalFundingCycleMetadataResolver {\n function setTerminalsAllowed(uint8 _data) internal pure returns (bool) {\n return (_data & 1) == 1;\n }\n\n function setControllerAllowed(uint8 _data) internal pure returns (bool) {\n return ((_data >> 1) & 1) == 1;\n }\n\n function transfersPaused(uint8 _data) internal pure returns (bool) {\n return ((_data >> 2) & 1) == 1;\n }\n\n /// @notice Pack the global funding cycle metadata.\n /// @param _metadata The metadata to validate and pack.\n /// @return packed The packed uint256 of all global metadata params. The first 8 bits specify the version.\n function packFundingCycleGlobalMetadata(\n JBGlobalFundingCycleMetadata memory _metadata\n ) internal pure returns (uint256 packed) {\n // allow set terminals in bit 0.\n if (_metadata.allowSetTerminals) packed |= 1;\n // allow set controller in bit 1.\n if (_metadata.allowSetController) packed |= 1 << 1;\n // pause transfers in bit 2.\n if (_metadata.pauseTransfers) packed |= 1 << 2;\n }\n\n /// @notice Expand the global funding cycle metadata.\n /// @param _packedMetadata The packed metadata to expand.\n /// @return metadata The global metadata object.\n function expandMetadata(\n uint8 _packedMetadata\n ) internal pure returns (JBGlobalFundingCycleMetadata memory metadata) {\n return\n JBGlobalFundingCycleMetadata(\n setTerminalsAllowed(_packedMetadata),\n setControllerAllowed(_packedMetadata),\n transfersPaused(_packedMetadata)\n );\n }\n}\n" + }, + "@openzeppelin/contracts/access/Ownable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n _;\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (token/ERC20/extensions/ERC20Votes.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./draft-ERC20Permit.sol\";\nimport \"../../../utils/math/Math.sol\";\nimport \"../../../governance/utils/IVotes.sol\";\nimport \"../../../utils/math/SafeCast.sol\";\nimport \"../../../utils/cryptography/ECDSA.sol\";\n\n/**\n * @dev Extension of ERC20 to support Compound-like voting and delegation. This version is more generic than Compound's,\n * and supports token supply up to 2^224^ - 1, while COMP is limited to 2^96^ - 1.\n *\n * NOTE: If exact COMP compatibility is required, use the {ERC20VotesComp} variant of this module.\n *\n * This extension keeps a history (checkpoints) of each account's vote power. Vote power can be delegated either\n * by calling the {delegate} function directly, or by providing a signature to be used with {delegateBySig}. Voting\n * power can be queried through the public accessors {getVotes} and {getPastVotes}.\n *\n * By default, token balance does not account for voting power. This makes transfers cheaper. The downside is that it\n * requires users to delegate to themselves in order to activate checkpoints and have their voting power tracked.\n *\n * _Available since v4.2._\n */\nabstract contract ERC20Votes is IVotes, ERC20Permit {\n struct Checkpoint {\n uint32 fromBlock;\n uint224 votes;\n }\n\n bytes32 private constant _DELEGATION_TYPEHASH =\n keccak256(\"Delegation(address delegatee,uint256 nonce,uint256 expiry)\");\n\n mapping(address => address) private _delegates;\n mapping(address => Checkpoint[]) private _checkpoints;\n Checkpoint[] private _totalSupplyCheckpoints;\n\n /**\n * @dev Get the `pos`-th checkpoint for `account`.\n */\n function checkpoints(address account, uint32 pos) public view virtual returns (Checkpoint memory) {\n return _checkpoints[account][pos];\n }\n\n /**\n * @dev Get number of checkpoints for `account`.\n */\n function numCheckpoints(address account) public view virtual returns (uint32) {\n return SafeCast.toUint32(_checkpoints[account].length);\n }\n\n /**\n * @dev Get the address `account` is currently delegating to.\n */\n function delegates(address account) public view virtual override returns (address) {\n return _delegates[account];\n }\n\n /**\n * @dev Gets the current votes balance for `account`\n */\n function getVotes(address account) public view virtual override returns (uint256) {\n uint256 pos = _checkpoints[account].length;\n return pos == 0 ? 0 : _checkpoints[account][pos - 1].votes;\n }\n\n /**\n * @dev Retrieve the number of votes for `account` at the end of `blockNumber`.\n *\n * Requirements:\n *\n * - `blockNumber` must have been already mined\n */\n function getPastVotes(address account, uint256 blockNumber) public view virtual override returns (uint256) {\n require(blockNumber < block.number, \"ERC20Votes: block not yet mined\");\n return _checkpointsLookup(_checkpoints[account], blockNumber);\n }\n\n /**\n * @dev Retrieve the `totalSupply` at the end of `blockNumber`. Note, this value is the sum of all balances.\n * It is but NOT the sum of all the delegated votes!\n *\n * Requirements:\n *\n * - `blockNumber` must have been already mined\n */\n function getPastTotalSupply(uint256 blockNumber) public view virtual override returns (uint256) {\n require(blockNumber < block.number, \"ERC20Votes: block not yet mined\");\n return _checkpointsLookup(_totalSupplyCheckpoints, blockNumber);\n }\n\n /**\n * @dev Lookup a value in a list of (sorted) checkpoints.\n */\n function _checkpointsLookup(Checkpoint[] storage ckpts, uint256 blockNumber) private view returns (uint256) {\n // We run a binary search to look for the earliest checkpoint taken after `blockNumber`.\n //\n // During the loop, the index of the wanted checkpoint remains in the range [low-1, high).\n // With each iteration, either `low` or `high` is moved towards the middle of the range to maintain the invariant.\n // - If the middle checkpoint is after `blockNumber`, we look in [low, mid)\n // - If the middle checkpoint is before or equal to `blockNumber`, we look in [mid+1, high)\n // Once we reach a single value (when low == high), we've found the right checkpoint at the index high-1, if not\n // out of bounds (in which case we're looking too far in the past and the result is 0).\n // Note that if the latest checkpoint available is exactly for `blockNumber`, we end up with an index that is\n // past the end of the array, so we technically don't find a checkpoint after `blockNumber`, but it works out\n // the same.\n uint256 high = ckpts.length;\n uint256 low = 0;\n while (low < high) {\n uint256 mid = Math.average(low, high);\n if (ckpts[mid].fromBlock > blockNumber) {\n high = mid;\n } else {\n low = mid + 1;\n }\n }\n\n return high == 0 ? 0 : ckpts[high - 1].votes;\n }\n\n /**\n * @dev Delegate votes from the sender to `delegatee`.\n */\n function delegate(address delegatee) public virtual override {\n _delegate(_msgSender(), delegatee);\n }\n\n /**\n * @dev Delegates votes from signer to `delegatee`\n */\n function delegateBySig(\n address delegatee,\n uint256 nonce,\n uint256 expiry,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) public virtual override {\n require(block.timestamp <= expiry, \"ERC20Votes: signature expired\");\n address signer = ECDSA.recover(\n _hashTypedDataV4(keccak256(abi.encode(_DELEGATION_TYPEHASH, delegatee, nonce, expiry))),\n v,\n r,\n s\n );\n require(nonce == _useNonce(signer), \"ERC20Votes: invalid nonce\");\n _delegate(signer, delegatee);\n }\n\n /**\n * @dev Maximum token supply. Defaults to `type(uint224).max` (2^224^ - 1).\n */\n function _maxSupply() internal view virtual returns (uint224) {\n return type(uint224).max;\n }\n\n /**\n * @dev Snapshots the totalSupply after it has been increased.\n */\n function _mint(address account, uint256 amount) internal virtual override {\n super._mint(account, amount);\n require(totalSupply() <= _maxSupply(), \"ERC20Votes: total supply risks overflowing votes\");\n\n _writeCheckpoint(_totalSupplyCheckpoints, _add, amount);\n }\n\n /**\n * @dev Snapshots the totalSupply after it has been decreased.\n */\n function _burn(address account, uint256 amount) internal virtual override {\n super._burn(account, amount);\n\n _writeCheckpoint(_totalSupplyCheckpoints, _subtract, amount);\n }\n\n /**\n * @dev Move voting power when tokens are transferred.\n *\n * Emits a {DelegateVotesChanged} event.\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual override {\n super._afterTokenTransfer(from, to, amount);\n\n _moveVotingPower(delegates(from), delegates(to), amount);\n }\n\n /**\n * @dev Change delegation for `delegator` to `delegatee`.\n *\n * Emits events {DelegateChanged} and {DelegateVotesChanged}.\n */\n function _delegate(address delegator, address delegatee) internal virtual {\n address currentDelegate = delegates(delegator);\n uint256 delegatorBalance = balanceOf(delegator);\n _delegates[delegator] = delegatee;\n\n emit DelegateChanged(delegator, currentDelegate, delegatee);\n\n _moveVotingPower(currentDelegate, delegatee, delegatorBalance);\n }\n\n function _moveVotingPower(\n address src,\n address dst,\n uint256 amount\n ) private {\n if (src != dst && amount > 0) {\n if (src != address(0)) {\n (uint256 oldWeight, uint256 newWeight) = _writeCheckpoint(_checkpoints[src], _subtract, amount);\n emit DelegateVotesChanged(src, oldWeight, newWeight);\n }\n\n if (dst != address(0)) {\n (uint256 oldWeight, uint256 newWeight) = _writeCheckpoint(_checkpoints[dst], _add, amount);\n emit DelegateVotesChanged(dst, oldWeight, newWeight);\n }\n }\n }\n\n function _writeCheckpoint(\n Checkpoint[] storage ckpts,\n function(uint256, uint256) view returns (uint256) op,\n uint256 delta\n ) private returns (uint256 oldWeight, uint256 newWeight) {\n uint256 pos = ckpts.length;\n oldWeight = pos == 0 ? 0 : ckpts[pos - 1].votes;\n newWeight = op(oldWeight, delta);\n\n if (pos > 0 && ckpts[pos - 1].fromBlock == block.number) {\n ckpts[pos - 1].votes = SafeCast.toUint224(newWeight);\n } else {\n ckpts.push(Checkpoint({fromBlock: SafeCast.toUint32(block.number), votes: SafeCast.toUint224(newWeight)}));\n }\n }\n\n function _add(uint256 a, uint256 b) private pure returns (uint256) {\n return a + b;\n }\n\n function _subtract(uint256 a, uint256 b) private pure returns (uint256) {\n return a - b;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Context.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-ERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./draft-IERC20Permit.sol\";\nimport \"../ERC20.sol\";\nimport \"../../../utils/cryptography/draft-EIP712.sol\";\nimport \"../../../utils/cryptography/ECDSA.sol\";\nimport \"../../../utils/Counters.sol\";\n\n/**\n * @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * _Available since v3.4._\n */\nabstract contract ERC20Permit is ERC20, IERC20Permit, EIP712 {\n using Counters for Counters.Counter;\n\n mapping(address => Counters.Counter) private _nonces;\n\n // solhint-disable-next-line var-name-mixedcase\n bytes32 private immutable _PERMIT_TYPEHASH =\n keccak256(\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\");\n\n /**\n * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `\"1\"`.\n *\n * It's a good idea to use the same `name` that is defined as the ERC20 token name.\n */\n constructor(string memory name) EIP712(name, \"1\") {}\n\n /**\n * @dev See {IERC20Permit-permit}.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) public virtual override {\n require(block.timestamp <= deadline, \"ERC20Permit: expired deadline\");\n\n bytes32 structHash = keccak256(abi.encode(_PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline));\n\n bytes32 hash = _hashTypedDataV4(structHash);\n\n address signer = ECDSA.recover(hash, v, r, s);\n require(signer == owner, \"ERC20Permit: invalid signature\");\n\n _approve(owner, spender, value);\n }\n\n /**\n * @dev See {IERC20Permit-nonces}.\n */\n function nonces(address owner) public view virtual override returns (uint256) {\n return _nonces[owner].current();\n }\n\n /**\n * @dev See {IERC20Permit-DOMAIN_SEPARATOR}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view override returns (bytes32) {\n return _domainSeparatorV4();\n }\n\n /**\n * @dev \"Consume a nonce\": return the current value and increment.\n *\n * _Available since v4.1._\n */\n function _useNonce(address owner) internal virtual returns (uint256 current) {\n Counters.Counter storage nonce = _nonces[owner];\n current = nonce.current();\n nonce.increment();\n }\n}\n" + }, + "@openzeppelin/contracts/utils/math/Math.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n /**\n * @dev Returns the largest of two numbers.\n */\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\n return a >= b ? a : b;\n }\n\n /**\n * @dev Returns the smallest of two numbers.\n */\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\n return a < b ? a : b;\n }\n\n /**\n * @dev Returns the average of two numbers. The result is rounded towards\n * zero.\n */\n function average(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b) / 2 can overflow.\n return (a & b) + (a ^ b) / 2;\n }\n\n /**\n * @dev Returns the ceiling of the division of two numbers.\n *\n * This differs from standard division with `/` in that it rounds up instead\n * of rounding down.\n */\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b - 1) / b can overflow on addition, so we distribute.\n return a / b + (a % b == 0 ? 0 : 1);\n }\n\n /**\n * @dev Returns the absolute unsigned value of a signed value.\n */\n function abs(int256 n) internal pure returns (uint256) {\n unchecked {\n // must be unchecked in order to support `n = type(int256).min`\n return uint256(n >= 0 ? n : -n);\n }\n }\n}\n" + }, + "@openzeppelin/contracts/governance/utils/IVotes.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (governance/utils/IVotes.sol)\npragma solidity ^0.8.0;\n\n/**\n * @dev Common interface for {ERC20Votes}, {ERC721Votes}, and other {Votes}-enabled contracts.\n *\n * _Available since v4.5._\n */\ninterface IVotes {\n /**\n * @dev Emitted when an account changes their delegate.\n */\n event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);\n\n /**\n * @dev Emitted when a token transfer or delegate change results in changes to a delegate's number of votes.\n */\n event DelegateVotesChanged(address indexed delegate, uint256 previousBalance, uint256 newBalance);\n\n /**\n * @dev Returns the current amount of votes that `account` has.\n */\n function getVotes(address account) external view returns (uint256);\n\n /**\n * @dev Returns the amount of votes that `account` had at the end of a past block (`blockNumber`).\n */\n function getPastVotes(address account, uint256 blockNumber) external view returns (uint256);\n\n /**\n * @dev Returns the total supply of votes available at the end of a past block (`blockNumber`).\n *\n * NOTE: This value is the sum of all available votes, which is not necessarily the sum of all delegated votes.\n * Votes that have not been delegated are still part of total supply, even though they would not participate in a\n * vote.\n */\n function getPastTotalSupply(uint256 blockNumber) external view returns (uint256);\n\n /**\n * @dev Returns the delegate that `account` has chosen.\n */\n function delegates(address account) external view returns (address);\n\n /**\n * @dev Delegates votes from the sender to `delegatee`.\n */\n function delegate(address delegatee) external;\n\n /**\n * @dev Delegates votes from signer to `delegatee`.\n */\n function delegateBySig(\n address delegatee,\n uint256 nonce,\n uint256 expiry,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n}\n" + }, + "@openzeppelin/contracts/utils/math/SafeCast.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeCast.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow\n * checks.\n *\n * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can\n * easily result in undesired exploitation or bugs, since developers usually\n * assume that overflows raise errors. `SafeCast` restores this intuition by\n * reverting the transaction when such an operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n *\n * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing\n * all math on `uint256` and `int256` and then downcasting.\n */\nlibrary SafeCast {\n /**\n * @dev Returns the downcasted uint224 from uint256, reverting on\n * overflow (when the input is greater than largest uint224).\n *\n * Counterpart to Solidity's `uint224` operator.\n *\n * Requirements:\n *\n * - input must fit into 224 bits\n */\n function toUint224(uint256 value) internal pure returns (uint224) {\n require(value <= type(uint224).max, \"SafeCast: value doesn't fit in 224 bits\");\n return uint224(value);\n }\n\n /**\n * @dev Returns the downcasted uint128 from uint256, reverting on\n * overflow (when the input is greater than largest uint128).\n *\n * Counterpart to Solidity's `uint128` operator.\n *\n * Requirements:\n *\n * - input must fit into 128 bits\n */\n function toUint128(uint256 value) internal pure returns (uint128) {\n require(value <= type(uint128).max, \"SafeCast: value doesn't fit in 128 bits\");\n return uint128(value);\n }\n\n /**\n * @dev Returns the downcasted uint96 from uint256, reverting on\n * overflow (when the input is greater than largest uint96).\n *\n * Counterpart to Solidity's `uint96` operator.\n *\n * Requirements:\n *\n * - input must fit into 96 bits\n */\n function toUint96(uint256 value) internal pure returns (uint96) {\n require(value <= type(uint96).max, \"SafeCast: value doesn't fit in 96 bits\");\n return uint96(value);\n }\n\n /**\n * @dev Returns the downcasted uint64 from uint256, reverting on\n * overflow (when the input is greater than largest uint64).\n *\n * Counterpart to Solidity's `uint64` operator.\n *\n * Requirements:\n *\n * - input must fit into 64 bits\n */\n function toUint64(uint256 value) internal pure returns (uint64) {\n require(value <= type(uint64).max, \"SafeCast: value doesn't fit in 64 bits\");\n return uint64(value);\n }\n\n /**\n * @dev Returns the downcasted uint32 from uint256, reverting on\n * overflow (when the input is greater than largest uint32).\n *\n * Counterpart to Solidity's `uint32` operator.\n *\n * Requirements:\n *\n * - input must fit into 32 bits\n */\n function toUint32(uint256 value) internal pure returns (uint32) {\n require(value <= type(uint32).max, \"SafeCast: value doesn't fit in 32 bits\");\n return uint32(value);\n }\n\n /**\n * @dev Returns the downcasted uint16 from uint256, reverting on\n * overflow (when the input is greater than largest uint16).\n *\n * Counterpart to Solidity's `uint16` operator.\n *\n * Requirements:\n *\n * - input must fit into 16 bits\n */\n function toUint16(uint256 value) internal pure returns (uint16) {\n require(value <= type(uint16).max, \"SafeCast: value doesn't fit in 16 bits\");\n return uint16(value);\n }\n\n /**\n * @dev Returns the downcasted uint8 from uint256, reverting on\n * overflow (when the input is greater than largest uint8).\n *\n * Counterpart to Solidity's `uint8` operator.\n *\n * Requirements:\n *\n * - input must fit into 8 bits.\n */\n function toUint8(uint256 value) internal pure returns (uint8) {\n require(value <= type(uint8).max, \"SafeCast: value doesn't fit in 8 bits\");\n return uint8(value);\n }\n\n /**\n * @dev Converts a signed int256 into an unsigned uint256.\n *\n * Requirements:\n *\n * - input must be greater than or equal to 0.\n */\n function toUint256(int256 value) internal pure returns (uint256) {\n require(value >= 0, \"SafeCast: value must be positive\");\n return uint256(value);\n }\n\n /**\n * @dev Returns the downcasted int128 from int256, reverting on\n * overflow (when the input is less than smallest int128 or\n * greater than largest int128).\n *\n * Counterpart to Solidity's `int128` operator.\n *\n * Requirements:\n *\n * - input must fit into 128 bits\n *\n * _Available since v3.1._\n */\n function toInt128(int256 value) internal pure returns (int128) {\n require(value >= type(int128).min && value <= type(int128).max, \"SafeCast: value doesn't fit in 128 bits\");\n return int128(value);\n }\n\n /**\n * @dev Returns the downcasted int64 from int256, reverting on\n * overflow (when the input is less than smallest int64 or\n * greater than largest int64).\n *\n * Counterpart to Solidity's `int64` operator.\n *\n * Requirements:\n *\n * - input must fit into 64 bits\n *\n * _Available since v3.1._\n */\n function toInt64(int256 value) internal pure returns (int64) {\n require(value >= type(int64).min && value <= type(int64).max, \"SafeCast: value doesn't fit in 64 bits\");\n return int64(value);\n }\n\n /**\n * @dev Returns the downcasted int32 from int256, reverting on\n * overflow (when the input is less than smallest int32 or\n * greater than largest int32).\n *\n * Counterpart to Solidity's `int32` operator.\n *\n * Requirements:\n *\n * - input must fit into 32 bits\n *\n * _Available since v3.1._\n */\n function toInt32(int256 value) internal pure returns (int32) {\n require(value >= type(int32).min && value <= type(int32).max, \"SafeCast: value doesn't fit in 32 bits\");\n return int32(value);\n }\n\n /**\n * @dev Returns the downcasted int16 from int256, reverting on\n * overflow (when the input is less than smallest int16 or\n * greater than largest int16).\n *\n * Counterpart to Solidity's `int16` operator.\n *\n * Requirements:\n *\n * - input must fit into 16 bits\n *\n * _Available since v3.1._\n */\n function toInt16(int256 value) internal pure returns (int16) {\n require(value >= type(int16).min && value <= type(int16).max, \"SafeCast: value doesn't fit in 16 bits\");\n return int16(value);\n }\n\n /**\n * @dev Returns the downcasted int8 from int256, reverting on\n * overflow (when the input is less than smallest int8 or\n * greater than largest int8).\n *\n * Counterpart to Solidity's `int8` operator.\n *\n * Requirements:\n *\n * - input must fit into 8 bits.\n *\n * _Available since v3.1._\n */\n function toInt8(int256 value) internal pure returns (int8) {\n require(value >= type(int8).min && value <= type(int8).max, \"SafeCast: value doesn't fit in 8 bits\");\n return int8(value);\n }\n\n /**\n * @dev Converts an unsigned uint256 into a signed int256.\n *\n * Requirements:\n *\n * - input must be less than or equal to maxInt256.\n */\n function toInt256(uint256 value) internal pure returns (int256) {\n // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive\n require(value <= uint256(type(int256).max), \"SafeCast: value doesn't fit in an int256\");\n return int256(value);\n }\n}\n" + }, + "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n // Check the signature length\n // - case 65: r,s,v signature (standard)\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else if (signature.length == 64) {\n bytes32 r;\n bytes32 vs;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n vs := mload(add(signature, 0x40))\n }\n return tryRecover(hash, r, vs);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/ERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `recipient` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address recipient, uint256 amount) public virtual override returns (bool) {\n _transfer(_msgSender(), recipient, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n _approve(_msgSender(), spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `sender` and `recipient` cannot be the zero address.\n * - `sender` must have a balance of at least `amount`.\n * - the caller must have allowance for ``sender``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) public virtual override returns (bool) {\n uint256 currentAllowance = _allowances[sender][_msgSender()];\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: transfer amount exceeds allowance\");\n unchecked {\n _approve(sender, _msgSender(), currentAllowance - amount);\n }\n }\n\n _transfer(sender, recipient, amount);\n\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n _approve(_msgSender(), spender, _allowances[_msgSender()][spender] + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n uint256 currentAllowance = _allowances[_msgSender()][spender];\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(_msgSender(), spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `sender` cannot be the zero address.\n * - `recipient` cannot be the zero address.\n * - `sender` must have a balance of at least `amount`.\n */\n function _transfer(\n address sender,\n address recipient,\n uint256 amount\n ) internal virtual {\n require(sender != address(0), \"ERC20: transfer from the zero address\");\n require(recipient != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(sender, recipient, amount);\n\n uint256 senderBalance = _balances[sender];\n require(senderBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[sender] = senderBalance - amount;\n }\n _balances[recipient] += amount;\n\n emit Transfer(sender, recipient, amount);\n\n _afterTokenTransfer(sender, recipient, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" + }, + "@openzeppelin/contracts/utils/cryptography/draft-EIP712.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/cryptography/draft-EIP712.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./ECDSA.sol\";\n\n/**\n * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.\n *\n * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,\n * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding\n * they need in their contracts using a combination of `abi.encode` and `keccak256`.\n *\n * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding\n * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA\n * ({_hashTypedDataV4}).\n *\n * The implementation of the domain separator was designed to be as efficient as possible while still properly updating\n * the chain id to protect against replay attacks on an eventual fork of the chain.\n *\n * NOTE: This contract implements the version of the encoding known as \"v4\", as implemented by the JSON RPC method\n * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].\n *\n * _Available since v3.4._\n */\nabstract contract EIP712 {\n /* solhint-disable var-name-mixedcase */\n // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to\n // invalidate the cached domain separator if the chain id changes.\n bytes32 private immutable _CACHED_DOMAIN_SEPARATOR;\n uint256 private immutable _CACHED_CHAIN_ID;\n address private immutable _CACHED_THIS;\n\n bytes32 private immutable _HASHED_NAME;\n bytes32 private immutable _HASHED_VERSION;\n bytes32 private immutable _TYPE_HASH;\n\n /* solhint-enable var-name-mixedcase */\n\n /**\n * @dev Initializes the domain separator and parameter caches.\n *\n * The meaning of `name` and `version` is specified in\n * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:\n *\n * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.\n * - `version`: the current major version of the signing domain.\n *\n * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart\n * contract upgrade].\n */\n constructor(string memory name, string memory version) {\n bytes32 hashedName = keccak256(bytes(name));\n bytes32 hashedVersion = keccak256(bytes(version));\n bytes32 typeHash = keccak256(\n \"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\"\n );\n _HASHED_NAME = hashedName;\n _HASHED_VERSION = hashedVersion;\n _CACHED_CHAIN_ID = block.chainid;\n _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion);\n _CACHED_THIS = address(this);\n _TYPE_HASH = typeHash;\n }\n\n /**\n * @dev Returns the domain separator for the current chain.\n */\n function _domainSeparatorV4() internal view returns (bytes32) {\n if (address(this) == _CACHED_THIS && block.chainid == _CACHED_CHAIN_ID) {\n return _CACHED_DOMAIN_SEPARATOR;\n } else {\n return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION);\n }\n }\n\n function _buildDomainSeparator(\n bytes32 typeHash,\n bytes32 nameHash,\n bytes32 versionHash\n ) private view returns (bytes32) {\n return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this)));\n }\n\n /**\n * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this\n * function returns the hash of the fully encoded EIP712 message for this domain.\n *\n * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:\n *\n * ```solidity\n * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(\n * keccak256(\"Mail(address to,string contents)\"),\n * mailTo,\n * keccak256(bytes(mailContents))\n * )));\n * address signer = ECDSA.recover(digest, signature);\n * ```\n */\n function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {\n return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Counters.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Counters.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @title Counters\n * @author Matt Condon (@shrugs)\n * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number\n * of elements in a mapping, issuing ERC721 ids, or counting request ids.\n *\n * Include with `using Counters for Counters.Counter;`\n */\nlibrary Counters {\n struct Counter {\n // This variable should never be directly accessed by users of the library: interactions must be restricted to\n // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add\n // this feature: see https://github.com/ethereum/solidity/issues/4637\n uint256 _value; // default: 0\n }\n\n function current(Counter storage counter) internal view returns (uint256) {\n return counter._value;\n }\n\n function increment(Counter storage counter) internal {\n unchecked {\n counter._value += 1;\n }\n }\n\n function decrement(Counter storage counter) internal {\n uint256 value = counter._value;\n require(value > 0, \"Counter: decrement overflow\");\n unchecked {\n counter._value = value - 1;\n }\n }\n\n function reset(Counter storage counter) internal {\n counter._value = 0;\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/IERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address recipient, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) external returns (bool);\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" + }, + "@openzeppelin/contracts/utils/Strings.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n}\n" + }, + "contracts/JBController3_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {ERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {JBOperatable} from './abstract/JBOperatable.sol';\nimport {JBBallotState} from './enums/JBBallotState.sol';\nimport {IJBController3_0_1} from './interfaces/IJBController3_0_1.sol';\nimport {IJBController3_1} from './interfaces/IJBController3_1.sol';\nimport {IJBController} from './interfaces/IJBController.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBFundAccessConstraintsStore} from './interfaces/IJBFundAccessConstraintsStore.sol';\nimport {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol';\nimport {IJBMigratable} from './interfaces/IJBMigratable.sol';\nimport {IJBOperatable} from './interfaces/IJBOperatable.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {IJBSplitAllocator} from './interfaces/IJBSplitAllocator.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {IJBTokenStore} from './interfaces/IJBTokenStore.sol';\nimport {JBConstants} from './libraries/JBConstants.sol';\nimport {JBFundingCycleMetadataResolver} from './libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBOperations} from './libraries/JBOperations.sol';\nimport {JBSplitsGroups} from './libraries/JBSplitsGroups.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\nimport {JBSplitAllocationData} from './structs/JBSplitAllocationData.sol';\nimport {JBFundAccessConstraints} from './structs/JBFundAccessConstraints.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\nimport {JBFundingCycleData} from './structs/JBFundingCycleData.sol';\nimport {JBFundingCycleMetadata} from './structs/JBFundingCycleMetadata.sol';\nimport {JBGroupedSplits} from './structs/JBGroupedSplits.sol';\nimport {JBProjectMetadata} from './structs/JBProjectMetadata.sol';\nimport {JBSplit} from './structs/JBSplit.sol';\n\n/// @notice Stitches together funding cycles and project tokens, making sure all activity is accounted for and correct.\n/// @dev This Controller has the same functionality as JBController3_0_1, except it is not backwards compatible with the original IJBController view methods.\ncontract JBController3_1 is JBOperatable, ERC165, IJBController3_1, IJBMigratable {\n // A library that parses the packed funding cycle metadata into a more friendly format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n\n error BURN_PAUSED_AND_SENDER_NOT_VALID_TERMINAL_DELEGATE();\n error FUNDING_CYCLE_ALREADY_LAUNCHED();\n error INVALID_BALLOT_REDEMPTION_RATE();\n error INVALID_REDEMPTION_RATE();\n error INVALID_RESERVED_RATE();\n error MIGRATION_NOT_ALLOWED();\n error MINT_NOT_ALLOWED_AND_NOT_TERMINAL_DELEGATE();\n error NO_BURNABLE_TOKENS();\n error NOT_CURRENT_CONTROLLER();\n error ZERO_TOKENS_TO_MINT();\n\n //*********************************************************************//\n // --------------------- internal stored properties ------------------ //\n //*********************************************************************//\n\n /// @notice Data regarding the distribution limit of a project during a configuration.\n /// @dev bits 0-231: The amount of token that a project can distribute per funding cycle.\n /// @dev bits 232-255: The currency of amount that a project can distribute.\n /// @custom:param _projectId The ID of the project to get the packed distribution limit data of.\n /// @custom:param _configuration The configuration during which the packed distribution limit data applies.\n /// @custom:param _terminal The terminal from which distributions are being limited.\n /// @custom:param _token The token for which distributions are being limited.\n mapping(uint256 => mapping(uint256 => mapping(IJBPaymentTerminal => mapping(address => uint256))))\n internal _packedDistributionLimitDataOf;\n\n /// @notice Data regarding the overflow allowance of a project during a configuration.\n /// @dev bits 0-231: The amount of overflow that a project is allowed to tap into on-demand throughout the configuration.\n /// @dev bits 232-255: The currency of the amount of overflow that a project is allowed to tap.\n /// @custom:param _projectId The ID of the project to get the packed overflow allowance data of.\n /// @custom:param _configuration The configuration during which the packed overflow allowance data applies.\n /// @custom:param _terminal The terminal managing the overflow.\n /// @custom:param _token The token for which overflow is being allowed.\n mapping(uint256 => mapping(uint256 => mapping(IJBPaymentTerminal => mapping(address => uint256))))\n internal _packedOverflowAllowanceDataOf;\n\n //*********************************************************************//\n // --------------- public immutable stored properties ---------------- //\n //*********************************************************************//\n\n /// @notice Mints ERC-721's that represent project ownership.\n IJBProjects public immutable override projects;\n\n /// @notice The contract storing all funding cycle configurations.\n IJBFundingCycleStore public immutable override fundingCycleStore;\n\n /// @notice The contract that manages token minting and burning.\n IJBTokenStore public immutable override tokenStore;\n\n /// @notice The contract that stores splits for each project.\n IJBSplitsStore public immutable override splitsStore;\n\n /// @notice A contract that stores fund access constraints for each project.\n IJBFundAccessConstraintsStore public immutable override fundAccessConstraintsStore;\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The current undistributed reserved token balance of.\n mapping(uint256 => uint256) public override reservedTokenBalanceOf;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice A project's funding cycle for the specified configuration along with its metadata.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The funding cycle.\n /// @return metadata The funding cycle's metadata.\n function getFundingCycleOf(\n uint256 _projectId,\n uint256 _configuration\n )\n external\n view\n override\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata)\n {\n fundingCycle = fundingCycleStore.get(_projectId, _configuration);\n metadata = fundingCycle.expandMetadata();\n }\n\n /// @notice A project's latest configured funding cycle along with its metadata and the ballot state of the configuration.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The latest configured funding cycle.\n /// @return metadata The latest configured funding cycle's metadata.\n /// @return ballotState The state of the configuration.\n function latestConfiguredFundingCycleOf(\n uint256 _projectId\n )\n external\n view\n override\n returns (\n JBFundingCycle memory fundingCycle,\n JBFundingCycleMetadata memory metadata,\n JBBallotState ballotState\n )\n {\n (fundingCycle, ballotState) = fundingCycleStore.latestConfiguredOf(_projectId);\n metadata = fundingCycle.expandMetadata();\n }\n\n /// @notice A project's current funding cycle along with its metadata.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The current funding cycle.\n /// @return metadata The current funding cycle's metadata.\n function currentFundingCycleOf(\n uint256 _projectId\n )\n external\n view\n override\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata)\n {\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n metadata = fundingCycle.expandMetadata();\n }\n\n /// @notice A project's queued funding cycle along with its metadata.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The queued funding cycle.\n /// @return metadata The queued funding cycle's metadata.\n function queuedFundingCycleOf(\n uint256 _projectId\n )\n external\n view\n override\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata)\n {\n fundingCycle = fundingCycleStore.queuedOf(_projectId);\n metadata = fundingCycle.expandMetadata();\n }\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice Gets the current total amount of outstanding tokens for a project.\n /// @param _projectId The ID of the project to get total outstanding tokens of.\n /// @return The current total amount of outstanding tokens for the project.\n function totalOutstandingTokensOf(uint256 _projectId) public view override returns (uint256) {\n // Add the reserved tokens to the total supply.\n return tokenStore.totalSupplyOf(_projectId) + reservedTokenBalanceOf[_projectId];\n }\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if the provided interface ID is supported.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(ERC165, IERC165) returns (bool) {\n return\n _interfaceId == type(IJBController3_1).interfaceId ||\n _interfaceId == type(IJBController3_0_1).interfaceId ||\n _interfaceId == type(IJBMigratable).interfaceId ||\n _interfaceId == type(IJBOperatable).interfaceId ||\n super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // ---------------------------- constructor -------------------------- //\n //*********************************************************************//\n\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _fundingCycleStore A contract storing all funding cycle configurations.\n /// @param _tokenStore A contract that manages token minting and burning.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _fundAccessConstraintsStore A contract that stores fund access constraints for each project.\n constructor(\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBFundingCycleStore _fundingCycleStore,\n IJBTokenStore _tokenStore,\n IJBSplitsStore _splitsStore,\n IJBFundAccessConstraintsStore _fundAccessConstraintsStore\n ) JBOperatable(_operatorStore) {\n projects = _projects;\n directory = _directory;\n fundingCycleStore = _fundingCycleStore;\n tokenStore = _tokenStore;\n splitsStore = _splitsStore;\n fundAccessConstraintsStore = _fundAccessConstraintsStore;\n }\n\n //*********************************************************************//\n // --------------------- external transactions ----------------------- //\n //*********************************************************************//\n\n /// @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.\n /// @dev Each operation within this transaction can be done in sequence separately.\n /// @dev Anyone can deploy a project on an owner's behalf.\n /// @param _owner The address to set as the owner of the project. The project ERC-721 will be owned by this address.\n /// @param _projectMetadata Metadata to associate with the project within a particular domain. This can be updated any time by the owner of the project.\n /// @param _data Data that defines the project's first funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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`.\n /// @param _terminals Payment terminals to add for the project.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return projectId The ID of the project.\n function launchProjectFor(\n address _owner,\n JBProjectMetadata calldata _projectMetadata,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] calldata _groupedSplits,\n JBFundAccessConstraints[] calldata _fundAccessConstraints,\n IJBPaymentTerminal[] memory _terminals,\n string memory _memo\n ) external virtual override returns (uint256 projectId) {\n // Keep a reference to the directory.\n IJBDirectory _directory = directory;\n\n // Mint the project into the wallet of the owner.\n projectId = projects.createFor(_owner, _projectMetadata);\n\n // Set this contract as the project's controller in the directory.\n _directory.setControllerOf(projectId, address(this));\n\n // Configure the first funding cycle.\n uint256 _configuration = _configure(\n projectId,\n _data,\n _metadata,\n _mustStartAtOrAfter,\n _groupedSplits,\n _fundAccessConstraints\n );\n\n // Add the provided terminals to the list of terminals.\n if (_terminals.length > 0) _directory.setTerminalsOf(projectId, _terminals);\n\n emit LaunchProject(_configuration, projectId, _memo, msg.sender);\n }\n\n /// @notice Creates a funding cycle for an already existing project ERC-721.\n /// @dev Each operation within this transaction can be done in sequence separately.\n /// @dev Only a project owner or operator can launch its funding cycles.\n /// @param _projectId The ID of the project to launch funding cycles for.\n /// @param _data Data that defines the project's first funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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`.\n /// @param _terminals Payment terminals to add for the project.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return configuration The configuration of the funding cycle that was successfully created.\n function launchFundingCyclesFor(\n uint256 _projectId,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] calldata _groupedSplits,\n JBFundAccessConstraints[] memory _fundAccessConstraints,\n IJBPaymentTerminal[] memory _terminals,\n string memory _memo\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.RECONFIGURE)\n returns (uint256 configuration)\n {\n // If there is a previous configuration, reconfigureFundingCyclesOf should be called instead\n if (fundingCycleStore.latestConfigurationOf(_projectId) > 0)\n revert FUNDING_CYCLE_ALREADY_LAUNCHED();\n\n // Set this contract as the project's controller in the directory.\n directory.setControllerOf(_projectId, address(this));\n\n // Configure the first funding cycle.\n configuration = _configure(\n _projectId,\n _data,\n _metadata,\n _mustStartAtOrAfter,\n _groupedSplits,\n _fundAccessConstraints\n );\n\n // Add the provided terminals to the list of terminals.\n if (_terminals.length > 0) directory.setTerminalsOf(_projectId, _terminals);\n\n emit LaunchFundingCycles(configuration, _projectId, _memo, msg.sender);\n }\n\n /// @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.\n /// @dev Only a project's owner or a designated operator can configure its funding cycles.\n /// @param _projectId The ID of the project whose funding cycles are being reconfigured.\n /// @param _data Data that defines the funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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`.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return configuration The configuration of the funding cycle that was successfully reconfigured.\n function reconfigureFundingCyclesOf(\n uint256 _projectId,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] calldata _groupedSplits,\n JBFundAccessConstraints[] calldata _fundAccessConstraints,\n string calldata _memo\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.RECONFIGURE)\n returns (uint256 configuration)\n {\n // Configure the next funding cycle.\n configuration = _configure(\n _projectId,\n _data,\n _metadata,\n _mustStartAtOrAfter,\n _groupedSplits,\n _fundAccessConstraints\n );\n\n emit ReconfigureFundingCycles(configuration, _projectId, _memo, msg.sender);\n }\n\n /// @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.\n /// @dev Only a project's owner, a designated operator, one of its terminals, or the current data source can mint its tokens.\n /// @param _projectId The ID of the project to which the tokens being minted belong.\n /// @param _tokenCount The amount of tokens to mint in total, counting however many should be reserved.\n /// @param _beneficiary The account that the tokens are being minted for.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _preferClaimedTokens A flag indicating whether a project's attached token contract should be minted if they have been issued.\n /// @param _useReservedRate Whether to use the current funding cycle's reserved rate in the mint calculation.\n /// @return beneficiaryTokenCount The amount of tokens minted for the beneficiary.\n function mintTokensOf(\n uint256 _projectId,\n uint256 _tokenCount,\n address _beneficiary,\n string calldata _memo,\n bool _preferClaimedTokens,\n bool _useReservedRate\n ) external virtual override returns (uint256 beneficiaryTokenCount) {\n // There should be tokens to mint.\n if (_tokenCount == 0) revert ZERO_TOKENS_TO_MINT();\n\n // Define variables that will be needed outside scoped section below.\n // Keep a reference to the reserved rate to use\n uint256 _reservedRate;\n\n // Scoped section prevents stack too deep. `_fundingCycle` only used within scope.\n {\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Minting limited to: project owner, authorized callers, project terminal and current funding cycle data source\n _requirePermissionAllowingOverride(\n projects.ownerOf(_projectId),\n _projectId,\n JBOperations.MINT,\n directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender)) ||\n msg.sender == address(_fundingCycle.dataSource())\n );\n\n // If the message sender is not a terminal or a datasource, the current funding cycle must allow minting.\n if (\n !_fundingCycle.mintingAllowed() &&\n !directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender)) &&\n msg.sender != address(_fundingCycle.dataSource())\n ) revert MINT_NOT_ALLOWED_AND_NOT_TERMINAL_DELEGATE();\n\n // Determine the reserved rate to use.\n _reservedRate = _useReservedRate ? _fundingCycle.reservedRate() : 0;\n\n // Override the claimed token preference with the funding cycle value.\n _preferClaimedTokens = _preferClaimedTokens == true\n ? _preferClaimedTokens\n : _fundingCycle.preferClaimedTokenOverride();\n }\n\n if (_reservedRate != JBConstants.MAX_RESERVED_RATE) {\n // The unreserved token count that will be minted for the beneficiary.\n beneficiaryTokenCount = PRBMath.mulDiv(\n _tokenCount,\n JBConstants.MAX_RESERVED_RATE - _reservedRate,\n JBConstants.MAX_RESERVED_RATE\n );\n\n // Mint the tokens.\n tokenStore.mintFor(_beneficiary, _projectId, beneficiaryTokenCount, _preferClaimedTokens);\n }\n\n // Add reserved tokens if needed\n if (_reservedRate > 0)\n reservedTokenBalanceOf[_projectId] += _tokenCount - beneficiaryTokenCount;\n\n emit MintTokens(\n _beneficiary,\n _projectId,\n _tokenCount,\n beneficiaryTokenCount,\n _memo,\n _reservedRate,\n msg.sender\n );\n }\n\n /// @notice Burns a token holder's supply.\n /// @dev Only a token's holder, a designated operator, or a project's terminal can burn it.\n /// @param _holder The account that is having its tokens burned.\n /// @param _projectId The ID of the project to which the tokens being burned belong.\n /// @param _tokenCount The number of tokens to burn.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _preferClaimedTokens A flag indicating whether a project's attached token contract should be burned first if they have been issued.\n function burnTokensOf(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n string calldata _memo,\n bool _preferClaimedTokens\n )\n external\n virtual\n override\n requirePermissionAllowingOverride(\n _holder,\n _projectId,\n JBOperations.BURN,\n directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender))\n )\n {\n // There should be tokens to burn\n if (_tokenCount == 0) revert NO_BURNABLE_TOKENS();\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // If the message sender is a terminal, the current funding cycle must not be paused.\n if (\n _fundingCycle.burnPaused() &&\n !directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender))\n ) revert BURN_PAUSED_AND_SENDER_NOT_VALID_TERMINAL_DELEGATE();\n\n // Burn the tokens.\n tokenStore.burnFrom(_holder, _projectId, _tokenCount, _preferClaimedTokens);\n\n emit BurnTokens(_holder, _projectId, _tokenCount, _memo, msg.sender);\n }\n\n /// @notice Distributes all outstanding reserved tokens for a project.\n /// @param _projectId The ID of the project to which the reserved tokens belong.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return The amount of minted reserved tokens.\n function distributeReservedTokensOf(\n uint256 _projectId,\n string calldata _memo\n ) external virtual override returns (uint256) {\n return _distributeReservedTokensOf(_projectId, _memo);\n }\n\n /// @notice Allows other controllers to signal to this one that a migration is expected for the specified project.\n /// @dev This controller should not yet be the project's controller.\n /// @param _projectId The ID of the project that will be migrated to this controller.\n /// @param _from The controller being migrated from.\n function prepForMigrationOf(uint256 _projectId, address _from) external virtual override {\n _projectId; // Prevents unused var compiler and natspec complaints.\n _from; // Prevents unused var compiler and natspec complaints.\n }\n\n /// @notice Allows a project to migrate from this controller to another.\n /// @dev Only a project's owner or a designated operator can migrate it.\n /// @param _projectId The ID of the project that will be migrated from this controller.\n /// @param _to The controller to which the project is migrating.\n function migrate(\n uint256 _projectId,\n IJBMigratable _to\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.MIGRATE_CONTROLLER)\n {\n // Keep a reference to the directory.\n IJBDirectory _directory = directory;\n\n // This controller must be the project's current controller.\n if (_directory.controllerOf(_projectId) != address(this)) revert NOT_CURRENT_CONTROLLER();\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Migration must be allowed.\n if (!_fundingCycle.controllerMigrationAllowed()) revert MIGRATION_NOT_ALLOWED();\n\n // All reserved tokens must be minted before migrating.\n if (reservedTokenBalanceOf[_projectId] != 0) _distributeReservedTokensOf(_projectId, '');\n\n // Make sure the new controller is prepped for the migration.\n _to.prepForMigrationOf(_projectId, address(this));\n\n // Set the new controller.\n _directory.setControllerOf(_projectId, address(_to));\n\n emit Migrate(_projectId, _to, msg.sender);\n }\n\n //*********************************************************************//\n // ------------------------ internal functions ----------------------- //\n //*********************************************************************//\n\n /// @notice Distributes all outstanding reserved tokens for a project.\n /// @param _projectId The ID of the project to which the reserved tokens belong.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return tokenCount The amount of minted reserved tokens.\n function _distributeReservedTokensOf(\n uint256 _projectId,\n string memory _memo\n ) internal returns (uint256 tokenCount) {\n // Keep a reference to the token store.\n IJBTokenStore _tokenStore = tokenStore;\n\n // Get the current funding cycle to read the reserved rate from.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Get a reference to the number of tokens that need to be minted.\n tokenCount = reservedTokenBalanceOf[_projectId];\n\n // Reset the reserved token balance\n reservedTokenBalanceOf[_projectId] = 0;\n\n // Get a reference to the project owner.\n address _owner = projects.ownerOf(_projectId);\n\n // Distribute tokens to splits and get a reference to the leftover amount to mint after all splits have gotten their share.\n uint256 _leftoverTokenCount = tokenCount == 0\n ? 0\n : _distributeToReservedTokenSplitsOf(\n _projectId,\n _fundingCycle.configuration,\n JBSplitsGroups.RESERVED_TOKENS,\n tokenCount\n );\n\n // Mint any leftover tokens to the project owner.\n if (_leftoverTokenCount > 0)\n _tokenStore.mintFor(_owner, _projectId, _leftoverTokenCount, false);\n\n emit DistributeReservedTokens(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _owner,\n tokenCount,\n _leftoverTokenCount,\n _memo,\n msg.sender\n );\n }\n\n /// @notice Distribute tokens to the splits according to the specified funding cycle configuration.\n /// @param _projectId The ID of the project for which reserved token splits are being distributed.\n /// @param _domain The domain of the splits to distribute the reserved tokens between.\n /// @param _group The group of the splits to distribute the reserved tokens between.\n /// @param _amount The total amount of tokens to mint.\n /// @return leftoverAmount If the splits percents dont add up to 100%, the leftover amount is returned.\n function _distributeToReservedTokenSplitsOf(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group,\n uint256 _amount\n ) internal returns (uint256 leftoverAmount) {\n // Keep a reference to the token store.\n IJBTokenStore _tokenStore = tokenStore;\n\n // Set the leftover amount to the initial amount.\n leftoverAmount = _amount;\n\n // Get a reference to the project's reserved token splits.\n JBSplit[] memory _splits = splitsStore.splitsOf(_projectId, _domain, _group);\n\n //Transfer between all splits.\n for (uint256 _i; _i < _splits.length; ) {\n // Get a reference to the split being iterated on.\n JBSplit memory _split = _splits[_i];\n\n // The amount to send towards the split.\n uint256 _tokenCount = PRBMath.mulDiv(\n _amount,\n _split.percent,\n JBConstants.SPLITS_TOTAL_PERCENT\n );\n\n // Mints tokens for the split if needed.\n if (_tokenCount > 0) {\n _tokenStore.mintFor(\n // If an allocator is set in the splits, set it as the beneficiary.\n // Otherwise if a projectId is set in the split, set the project's owner as the beneficiary.\n // If the split has a beneficiary send to the split's beneficiary. Otherwise send to the msg.sender.\n _split.allocator != IJBSplitAllocator(address(0))\n ? address(_split.allocator)\n : _split.projectId != 0\n ? projects.ownerOf(_split.projectId)\n : _split.beneficiary != address(0)\n ? _split.beneficiary\n : msg.sender,\n _projectId,\n _tokenCount,\n _split.preferClaimed\n );\n\n // If there's an allocator set, trigger its `allocate` function.\n if (_split.allocator != IJBSplitAllocator(address(0)))\n _split.allocator.allocate(\n JBSplitAllocationData(\n address(_tokenStore.tokenOf(_projectId)),\n _tokenCount,\n 18,\n _projectId,\n _group,\n _split\n )\n );\n\n // Subtract from the amount to be sent to the beneficiary.\n leftoverAmount = leftoverAmount - _tokenCount;\n }\n\n emit DistributeToReservedTokenSplit(\n _projectId,\n _domain,\n _group,\n _split,\n _tokenCount,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n\n /// @notice Configures a funding cycle and stores information pertinent to the configuration.\n /// @param _projectId The ID of the project whose funding cycles are being reconfigured.\n /// @param _data Data that defines the funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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.\n /// @return configuration The configuration of the funding cycle that was successfully reconfigured.\n function _configure(\n uint256 _projectId,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] memory _groupedSplits,\n JBFundAccessConstraints[] memory _fundAccessConstraints\n ) internal returns (uint256) {\n // Make sure the provided reserved rate is valid.\n if (_metadata.reservedRate > JBConstants.MAX_RESERVED_RATE) revert INVALID_RESERVED_RATE();\n\n // Make sure the provided redemption rate is valid.\n if (_metadata.redemptionRate > JBConstants.MAX_REDEMPTION_RATE)\n revert INVALID_REDEMPTION_RATE();\n\n // Make sure the provided ballot redemption rate is valid.\n if (_metadata.ballotRedemptionRate > JBConstants.MAX_REDEMPTION_RATE)\n revert INVALID_BALLOT_REDEMPTION_RATE();\n\n // Configure the funding cycle's properties.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.configureFor(\n _projectId,\n _data,\n JBFundingCycleMetadataResolver.packFundingCycleMetadata(_metadata),\n _mustStartAtOrAfter\n );\n\n // Set splits for the group.\n splitsStore.set(_projectId, _fundingCycle.configuration, _groupedSplits);\n\n // Set the funds access constraints.\n fundAccessConstraintsStore.setFor(\n _projectId,\n _fundingCycle.configuration,\n _fundAccessConstraints\n );\n\n return _fundingCycle.configuration;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/introspection/ERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC165.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n *\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n" + }, + "@paulrberg/contracts/math/PRBMath.sol": { + "content": "// SPDX-License-Identifier: Unlicense\npragma solidity >=0.8.4;\n\nimport \"prb-math/contracts/PRBMath.sol\";\n" + }, + "contracts/interfaces/IJBController3_0_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBController3_0_1 {\n function reservedTokenBalanceOf(uint256 projectId) external view returns (uint256);\n\n function totalOutstandingTokensOf(uint256 projectId) external view returns (uint256);\n}\n" + }, + "contracts/interfaces/IJBController3_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBBallotState} from './../enums/JBBallotState.sol';\nimport {JBFundAccessConstraints} from './../structs/JBFundAccessConstraints.sol';\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\nimport {JBFundingCycleData} from './../structs/JBFundingCycleData.sol';\nimport {JBFundingCycleMetadata} from './../structs/JBFundingCycleMetadata.sol';\nimport {JBGroupedSplits} from './../structs/JBGroupedSplits.sol';\nimport {JBProjectMetadata} from './../structs/JBProjectMetadata.sol';\nimport {JBSplit} from './../structs/JBSplit.sol';\nimport {IJBController3_0_1} from './IJBController3_0_1.sol';\nimport {IJBDirectory} from './IJBDirectory.sol';\nimport {IJBFundAccessConstraintsStore} from './IJBFundAccessConstraintsStore.sol';\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\nimport {IJBMigratable} from './IJBMigratable.sol';\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\nimport {IJBProjects} from './IJBProjects.sol';\nimport {IJBSplitsStore} from './IJBSplitsStore.sol';\nimport {IJBTokenStore} from './IJBTokenStore.sol';\n\ninterface IJBController3_1 is IJBController3_0_1, IERC165 {\n event LaunchProject(uint256 configuration, uint256 projectId, string memo, address caller);\n\n event LaunchFundingCycles(uint256 configuration, uint256 projectId, string memo, address caller);\n\n event ReconfigureFundingCycles(\n uint256 configuration,\n uint256 projectId,\n string memo,\n address caller\n );\n\n event DistributeReservedTokens(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n address beneficiary,\n uint256 tokenCount,\n uint256 beneficiaryTokenCount,\n string memo,\n address caller\n );\n\n event DistributeToReservedTokenSplit(\n uint256 indexed projectId,\n uint256 indexed domain,\n uint256 indexed group,\n JBSplit split,\n uint256 tokenCount,\n address caller\n );\n\n event MintTokens(\n address indexed beneficiary,\n uint256 indexed projectId,\n uint256 tokenCount,\n uint256 beneficiaryTokenCount,\n string memo,\n uint256 reservedRate,\n address caller\n );\n\n event BurnTokens(\n address indexed holder,\n uint256 indexed projectId,\n uint256 tokenCount,\n string memo,\n address caller\n );\n\n event Migrate(uint256 indexed projectId, IJBMigratable to, address caller);\n\n event PrepMigration(uint256 indexed projectId, address from, address caller);\n\n function projects() external view returns (IJBProjects);\n\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\n\n function tokenStore() external view returns (IJBTokenStore);\n\n function splitsStore() external view returns (IJBSplitsStore);\n\n function fundAccessConstraintsStore() external view returns (IJBFundAccessConstraintsStore);\n\n function directory() external view returns (IJBDirectory);\n\n function reservedTokenBalanceOf(uint256 projectId) external view returns (uint256);\n\n function totalOutstandingTokensOf(uint256 projectId) external view returns (uint256);\n\n function getFundingCycleOf(\n uint256 projectId,\n uint256 configuration\n )\n external\n view\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata);\n\n function latestConfiguredFundingCycleOf(\n uint256 projectId\n )\n external\n view\n returns (JBFundingCycle memory, JBFundingCycleMetadata memory metadata, JBBallotState);\n\n function currentFundingCycleOf(\n uint256 projectId\n )\n external\n view\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata);\n\n function queuedFundingCycleOf(\n uint256 projectId\n )\n external\n view\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata);\n\n function launchProjectFor(\n address owner,\n JBProjectMetadata calldata projectMetadata,\n JBFundingCycleData calldata data,\n JBFundingCycleMetadata calldata metadata,\n uint256 mustStartAtOrAfter,\n JBGroupedSplits[] memory groupedSplits,\n JBFundAccessConstraints[] memory fundAccessConstraints,\n IJBPaymentTerminal[] memory terminals,\n string calldata memo\n ) external returns (uint256 projectId);\n\n function launchFundingCyclesFor(\n uint256 projectId,\n JBFundingCycleData calldata data,\n JBFundingCycleMetadata calldata metadata,\n uint256 mustStartAtOrAfter,\n JBGroupedSplits[] memory groupedSplits,\n JBFundAccessConstraints[] memory fundAccessConstraints,\n IJBPaymentTerminal[] memory terminals,\n string calldata memo\n ) external returns (uint256 configuration);\n\n function reconfigureFundingCyclesOf(\n uint256 projectId,\n JBFundingCycleData calldata data,\n JBFundingCycleMetadata calldata metadata,\n uint256 mustStartAtOrAfter,\n JBGroupedSplits[] memory groupedSplits,\n JBFundAccessConstraints[] memory fundAccessConstraints,\n string calldata memo\n ) external returns (uint256);\n\n function mintTokensOf(\n uint256 projectId,\n uint256 tokenCount,\n address beneficiary,\n string calldata memo,\n bool preferClaimedTokens,\n bool useReservedRate\n ) external returns (uint256 beneficiaryTokenCount);\n\n function burnTokensOf(\n address holder,\n uint256 projectId,\n uint256 tokenCount,\n string calldata memo,\n bool preferClaimedTokens\n ) external;\n\n function distributeReservedTokensOf(\n uint256 projectId,\n string memory memo\n ) external returns (uint256);\n\n function migrate(uint256 projectId, IJBMigratable to) external;\n}\n" + }, + "contracts/interfaces/IJBController.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBBallotState} from './../enums/JBBallotState.sol';\nimport {JBFundAccessConstraints} from './../structs/JBFundAccessConstraints.sol';\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\nimport {JBFundingCycleData} from './../structs/JBFundingCycleData.sol';\nimport {JBFundingCycleMetadata} from './../structs/JBFundingCycleMetadata.sol';\nimport {JBGroupedSplits} from './../structs/JBGroupedSplits.sol';\nimport {JBProjectMetadata} from './../structs/JBProjectMetadata.sol';\nimport {JBSplit} from './../structs/JBSplit.sol';\nimport {IJBDirectory} from './IJBDirectory.sol';\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\nimport {IJBMigratable} from './IJBMigratable.sol';\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\nimport {IJBProjects} from './IJBProjects.sol';\nimport {IJBSplitsStore} from './IJBSplitsStore.sol';\nimport {IJBTokenStore} from './IJBTokenStore.sol';\n\ninterface IJBController is IERC165 {\n event LaunchProject(uint256 configuration, uint256 projectId, string memo, address caller);\n\n event LaunchFundingCycles(uint256 configuration, uint256 projectId, string memo, address caller);\n\n event ReconfigureFundingCycles(\n uint256 configuration,\n uint256 projectId,\n string memo,\n address caller\n );\n\n event SetFundAccessConstraints(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n JBFundAccessConstraints constraints,\n address caller\n );\n\n event DistributeReservedTokens(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n address beneficiary,\n uint256 tokenCount,\n uint256 beneficiaryTokenCount,\n string memo,\n address caller\n );\n\n event DistributeToReservedTokenSplit(\n uint256 indexed projectId,\n uint256 indexed domain,\n uint256 indexed group,\n JBSplit split,\n uint256 tokenCount,\n address caller\n );\n\n event MintTokens(\n address indexed beneficiary,\n uint256 indexed projectId,\n uint256 tokenCount,\n uint256 beneficiaryTokenCount,\n string memo,\n uint256 reservedRate,\n address caller\n );\n\n event BurnTokens(\n address indexed holder,\n uint256 indexed projectId,\n uint256 tokenCount,\n string memo,\n address caller\n );\n\n event Migrate(uint256 indexed projectId, IJBMigratable to, address caller);\n\n event PrepMigration(uint256 indexed projectId, address from, address caller);\n\n function projects() external view returns (IJBProjects);\n\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\n\n function tokenStore() external view returns (IJBTokenStore);\n\n function splitsStore() external view returns (IJBSplitsStore);\n\n function directory() external view returns (IJBDirectory);\n\n function reservedTokenBalanceOf(\n uint256 projectId,\n uint256 reservedRate\n ) external view returns (uint256);\n\n function distributionLimitOf(\n uint256 projectId,\n uint256 configuration,\n IJBPaymentTerminal terminal,\n address token\n ) external view returns (uint256 distributionLimit, uint256 distributionLimitCurrency);\n\n function overflowAllowanceOf(\n uint256 projectId,\n uint256 configuration,\n IJBPaymentTerminal terminal,\n address token\n ) external view returns (uint256 overflowAllowance, uint256 overflowAllowanceCurrency);\n\n function totalOutstandingTokensOf(\n uint256 projectId,\n uint256 reservedRate\n ) external view returns (uint256);\n\n function getFundingCycleOf(\n uint256 projectId,\n uint256 configuration\n )\n external\n view\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata);\n\n function latestConfiguredFundingCycleOf(\n uint256 projectId\n )\n external\n view\n returns (JBFundingCycle memory, JBFundingCycleMetadata memory metadata, JBBallotState);\n\n function currentFundingCycleOf(\n uint256 projectId\n )\n external\n view\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata);\n\n function queuedFundingCycleOf(\n uint256 projectId\n )\n external\n view\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata);\n\n function launchProjectFor(\n address owner,\n JBProjectMetadata calldata projectMetadata,\n JBFundingCycleData calldata data,\n JBFundingCycleMetadata calldata metadata,\n uint256 mustStartAtOrAfter,\n JBGroupedSplits[] memory groupedSplits,\n JBFundAccessConstraints[] memory fundAccessConstraints,\n IJBPaymentTerminal[] memory terminals,\n string calldata memo\n ) external returns (uint256 projectId);\n\n function launchFundingCyclesFor(\n uint256 projectId,\n JBFundingCycleData calldata data,\n JBFundingCycleMetadata calldata metadata,\n uint256 mustStartAtOrAfter,\n JBGroupedSplits[] memory groupedSplits,\n JBFundAccessConstraints[] memory fundAccessConstraints,\n IJBPaymentTerminal[] memory terminals,\n string calldata memo\n ) external returns (uint256 configuration);\n\n function reconfigureFundingCyclesOf(\n uint256 projectId,\n JBFundingCycleData calldata data,\n JBFundingCycleMetadata calldata metadata,\n uint256 mustStartAtOrAfter,\n JBGroupedSplits[] memory groupedSplits,\n JBFundAccessConstraints[] memory fundAccessConstraints,\n string calldata memo\n ) external returns (uint256);\n\n function mintTokensOf(\n uint256 projectId,\n uint256 tokenCount,\n address beneficiary,\n string calldata memo,\n bool preferClaimedTokens,\n bool useReservedRate\n ) external returns (uint256 beneficiaryTokenCount);\n\n function burnTokensOf(\n address holder,\n uint256 projectId,\n uint256 tokenCount,\n string calldata memo,\n bool preferClaimedTokens\n ) external;\n\n function distributeReservedTokensOf(\n uint256 projectId,\n string memory memo\n ) external returns (uint256);\n\n function migrate(uint256 projectId, IJBMigratable to) external;\n}\n" + }, + "contracts/interfaces/IJBFundAccessConstraintsStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBFundAccessConstraints} from './../structs/JBFundAccessConstraints.sol';\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\n\ninterface IJBFundAccessConstraintsStore is IERC165 {\n event SetFundAccessConstraints(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed projectId,\n JBFundAccessConstraints constraints,\n address caller\n );\n\n function distributionLimitOf(\n uint256 projectId,\n uint256 configuration,\n IJBPaymentTerminal terminal,\n address token\n ) external view returns (uint256 distributionLimit, uint256 distributionLimitCurrency);\n\n function overflowAllowanceOf(\n uint256 projectId,\n uint256 configuration,\n IJBPaymentTerminal terminal,\n address token\n ) external view returns (uint256 overflowAllowance, uint256 overflowAllowanceCurrency);\n\n function setFor(\n uint256 projectId,\n uint256 configuration,\n JBFundAccessConstraints[] memory fundAccessConstaints\n ) external;\n}\n" + }, + "contracts/interfaces/IJBMigratable.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBMigratable {\n function prepForMigrationOf(uint256 projectId, address from) external;\n}\n" + }, + "contracts/interfaces/IJBSplitAllocator.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBSplitAllocationData} from '../structs/JBSplitAllocationData.sol';\n\n/// @title Split allocator\n/// @notice Provide a way to process a single split with extra logic\n/// @dev The contract address should be set as an allocator in the adequate split\ninterface IJBSplitAllocator is IERC165 {\n /// @notice This function is called by JBPaymentTerminal.distributePayoutOf(..), during the processing of the split including it\n /// @dev Critical business logic should be protected by an appropriate access control. The token and/or eth are optimistically transfered to the allocator for its logic.\n /// @param data the data passed by the terminal, as a JBSplitAllocationData struct:\n function allocate(JBSplitAllocationData calldata data) external payable;\n}\n" + }, + "contracts/interfaces/IJBSplitsStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBGroupedSplits} from './../structs/JBGroupedSplits.sol';\nimport {JBSplit} from './../structs/JBSplit.sol';\nimport {IJBDirectory} from './IJBDirectory.sol';\nimport {IJBProjects} from './IJBProjects.sol';\n\ninterface IJBSplitsStore {\n event SetSplit(\n uint256 indexed projectId,\n uint256 indexed domain,\n uint256 indexed group,\n JBSplit split,\n address caller\n );\n\n function projects() external view returns (IJBProjects);\n\n function directory() external view returns (IJBDirectory);\n\n function splitsOf(\n uint256 projectId,\n uint256 domain,\n uint256 group\n ) external view returns (JBSplit[] memory);\n\n function set(uint256 projectId, uint256 domain, JBGroupedSplits[] memory groupedSplits) external;\n}\n" + }, + "contracts/libraries/JBSplitsGroups.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nlibrary JBSplitsGroups {\n uint256 public constant ETH_PAYOUT = 1;\n uint256 public constant RESERVED_TOKENS = 2;\n}\n" + }, + "contracts/structs/JBSplitAllocationData.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBSplit} from './JBSplit.sol';\n\n/// @custom:member token The token being sent to the split allocator.\n/// @custom:member amount The amount being sent to the split allocator, as a fixed point number.\n/// @custom:member decimals The number of decimals in the amount.\n/// @custom:member projectId The project to which the split belongs.\n/// @custom:member group The group to which the split belongs.\n/// @custom:member split The split that caused the allocation.\nstruct JBSplitAllocationData {\n address token;\n uint256 amount;\n uint256 decimals;\n uint256 projectId;\n uint256 group;\n JBSplit split;\n}\n" + }, + "contracts/structs/JBFundAccessConstraints.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\n\n/// @custom:member terminal The terminal within which the distribution limit and the overflow allowance applies.\n/// @custom:member token The token for which the fund access constraints apply.\n/// @custom:member distributionLimit The amount of the distribution limit, as a fixed point number with the same number of decimals as the terminal within which the limit applies.\n/// @custom:member distributionLimitCurrency The currency of the distribution limit.\n/// @custom:member overflowAllowance The amount of the allowance, as a fixed point number with the same number of decimals as the terminal within which the allowance applies.\n/// @custom:member overflowAllowanceCurrency The currency of the overflow allowance.\nstruct JBFundAccessConstraints {\n IJBPaymentTerminal terminal;\n address token;\n uint256 distributionLimit;\n uint256 distributionLimitCurrency;\n uint256 overflowAllowance;\n uint256 overflowAllowanceCurrency;\n}\n" + }, + "contracts/structs/JBGroupedSplits.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBSplit} from './JBSplit.sol';\n\n/// @custom:member group The group indentifier.\n/// @custom:member splits The splits to associate with the group.\nstruct JBGroupedSplits {\n uint256 group;\n JBSplit[] splits;\n}\n" + }, + "contracts/structs/JBSplit.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBSplitAllocator} from './../interfaces/IJBSplitAllocator.sol';\n\n/// @custom:member preferClaimed A flag that only has effect if a projectId is also specified, and the project has a token contract attached. If so, this flag indicates if the tokens that result from making a payment to the project should be delivered claimed into the beneficiary's wallet, or unclaimed to save gas.\n/// @custom:member preferAddToBalance A flag indicating if a distribution to a project should prefer triggering it's addToBalance function instead of its pay function.\n/// @custom:member percent The percent of the whole group that this split occupies. This number is out of `JBConstants.SPLITS_TOTAL_PERCENT`.\n/// @custom:member projectId The ID of a project. If an allocator is not set but a projectId is set, funds will be sent to the protocol treasury belonging to the project who's ID is specified. Resulting tokens will be routed to the beneficiary with the claimed token preference respected.\n/// @custom:member beneficiary An address. The role the of the beneficary depends on whether or not projectId is specified, and whether or not an allocator is specified. If allocator is set, the beneficiary will be forwarded to the allocator for it to use. If allocator is not set but projectId is set, the beneficiary is the address to which the project's tokens will be sent that result from a payment to it. If neither allocator or projectId are set, the beneficiary is where the funds from the split will be sent.\n/// @custom:member lockedUntil Specifies if the split should be unchangeable until the specified time, with the exception of extending the locked period.\n/// @custom:member allocator If an allocator is specified, funds will be sent to the allocator contract along with all properties of this split.\nstruct JBSplit {\n bool preferClaimed;\n bool preferAddToBalance;\n uint256 percent;\n uint256 projectId;\n address payable beneficiary;\n uint256 lockedUntil;\n IJBSplitAllocator allocator;\n}\n" + }, + "prb-math/contracts/PRBMath.sol": { + "content": "// SPDX-License-Identifier: Unlicense\npragma solidity >=0.8.4;\n\n/// @notice Emitted when the result overflows uint256.\nerror PRBMath__MulDivFixedPointOverflow(uint256 prod1);\n\n/// @notice Emitted when the result overflows uint256.\nerror PRBMath__MulDivOverflow(uint256 prod1, uint256 denominator);\n\n/// @notice Emitted when one of the inputs is type(int256).min.\nerror PRBMath__MulDivSignedInputTooSmall();\n\n/// @notice Emitted when the intermediary absolute result overflows int256.\nerror PRBMath__MulDivSignedOverflow(uint256 rAbs);\n\n/// @notice Emitted when the input is MIN_SD59x18.\nerror PRBMathSD59x18__AbsInputTooSmall();\n\n/// @notice Emitted when ceiling a number overflows SD59x18.\nerror PRBMathSD59x18__CeilOverflow(int256 x);\n\n/// @notice Emitted when one of the inputs is MIN_SD59x18.\nerror PRBMathSD59x18__DivInputTooSmall();\n\n/// @notice Emitted when one of the intermediary unsigned results overflows SD59x18.\nerror PRBMathSD59x18__DivOverflow(uint256 rAbs);\n\n/// @notice Emitted when the input is greater than 133.084258667509499441.\nerror PRBMathSD59x18__ExpInputTooBig(int256 x);\n\n/// @notice Emitted when the input is greater than 192.\nerror PRBMathSD59x18__Exp2InputTooBig(int256 x);\n\n/// @notice Emitted when flooring a number underflows SD59x18.\nerror PRBMathSD59x18__FloorUnderflow(int256 x);\n\n/// @notice Emitted when converting a basic integer to the fixed-point format overflows SD59x18.\nerror PRBMathSD59x18__FromIntOverflow(int256 x);\n\n/// @notice Emitted when converting a basic integer to the fixed-point format underflows SD59x18.\nerror PRBMathSD59x18__FromIntUnderflow(int256 x);\n\n/// @notice Emitted when the product of the inputs is negative.\nerror PRBMathSD59x18__GmNegativeProduct(int256 x, int256 y);\n\n/// @notice Emitted when multiplying the inputs overflows SD59x18.\nerror PRBMathSD59x18__GmOverflow(int256 x, int256 y);\n\n/// @notice Emitted when the input is less than or equal to zero.\nerror PRBMathSD59x18__LogInputTooSmall(int256 x);\n\n/// @notice Emitted when one of the inputs is MIN_SD59x18.\nerror PRBMathSD59x18__MulInputTooSmall();\n\n/// @notice Emitted when the intermediary absolute result overflows SD59x18.\nerror PRBMathSD59x18__MulOverflow(uint256 rAbs);\n\n/// @notice Emitted when the intermediary absolute result overflows SD59x18.\nerror PRBMathSD59x18__PowuOverflow(uint256 rAbs);\n\n/// @notice Emitted when the input is negative.\nerror PRBMathSD59x18__SqrtNegativeInput(int256 x);\n\n/// @notice Emitted when the calculating the square root overflows SD59x18.\nerror PRBMathSD59x18__SqrtOverflow(int256 x);\n\n/// @notice Emitted when addition overflows UD60x18.\nerror PRBMathUD60x18__AddOverflow(uint256 x, uint256 y);\n\n/// @notice Emitted when ceiling a number overflows UD60x18.\nerror PRBMathUD60x18__CeilOverflow(uint256 x);\n\n/// @notice Emitted when the input is greater than 133.084258667509499441.\nerror PRBMathUD60x18__ExpInputTooBig(uint256 x);\n\n/// @notice Emitted when the input is greater than 192.\nerror PRBMathUD60x18__Exp2InputTooBig(uint256 x);\n\n/// @notice Emitted when converting a basic integer to the fixed-point format format overflows UD60x18.\nerror PRBMathUD60x18__FromUintOverflow(uint256 x);\n\n/// @notice Emitted when multiplying the inputs overflows UD60x18.\nerror PRBMathUD60x18__GmOverflow(uint256 x, uint256 y);\n\n/// @notice Emitted when the input is less than 1.\nerror PRBMathUD60x18__LogInputTooSmall(uint256 x);\n\n/// @notice Emitted when the calculating the square root overflows UD60x18.\nerror PRBMathUD60x18__SqrtOverflow(uint256 x);\n\n/// @notice Emitted when subtraction underflows UD60x18.\nerror PRBMathUD60x18__SubUnderflow(uint256 x, uint256 y);\n\n/// @dev Common mathematical functions used in both PRBMathSD59x18 and PRBMathUD60x18. Note that this shared library\n/// does not always assume the signed 59.18-decimal fixed-point or the unsigned 60.18-decimal fixed-point\n/// representation. When it does not, it is explicitly mentioned in the NatSpec documentation.\nlibrary PRBMath {\n /// STRUCTS ///\n\n struct SD59x18 {\n int256 value;\n }\n\n struct UD60x18 {\n uint256 value;\n }\n\n /// STORAGE ///\n\n /// @dev How many trailing decimals can be represented.\n uint256 internal constant SCALE = 1e18;\n\n /// @dev Largest power of two divisor of SCALE.\n uint256 internal constant SCALE_LPOTD = 262144;\n\n /// @dev SCALE inverted mod 2^256.\n uint256 internal constant SCALE_INVERSE =\n 78156646155174841979727994598816262306175212592076161876661_508869554232690281;\n\n /// FUNCTIONS ///\n\n /// @notice Calculates the binary exponent of x using the binary fraction method.\n /// @dev Has to use 192.64-bit fixed-point numbers.\n /// See https://ethereum.stackexchange.com/a/96594/24693.\n /// @param x The exponent as an unsigned 192.64-bit fixed-point number.\n /// @return result The result as an unsigned 60.18-decimal fixed-point number.\n function exp2(uint256 x) internal pure returns (uint256 result) {\n unchecked {\n // Start from 0.5 in the 192.64-bit fixed-point format.\n result = 0x800000000000000000000000000000000000000000000000;\n\n // Multiply the result by root(2, 2^-i) when the bit at position i is 1. None of the intermediary results overflows\n // because the initial result is 2^191 and all magic factors are less than 2^65.\n if (x & 0x8000000000000000 > 0) {\n result = (result * 0x16A09E667F3BCC909) >> 64;\n }\n if (x & 0x4000000000000000 > 0) {\n result = (result * 0x1306FE0A31B7152DF) >> 64;\n }\n if (x & 0x2000000000000000 > 0) {\n result = (result * 0x1172B83C7D517ADCE) >> 64;\n }\n if (x & 0x1000000000000000 > 0) {\n result = (result * 0x10B5586CF9890F62A) >> 64;\n }\n if (x & 0x800000000000000 > 0) {\n result = (result * 0x1059B0D31585743AE) >> 64;\n }\n if (x & 0x400000000000000 > 0) {\n result = (result * 0x102C9A3E778060EE7) >> 64;\n }\n if (x & 0x200000000000000 > 0) {\n result = (result * 0x10163DA9FB33356D8) >> 64;\n }\n if (x & 0x100000000000000 > 0) {\n result = (result * 0x100B1AFA5ABCBED61) >> 64;\n }\n if (x & 0x80000000000000 > 0) {\n result = (result * 0x10058C86DA1C09EA2) >> 64;\n }\n if (x & 0x40000000000000 > 0) {\n result = (result * 0x1002C605E2E8CEC50) >> 64;\n }\n if (x & 0x20000000000000 > 0) {\n result = (result * 0x100162F3904051FA1) >> 64;\n }\n if (x & 0x10000000000000 > 0) {\n result = (result * 0x1000B175EFFDC76BA) >> 64;\n }\n if (x & 0x8000000000000 > 0) {\n result = (result * 0x100058BA01FB9F96D) >> 64;\n }\n if (x & 0x4000000000000 > 0) {\n result = (result * 0x10002C5CC37DA9492) >> 64;\n }\n if (x & 0x2000000000000 > 0) {\n result = (result * 0x1000162E525EE0547) >> 64;\n }\n if (x & 0x1000000000000 > 0) {\n result = (result * 0x10000B17255775C04) >> 64;\n }\n if (x & 0x800000000000 > 0) {\n result = (result * 0x1000058B91B5BC9AE) >> 64;\n }\n if (x & 0x400000000000 > 0) {\n result = (result * 0x100002C5C89D5EC6D) >> 64;\n }\n if (x & 0x200000000000 > 0) {\n result = (result * 0x10000162E43F4F831) >> 64;\n }\n if (x & 0x100000000000 > 0) {\n result = (result * 0x100000B1721BCFC9A) >> 64;\n }\n if (x & 0x80000000000 > 0) {\n result = (result * 0x10000058B90CF1E6E) >> 64;\n }\n if (x & 0x40000000000 > 0) {\n result = (result * 0x1000002C5C863B73F) >> 64;\n }\n if (x & 0x20000000000 > 0) {\n result = (result * 0x100000162E430E5A2) >> 64;\n }\n if (x & 0x10000000000 > 0) {\n result = (result * 0x1000000B172183551) >> 64;\n }\n if (x & 0x8000000000 > 0) {\n result = (result * 0x100000058B90C0B49) >> 64;\n }\n if (x & 0x4000000000 > 0) {\n result = (result * 0x10000002C5C8601CC) >> 64;\n }\n if (x & 0x2000000000 > 0) {\n result = (result * 0x1000000162E42FFF0) >> 64;\n }\n if (x & 0x1000000000 > 0) {\n result = (result * 0x10000000B17217FBB) >> 64;\n }\n if (x & 0x800000000 > 0) {\n result = (result * 0x1000000058B90BFCE) >> 64;\n }\n if (x & 0x400000000 > 0) {\n result = (result * 0x100000002C5C85FE3) >> 64;\n }\n if (x & 0x200000000 > 0) {\n result = (result * 0x10000000162E42FF1) >> 64;\n }\n if (x & 0x100000000 > 0) {\n result = (result * 0x100000000B17217F8) >> 64;\n }\n if (x & 0x80000000 > 0) {\n result = (result * 0x10000000058B90BFC) >> 64;\n }\n if (x & 0x40000000 > 0) {\n result = (result * 0x1000000002C5C85FE) >> 64;\n }\n if (x & 0x20000000 > 0) {\n result = (result * 0x100000000162E42FF) >> 64;\n }\n if (x & 0x10000000 > 0) {\n result = (result * 0x1000000000B17217F) >> 64;\n }\n if (x & 0x8000000 > 0) {\n result = (result * 0x100000000058B90C0) >> 64;\n }\n if (x & 0x4000000 > 0) {\n result = (result * 0x10000000002C5C860) >> 64;\n }\n if (x & 0x2000000 > 0) {\n result = (result * 0x1000000000162E430) >> 64;\n }\n if (x & 0x1000000 > 0) {\n result = (result * 0x10000000000B17218) >> 64;\n }\n if (x & 0x800000 > 0) {\n result = (result * 0x1000000000058B90C) >> 64;\n }\n if (x & 0x400000 > 0) {\n result = (result * 0x100000000002C5C86) >> 64;\n }\n if (x & 0x200000 > 0) {\n result = (result * 0x10000000000162E43) >> 64;\n }\n if (x & 0x100000 > 0) {\n result = (result * 0x100000000000B1721) >> 64;\n }\n if (x & 0x80000 > 0) {\n result = (result * 0x10000000000058B91) >> 64;\n }\n if (x & 0x40000 > 0) {\n result = (result * 0x1000000000002C5C8) >> 64;\n }\n if (x & 0x20000 > 0) {\n result = (result * 0x100000000000162E4) >> 64;\n }\n if (x & 0x10000 > 0) {\n result = (result * 0x1000000000000B172) >> 64;\n }\n if (x & 0x8000 > 0) {\n result = (result * 0x100000000000058B9) >> 64;\n }\n if (x & 0x4000 > 0) {\n result = (result * 0x10000000000002C5D) >> 64;\n }\n if (x & 0x2000 > 0) {\n result = (result * 0x1000000000000162E) >> 64;\n }\n if (x & 0x1000 > 0) {\n result = (result * 0x10000000000000B17) >> 64;\n }\n if (x & 0x800 > 0) {\n result = (result * 0x1000000000000058C) >> 64;\n }\n if (x & 0x400 > 0) {\n result = (result * 0x100000000000002C6) >> 64;\n }\n if (x & 0x200 > 0) {\n result = (result * 0x10000000000000163) >> 64;\n }\n if (x & 0x100 > 0) {\n result = (result * 0x100000000000000B1) >> 64;\n }\n if (x & 0x80 > 0) {\n result = (result * 0x10000000000000059) >> 64;\n }\n if (x & 0x40 > 0) {\n result = (result * 0x1000000000000002C) >> 64;\n }\n if (x & 0x20 > 0) {\n result = (result * 0x10000000000000016) >> 64;\n }\n if (x & 0x10 > 0) {\n result = (result * 0x1000000000000000B) >> 64;\n }\n if (x & 0x8 > 0) {\n result = (result * 0x10000000000000006) >> 64;\n }\n if (x & 0x4 > 0) {\n result = (result * 0x10000000000000003) >> 64;\n }\n if (x & 0x2 > 0) {\n result = (result * 0x10000000000000001) >> 64;\n }\n if (x & 0x1 > 0) {\n result = (result * 0x10000000000000001) >> 64;\n }\n\n // We're doing two things at the same time:\n //\n // 1. Multiply the result by 2^n + 1, where \"2^n\" is the integer part and the one is added to account for\n // the fact that we initially set the result to 0.5. This is accomplished by subtracting from 191\n // rather than 192.\n // 2. Convert the result to the unsigned 60.18-decimal fixed-point format.\n //\n // This works because 2^(191-ip) = 2^ip / 2^191, where \"ip\" is the integer part \"2^n\".\n result *= SCALE;\n result >>= (191 - (x >> 64));\n }\n }\n\n /// @notice Finds the zero-based index of the first one in the binary representation of x.\n /// @dev See the note on msb in the \"Find First Set\" Wikipedia article https://en.wikipedia.org/wiki/Find_first_set\n /// @param x The uint256 number for which to find the index of the most significant bit.\n /// @return msb The index of the most significant bit as an uint256.\n function mostSignificantBit(uint256 x) internal pure returns (uint256 msb) {\n if (x >= 2**128) {\n x >>= 128;\n msb += 128;\n }\n if (x >= 2**64) {\n x >>= 64;\n msb += 64;\n }\n if (x >= 2**32) {\n x >>= 32;\n msb += 32;\n }\n if (x >= 2**16) {\n x >>= 16;\n msb += 16;\n }\n if (x >= 2**8) {\n x >>= 8;\n msb += 8;\n }\n if (x >= 2**4) {\n x >>= 4;\n msb += 4;\n }\n if (x >= 2**2) {\n x >>= 2;\n msb += 2;\n }\n if (x >= 2**1) {\n // No need to shift x any more.\n msb += 1;\n }\n }\n\n /// @notice Calculates floor(x*y÷denominator) with full precision.\n ///\n /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv.\n ///\n /// Requirements:\n /// - The denominator cannot be zero.\n /// - The result must fit within uint256.\n ///\n /// Caveats:\n /// - This function does not work with fixed-point numbers.\n ///\n /// @param x The multiplicand as an uint256.\n /// @param y The multiplier as an uint256.\n /// @param denominator The divisor as an uint256.\n /// @return result The result as an uint256.\n function mulDiv(\n uint256 x,\n uint256 y,\n uint256 denominator\n ) internal pure returns (uint256 result) {\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n // variables such that product = prod1 * 2^256 + prod0.\n uint256 prod0; // Least significant 256 bits of the product\n uint256 prod1; // Most significant 256 bits of the product\n assembly {\n let mm := mulmod(x, y, not(0))\n prod0 := mul(x, y)\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n }\n\n // Handle non-overflow cases, 256 by 256 division.\n if (prod1 == 0) {\n unchecked {\n result = prod0 / denominator;\n }\n return result;\n }\n\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\n if (prod1 >= denominator) {\n revert PRBMath__MulDivOverflow(prod1, denominator);\n }\n\n ///////////////////////////////////////////////\n // 512 by 256 division.\n ///////////////////////////////////////////////\n\n // Make division exact by subtracting the remainder from [prod1 prod0].\n uint256 remainder;\n assembly {\n // Compute remainder using mulmod.\n remainder := mulmod(x, y, denominator)\n\n // Subtract 256 bit number from 512 bit number.\n prod1 := sub(prod1, gt(remainder, prod0))\n prod0 := sub(prod0, remainder)\n }\n\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\n // See https://cs.stackexchange.com/q/138556/92363.\n unchecked {\n // Does not overflow because the denominator cannot be zero at this stage in the function.\n uint256 lpotdod = denominator & (~denominator + 1);\n assembly {\n // Divide denominator by lpotdod.\n denominator := div(denominator, lpotdod)\n\n // Divide [prod1 prod0] by lpotdod.\n prod0 := div(prod0, lpotdod)\n\n // Flip lpotdod such that it is 2^256 / lpotdod. If lpotdod is zero, then it becomes one.\n lpotdod := add(div(sub(0, lpotdod), lpotdod), 1)\n }\n\n // Shift in bits from prod1 into prod0.\n prod0 |= prod1 * lpotdod;\n\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\n // four bits. That is, denominator * inv = 1 mod 2^4.\n uint256 inverse = (3 * denominator) ^ 2;\n\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\n // in modular arithmetic, doubling the correct bits in each step.\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\n\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\n // is no longer required.\n result = prod0 * inverse;\n return result;\n }\n }\n\n /// @notice Calculates floor(x*y÷1e18) with full precision.\n ///\n /// @dev Variant of \"mulDiv\" with constant folding, i.e. in which the denominator is always 1e18. Before returning the\n /// final result, we add 1 if (x * y) % SCALE >= HALF_SCALE. Without this, 6.6e-19 would be truncated to 0 instead of\n /// being rounded to 1e-18. See \"Listing 6\" and text above it at https://accu.org/index.php/journals/1717.\n ///\n /// Requirements:\n /// - The result must fit within uint256.\n ///\n /// Caveats:\n /// - The body is purposely left uncommented; see the NatSpec comments in \"PRBMath.mulDiv\" to understand how this works.\n /// - It is assumed that the result can never be type(uint256).max when x and y solve the following two equations:\n /// 1. x * y = type(uint256).max * SCALE\n /// 2. (x * y) % SCALE >= SCALE / 2\n ///\n /// @param x The multiplicand as an unsigned 60.18-decimal fixed-point number.\n /// @param y The multiplier as an unsigned 60.18-decimal fixed-point number.\n /// @return result The result as an unsigned 60.18-decimal fixed-point number.\n function mulDivFixedPoint(uint256 x, uint256 y) internal pure returns (uint256 result) {\n uint256 prod0;\n uint256 prod1;\n assembly {\n let mm := mulmod(x, y, not(0))\n prod0 := mul(x, y)\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n }\n\n if (prod1 >= SCALE) {\n revert PRBMath__MulDivFixedPointOverflow(prod1);\n }\n\n uint256 remainder;\n uint256 roundUpUnit;\n assembly {\n remainder := mulmod(x, y, SCALE)\n roundUpUnit := gt(remainder, 499999999999999999)\n }\n\n if (prod1 == 0) {\n unchecked {\n result = (prod0 / SCALE) + roundUpUnit;\n return result;\n }\n }\n\n assembly {\n result := add(\n mul(\n or(\n div(sub(prod0, remainder), SCALE_LPOTD),\n mul(sub(prod1, gt(remainder, prod0)), add(div(sub(0, SCALE_LPOTD), SCALE_LPOTD), 1))\n ),\n SCALE_INVERSE\n ),\n roundUpUnit\n )\n }\n }\n\n /// @notice Calculates floor(x*y÷denominator) with full precision.\n ///\n /// @dev An extension of \"mulDiv\" for signed numbers. Works by computing the signs and the absolute values separately.\n ///\n /// Requirements:\n /// - None of the inputs can be type(int256).min.\n /// - The result must fit within int256.\n ///\n /// @param x The multiplicand as an int256.\n /// @param y The multiplier as an int256.\n /// @param denominator The divisor as an int256.\n /// @return result The result as an int256.\n function mulDivSigned(\n int256 x,\n int256 y,\n int256 denominator\n ) internal pure returns (int256 result) {\n if (x == type(int256).min || y == type(int256).min || denominator == type(int256).min) {\n revert PRBMath__MulDivSignedInputTooSmall();\n }\n\n // Get hold of the absolute values of x, y and the denominator.\n uint256 ax;\n uint256 ay;\n uint256 ad;\n unchecked {\n ax = x < 0 ? uint256(-x) : uint256(x);\n ay = y < 0 ? uint256(-y) : uint256(y);\n ad = denominator < 0 ? uint256(-denominator) : uint256(denominator);\n }\n\n // Compute the absolute value of (x*y)÷denominator. The result must fit within int256.\n uint256 rAbs = mulDiv(ax, ay, ad);\n if (rAbs > uint256(type(int256).max)) {\n revert PRBMath__MulDivSignedOverflow(rAbs);\n }\n\n // Get the signs of x, y and the denominator.\n uint256 sx;\n uint256 sy;\n uint256 sd;\n assembly {\n sx := sgt(x, sub(0, 1))\n sy := sgt(y, sub(0, 1))\n sd := sgt(denominator, sub(0, 1))\n }\n\n // XOR over sx, sy and sd. This is checking whether there are one or three negative signs in the inputs.\n // If yes, the result should be negative.\n result = sx ^ sy ^ sd == 0 ? -int256(rAbs) : int256(rAbs);\n }\n\n /// @notice Calculates the square root of x, rounding down.\n /// @dev Uses the Babylonian method https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method.\n ///\n /// Caveats:\n /// - This function does not work with fixed-point numbers.\n ///\n /// @param x The uint256 number for which to calculate the square root.\n /// @return result The result as an uint256.\n function sqrt(uint256 x) internal pure returns (uint256 result) {\n if (x == 0) {\n return 0;\n }\n\n // Set the initial guess to the closest power of two that is higher than x.\n uint256 xAux = uint256(x);\n result = 1;\n if (xAux >= 0x100000000000000000000000000000000) {\n xAux >>= 128;\n result <<= 64;\n }\n if (xAux >= 0x10000000000000000) {\n xAux >>= 64;\n result <<= 32;\n }\n if (xAux >= 0x100000000) {\n xAux >>= 32;\n result <<= 16;\n }\n if (xAux >= 0x10000) {\n xAux >>= 16;\n result <<= 8;\n }\n if (xAux >= 0x100) {\n xAux >>= 8;\n result <<= 4;\n }\n if (xAux >= 0x10) {\n xAux >>= 4;\n result <<= 2;\n }\n if (xAux >= 0x8) {\n result <<= 1;\n }\n\n // The operations can never overflow because the result is max 2^127 when it enters this block.\n unchecked {\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1; // Seven iterations should be enough\n uint256 roundedDownResult = x / result;\n return result >= roundedDownResult ? roundedDownResult : result;\n }\n }\n}\n" + }, + "contracts/JBSplitsStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {JBOperatable} from './abstract/JBOperatable.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {IJBSplitAllocator} from './interfaces/IJBSplitAllocator.sol';\nimport {JBConstants} from './libraries/JBConstants.sol';\nimport {JBOperations} from './libraries/JBOperations.sol';\nimport {JBGroupedSplits} from './structs/JBGroupedSplits.sol';\nimport {JBSplit} from './structs/JBSplit.sol';\n\n/// @notice Stores splits for each project.\ncontract JBSplitsStore is JBOperatable, IJBSplitsStore {\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error INVALID_LOCKED_UNTIL();\n error INVALID_PROJECT_ID();\n error INVALID_SPLIT_PERCENT();\n error INVALID_TOTAL_PERCENT();\n error PREVIOUS_LOCKED_SPLITS_NOT_INCLUDED();\n\n //*********************************************************************//\n // --------------------- private stored properties ------------------- //\n //*********************************************************************//\n\n /// @notice The number of splits currently set for each project ID's configurations.\n /// @custom:param _projectId The ID of the project to get the split count for.\n /// @custom:param _domain An identifier within which the returned splits should be considered active.\n /// @custom:param _group The identifying group of the splits.\n mapping(uint256 => mapping(uint256 => mapping(uint256 => uint256))) private _splitCountOf;\n\n /// @notice Packed data of splits for each project ID's configurations.\n /// @custom:param _projectId The ID of the project to get packed splits data for.\n /// @custom:param _domain An identifier within which the returned splits should be considered active.\n /// @custom:param _group The identifying group of the splits.\n /// @custom:param _index The indexed order that the split was set at.\n mapping(uint256 => mapping(uint256 => mapping(uint256 => mapping(uint256 => uint256))))\n private _packedSplitParts1Of;\n\n /// @notice More packed data of splits for each project ID's configurations.\n /// @dev This packed data is often 0.\n /// @custom:param _projectId The ID of the project to get packed splits data for.\n /// @custom:param _domain An identifier within which the returned splits should be considered active.\n /// @custom:param _group The identifying group of the splits.\n /// @custom:param _index The indexed order that the split was set at.\n mapping(uint256 => mapping(uint256 => mapping(uint256 => mapping(uint256 => uint256))))\n private _packedSplitParts2Of;\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice Mints ERC-721's that represent project ownership and transfers.\n IJBProjects public immutable override projects;\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Get all splits for the specified project ID, within the specified domain, for the specified group.\n /// @param _projectId The ID of the project to get splits for.\n /// @param _domain An identifier within which the returned splits should be considered active.\n /// @param _group The identifying group of the splits.\n /// @return An array of all splits for the project.\n function splitsOf(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group\n ) external view override returns (JBSplit[] memory) {\n return _getStructsFor(_projectId, _domain, _group);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n constructor(\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory\n ) JBOperatable(_operatorStore) {\n projects = _projects;\n directory = _directory;\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Sets a project's splits.\n /// @dev Only the owner or operator of a project, or the current controller contract of the project, can set its splits.\n /// @dev The new splits must include any currently set splits that are locked.\n /// @param _projectId The ID of the project for which splits are being added.\n /// @param _domain An identifier within which the splits should be considered active.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n function set(\n uint256 _projectId,\n uint256 _domain,\n JBGroupedSplits[] calldata _groupedSplits\n )\n external\n override\n requirePermissionAllowingOverride(\n projects.ownerOf(_projectId),\n _projectId,\n JBOperations.SET_SPLITS,\n address(directory.controllerOf(_projectId)) == msg.sender\n )\n {\n // Push array length in stack\n uint256 _groupedSplitsLength = _groupedSplits.length;\n\n // Set each grouped splits.\n for (uint256 _i; _i < _groupedSplitsLength; ) {\n // Get a reference to the grouped split being iterated on.\n JBGroupedSplits memory _groupedSplit = _groupedSplits[_i];\n\n // Set the splits for the group.\n _set(_projectId, _domain, _groupedSplit.group, _groupedSplit.splits);\n\n unchecked {\n ++_i;\n }\n }\n }\n\n //*********************************************************************//\n // --------------------- private helper functions -------------------- //\n //*********************************************************************//\n\n /// @notice Sets a project's splits.\n /// @dev The new splits must include any currently set splits that are locked.\n /// @param _projectId The ID of the project for which splits are being added.\n /// @param _domain An identifier within which the splits should be considered active.\n /// @param _group An identifier between of splits being set. All splits within this _group must add up to within 100%.\n /// @param _splits The splits to set.\n function _set(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group,\n JBSplit[] memory _splits\n ) internal {\n // Get a reference to the project's current splits.\n JBSplit[] memory _currentSplits = _getStructsFor(_projectId, _domain, _group);\n\n // Keep a reference to the number of splits.\n uint256 _currentSplitsLength = _currentSplits.length;\n\n // Check to see if all locked splits are included.\n for (uint256 _i; _i < _currentSplitsLength; ) {\n // If not locked, continue.\n if (\n block.timestamp < _currentSplits[_i].lockedUntil &&\n !_includesLocked(_splits, _currentSplits[_i])\n ) revert PREVIOUS_LOCKED_SPLITS_NOT_INCLUDED();\n\n unchecked {\n ++_i;\n }\n }\n\n // Add up all the percents to make sure they cumulatively are under 100%.\n uint256 _percentTotal;\n\n // Keep a reference to the number of splits.\n uint256 _splitsLength = _splits.length;\n\n for (uint256 _i; _i < _splitsLength; ) {\n // The percent should be greater than 0.\n if (_splits[_i].percent == 0) revert INVALID_SPLIT_PERCENT();\n\n // ProjectId should be within a uint56\n if (_splits[_i].projectId > type(uint56).max) revert INVALID_PROJECT_ID();\n\n // Add to the total percents.\n _percentTotal = _percentTotal + _splits[_i].percent;\n\n // Validate the total does not exceed the expected value.\n if (_percentTotal > JBConstants.SPLITS_TOTAL_PERCENT) revert INVALID_TOTAL_PERCENT();\n\n uint256 _packedSplitParts1;\n\n // prefer claimed in bit 0.\n if (_splits[_i].preferClaimed) _packedSplitParts1 = 1;\n // prefer add to balance in bit 1.\n if (_splits[_i].preferAddToBalance) _packedSplitParts1 |= 1 << 1;\n // percent in bits 2-33.\n _packedSplitParts1 |= _splits[_i].percent << 2;\n // projectId in bits 32-89.\n _packedSplitParts1 |= _splits[_i].projectId << 34;\n // beneficiary in bits 90-249.\n _packedSplitParts1 |= uint256(uint160(address(_splits[_i].beneficiary))) << 90;\n\n // Store the first split part.\n _packedSplitParts1Of[_projectId][_domain][_group][_i] = _packedSplitParts1;\n\n // If there's data to store in the second packed split part, pack and store.\n if (_splits[_i].lockedUntil > 0 || _splits[_i].allocator != IJBSplitAllocator(address(0))) {\n // Locked until should be within a uint48\n if (_splits[_i].lockedUntil > type(uint48).max) revert INVALID_LOCKED_UNTIL();\n\n // lockedUntil in bits 0-47.\n uint256 _packedSplitParts2 = uint48(_splits[_i].lockedUntil);\n // allocator in bits 48-207.\n _packedSplitParts2 |= uint256(uint160(address(_splits[_i].allocator))) << 48;\n\n // Store the second split part.\n _packedSplitParts2Of[_projectId][_domain][_group][_i] = _packedSplitParts2;\n\n // Otherwise if there's a value stored in the indexed position, delete it.\n } else if (_packedSplitParts2Of[_projectId][_domain][_group][_i] > 0)\n delete _packedSplitParts2Of[_projectId][_domain][_group][_i];\n\n emit SetSplit(_projectId, _domain, _group, _splits[_i], msg.sender);\n\n unchecked {\n ++_i;\n }\n }\n\n // Set the new length of the splits.\n _splitCountOf[_projectId][_domain][_group] = _splitsLength;\n }\n\n /// @notice A flag indiciating if the provided splits array includes the locked split.\n /// @param _splits The array of splits to check within.\n /// @param _lockedSplit The locked split.\n /// @return A flag indicating if the `_lockedSplit` is contained in the `_splits`.\n function _includesLocked(\n JBSplit[] memory _splits,\n JBSplit memory _lockedSplit\n ) private pure returns (bool) {\n // Keep a reference to the number of splits.\n uint256 _numberOfSplits = _splits.length;\n\n for (uint256 _i; _i < _numberOfSplits; ) {\n // Check for sameness.\n if (\n _splits[_i].percent == _lockedSplit.percent &&\n _splits[_i].beneficiary == _lockedSplit.beneficiary &&\n _splits[_i].allocator == _lockedSplit.allocator &&\n _splits[_i].projectId == _lockedSplit.projectId &&\n _splits[_i].preferClaimed == _lockedSplit.preferClaimed &&\n _splits[_i].preferAddToBalance == _lockedSplit.preferAddToBalance &&\n // Allow lock extention.\n _splits[_i].lockedUntil >= _lockedSplit.lockedUntil\n ) return true;\n\n unchecked {\n ++_i;\n }\n }\n\n return false;\n }\n\n /// @notice Unpack splits' packed stored values into easy-to-work-with split structs.\n /// @param _projectId The ID of the project to which the split belongs.\n /// @param _domain The identifier within which the returned splits should be considered active.\n /// @param _group The identifying group of the splits.\n /// @return splits The split structs.\n function _getStructsFor(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group\n ) private view returns (JBSplit[] memory) {\n // Get a reference to the number of splits that need to be added to the returned array.\n uint256 _splitCount = _splitCountOf[_projectId][_domain][_group];\n\n // Initialize an array to be returned that has the set length.\n JBSplit[] memory _splits = new JBSplit[](_splitCount);\n\n // Loop through each split and unpack the values into structs.\n for (uint256 _i; _i < _splitCount; ) {\n // Get a reference to the fist packed data.\n uint256 _packedSplitPart1 = _packedSplitParts1Of[_projectId][_domain][_group][_i];\n\n // Populate the split struct.\n JBSplit memory _split;\n\n // prefer claimed in bit 0.\n _split.preferClaimed = _packedSplitPart1 & 1 == 1;\n // prefer add to balance in bit 1.\n _split.preferAddToBalance = (_packedSplitPart1 >> 1) & 1 == 1;\n // percent in bits 2-33.\n _split.percent = uint256(uint32(_packedSplitPart1 >> 2));\n // projectId in bits 32-89.\n _split.projectId = uint256(uint56(_packedSplitPart1 >> 34));\n // beneficiary in bits 90-249.\n _split.beneficiary = payable(address(uint160(_packedSplitPart1 >> 90)));\n\n // Get a reference to the second packed data.\n uint256 _packedSplitPart2 = _packedSplitParts2Of[_projectId][_domain][_group][_i];\n\n // If there's anything in it, unpack.\n if (_packedSplitPart2 > 0) {\n // lockedUntil in bits 0-47.\n _split.lockedUntil = uint256(uint48(_packedSplitPart2));\n // allocator in bits 48-207.\n _split.allocator = IJBSplitAllocator(address(uint160(_packedSplitPart2 >> 48)));\n }\n\n // Add the split to the value being returned.\n _splits[_i] = _split;\n\n unchecked {\n ++_i;\n }\n }\n\n return _splits;\n }\n}\n" + }, + "contracts/JBETHERC20SplitsPayerDeployer.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Clones} from '@openzeppelin/contracts/proxy/Clones.sol';\nimport {IJBETHERC20SplitsPayerDeployer} from './interfaces/IJBETHERC20SplitsPayerDeployer.sol';\nimport {IJBSplitsPayer} from './interfaces/IJBSplitsPayer.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {JBSplit} from './structs/JBSplit.sol';\nimport {JBGroupedSplits} from './structs/JBGroupedSplits.sol';\nimport {JBETHERC20SplitsPayer} from './JBETHERC20SplitsPayer.sol';\n\n/// @notice Deploys splits payer contracts.\ncontract JBETHERC20SplitsPayerDeployer is IJBETHERC20SplitsPayerDeployer {\n //*********************************************************************//\n // --------------- public immutable stored properties ---------------- //\n //*********************************************************************//\n\n /// @notice The implementation contract on which Clones will be based.\n address immutable implementation;\n\n /// @notice The contract that stores splits for each project.\n IJBSplitsStore immutable splitsStore;\n\n //*********************************************************************//\n // ---------------------------- constructor -------------------------- //\n //*********************************************************************//\n\n /// @param _splitsStore The contract that stores splits for each project.\n constructor(IJBSplitsStore _splitsStore) {\n implementation = address(new JBETHERC20SplitsPayer(_splitsStore));\n splitsStore = _splitsStore;\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Allows anyone to deploy a new splits payer contract.\n /// @dev This contract must have Operator permissions over the SET_SPLITS permission of the specified `_defaultSplitsProjectId`.\n /// @param _defaultSplitsProjectId The ID of project for which the default splits are stored.\n /// @param _defaultSplits The splits to payout when this contract receives direct payments.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _defaultProjectId The ID of the project whose treasury should be forwarded the splits payer contract's received payment leftovers after distributing to the default splits group.\n /// @param _defaultBeneficiary The address that'll receive the project's tokens when the splits payer receives payments.\n /// @param _defaultPreferClaimedTokens A flag indicating whether issued tokens from the splits payer's received payments should be automatically claimed into the beneficiary's wallet.\n /// @param _defaultMemo The memo that'll be forwarded with the splits payer's received payments.\n /// @param _defaultMetadata The metadata that'll be forwarded with the splits payer's received payments.\n /// @param _defaultPreferAddToBalance A flag indicating if received payments should call the `pay` function or the `addToBalance` function of a project.\n /// @param _owner The address that will own the splits payer.\n /// @return splitsPayer The splits payer contract.\n function deploySplitsPayerWithSplits(\n uint256 _defaultSplitsProjectId,\n JBSplit[] memory _defaultSplits,\n IJBSplitsStore _splitsStore,\n uint256 _defaultProjectId,\n address payable _defaultBeneficiary,\n bool _defaultPreferClaimedTokens,\n string memory _defaultMemo,\n bytes memory _defaultMetadata,\n bool _defaultPreferAddToBalance,\n address _owner\n ) external override returns (IJBSplitsPayer splitsPayer) {\n // Use this contract's address as the domain.\n uint256 _domain = uint256(uint160(address(this)));\n\n // Create the random hash using data unique to this instance that'll be used as the storage domain.\n uint256 _group = uint256(keccak256(abi.encodePacked(msg.sender, block.number)));\n\n // Set the splits in the store.\n JBGroupedSplits[] memory _groupedSplits;\n _groupedSplits = new JBGroupedSplits[](1);\n _groupedSplits[0] = JBGroupedSplits(_group, _defaultSplits);\n _splitsStore.set(_defaultSplitsProjectId, _domain, _groupedSplits);\n\n return\n deploySplitsPayer(\n _defaultSplitsProjectId,\n _domain,\n _group,\n _defaultProjectId,\n _defaultBeneficiary,\n _defaultPreferClaimedTokens,\n _defaultMemo,\n _defaultMetadata,\n _defaultPreferAddToBalance,\n _owner\n );\n }\n\n //*********************************************************************//\n // ---------------------- public transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Allows anyone to deploy a new splits payer contract.\n /// @param _defaultSplitsProjectId The ID of project for which the default splits are stored.\n /// @param _defaultSplitsDomain The splits domain to payout when this contract receives direct payments.\n /// @param _defaultSplitsGroup The splits group to payout when this contract receives direct payments.\n /// @param _defaultProjectId The ID of the project whose treasury should be forwarded the splits payer contract's received payment leftovers after distributing to the default splits group.\n /// @param _defaultBeneficiary The address that'll receive the project's tokens when the splits payer receives payments.\n /// @param _defaultPreferClaimedTokens A flag indicating whether issued tokens from the splits payer's received payments should be automatically claimed into the beneficiary's wallet.\n /// @param _defaultMemo The memo that'll be forwarded with the splits payer's received payments.\n /// @param _defaultMetadata The metadata that'll be forwarded with the splits payer's received payments.\n /// @param _defaultPreferAddToBalance A flag indicating if received payments should call the `pay` function or the `addToBalance` function of a project.\n /// @param _owner The address that will own the splits payer.\n /// @return splitsPayer The splits payer contract.\n function deploySplitsPayer(\n uint256 _defaultSplitsProjectId,\n uint256 _defaultSplitsDomain,\n uint256 _defaultSplitsGroup,\n uint256 _defaultProjectId,\n address payable _defaultBeneficiary,\n bool _defaultPreferClaimedTokens,\n string memory _defaultMemo,\n bytes memory _defaultMetadata,\n bool _defaultPreferAddToBalance,\n address _owner\n ) public override returns (IJBSplitsPayer splitsPayer) {\n // Deploy the splits payer.\n splitsPayer = IJBSplitsPayer(payable(Clones.clone(implementation)));\n\n splitsPayer.initialize(\n _defaultSplitsProjectId,\n _defaultSplitsDomain,\n _defaultSplitsGroup,\n _defaultProjectId,\n _defaultBeneficiary,\n _defaultPreferClaimedTokens,\n _defaultMemo,\n _defaultMetadata,\n _defaultPreferAddToBalance,\n _owner\n );\n\n emit DeploySplitsPayer(\n splitsPayer,\n _defaultSplitsProjectId,\n _defaultSplitsDomain,\n _defaultSplitsGroup,\n splitsStore,\n _defaultProjectId,\n _defaultBeneficiary,\n _defaultPreferClaimedTokens,\n _defaultMemo,\n _defaultMetadata,\n _defaultPreferAddToBalance,\n _owner,\n msg.sender\n );\n }\n}\n" + }, + "@openzeppelin/contracts/proxy/Clones.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (proxy/Clones.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for\n * deploying minimal proxy contracts, also known as \"clones\".\n *\n * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies\n * > a minimal bytecode implementation that delegates all calls to a known, fixed address.\n *\n * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`\n * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the\n * deterministic method.\n *\n * _Available since v3.4._\n */\nlibrary Clones {\n /**\n * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.\n *\n * This function uses the create opcode, which should never revert.\n */\n function clone(address implementation) internal returns (address instance) {\n assembly {\n let ptr := mload(0x40)\n mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)\n mstore(add(ptr, 0x14), shl(0x60, implementation))\n mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)\n instance := create(0, ptr, 0x37)\n }\n require(instance != address(0), \"ERC1167: create failed\");\n }\n\n /**\n * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.\n *\n * This function uses the create2 opcode and a `salt` to deterministically deploy\n * the clone. Using the same `implementation` and `salt` multiple time will revert, since\n * the clones cannot be deployed twice at the same address.\n */\n function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {\n assembly {\n let ptr := mload(0x40)\n mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)\n mstore(add(ptr, 0x14), shl(0x60, implementation))\n mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)\n instance := create2(0, ptr, 0x37, salt)\n }\n require(instance != address(0), \"ERC1167: create2 failed\");\n }\n\n /**\n * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.\n */\n function predictDeterministicAddress(\n address implementation,\n bytes32 salt,\n address deployer\n ) internal pure returns (address predicted) {\n assembly {\n let ptr := mload(0x40)\n mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)\n mstore(add(ptr, 0x14), shl(0x60, implementation))\n mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf3ff00000000000000000000000000000000)\n mstore(add(ptr, 0x38), shl(0x60, deployer))\n mstore(add(ptr, 0x4c), salt)\n mstore(add(ptr, 0x6c), keccak256(ptr, 0x37))\n predicted := keccak256(add(ptr, 0x37), 0x55)\n }\n }\n\n /**\n * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.\n */\n function predictDeterministicAddress(address implementation, bytes32 salt)\n internal\n view\n returns (address predicted)\n {\n return predictDeterministicAddress(implementation, salt, address(this));\n }\n}\n" + }, + "contracts/interfaces/IJBETHERC20SplitsPayerDeployer.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBSplitsPayer} from './IJBSplitsPayer.sol';\nimport {IJBSplitsStore} from './IJBSplitsStore.sol';\nimport {JBSplit} from './../structs/JBSplit.sol';\n\ninterface IJBETHERC20SplitsPayerDeployer {\n event DeploySplitsPayer(\n IJBSplitsPayer indexed splitsPayer,\n uint256 defaultSplitsProjectId,\n uint256 defaultSplitsDomain,\n uint256 defaultSplitsGroup,\n IJBSplitsStore splitsStore,\n uint256 defaultProjectId,\n address defaultBeneficiary,\n bool defaultPreferClaimedTokens,\n string defaultMemo,\n bytes defaultMetadata,\n bool preferAddToBalance,\n address owner,\n address caller\n );\n\n function deploySplitsPayer(\n uint256 defaultSplitsProjectId,\n uint256 defaultSplitsDomain,\n uint256 defaultSplitsGroup,\n uint256 defaultProjectId,\n address payable defaultBeneficiary,\n bool defaultPreferClaimedTokens,\n string calldata defaultMemo,\n bytes calldata defaultMetadata,\n bool preferAddToBalance,\n address owner\n ) external returns (IJBSplitsPayer splitsPayer);\n\n function deploySplitsPayerWithSplits(\n uint256 defaultSplitsProjectId,\n JBSplit[] memory defaultSplits,\n IJBSplitsStore splitsStore,\n uint256 defaultProjectId,\n address payable defaultBeneficiary,\n bool defaultPreferClaimedTokens,\n string memory defaultMemo,\n bytes memory defaultMetadata,\n bool defaultPreferAddToBalance,\n address owner\n ) external returns (IJBSplitsPayer splitsPayer);\n}\n" + }, + "contracts/interfaces/IJBSplitsPayer.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBSplit} from './../structs/JBSplit.sol';\nimport {JBGroupedSplits} from './../structs/JBGroupedSplits.sol';\nimport {IJBSplitsStore} from './IJBSplitsStore.sol';\n\ninterface IJBSplitsPayer is IERC165 {\n event SetDefaultSplitsReference(\n uint256 indexed projectId,\n uint256 indexed domain,\n uint256 indexed group,\n address caller\n );\n event Pay(\n uint256 indexed projectId,\n address beneficiary,\n address token,\n uint256 amount,\n uint256 decimals,\n uint256 leftoverAmount,\n uint256 minReturnedTokens,\n bool preferClaimedTokens,\n string memo,\n bytes metadata,\n address caller\n );\n\n event AddToBalance(\n uint256 indexed projectId,\n address beneficiary,\n address token,\n uint256 amount,\n uint256 decimals,\n uint256 leftoverAmount,\n string memo,\n bytes metadata,\n address caller\n );\n\n event DistributeToSplitGroup(\n uint256 indexed projectId,\n uint256 indexed domain,\n uint256 indexed group,\n address caller\n );\n\n event DistributeToSplit(\n JBSplit split,\n uint256 amount,\n address defaultBeneficiary,\n address caller\n );\n\n function defaultSplitsProjectId() external view returns (uint256);\n\n function defaultSplitsDomain() external view returns (uint256);\n\n function defaultSplitsGroup() external view returns (uint256);\n\n function splitsStore() external view returns (IJBSplitsStore);\n\n function initialize(\n uint256 defaultSplitsProjectId,\n uint256 defaultSplitsDomain,\n uint256 defaultSplitsGroup,\n uint256 defaultProjectId,\n address payable defaultBeneficiary,\n bool defaultPreferClaimedTokens,\n string memory defaultMemo,\n bytes memory defaultMetadata,\n bool preferAddToBalance,\n address owner\n ) external;\n\n function setDefaultSplitsReference(uint256 projectId, uint256 domain, uint256 group) external;\n\n function setDefaultSplits(\n uint256 projectId,\n uint256 domain,\n uint256 group,\n JBGroupedSplits[] memory splitsGroup\n ) external;\n}\n" + }, + "contracts/JBETHERC20SplitsPayer.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {ReentrancyGuard} from '@openzeppelin/contracts/security/ReentrancyGuard.sol';\nimport {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';\nimport {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';\nimport {Address} from '@openzeppelin/contracts/utils/Address.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {IJBSplitsPayer} from './interfaces/IJBSplitsPayer.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {JBConstants} from './libraries/JBConstants.sol';\nimport {JBETHERC20ProjectPayer} from './JBETHERC20ProjectPayer.sol';\nimport {IJBSplitAllocator} from './interfaces/IJBSplitAllocator.sol';\nimport {JBTokens} from './libraries/JBTokens.sol';\nimport {JBGroupedSplits} from './structs/JBGroupedSplits.sol';\nimport {JBSplit} from './structs/JBSplit.sol';\nimport {JBSplitAllocationData} from './structs/JBSplitAllocationData.sol';\n\n/// @notice Sends ETH or ERC20's to a group of splits as it receives direct payments or has its functions called.\n/// @dev Inherit from this contract or borrow from its logic to forward ETH or ERC20's to a group of splits from within other contracts.\ncontract JBETHERC20SplitsPayer is JBETHERC20ProjectPayer, ReentrancyGuard, IJBSplitsPayer {\n using SafeERC20 for IERC20;\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice The contract that stores splits for each project.\n IJBSplitsStore public immutable override splitsStore;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The ID of project for which the default splits are stored.\n uint256 public override defaultSplitsProjectId;\n\n /// @notice The domain within which the default splits are stored.\n uint256 public override defaultSplitsDomain;\n\n /// @notice The group within which the default splits are stored.\n uint256 public override defaultSplitsGroup;\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if this contract adheres to the specified interface.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(JBETHERC20ProjectPayer, IERC165) returns (bool) {\n return\n _interfaceId == type(IJBSplitsPayer).interfaceId || super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _splitsStore A contract that stores splits for each project.\n constructor(IJBSplitsStore _splitsStore) JBETHERC20ProjectPayer(_splitsStore.directory()) {\n splitsStore = _splitsStore;\n }\n\n /// @dev The re-initialize check is done in the inherited paroject payer\n /// @param _defaultSplitsProjectId The ID of project for which the default splits are stored.\n /// @param _defaultSplitsDomain The splits domain to payout when this contract receives direct payments.\n /// @param _defaultSplitsGroup The splits group to payout when this contract receives direct payments.\n /// @param _defaultProjectId The ID of the project whose treasury should be forwarded the splits payer contract's received payment leftovers after distributing to the default splits group.\n /// @param _defaultBeneficiary The address that'll receive the project's tokens.\n /// @param _defaultPreferClaimedTokens A flag indicating whether issued tokens should be automatically claimed into the beneficiary's wallet.\n /// @param _defaultMemo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _defaultMetadata Bytes to send along to the project's data source and delegate, if provided.\n /// @param _preferAddToBalance A flag indicating if received payments should call the `pay` function or the `addToBalance` function of a project.\n /// @param _owner The address that will own the contract.\n function initialize(\n uint256 _defaultSplitsProjectId,\n uint256 _defaultSplitsDomain,\n uint256 _defaultSplitsGroup,\n uint256 _defaultProjectId,\n address payable _defaultBeneficiary,\n bool _defaultPreferClaimedTokens,\n string memory _defaultMemo,\n bytes memory _defaultMetadata,\n bool _preferAddToBalance,\n address _owner\n ) external override {\n super.initialize(\n _defaultProjectId,\n _defaultBeneficiary,\n _defaultPreferClaimedTokens,\n _defaultMemo,\n _defaultMetadata,\n _preferAddToBalance,\n _owner\n );\n\n defaultSplitsProjectId = _defaultSplitsProjectId;\n defaultSplitsDomain = _defaultSplitsDomain;\n defaultSplitsGroup = _defaultSplitsGroup;\n }\n\n //*********************************************************************//\n // ------------------------- default receive ------------------------- //\n //*********************************************************************//\n\n /// @notice Received funds are paid to the default split group using the stored default properties.\n /// @dev This function is called automatically when the contract receives an ETH payment.\n receive() external payable virtual override nonReentrant {\n // Pay the splits and get a reference to the amount leftover.\n uint256 _leftoverAmount = _payToSplits(\n defaultSplitsProjectId,\n defaultSplitsDomain,\n defaultSplitsGroup,\n JBTokens.ETH,\n address(this).balance,\n 18, // decimals.\n defaultBeneficiary != address(0) ? defaultBeneficiary : tx.origin\n );\n\n // If there is no leftover amount, nothing left to pay.\n if (_leftoverAmount == 0) return;\n\n // If there's a default project ID, try to pay it.\n if (defaultProjectId != 0)\n if (defaultPreferAddToBalance)\n // Pay the project by adding to its balance if prefered.\n _addToBalanceOf(\n defaultProjectId,\n JBTokens.ETH,\n _leftoverAmount,\n 18, // decimals.\n defaultMemo,\n defaultMetadata\n );\n // Otherwise, issue a payment to the project.\n else\n _pay(\n defaultProjectId,\n JBTokens.ETH,\n _leftoverAmount,\n 18, // decimals.\n defaultBeneficiary != address(0) ? defaultBeneficiary : tx.origin,\n 0, // min returned tokens.\n defaultPreferClaimedTokens,\n defaultMemo,\n defaultMetadata\n );\n // If no project was specified, send the funds directly to the beneficiary or the tx.origin.\n else\n Address.sendValue(\n defaultBeneficiary != address(0) ? payable(defaultBeneficiary) : payable(tx.origin),\n _leftoverAmount\n );\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Sets the splits in the splits store that payments this contract receives will be split between.\n /// @param _projectId The ID of project for which the default splits are stored.\n /// @param _domain The domain within which the default splits are stored.\n /// @param _group The group within which the default splits are stored.\n /// @param _groupedSplits The split groups to set.\n function setDefaultSplits(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group,\n JBGroupedSplits[] memory _groupedSplits\n ) external virtual override onlyOwner {\n // Set the splits in the store.\n splitsStore.set(_projectId, _domain, _groupedSplits);\n\n // Set the splits reference.\n setDefaultSplitsReference(_projectId, _domain, _group);\n }\n\n //*********************************************************************//\n // ----------------------- public transactions ----------------------- //\n //*********************************************************************//\n\n /// @notice Sets the location of the splits that payments this contract receives will be split between.\n /// @param _projectId The ID of project for which the default splits are stored.\n /// @param _domain The domain within which the default splits are stored.\n /// @param _group The group within which the default splits are stored.\n function setDefaultSplitsReference(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group\n ) public virtual override onlyOwner {\n // Set the default splits project ID if it's changing.\n if (_projectId != defaultSplitsProjectId) defaultSplitsProjectId = _projectId;\n\n // Set the default splits domain if it's changing.\n if (_domain != defaultSplitsDomain) defaultSplitsDomain = _domain;\n\n // Set the default splits group if it's changing.\n if (_group != defaultSplitsGroup) defaultSplitsGroup = _group;\n\n emit SetDefaultSplitsReference(_projectId, _domain, _group, msg.sender);\n }\n\n /// @notice Make a payment to the specified project after first splitting the amount among the stored default splits.\n /// @param _projectId The ID of the project that is being paid after.\n /// @param _token The token being paid in.\n /// @param _amount The amount of tokens being paid, as a fixed point number. If the token is ETH, this is ignored and msg.value is used in its place.\n /// @param _decimals The number of decimals in the `_amount` fixed point number. If the token is ETH, this is ignored and 18 is used in its place, which corresponds to the amount of decimals expected in msg.value.\n /// @param _beneficiary The address who will receive tokens from the payment made with leftover funds.\n /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with 18 decimals.\n /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\n /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n function pay(\n uint256 _projectId,\n address _token,\n uint256 _amount,\n uint256 _decimals,\n address _beneficiary,\n uint256 _minReturnedTokens,\n bool _preferClaimedTokens,\n string calldata _memo,\n bytes calldata _metadata\n ) public payable virtual override nonReentrant {\n // ETH shouldn't be sent if the token isn't ETH.\n if (address(_token) != JBTokens.ETH) {\n if (msg.value > 0) revert NO_MSG_VALUE_ALLOWED();\n\n // Get a reference to the balance before receiving tokens.\n uint256 _balanceBefore = IERC20(_token).balanceOf(address(this));\n\n // Transfer tokens to this contract from the msg sender.\n IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount);\n\n // The amount should reflect the change in balance.\n _amount = IERC20(_token).balanceOf(address(this)) - _balanceBefore;\n } else {\n // If ETH is being paid, set the amount to the message value, and decimals to 18.\n _amount = msg.value;\n _decimals = 18;\n }\n\n // Pay the splits and get a reference to the amount leftover.\n uint256 _leftoverAmount = _payToSplits(\n defaultSplitsProjectId,\n defaultSplitsDomain,\n defaultSplitsGroup,\n _token,\n _amount,\n _decimals,\n defaultBeneficiary != address(0) ? defaultBeneficiary : tx.origin\n );\n\n // Pay any leftover amount.\n if (_leftoverAmount > 0) {\n // If there's a default project ID, try to pay it.\n if (_projectId != 0) {\n _pay(\n _projectId,\n _token,\n _leftoverAmount,\n _decimals,\n _beneficiary != address(0) ? _beneficiary : defaultBeneficiary != address(0)\n ? defaultBeneficiary\n : tx.origin,\n _minReturnedTokens,\n _preferClaimedTokens,\n _memo,\n _metadata\n );\n }\n // If no project was specified, send the funds directly to the beneficiary or the tx.origin.\n else {\n // Transfer the ETH.\n if (_token == JBTokens.ETH)\n Address.sendValue(\n // If there's a beneficiary, send the funds directly to the beneficiary. Otherwise send to the tx.origin.\n _beneficiary != address(0) ? payable(_beneficiary) : defaultBeneficiary != address(0)\n ? defaultBeneficiary\n : payable(tx.origin),\n _leftoverAmount\n );\n // Or, transfer the ERC20.\n else\n IERC20(_token).safeTransfer(\n // If there's a beneficiary, send the funds directly to the beneficiary. Otherwise send to the tx.origin.\n _beneficiary != address(0) ? _beneficiary : defaultBeneficiary != address(0)\n ? defaultBeneficiary\n : tx.origin,\n _leftoverAmount\n );\n }\n }\n\n emit Pay(\n _projectId,\n _beneficiary != address(0) ? _beneficiary : defaultBeneficiary != address(0)\n ? defaultBeneficiary\n : tx.origin,\n _token,\n _amount,\n _decimals,\n _leftoverAmount,\n _minReturnedTokens,\n _preferClaimedTokens,\n _memo,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Add to the balance of the specified project after first splitting the amount among the stored default splits.\n /// @param _projectId The ID of the project that is being paid after.\n /// @param _token The token being paid in.\n /// @param _amount The amount of tokens being paid, as a fixed point number. If the token is ETH, this is ignored and msg.value is used in its place.\n /// @param _decimals The number of decimals in the `_amount` fixed point number. If the token is ETH, this is ignored and 18 is used in its place, which corresponds to the amount of decimals expected in msg.value.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the terminal.\n function addToBalanceOf(\n uint256 _projectId,\n address _token,\n uint256 _amount,\n uint256 _decimals,\n string calldata _memo,\n bytes calldata _metadata\n ) public payable virtual override nonReentrant {\n // ETH shouldn't be sent if this terminal's token isn't ETH.\n if (address(_token) != JBTokens.ETH) {\n if (msg.value > 0) revert NO_MSG_VALUE_ALLOWED();\n\n // Get a reference to the balance before receiving tokens.\n uint256 _balanceBefore = IERC20(_token).balanceOf(address(this));\n\n // Transfer tokens to this contract from the msg sender.\n IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount);\n\n // The amount should reflect the change in balance.\n _amount = IERC20(_token).balanceOf(address(this)) - _balanceBefore;\n } else {\n // If ETH is being paid, set the amount to the message value, and decimals to 18.\n _amount = msg.value;\n _decimals = 18;\n }\n\n // Pay the splits and get a reference to the amount leftover.\n uint256 _leftoverAmount = _payToSplits(\n defaultSplitsProjectId,\n defaultSplitsDomain,\n defaultSplitsGroup,\n _token,\n _amount,\n _decimals,\n defaultBeneficiary != address(0) ? defaultBeneficiary : tx.origin\n );\n\n // Distribute any leftover amount.\n if (_leftoverAmount > 0) {\n // If there's a default project ID, try to add to its balance.\n if (_projectId != 0)\n // Add to the project's balance.\n _addToBalanceOf(_projectId, _token, _leftoverAmount, _decimals, _memo, _metadata);\n\n // Otherwise, send a payment to the beneficiary.\n else {\n // Transfer the ETH.\n if (_token == JBTokens.ETH)\n Address.sendValue(\n // If there's a default beneficiary, send the funds directly to the beneficiary. Otherwise send to the tx.origin.\n defaultBeneficiary != address(0) ? defaultBeneficiary : payable(tx.origin),\n _leftoverAmount\n );\n // Or, transfer the ERC20.\n else\n IERC20(_token).safeTransfer(\n // If there's a default beneficiary, send the funds directly to the beneficiary. Otherwise send to the tx.origin.\n defaultBeneficiary != address(0) ? defaultBeneficiary : tx.origin,\n _leftoverAmount\n );\n }\n }\n\n emit AddToBalance(\n _projectId,\n defaultBeneficiary != address(0) ? defaultBeneficiary : tx.origin,\n _token,\n _amount,\n _decimals,\n _leftoverAmount,\n _memo,\n _metadata,\n msg.sender\n );\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Split an amount between all splits.\n /// @param _splitsProjectId The ID of the project to which the splits belong.\n /// @param _splitsDomain The splits domain to which the group belongs.\n /// @param _splitsGroup The splits group to pay.\n /// @param _token The token the amonut being split is in.\n /// @param _amount The amount of tokens being split, as a fixed point number. If the `_token` is ETH, this is ignored and msg.value is used in its place.\n /// @param _decimals The number of decimals in the `_amount` fixed point number.\n /// @param _defaultBeneficiary The address that will benefit from any non-specified beneficiaries in splits.\n /// @return leftoverAmount The amount leftover after all splits were paid.\n function _payToSplits(\n uint256 _splitsProjectId,\n uint256 _splitsDomain,\n uint256 _splitsGroup,\n address _token,\n uint256 _amount,\n uint256 _decimals,\n address _defaultBeneficiary\n ) internal virtual returns (uint256 leftoverAmount) {\n // Pay the splits.\n leftoverAmount = _payTo(\n splitsStore.splitsOf(_splitsProjectId, _splitsDomain, _splitsGroup),\n _token,\n _amount,\n _decimals,\n _defaultBeneficiary\n );\n emit DistributeToSplitGroup(_splitsProjectId, _splitsDomain, _splitsGroup, msg.sender);\n }\n\n /// @notice Split an amount between all splits.\n /// @param _splits The splits.\n /// @param _token The token the amonut being split is in.\n /// @param _amount The amount of tokens being split, as a fixed point number. If the `_token` is ETH, this is ignored and msg.value is used in its place.\n /// @param _decimals The number of decimals in the `_amount` fixed point number.\n /// @param _defaultBeneficiary The address that will benefit from any non-specified beneficiaries in splits.\n /// @return leftoverAmount The amount leftover after all splits were paid.\n function _payTo(\n JBSplit[] memory _splits,\n address _token,\n uint256 _amount,\n uint256 _decimals,\n address _defaultBeneficiary\n ) internal virtual returns (uint256 leftoverAmount) {\n // Set the leftover amount to the initial balance.\n leftoverAmount = _amount;\n\n // Settle between all splits.\n for (uint256 i; i < _splits.length; ) {\n // Get a reference to the split being iterated on.\n JBSplit memory _split = _splits[i];\n\n // The amount to send towards the split.\n uint256 _splitAmount = PRBMath.mulDiv(\n _amount,\n _split.percent,\n JBConstants.SPLITS_TOTAL_PERCENT\n );\n\n if (_splitAmount > 0) {\n // Transfer tokens to the split.\n // If there's an allocator set, transfer to its `allocate` function.\n if (_split.allocator != IJBSplitAllocator(address(0))) {\n // Create the data to send to the allocator.\n JBSplitAllocationData memory _data = JBSplitAllocationData(\n _token,\n _splitAmount,\n _decimals,\n defaultProjectId,\n 0,\n _split\n );\n\n // Approve the `_amount` of tokens for the split allocator to transfer tokens from this contract.\n if (_token != JBTokens.ETH)\n IERC20(_token).safeApprove(address(_split.allocator), _splitAmount);\n\n // If the token is ETH, send it in msg.value.\n uint256 _payableValue = _token == JBTokens.ETH ? _splitAmount : 0;\n\n // Trigger the allocator's `allocate` function.\n _split.allocator.allocate{value: _payableValue}(_data);\n\n // Otherwise, if a project is specified, make a payment to it.\n } else if (_split.projectId != 0) {\n if (_split.preferAddToBalance)\n _addToBalanceOf(\n _split.projectId,\n _token,\n _splitAmount,\n _decimals,\n defaultMemo,\n defaultMetadata\n );\n else\n _pay(\n _split.projectId,\n _token,\n _splitAmount,\n _decimals,\n _split.beneficiary != address(0) ? _split.beneficiary : _defaultBeneficiary,\n 0,\n _split.preferClaimed,\n defaultMemo,\n defaultMetadata\n );\n } else {\n // Transfer the ETH.\n if (_token == JBTokens.ETH)\n Address.sendValue(\n // Get a reference to the address receiving the tokens. If there's a beneficiary, send the funds directly to the beneficiary. Otherwise send to _defaultBeneficiary.\n _split.beneficiary != address(0) ? _split.beneficiary : payable(_defaultBeneficiary),\n _splitAmount\n );\n // Or, transfer the ERC20.\n else {\n IERC20(_token).safeTransfer(\n // Get a reference to the address receiving the tokens. If there's a beneficiary, send the funds directly to the beneficiary. Otherwise send to _defaultBeneficiary.\n _split.beneficiary != address(0) ? _split.beneficiary : _defaultBeneficiary,\n _splitAmount\n );\n }\n }\n\n // Subtract from the amount to be sent to the beneficiary.\n leftoverAmount = leftoverAmount - _splitAmount;\n }\n\n emit DistributeToSplit(_split, _splitAmount, _defaultBeneficiary, msg.sender);\n\n unchecked {\n ++i;\n }\n }\n }\n}\n" + }, + "@openzeppelin/contracts/security/ReentrancyGuard.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuard {\n // Booleans are more expensive than uint256 or any type that takes up a full\n // word because each write operation emits an extra SLOAD to first read the\n // slot's contents, replace the bits taken up by the boolean, and then write\n // back. This is the compiler's defense against contract upgrades and\n // pointer aliasing, and it cannot be disabled.\n\n // The values being non-zero value makes deployment a bit more expensive,\n // but in exchange the refund on every call to nonReentrant will be lower in\n // amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to\n // increase the likelihood of the full refund coming into effect.\n uint256 private constant _NOT_ENTERED = 1;\n uint256 private constant _ENTERED = 2;\n\n uint256 private _status;\n\n constructor() {\n _status = _NOT_ENTERED;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a `nonReentrant` function from another `nonReentrant`\n * function is not supported. It is possible to prevent this from happening\n * by making the `nonReentrant` function external, and making it call a\n * `private` function that does the actual work.\n */\n modifier nonReentrant() {\n // On the first call to nonReentrant, _notEntered will be true\n require(_status != _ENTERED, \"ReentrancyGuard: reentrant call\");\n\n // Any calls to nonReentrant after this point will fail\n _status = _ENTERED;\n\n _;\n\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _status = _NOT_ENTERED;\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length > 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Address.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n *\n * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCall(target, data, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n require(isContract(target), \"Address: call to non-contract\");\n\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n require(isContract(target), \"Address: static call to non-contract\");\n\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(isContract(target), \"Address: delegate call to non-contract\");\n\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n }\n}\n" + }, + "contracts/JBETHERC20ProjectPayer.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';\nimport {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';\nimport {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';\nimport {ERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBProjectPayer} from './interfaces/IJBProjectPayer.sol';\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\nimport {JBTokens} from './libraries/JBTokens.sol';\n\n/// @notice Sends ETH or ERC20's to a project treasury as it receives direct payments or has it's functions called.\n/// @dev Inherit from this contract or borrow from its logic to forward ETH or ERC20's to project treasuries from within other contracts.\ncontract JBETHERC20ProjectPayer is Ownable, ERC165, IJBProjectPayer {\n using SafeERC20 for IERC20;\n\n //*********************************************************************//\n // -------------------------- custom errors -------------------------- //\n //*********************************************************************//\n error INCORRECT_DECIMAL_AMOUNT();\n error ALREADY_INITIALIZED();\n error NO_MSG_VALUE_ALLOWED();\n error TERMINAL_NOT_FOUND();\n\n //*********************************************************************//\n // ------------------- public immutable properties ------------------- //\n //*********************************************************************//\n\n /// @notice A contract storing directories of terminals and controllers for each project.\n IJBDirectory public immutable override directory;\n\n /// @notice The deployer associated with this implementation. Used to rule out double initialization.\n address public immutable override projectPayerDeployer;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The ID of the project that should be used to forward this contract's received payments.\n uint256 public override defaultProjectId;\n\n /// @notice The beneficiary that should be used in the payment made when this contract receives payments.\n address payable public override defaultBeneficiary;\n\n /// @notice A flag indicating whether issued tokens should be automatically claimed into the beneficiary's wallet. Leaving tokens unclaimed saves gas.\n bool public override defaultPreferClaimedTokens;\n\n /// @notice The memo that should be used in the payment made when this contract receives payments.\n string public override defaultMemo;\n\n /// @notice The metadata that should be used in the payment made when this contract receives payments.\n bytes public override defaultMetadata;\n\n /// @notice A flag indicating if received payments should call the `pay` function or the `addToBalance` function of a project.\n bool public override defaultPreferAddToBalance;\n\n //*********************************************************************//\n // ------------------------- public views ---------------------------- //\n //*********************************************************************//\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if the provided interface ID is supported.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(ERC165, IERC165) returns (bool) {\n return\n _interfaceId == type(IJBProjectPayer).interfaceId || super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // -------------------------- constructors --------------------------- //\n //*********************************************************************//\n\n /// @dev This is the constructor of the implementation. The directory is shared between project payers and is immutable. If a new JBDirectory is needed, a new JBProjectPayerDeployer should be deployed.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n constructor(IJBDirectory _directory) {\n directory = _directory;\n projectPayerDeployer = msg.sender;\n }\n\n /// @param _defaultProjectId The ID of the project whose treasury should be forwarded this contract's received payments.\n /// @param _defaultBeneficiary The address that'll receive the project's tokens.\n /// @param _defaultPreferClaimedTokens A flag indicating whether issued tokens should be automatically claimed into the beneficiary's wallet.\n /// @param _defaultMemo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _defaultMetadata Bytes to send along to the project's data source and delegate, if provided.\n /// @param _defaultPreferAddToBalance A flag indicating if received payments should call the `pay` function or the `addToBalance` function of a project.\n /// @param _owner The address that will own the contract.\n function initialize(\n uint256 _defaultProjectId,\n address payable _defaultBeneficiary,\n bool _defaultPreferClaimedTokens,\n string memory _defaultMemo,\n bytes memory _defaultMetadata,\n bool _defaultPreferAddToBalance,\n address _owner\n ) public {\n if (msg.sender != projectPayerDeployer) revert ALREADY_INITIALIZED();\n\n defaultProjectId = _defaultProjectId;\n defaultBeneficiary = _defaultBeneficiary;\n defaultPreferClaimedTokens = _defaultPreferClaimedTokens;\n defaultMemo = _defaultMemo;\n defaultMetadata = _defaultMetadata;\n defaultPreferAddToBalance = _defaultPreferAddToBalance;\n _transferOwnership(_owner);\n }\n\n //*********************************************************************//\n // ------------------------- default receive ------------------------- //\n //*********************************************************************//\n\n /// @notice Received funds are paid to the default project ID using the stored default properties.\n /// @dev Use the `addToBalance` function if there's a preference to do so. Otherwise use `pay`.\n /// @dev This function is called automatically when the contract receives an ETH payment.\n receive() external payable virtual override {\n if (defaultPreferAddToBalance)\n _addToBalanceOf(\n defaultProjectId,\n JBTokens.ETH,\n address(this).balance,\n 18, // balance is a fixed point number with 18 decimals.\n defaultMemo,\n defaultMetadata\n );\n else\n _pay(\n defaultProjectId,\n JBTokens.ETH,\n address(this).balance,\n 18, // balance is a fixed point number with 18 decimals.\n defaultBeneficiary == address(0) ? tx.origin : defaultBeneficiary,\n 0, // Can't determine expectation of returned tokens ahead of time.\n defaultPreferClaimedTokens,\n defaultMemo,\n defaultMetadata\n );\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Sets the default values that determine how to interact with a protocol treasury when this contract receives ETH directly.\n /// @param _projectId The ID of the project whose treasury should be forwarded this contract's received payments.\n /// @param _beneficiary The address that'll receive the project's tokens.\n /// @param _preferClaimedTokens A flag indicating whether issued tokens should be automatically claimed into the beneficiary's wallet.\n /// @param _memo The memo that'll be used.\n /// @param _metadata The metadata that'll be sent.\n /// @param _defaultPreferAddToBalance A flag indicating if received payments should call the `pay` function or the `addToBalance` function of a project.\n function setDefaultValues(\n uint256 _projectId,\n address payable _beneficiary,\n bool _preferClaimedTokens,\n string memory _memo,\n bytes memory _metadata,\n bool _defaultPreferAddToBalance\n ) external virtual override onlyOwner {\n // Set the default project ID if it has changed.\n if (_projectId != defaultProjectId) defaultProjectId = _projectId;\n\n // Set the default beneficiary if it has changed.\n if (_beneficiary != defaultBeneficiary) defaultBeneficiary = _beneficiary;\n\n // Set the default claimed token preference if it has changed.\n if (_preferClaimedTokens != defaultPreferClaimedTokens)\n defaultPreferClaimedTokens = _preferClaimedTokens;\n\n // Set the default memo if it has changed.\n if (keccak256(abi.encodePacked(_memo)) != keccak256(abi.encodePacked(defaultMemo)))\n defaultMemo = _memo;\n\n // Set the default metadata if it has changed.\n if (keccak256(abi.encodePacked(_metadata)) != keccak256(abi.encodePacked(defaultMetadata)))\n defaultMetadata = _metadata;\n\n // Set the add to balance preference if it has changed.\n if (_defaultPreferAddToBalance != defaultPreferAddToBalance)\n defaultPreferAddToBalance = _defaultPreferAddToBalance;\n\n emit SetDefaultValues(\n _projectId,\n _beneficiary,\n _preferClaimedTokens,\n _memo,\n _metadata,\n _defaultPreferAddToBalance,\n msg.sender\n );\n }\n\n //*********************************************************************//\n // ----------------------- public transactions ----------------------- //\n //*********************************************************************//\n\n /// @notice Make a payment to the specified project.\n /// @param _projectId The ID of the project that is being paid.\n /// @param _token The token being paid in.\n /// @param _amount The amount of tokens being paid, as a fixed point number. If the token is ETH, this is ignored and msg.value is used in its place.\n /// @param _decimals The number of decimals in the `_amount` fixed point number. If the token is ETH, this is ignored and 18 is used in its place, which corresponds to the amount of decimals expected in msg.value.\n /// @param _beneficiary The address who will receive tokens from the payment.\n /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with 18 decimals.\n /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\n /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n function pay(\n uint256 _projectId,\n address _token,\n uint256 _amount,\n uint256 _decimals,\n address _beneficiary,\n uint256 _minReturnedTokens,\n bool _preferClaimedTokens,\n string calldata _memo,\n bytes calldata _metadata\n ) public payable virtual override {\n // ETH shouldn't be sent if the token isn't ETH.\n if (address(_token) != JBTokens.ETH) {\n if (msg.value > 0) revert NO_MSG_VALUE_ALLOWED();\n\n // Get a reference to the balance before receiving tokens.\n uint256 _balanceBefore = IERC20(_token).balanceOf(address(this));\n\n // Transfer tokens to this contract from the msg sender.\n IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount);\n\n // The amount should reflect the change in balance.\n _amount = IERC20(_token).balanceOf(address(this)) - _balanceBefore;\n } else {\n // If ETH is being paid, set the amount to the message value, and decimals to 18.\n _amount = msg.value;\n _decimals = 18;\n }\n\n _pay(\n _projectId,\n _token,\n _amount,\n _decimals,\n _beneficiary,\n _minReturnedTokens,\n _preferClaimedTokens,\n _memo,\n _metadata\n );\n }\n\n /// @notice Add to the balance of the specified project.\n /// @param _projectId The ID of the project that is being paid.\n /// @param _token The token being paid in.\n /// @param _amount The amount of tokens being paid, as a fixed point number. If the token is ETH, this is ignored and msg.value is used in its place.\n /// @param _decimals The number of decimals in the `_amount` fixed point number. If the token is ETH, this is ignored and 18 is used in its place, which corresponds to the amount of decimals expected in msg.value.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the terminal.\n function addToBalanceOf(\n uint256 _projectId,\n address _token,\n uint256 _amount,\n uint256 _decimals,\n string calldata _memo,\n bytes calldata _metadata\n ) public payable virtual override {\n // ETH shouldn't be sent if the token isn't ETH.\n if (address(_token) != JBTokens.ETH) {\n if (msg.value > 0) revert NO_MSG_VALUE_ALLOWED();\n\n // Get a reference to the balance before receiving tokens.\n uint256 _balanceBefore = IERC20(_token).balanceOf(address(this));\n\n // Transfer tokens to this contract from the msg sender.\n IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount);\n\n // The amount should reflect the change in balance.\n _amount = IERC20(_token).balanceOf(address(this)) - _balanceBefore;\n } else {\n // If ETH is being paid, set the amount to the message value, and decimals to 18.\n _amount = msg.value;\n _decimals = 18;\n }\n\n _addToBalanceOf(_projectId, _token, _amount, _decimals, _memo, _metadata);\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Make a payment to the specified project.\n /// @param _projectId The ID of the project that is being paid.\n /// @param _token The token being paid in.\n /// @param _amount The amount of tokens being paid, as a fixed point number.\n /// @param _decimals The number of decimals in the `_amount` fixed point number.\n /// @param _beneficiary The address who will receive tokens from the payment.\n /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with 18 decimals.\n /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\n /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _metadata Bytes to send along to the data source and delegate, if provided.\n function _pay(\n uint256 _projectId,\n address _token,\n uint256 _amount,\n uint256 _decimals,\n address _beneficiary,\n uint256 _minReturnedTokens,\n bool _preferClaimedTokens,\n string memory _memo,\n bytes memory _metadata\n ) internal virtual {\n // Find the terminal for the specified project.\n IJBPaymentTerminal _terminal = directory.primaryTerminalOf(_projectId, _token);\n\n // There must be a terminal.\n if (_terminal == IJBPaymentTerminal(address(0))) revert TERMINAL_NOT_FOUND();\n\n // The amount's decimals must match the terminal's expected decimals.\n if (_terminal.decimalsForToken(_token) != _decimals) revert INCORRECT_DECIMAL_AMOUNT();\n\n // Approve the `_amount` of tokens from the destination terminal to transfer tokens from this contract.\n if (_token != JBTokens.ETH) IERC20(_token).safeApprove(address(_terminal), _amount);\n\n // If the token is ETH, send it in msg.value.\n uint256 _payableValue = _token == JBTokens.ETH ? _amount : 0;\n\n // Send funds to the terminal.\n // If the token is ETH, send it in msg.value.\n _terminal.pay{value: _payableValue}(\n _projectId,\n _amount, // ignored if the token is JBTokens.ETH.\n _token,\n _beneficiary != address(0) ? _beneficiary : defaultBeneficiary != address(0)\n ? defaultBeneficiary\n : tx.origin,\n _minReturnedTokens,\n _preferClaimedTokens,\n _memo,\n _metadata\n );\n }\n\n /// @notice Add to the balance of the specified project.\n /// @param _projectId The ID of the project that is being paid.\n /// @param _token The token being paid in.\n /// @param _amount The amount of tokens being paid, as a fixed point number. If the token is ETH, this is ignored and msg.value is used in its place.\n /// @param _decimals The number of decimals in the `_amount` fixed point number. If the token is ETH, this is ignored and 18 is used in its place, which corresponds to the amount of decimals expected in msg.value.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the terminal.\n function _addToBalanceOf(\n uint256 _projectId,\n address _token,\n uint256 _amount,\n uint256 _decimals,\n string memory _memo,\n bytes memory _metadata\n ) internal virtual {\n // Find the terminal for the specified project.\n IJBPaymentTerminal _terminal = directory.primaryTerminalOf(_projectId, _token);\n\n // There must be a terminal.\n if (_terminal == IJBPaymentTerminal(address(0))) revert TERMINAL_NOT_FOUND();\n\n // The amount's decimals must match the terminal's expected decimals.\n if (_terminal.decimalsForToken(_token) != _decimals) revert INCORRECT_DECIMAL_AMOUNT();\n\n // Approve the `_amount` of tokens from the destination terminal to transfer tokens from this contract.\n if (_token != JBTokens.ETH) IERC20(_token).safeApprove(address(_terminal), _amount);\n\n // If the token is ETH, send it in msg.value.\n uint256 _payableValue = _token == JBTokens.ETH ? _amount : 0;\n\n // Add to balance so tokens don't get issued.\n _terminal.addToBalanceOf{value: _payableValue}(_projectId, _amount, _token, _memo, _metadata);\n }\n}\n" + }, + "contracts/libraries/JBTokens.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nlibrary JBTokens {\n /// @notice The ETH token address in Juicebox is represented by 0x000000000000000000000000000000000000EEEe.\n address public constant ETH = address(0x000000000000000000000000000000000000EEEe);\n}\n" + }, + "contracts/interfaces/IJBProjectPayer.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {IJBDirectory} from './IJBDirectory.sol';\n\ninterface IJBProjectPayer is IERC165 {\n event SetDefaultValues(\n uint256 indexed projectId,\n address indexed beneficiary,\n bool preferClaimedTokens,\n string memo,\n bytes metadata,\n bool preferAddToBalance,\n address caller\n );\n\n function directory() external view returns (IJBDirectory);\n\n function projectPayerDeployer() external view returns (address);\n\n function defaultProjectId() external view returns (uint256);\n\n function defaultBeneficiary() external view returns (address payable);\n\n function defaultPreferClaimedTokens() external view returns (bool);\n\n function defaultMemo() external view returns (string memory);\n\n function defaultMetadata() external view returns (bytes memory);\n\n function defaultPreferAddToBalance() external view returns (bool);\n\n function initialize(\n uint256 defaultProjectId,\n address payable defaultBeneficiary,\n bool defaultPreferClaimedTokens,\n string memory defaultMemo,\n bytes memory defaultMetadata,\n bool defaultPreferAddToBalance,\n address owner\n ) external;\n\n function setDefaultValues(\n uint256 projectId,\n address payable beneficiary,\n bool preferClaimedTokens,\n string memory memo,\n bytes memory metadata,\n bool defaultPreferAddToBalance\n ) external;\n\n function pay(\n uint256 projectId,\n address token,\n uint256 amount,\n uint256 decimals,\n address beneficiary,\n uint256 minReturnedTokens,\n bool preferClaimedTokens,\n string memory memo,\n bytes memory metadata\n ) external payable;\n\n function addToBalanceOf(\n uint256 projectId,\n address token,\n uint256 amount,\n uint256 decimals,\n string memory memo,\n bytes memory metadata\n ) external payable;\n\n receive() external payable;\n}\n" + }, + "contracts/JBController3_0_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {ERC165, IERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {SafeCast} from '@openzeppelin/contracts/utils/math/SafeCast.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {JBOperatable} from './abstract/JBOperatable.sol';\nimport {JBBallotState} from './enums/JBBallotState.sol';\nimport {IJBController3_0_1} from './interfaces/IJBController3_0_1.sol';\nimport {IJBController} from './interfaces/IJBController.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol';\nimport {IJBMigratable} from './interfaces/IJBMigratable.sol';\nimport {IJBOperatable} from './interfaces/IJBOperatable.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {IJBSplitAllocator} from './interfaces/IJBSplitAllocator.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {IJBTokenStore} from './interfaces/IJBTokenStore.sol';\nimport {JBConstants} from './libraries/JBConstants.sol';\nimport {JBFundingCycleMetadataResolver} from './libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBOperations} from './libraries/JBOperations.sol';\nimport {JBSplitsGroups} from './libraries/JBSplitsGroups.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\nimport {JBSplitAllocationData} from './structs/JBSplitAllocationData.sol';\nimport {JBFundAccessConstraints} from './structs/JBFundAccessConstraints.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\nimport {JBFundingCycleData} from './structs/JBFundingCycleData.sol';\nimport {JBFundingCycleMetadata} from './structs/JBFundingCycleMetadata.sol';\nimport {JBGroupedSplits} from './structs/JBGroupedSplits.sol';\nimport {JBProjectMetadata} from './structs/JBProjectMetadata.sol';\nimport {JBSplit} from './structs/JBSplit.sol';\n\n/// @notice Stitches together funding cycles and project tokens, making sure all activity is accounted for and correct.\n/// @dev This Controller manages a project's reserved tokens explicitly instead of through a passive tracker property.\n/// @dev It is backwards compatible with the original IJBController, and exposes convenience view methods as part of IJBController3_1 for clearer queries.\ncontract JBController3_0_1 is\n JBOperatable,\n ERC165,\n IJBController,\n IJBController3_0_1,\n IJBMigratable\n{\n // A library that parses the packed funding cycle metadata into a more friendly format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error BURN_PAUSED_AND_SENDER_NOT_VALID_TERMINAL_DELEGATE();\n error FUNDING_CYCLE_ALREADY_LAUNCHED();\n error INVALID_BALLOT_REDEMPTION_RATE();\n error INVALID_DISTRIBUTION_LIMIT();\n error INVALID_DISTRIBUTION_LIMIT_CURRENCY();\n error INVALID_OVERFLOW_ALLOWANCE();\n error INVALID_OVERFLOW_ALLOWANCE_CURRENCY();\n error INVALID_REDEMPTION_RATE();\n error INVALID_RESERVED_RATE();\n error MIGRATION_NOT_ALLOWED();\n error MINT_NOT_ALLOWED_AND_NOT_TERMINAL_DELEGATE();\n error NO_BURNABLE_TOKENS();\n error NOT_CURRENT_CONTROLLER();\n error ZERO_TOKENS_TO_MINT();\n\n //*********************************************************************//\n // --------------------- internal stored properties ------------------ //\n //*********************************************************************//\n\n /// @notice Data regarding the distribution limit of a project during a configuration.\n /// @dev bits 0-231: The amount of token that a project can distribute per funding cycle.\n /// @dev bits 232-255: The currency of amount that a project can distribute.\n /// @custom:param _projectId The ID of the project to get the packed distribution limit data of.\n /// @custom:param _configuration The configuration during which the packed distribution limit data applies.\n /// @custom:param _terminal The terminal from which distributions are being limited.\n /// @custom:param _token The token for which distributions are being limited.\n mapping(uint256 => mapping(uint256 => mapping(IJBPaymentTerminal => mapping(address => uint256))))\n internal _packedDistributionLimitDataOf;\n\n /// @notice Data regarding the overflow allowance of a project during a configuration.\n /// @dev bits 0-231: The amount of overflow that a project is allowed to tap into on-demand throughout the configuration.\n /// @dev bits 232-255: The currency of the amount of overflow that a project is allowed to tap.\n /// @custom:param _projectId The ID of the project to get the packed overflow allowance data of.\n /// @custom:param _configuration The configuration during which the packed overflow allowance data applies.\n /// @custom:param _terminal The terminal managing the overflow.\n /// @custom:param _token The token for which overflow is being allowed.\n mapping(uint256 => mapping(uint256 => mapping(IJBPaymentTerminal => mapping(address => uint256))))\n internal _packedOverflowAllowanceDataOf;\n\n /// @notice The current undistributed reserved token balance of.\n /// @custom:param _projectId The ID of the project to get a reserved token balance of.\n mapping(uint256 => uint256) internal _reservedTokenBalanceOf;\n\n //*********************************************************************//\n // --------------- public immutable stored properties ---------------- //\n //*********************************************************************//\n\n /// @notice Mints ERC-721's that represent project ownership.\n IJBProjects public immutable override projects;\n\n /// @notice The contract storing all funding cycle configurations.\n IJBFundingCycleStore public immutable override fundingCycleStore;\n\n /// @notice The contract that manages token minting and burning.\n IJBTokenStore public immutable override tokenStore;\n\n /// @notice The contract that stores splits for each project.\n IJBSplitsStore public immutable override splitsStore;\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice The amount of token that a project can distribute per funding cycle, and the currency it's in terms of.\n /// @dev The number of decimals in the returned fixed point amount is the same as that of the specified terminal.\n /// @param _projectId The ID of the project to get the distribution limit of.\n /// @param _configuration The configuration during which the distribution limit applies.\n /// @param _terminal The terminal from which distributions are being limited.\n /// @param _token The token for which the distribution limit applies.\n /// @return The distribution limit, as a fixed point number with the same number of decimals as the provided terminal.\n /// @return The currency of the distribution limit.\n function distributionLimitOf(\n uint256 _projectId,\n uint256 _configuration,\n IJBPaymentTerminal _terminal,\n address _token\n ) external view override returns (uint256, uint256) {\n // Get a reference to the packed data.\n uint256 _data = _packedDistributionLimitDataOf[_projectId][_configuration][_terminal][_token];\n\n // The limit is in bits 0-231. The currency is in bits 232-255.\n return (uint256(uint232(_data)), _data >> 232);\n }\n\n /// @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.\n /// @dev The number of decimals in the returned fixed point amount is the same as that of the specified terminal.\n /// @param _projectId The ID of the project to get the overflow allowance of.\n /// @param _configuration The configuration of the during which the allowance applies.\n /// @param _terminal The terminal managing the overflow.\n /// @param _token The token for which the overflow allowance applies.\n /// @return The overflow allowance, as a fixed point number with the same number of decimals as the provided terminal.\n /// @return The currency of the overflow allowance.\n function overflowAllowanceOf(\n uint256 _projectId,\n uint256 _configuration,\n IJBPaymentTerminal _terminal,\n address _token\n ) external view override returns (uint256, uint256) {\n // Get a reference to the packed data.\n uint256 _data = _packedOverflowAllowanceDataOf[_projectId][_configuration][_terminal][_token];\n\n // The allowance is in bits 0-231. The currency is in bits 232-255.\n return (uint256(uint232(_data)), _data >> 232);\n }\n\n /// @notice A project's funding cycle for the specified configuration along with its metadata.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The funding cycle.\n /// @return metadata The funding cycle's metadata.\n function getFundingCycleOf(\n uint256 _projectId,\n uint256 _configuration\n )\n external\n view\n override\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata)\n {\n fundingCycle = fundingCycleStore.get(_projectId, _configuration);\n metadata = fundingCycle.expandMetadata();\n }\n\n /// @notice A project's latest configured funding cycle along with its metadata and the ballot state of the configuration.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The latest configured funding cycle.\n /// @return metadata The latest configured funding cycle's metadata.\n /// @return ballotState The state of the configuration.\n function latestConfiguredFundingCycleOf(\n uint256 _projectId\n )\n external\n view\n override\n returns (\n JBFundingCycle memory fundingCycle,\n JBFundingCycleMetadata memory metadata,\n JBBallotState ballotState\n )\n {\n (fundingCycle, ballotState) = fundingCycleStore.latestConfiguredOf(_projectId);\n metadata = fundingCycle.expandMetadata();\n }\n\n /// @notice A project's current funding cycle along with its metadata.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The current funding cycle.\n /// @return metadata The current funding cycle's metadata.\n function currentFundingCycleOf(\n uint256 _projectId\n )\n external\n view\n override\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata)\n {\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n metadata = fundingCycle.expandMetadata();\n }\n\n /// @notice A project's queued funding cycle along with its metadata.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The queued funding cycle.\n /// @return metadata The queued funding cycle's metadata.\n function queuedFundingCycleOf(\n uint256 _projectId\n )\n external\n view\n override\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata)\n {\n fundingCycle = fundingCycleStore.queuedOf(_projectId);\n metadata = fundingCycle.expandMetadata();\n }\n\n /// @notice\tGets the amount of reserved tokens that a project has available to distribute.\n /// @param _projectId The ID of the project to get a reserved token balance of.\n /// @return The current amount of reserved tokens.\n function reservedTokenBalanceOf(uint256 _projectId) external view override returns (uint256) {\n return _reservedTokenBalanceOf[_projectId];\n }\n\n /// @notice\tGets the amount of reserved tokens that a project has available to distribute.\n /// @dev This is just for IJBController backwards compatibility.\n /// @param _projectId The ID of the project to get a reserved token balance of.\n /// @param _reservedRate The reserved rate to use when making the calculation.\n /// @return The current amount of reserved tokens.\n function reservedTokenBalanceOf(\n uint256 _projectId,\n uint256 _reservedRate\n ) external view override returns (uint256) {\n _reservedRate;\n return _reservedTokenBalanceOf[_projectId];\n }\n\n /// @notice\tGets the current total amount of outstanding tokens for a project, given a reserved rate.\n /// @dev This is just for IJBController backwards compatibility.\n /// @param _projectId The ID of the project to get total outstanding tokens of.\n /// @param _reservedRate The reserved rate to use when making the calculation.\n /// @return The current total amount of outstanding tokens for the project.\n function totalOutstandingTokensOf(\n uint256 _projectId,\n uint256 _reservedRate\n ) external view override returns (uint256) {\n _reservedRate;\n // Add the reserved tokens to the total supply.\n return totalOutstandingTokensOf(_projectId);\n }\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice Gets the current total amount of outstanding tokens for a project.\n /// @param _projectId The ID of the project to get total outstanding tokens of.\n /// @return The current total amount of outstanding tokens for the project.\n function totalOutstandingTokensOf(uint256 _projectId) public view override returns (uint256) {\n // Add the reserved tokens to the total supply.\n return tokenStore.totalSupplyOf(_projectId) + _reservedTokenBalanceOf[_projectId];\n }\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if the provided interface ID is supported.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(ERC165, IERC165) returns (bool) {\n return\n _interfaceId == type(IJBController3_0_1).interfaceId ||\n _interfaceId == type(IJBMigratable).interfaceId ||\n _interfaceId == type(IJBOperatable).interfaceId ||\n super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // ---------------------------- constructor -------------------------- //\n //*********************************************************************//\n\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _fundingCycleStore A contract storing all funding cycle configurations.\n /// @param _tokenStore A contract that manages token minting and burning.\n /// @param _splitsStore A contract that stores splits for each project.\n constructor(\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBFundingCycleStore _fundingCycleStore,\n IJBTokenStore _tokenStore,\n IJBSplitsStore _splitsStore\n ) JBOperatable(_operatorStore) {\n projects = _projects;\n directory = _directory;\n fundingCycleStore = _fundingCycleStore;\n tokenStore = _tokenStore;\n splitsStore = _splitsStore;\n }\n\n //*********************************************************************//\n // --------------------- external transactions ----------------------- //\n //*********************************************************************//\n\n /// @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.\n /// @dev Each operation within this transaction can be done in sequence separately.\n /// @dev Anyone can deploy a project on an owner's behalf.\n /// @param _owner The address to set as the owner of the project. The project ERC-721 will be owned by this address.\n /// @param _projectMetadata Metadata to associate with the project within a particular domain. This can be updated any time by the owner of the project.\n /// @param _data Data that defines the project's first funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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`.\n /// @param _terminals Payment terminals to add for the project.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return projectId The ID of the project.\n function launchProjectFor(\n address _owner,\n JBProjectMetadata calldata _projectMetadata,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] calldata _groupedSplits,\n JBFundAccessConstraints[] calldata _fundAccessConstraints,\n IJBPaymentTerminal[] memory _terminals,\n string memory _memo\n ) external virtual override returns (uint256 projectId) {\n // Keep a reference to the directory.\n IJBDirectory _directory = directory;\n\n // Mint the project into the wallet of the owner.\n projectId = projects.createFor(_owner, _projectMetadata);\n\n // Set this contract as the project's controller in the directory.\n _directory.setControllerOf(projectId, address(this));\n\n // Configure the first funding cycle.\n uint256 _configuration = _configure(\n projectId,\n _data,\n _metadata,\n _mustStartAtOrAfter,\n _groupedSplits,\n _fundAccessConstraints\n );\n\n // Add the provided terminals to the list of terminals.\n if (_terminals.length > 0) _directory.setTerminalsOf(projectId, _terminals);\n\n emit LaunchProject(_configuration, projectId, _memo, msg.sender);\n }\n\n /// @notice Creates a funding cycle for an already existing project ERC-721.\n /// @dev Each operation within this transaction can be done in sequence separately.\n /// @dev Only a project owner or operator can launch its funding cycles.\n /// @param _projectId The ID of the project to launch funding cycles for.\n /// @param _data Data that defines the project's first funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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`.\n /// @param _terminals Payment terminals to add for the project.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return configuration The configuration of the funding cycle that was successfully created.\n function launchFundingCyclesFor(\n uint256 _projectId,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] calldata _groupedSplits,\n JBFundAccessConstraints[] memory _fundAccessConstraints,\n IJBPaymentTerminal[] memory _terminals,\n string memory _memo\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.RECONFIGURE)\n returns (uint256 configuration)\n {\n // If there is a previous configuration, reconfigureFundingCyclesOf should be called instead\n if (fundingCycleStore.latestConfigurationOf(_projectId) > 0)\n revert FUNDING_CYCLE_ALREADY_LAUNCHED();\n\n // Set this contract as the project's controller in the directory.\n directory.setControllerOf(_projectId, address(this));\n\n // Configure the first funding cycle.\n configuration = _configure(\n _projectId,\n _data,\n _metadata,\n _mustStartAtOrAfter,\n _groupedSplits,\n _fundAccessConstraints\n );\n\n // Add the provided terminals to the list of terminals.\n if (_terminals.length > 0) directory.setTerminalsOf(_projectId, _terminals);\n\n emit LaunchFundingCycles(configuration, _projectId, _memo, msg.sender);\n }\n\n /// @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.\n /// @dev Only a project's owner or a designated operator can configure its funding cycles.\n /// @param _projectId The ID of the project whose funding cycles are being reconfigured.\n /// @param _data Data that defines the funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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`.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return configuration The configuration of the funding cycle that was successfully reconfigured.\n function reconfigureFundingCyclesOf(\n uint256 _projectId,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] calldata _groupedSplits,\n JBFundAccessConstraints[] calldata _fundAccessConstraints,\n string calldata _memo\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.RECONFIGURE)\n returns (uint256 configuration)\n {\n // Configure the next funding cycle.\n configuration = _configure(\n _projectId,\n _data,\n _metadata,\n _mustStartAtOrAfter,\n _groupedSplits,\n _fundAccessConstraints\n );\n\n emit ReconfigureFundingCycles(configuration, _projectId, _memo, msg.sender);\n }\n\n /// @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.\n /// @dev Only a project's owner, a designated operator, one of its terminals, or the current data source can mint its tokens.\n /// @param _projectId The ID of the project to which the tokens being minted belong.\n /// @param _tokenCount The amount of tokens to mint in total, counting however many should be reserved.\n /// @param _beneficiary The account that the tokens are being minted for.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _preferClaimedTokens A flag indicating whether a project's attached token contract should be minted if they have been issued.\n /// @param _useReservedRate Whether to use the current funding cycle's reserved rate in the mint calculation.\n /// @return beneficiaryTokenCount The amount of tokens minted for the beneficiary.\n function mintTokensOf(\n uint256 _projectId,\n uint256 _tokenCount,\n address _beneficiary,\n string calldata _memo,\n bool _preferClaimedTokens,\n bool _useReservedRate\n ) external virtual override returns (uint256 beneficiaryTokenCount) {\n // There should be tokens to mint.\n if (_tokenCount == 0) revert ZERO_TOKENS_TO_MINT();\n\n // Define variables that will be needed outside scoped section below.\n // Keep a reference to the reserved rate to use\n uint256 _reservedRate;\n\n // Scoped section prevents stack too deep. `_fundingCycle` only used within scope.\n {\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Minting limited to: project owner, authorized callers, project terminal and current funding cycle data source\n _requirePermissionAllowingOverride(\n projects.ownerOf(_projectId),\n _projectId,\n JBOperations.MINT,\n directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender)) ||\n msg.sender == address(_fundingCycle.dataSource())\n );\n\n // If the message sender is not a terminal or a datasource, the current funding cycle must allow minting.\n if (\n !_fundingCycle.mintingAllowed() &&\n !directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender)) &&\n msg.sender != address(_fundingCycle.dataSource())\n ) revert MINT_NOT_ALLOWED_AND_NOT_TERMINAL_DELEGATE();\n\n // Determine the reserved rate to use.\n _reservedRate = _useReservedRate ? _fundingCycle.reservedRate() : 0;\n\n // Override the claimed token preference with the funding cycle value.\n _preferClaimedTokens = _preferClaimedTokens == true\n ? _preferClaimedTokens\n : _fundingCycle.preferClaimedTokenOverride();\n }\n\n if (_reservedRate != JBConstants.MAX_RESERVED_RATE) {\n // The unreserved token count that will be minted for the beneficiary.\n beneficiaryTokenCount = PRBMath.mulDiv(\n _tokenCount,\n JBConstants.MAX_RESERVED_RATE - _reservedRate,\n JBConstants.MAX_RESERVED_RATE\n );\n\n // Mint the tokens.\n tokenStore.mintFor(_beneficiary, _projectId, beneficiaryTokenCount, _preferClaimedTokens);\n }\n\n // Add reserved tokens if needed\n if (_reservedRate > 0)\n _reservedTokenBalanceOf[_projectId] += _tokenCount - beneficiaryTokenCount;\n\n emit MintTokens(\n _beneficiary,\n _projectId,\n _tokenCount,\n beneficiaryTokenCount,\n _memo,\n _reservedRate,\n msg.sender\n );\n }\n\n /// @notice Burns a token holder's supply.\n /// @dev Only a token's holder, a designated operator, or a project's terminal can burn it.\n /// @param _holder The account that is having its tokens burned.\n /// @param _projectId The ID of the project to which the tokens being burned belong.\n /// @param _tokenCount The number of tokens to burn.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _preferClaimedTokens A flag indicating whether a project's attached token contract should be burned first if they have been issued.\n function burnTokensOf(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n string calldata _memo,\n bool _preferClaimedTokens\n )\n external\n virtual\n override\n requirePermissionAllowingOverride(\n _holder,\n _projectId,\n JBOperations.BURN,\n directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender))\n )\n {\n // There should be tokens to burn\n if (_tokenCount == 0) revert NO_BURNABLE_TOKENS();\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // If the message sender is a terminal, the current funding cycle must not be paused.\n if (\n _fundingCycle.burnPaused() &&\n !directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender))\n ) revert BURN_PAUSED_AND_SENDER_NOT_VALID_TERMINAL_DELEGATE();\n\n // Burn the tokens.\n tokenStore.burnFrom(_holder, _projectId, _tokenCount, _preferClaimedTokens);\n\n emit BurnTokens(_holder, _projectId, _tokenCount, _memo, msg.sender);\n }\n\n /// @notice Distributes all outstanding reserved tokens for a project.\n /// @param _projectId The ID of the project to which the reserved tokens belong.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return The amount of minted reserved tokens.\n function distributeReservedTokensOf(\n uint256 _projectId,\n string calldata _memo\n ) external virtual override returns (uint256) {\n return _distributeReservedTokensOf(_projectId, _memo);\n }\n\n /// @notice Allows other controllers to signal to this one that a migration is expected for the specified project.\n /// @dev This controller should not yet be the project's controller.\n /// @param _projectId The ID of the project that will be migrated to this controller.\n /// @param _from The controller being migrated from.\n function prepForMigrationOf(uint256 _projectId, address _from) external virtual override {\n _projectId; // Prevents unused var compiler and natspec complaints.\n _from; // Prevents unused var compiler and natspec complaints.\n }\n\n /// @notice Allows a project to migrate from this controller to another.\n /// @dev Only a project's owner or a designated operator can migrate it.\n /// @param _projectId The ID of the project that will be migrated from this controller.\n /// @param _to The controller to which the project is migrating.\n function migrate(\n uint256 _projectId,\n IJBMigratable _to\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.MIGRATE_CONTROLLER)\n {\n // Keep a reference to the directory.\n IJBDirectory _directory = directory;\n\n // This controller must be the project's current controller.\n if (_directory.controllerOf(_projectId) != address(this)) revert NOT_CURRENT_CONTROLLER();\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Migration must be allowed.\n if (!_fundingCycle.controllerMigrationAllowed()) revert MIGRATION_NOT_ALLOWED();\n\n // All reserved tokens must be minted before migrating.\n if (_reservedTokenBalanceOf[_projectId] != 0) _distributeReservedTokensOf(_projectId, '');\n\n // Make sure the new controller is prepped for the migration.\n _to.prepForMigrationOf(_projectId, address(this));\n\n // Set the new controller.\n _directory.setControllerOf(_projectId, address(_to));\n\n emit Migrate(_projectId, _to, msg.sender);\n }\n\n //*********************************************************************//\n // ------------------------ internal functions ----------------------- //\n //*********************************************************************//\n\n /// @notice Distributes all outstanding reserved tokens for a project.\n /// @param _projectId The ID of the project to which the reserved tokens belong.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return tokenCount The amount of minted reserved tokens.\n function _distributeReservedTokensOf(\n uint256 _projectId,\n string memory _memo\n ) internal returns (uint256 tokenCount) {\n // Keep a reference to the token store.\n IJBTokenStore _tokenStore = tokenStore;\n\n // Get the current funding cycle to read the reserved rate from.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Get a reference to the number of tokens that need to be minted.\n tokenCount = _reservedTokenBalanceOf[_projectId];\n\n // Reset the reserved token balance\n _reservedTokenBalanceOf[_projectId] = 0;\n\n // Get a reference to the project owner.\n address _owner = projects.ownerOf(_projectId);\n\n // Distribute tokens to splits and get a reference to the leftover amount to mint after all splits have gotten their share.\n uint256 _leftoverTokenCount = tokenCount == 0\n ? 0\n : _distributeToReservedTokenSplitsOf(\n _projectId,\n _fundingCycle.configuration,\n JBSplitsGroups.RESERVED_TOKENS,\n tokenCount\n );\n\n // Mint any leftover tokens to the project owner.\n if (_leftoverTokenCount > 0)\n _tokenStore.mintFor(_owner, _projectId, _leftoverTokenCount, false);\n\n emit DistributeReservedTokens(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _owner,\n tokenCount,\n _leftoverTokenCount,\n _memo,\n msg.sender\n );\n }\n\n /// @notice Distribute tokens to the splits according to the specified funding cycle configuration.\n /// @param _projectId The ID of the project for which reserved token splits are being distributed.\n /// @param _domain The domain of the splits to distribute the reserved tokens between.\n /// @param _group The group of the splits to distribute the reserved tokens between.\n /// @param _amount The total amount of tokens to mint.\n /// @return leftoverAmount If the splits percents dont add up to 100%, the leftover amount is returned.\n function _distributeToReservedTokenSplitsOf(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group,\n uint256 _amount\n ) internal returns (uint256 leftoverAmount) {\n // Keep a reference to the token store.\n IJBTokenStore _tokenStore = tokenStore;\n\n // Set the leftover amount to the initial amount.\n leftoverAmount = _amount;\n\n // Get a reference to the project's reserved token splits.\n JBSplit[] memory _splits = splitsStore.splitsOf(_projectId, _domain, _group);\n\n //Transfer between all splits.\n for (uint256 _i; _i < _splits.length; ) {\n // Get a reference to the split being iterated on.\n JBSplit memory _split = _splits[_i];\n\n // The amount to send towards the split.\n uint256 _tokenCount = PRBMath.mulDiv(\n _amount,\n _split.percent,\n JBConstants.SPLITS_TOTAL_PERCENT\n );\n\n // Mints tokens for the split if needed.\n if (_tokenCount > 0) {\n _tokenStore.mintFor(\n // If an allocator is set in the splits, set it as the beneficiary.\n // Otherwise if a projectId is set in the split, set the project's owner as the beneficiary.\n // If the split has a beneficiary send to the split's beneficiary. Otherwise send to the msg.sender.\n _split.allocator != IJBSplitAllocator(address(0))\n ? address(_split.allocator)\n : _split.projectId != 0\n ? projects.ownerOf(_split.projectId)\n : _split.beneficiary != address(0)\n ? _split.beneficiary\n : msg.sender,\n _projectId,\n _tokenCount,\n _split.preferClaimed\n );\n\n // If there's an allocator set, trigger its `allocate` function.\n if (_split.allocator != IJBSplitAllocator(address(0)))\n _split.allocator.allocate(\n JBSplitAllocationData(\n address(_tokenStore.tokenOf(_projectId)),\n _tokenCount,\n 18,\n _projectId,\n _group,\n _split\n )\n );\n\n // Subtract from the amount to be sent to the beneficiary.\n leftoverAmount = leftoverAmount - _tokenCount;\n }\n\n emit DistributeToReservedTokenSplit(\n _projectId,\n _domain,\n _group,\n _split,\n _tokenCount,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n\n /// @notice Configures a funding cycle and stores information pertinent to the configuration.\n /// @param _projectId The ID of the project whose funding cycles are being reconfigured.\n /// @param _data Data that defines the funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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.\n /// @return configuration The configuration of the funding cycle that was successfully reconfigured.\n function _configure(\n uint256 _projectId,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] memory _groupedSplits,\n JBFundAccessConstraints[] memory _fundAccessConstraints\n ) internal returns (uint256) {\n // Make sure the provided reserved rate is valid.\n if (_metadata.reservedRate > JBConstants.MAX_RESERVED_RATE) revert INVALID_RESERVED_RATE();\n\n // Make sure the provided redemption rate is valid.\n if (_metadata.redemptionRate > JBConstants.MAX_REDEMPTION_RATE)\n revert INVALID_REDEMPTION_RATE();\n\n // Make sure the provided ballot redemption rate is valid.\n if (_metadata.ballotRedemptionRate > JBConstants.MAX_REDEMPTION_RATE)\n revert INVALID_BALLOT_REDEMPTION_RATE();\n\n // Configure the funding cycle's properties.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.configureFor(\n _projectId,\n _data,\n JBFundingCycleMetadataResolver.packFundingCycleMetadata(_metadata),\n _mustStartAtOrAfter\n );\n\n // Set splits for the group.\n splitsStore.set(_projectId, _fundingCycle.configuration, _groupedSplits);\n\n // Set distribution limits if there are any.\n for (uint256 _i; _i < _fundAccessConstraints.length; ) {\n JBFundAccessConstraints memory _constraints = _fundAccessConstraints[_i];\n\n // If distribution limit value is larger than 232 bits, revert.\n if (_constraints.distributionLimit > type(uint232).max) revert INVALID_DISTRIBUTION_LIMIT();\n\n // If distribution limit currency value is larger than 24 bits, revert.\n if (_constraints.distributionLimitCurrency > type(uint24).max)\n revert INVALID_DISTRIBUTION_LIMIT_CURRENCY();\n\n // If overflow allowance value is larger than 232 bits, revert.\n if (_constraints.overflowAllowance > type(uint232).max) revert INVALID_OVERFLOW_ALLOWANCE();\n\n // If overflow allowance currency value is larger than 24 bits, revert.\n if (_constraints.overflowAllowanceCurrency > type(uint24).max)\n revert INVALID_OVERFLOW_ALLOWANCE_CURRENCY();\n\n // Set the distribution limit if there is one.\n if (_constraints.distributionLimit > 0)\n _packedDistributionLimitDataOf[_projectId][_fundingCycle.configuration][\n _constraints.terminal\n ][_constraints.token] =\n _constraints.distributionLimit |\n (_constraints.distributionLimitCurrency << 232);\n\n // Set the overflow allowance if there is one.\n if (_constraints.overflowAllowance > 0)\n _packedOverflowAllowanceDataOf[_projectId][_fundingCycle.configuration][\n _constraints.terminal\n ][_constraints.token] =\n _constraints.overflowAllowance |\n (_constraints.overflowAllowanceCurrency << 232);\n\n emit SetFundAccessConstraints(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _constraints,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n\n return _fundingCycle.configuration;\n }\n}\n" + }, + "contracts/JBProjects.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';\nimport {ERC721Votes, ERC721, EIP712} from '@openzeppelin/contracts/token/ERC721/extensions/draft-ERC721Votes.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBOperatable} from './abstract/JBOperatable.sol';\nimport {IJBOperatable} from './interfaces/IJBOperatable.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {IJBTokenUriResolver} from './interfaces/IJBTokenUriResolver.sol';\nimport {JBOperations} from './libraries/JBOperations.sol';\nimport {JBProjectMetadata} from './structs/JBProjectMetadata.sol';\n\n/// @notice Stores project ownership and metadata.\n/// @dev Projects are represented as ERC-721's.\ncontract JBProjects is JBOperatable, ERC721Votes, Ownable, IJBProjects {\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The number of projects that have been created using this contract.\n /// @dev The count is incremented with each new project created.\n /// @dev The resulting ERC-721 token ID for each project is the newly incremented count value.\n uint256 public override count = 0;\n\n /// @notice The metadata for each project, which can be used across several domains.\n /// @custom:param _projectId The ID of the project to which the metadata belongs.\n /// @custom:param _domain The domain within which the metadata applies. Applications can use the domain namespace as they wish.\n mapping(uint256 => mapping(uint256 => string)) public override metadataContentOf;\n\n /// @notice The contract resolving each project ID to its ERC721 URI.\n IJBTokenUriResolver public override tokenUriResolver;\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice Returns the URI where the ERC-721 standard JSON of a project is hosted.\n /// @param _projectId The ID of the project to get a URI of.\n /// @return The token URI to use for the provided `_projectId`.\n function tokenURI(uint256 _projectId) public view override returns (string memory) {\n // Keep a reference to the resolver.\n IJBTokenUriResolver _tokenUriResolver = tokenUriResolver;\n\n // If there's no resolver, there's no URI.\n if (_tokenUriResolver == IJBTokenUriResolver(address(0))) return '';\n\n // Return the resolved URI.\n return _tokenUriResolver.getUri(_projectId);\n }\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if the provided interface ID is supported.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(IERC165, ERC721) returns (bool) {\n return\n _interfaceId == type(IJBProjects).interfaceId ||\n _interfaceId == type(IJBOperatable).interfaceId ||\n super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _operatorStore A contract storing operator assignments.\n constructor(\n IJBOperatorStore _operatorStore\n )\n ERC721('Juicebox Projects', 'JUICEBOX')\n EIP712('Juicebox Projects', '1')\n JBOperatable(_operatorStore)\n // solhint-disable-next-line no-empty-blocks\n {\n\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Create a new project for the specified owner, which mints an NFT (ERC-721) into their wallet.\n /// @dev Anyone can create a project on an owner's behalf.\n /// @param _owner The address that will be the owner of the project.\n /// @param _metadata A struct containing metadata content about the project, and domain within which the metadata applies.\n /// @return projectId The token ID of the newly created project.\n function createFor(\n address _owner,\n JBProjectMetadata calldata _metadata\n ) external override returns (uint256 projectId) {\n // Increment the count, which will be used as the ID.\n projectId = ++count;\n\n // Mint the project.\n _safeMint(_owner, projectId);\n\n // Set the metadata if one was provided.\n if (bytes(_metadata.content).length > 0)\n metadataContentOf[projectId][_metadata.domain] = _metadata.content;\n\n emit Create(projectId, _owner, _metadata, msg.sender);\n }\n\n /// @notice Allows a project owner to set the project's metadata content for a particular domain namespace.\n /// @dev Only a project's owner or operator can set its metadata.\n /// @dev Applications can use the domain namespace as they wish.\n /// @param _projectId The ID of the project who's metadata is being changed.\n /// @param _metadata A struct containing metadata content, and domain within which the metadata applies.\n function setMetadataOf(\n uint256 _projectId,\n JBProjectMetadata calldata _metadata\n )\n external\n override\n requirePermission(ownerOf(_projectId), _projectId, JBOperations.SET_METADATA)\n {\n // Set the project's new metadata content within the specified domain.\n metadataContentOf[_projectId][_metadata.domain] = _metadata.content;\n\n emit SetMetadata(_projectId, _metadata, msg.sender);\n }\n\n /// @notice Sets the address of the resolver used to retrieve the tokenURI of projects.\n /// @param _newResolver The address of the new resolver.\n function setTokenUriResolver(IJBTokenUriResolver _newResolver) external override onlyOwner {\n // Store the new resolver.\n tokenUriResolver = _newResolver;\n\n emit SetTokenUriResolver(_newResolver, msg.sender);\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC721/extensions/draft-ERC721Votes.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (token/ERC721/extensions/draft-ERC721Votes.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../ERC721.sol\";\nimport \"../../../governance/utils/Votes.sol\";\n\n/**\n * @dev Extension of ERC721 to support voting and delegation as implemented by {Votes}, where each individual NFT counts\n * as 1 vote unit.\n *\n * Tokens do not count as votes until they are delegated, because votes must be tracked which incurs an additional cost\n * on every transfer. Token holders can either delegate to a trusted representative who will decide how to make use of\n * the votes in governance decisions, or they can delegate to themselves to be their own representative.\n *\n * _Available since v4.5._\n */\nabstract contract ERC721Votes is ERC721, Votes {\n /**\n * @dev Adjusts votes when tokens are transferred.\n *\n * Emits a {Votes-DelegateVotesChanged} event.\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 tokenId\n ) internal virtual override {\n _transferVotingUnits(from, to, 1);\n super._afterTokenTransfer(from, to, tokenId);\n }\n\n /**\n * @dev Returns the balance of `account`.\n */\n function _getVotingUnits(address account) internal virtual override returns (uint256) {\n return balanceOf(account);\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC721/ERC721.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (token/ERC721/ERC721.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC721.sol\";\nimport \"./IERC721Receiver.sol\";\nimport \"./extensions/IERC721Metadata.sol\";\nimport \"../../utils/Address.sol\";\nimport \"../../utils/Context.sol\";\nimport \"../../utils/Strings.sol\";\nimport \"../../utils/introspection/ERC165.sol\";\n\n/**\n * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including\n * the Metadata extension, but not including the Enumerable extension, which is available separately as\n * {ERC721Enumerable}.\n */\ncontract ERC721 is Context, ERC165, IERC721, IERC721Metadata {\n using Address for address;\n using Strings for uint256;\n\n // Token name\n string private _name;\n\n // Token symbol\n string private _symbol;\n\n // Mapping from token ID to owner address\n mapping(uint256 => address) private _owners;\n\n // Mapping owner address to token count\n mapping(address => uint256) private _balances;\n\n // Mapping from token ID to approved address\n mapping(uint256 => address) private _tokenApprovals;\n\n // Mapping from owner to operator approvals\n mapping(address => mapping(address => bool)) private _operatorApprovals;\n\n /**\n * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {\n return\n interfaceId == type(IERC721).interfaceId ||\n interfaceId == type(IERC721Metadata).interfaceId ||\n super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev See {IERC721-balanceOf}.\n */\n function balanceOf(address owner) public view virtual override returns (uint256) {\n require(owner != address(0), \"ERC721: balance query for the zero address\");\n return _balances[owner];\n }\n\n /**\n * @dev See {IERC721-ownerOf}.\n */\n function ownerOf(uint256 tokenId) public view virtual override returns (address) {\n address owner = _owners[tokenId];\n require(owner != address(0), \"ERC721: owner query for nonexistent token\");\n return owner;\n }\n\n /**\n * @dev See {IERC721Metadata-name}.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev See {IERC721Metadata-symbol}.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev See {IERC721Metadata-tokenURI}.\n */\n function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {\n require(_exists(tokenId), \"ERC721Metadata: URI query for nonexistent token\");\n\n string memory baseURI = _baseURI();\n return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : \"\";\n }\n\n /**\n * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each\n * token will be the concatenation of the `baseURI` and the `tokenId`. Empty\n * by default, can be overriden in child contracts.\n */\n function _baseURI() internal view virtual returns (string memory) {\n return \"\";\n }\n\n /**\n * @dev See {IERC721-approve}.\n */\n function approve(address to, uint256 tokenId) public virtual override {\n address owner = ERC721.ownerOf(tokenId);\n require(to != owner, \"ERC721: approval to current owner\");\n\n require(\n _msgSender() == owner || isApprovedForAll(owner, _msgSender()),\n \"ERC721: approve caller is not owner nor approved for all\"\n );\n\n _approve(to, tokenId);\n }\n\n /**\n * @dev See {IERC721-getApproved}.\n */\n function getApproved(uint256 tokenId) public view virtual override returns (address) {\n require(_exists(tokenId), \"ERC721: approved query for nonexistent token\");\n\n return _tokenApprovals[tokenId];\n }\n\n /**\n * @dev See {IERC721-setApprovalForAll}.\n */\n function setApprovalForAll(address operator, bool approved) public virtual override {\n _setApprovalForAll(_msgSender(), operator, approved);\n }\n\n /**\n * @dev See {IERC721-isApprovedForAll}.\n */\n function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {\n return _operatorApprovals[owner][operator];\n }\n\n /**\n * @dev See {IERC721-transferFrom}.\n */\n function transferFrom(\n address from,\n address to,\n uint256 tokenId\n ) public virtual override {\n //solhint-disable-next-line max-line-length\n require(_isApprovedOrOwner(_msgSender(), tokenId), \"ERC721: transfer caller is not owner nor approved\");\n\n _transfer(from, to, tokenId);\n }\n\n /**\n * @dev See {IERC721-safeTransferFrom}.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId\n ) public virtual override {\n safeTransferFrom(from, to, tokenId, \"\");\n }\n\n /**\n * @dev See {IERC721-safeTransferFrom}.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId,\n bytes memory _data\n ) public virtual override {\n require(_isApprovedOrOwner(_msgSender(), tokenId), \"ERC721: transfer caller is not owner nor approved\");\n _safeTransfer(from, to, tokenId, _data);\n }\n\n /**\n * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\n * are aware of the ERC721 protocol to prevent tokens from being forever locked.\n *\n * `_data` is additional data, it has no specified format and it is sent in call to `to`.\n *\n * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.\n * implement alternative mechanisms to perform token transfer, such as signature-based.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must exist and be owned by `from`.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function _safeTransfer(\n address from,\n address to,\n uint256 tokenId,\n bytes memory _data\n ) internal virtual {\n _transfer(from, to, tokenId);\n require(_checkOnERC721Received(from, to, tokenId, _data), \"ERC721: transfer to non ERC721Receiver implementer\");\n }\n\n /**\n * @dev Returns whether `tokenId` exists.\n *\n * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.\n *\n * Tokens start existing when they are minted (`_mint`),\n * and stop existing when they are burned (`_burn`).\n */\n function _exists(uint256 tokenId) internal view virtual returns (bool) {\n return _owners[tokenId] != address(0);\n }\n\n /**\n * @dev Returns whether `spender` is allowed to manage `tokenId`.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n */\n function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {\n require(_exists(tokenId), \"ERC721: operator query for nonexistent token\");\n address owner = ERC721.ownerOf(tokenId);\n return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));\n }\n\n /**\n * @dev Safely mints `tokenId` and transfers it to `to`.\n *\n * Requirements:\n *\n * - `tokenId` must not exist.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function _safeMint(address to, uint256 tokenId) internal virtual {\n _safeMint(to, tokenId, \"\");\n }\n\n /**\n * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is\n * forwarded in {IERC721Receiver-onERC721Received} to contract recipients.\n */\n function _safeMint(\n address to,\n uint256 tokenId,\n bytes memory _data\n ) internal virtual {\n _mint(to, tokenId);\n require(\n _checkOnERC721Received(address(0), to, tokenId, _data),\n \"ERC721: transfer to non ERC721Receiver implementer\"\n );\n }\n\n /**\n * @dev Mints `tokenId` and transfers it to `to`.\n *\n * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible\n *\n * Requirements:\n *\n * - `tokenId` must not exist.\n * - `to` cannot be the zero address.\n *\n * Emits a {Transfer} event.\n */\n function _mint(address to, uint256 tokenId) internal virtual {\n require(to != address(0), \"ERC721: mint to the zero address\");\n require(!_exists(tokenId), \"ERC721: token already minted\");\n\n _beforeTokenTransfer(address(0), to, tokenId);\n\n _balances[to] += 1;\n _owners[tokenId] = to;\n\n emit Transfer(address(0), to, tokenId);\n\n _afterTokenTransfer(address(0), to, tokenId);\n }\n\n /**\n * @dev Destroys `tokenId`.\n * The approval is cleared when the token is burned.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n *\n * Emits a {Transfer} event.\n */\n function _burn(uint256 tokenId) internal virtual {\n address owner = ERC721.ownerOf(tokenId);\n\n _beforeTokenTransfer(owner, address(0), tokenId);\n\n // Clear approvals\n _approve(address(0), tokenId);\n\n _balances[owner] -= 1;\n delete _owners[tokenId];\n\n emit Transfer(owner, address(0), tokenId);\n\n _afterTokenTransfer(owner, address(0), tokenId);\n }\n\n /**\n * @dev Transfers `tokenId` from `from` to `to`.\n * As opposed to {transferFrom}, this imposes no restrictions on msg.sender.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - `tokenId` token must be owned by `from`.\n *\n * Emits a {Transfer} event.\n */\n function _transfer(\n address from,\n address to,\n uint256 tokenId\n ) internal virtual {\n require(ERC721.ownerOf(tokenId) == from, \"ERC721: transfer from incorrect owner\");\n require(to != address(0), \"ERC721: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, tokenId);\n\n // Clear approvals from the previous owner\n _approve(address(0), tokenId);\n\n _balances[from] -= 1;\n _balances[to] += 1;\n _owners[tokenId] = to;\n\n emit Transfer(from, to, tokenId);\n\n _afterTokenTransfer(from, to, tokenId);\n }\n\n /**\n * @dev Approve `to` to operate on `tokenId`\n *\n * Emits a {Approval} event.\n */\n function _approve(address to, uint256 tokenId) internal virtual {\n _tokenApprovals[tokenId] = to;\n emit Approval(ERC721.ownerOf(tokenId), to, tokenId);\n }\n\n /**\n * @dev Approve `operator` to operate on all of `owner` tokens\n *\n * Emits a {ApprovalForAll} event.\n */\n function _setApprovalForAll(\n address owner,\n address operator,\n bool approved\n ) internal virtual {\n require(owner != operator, \"ERC721: approve to caller\");\n _operatorApprovals[owner][operator] = approved;\n emit ApprovalForAll(owner, operator, approved);\n }\n\n /**\n * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.\n * The call is not executed if the target address is not a contract.\n *\n * @param from address representing the previous owner of the given token ID\n * @param to target address that will receive the tokens\n * @param tokenId uint256 ID of the token to be transferred\n * @param _data bytes optional data to send along with the call\n * @return bool whether the call correctly returned the expected magic value\n */\n function _checkOnERC721Received(\n address from,\n address to,\n uint256 tokenId,\n bytes memory _data\n ) private returns (bool) {\n if (to.isContract()) {\n try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) {\n return retval == IERC721Receiver.onERC721Received.selector;\n } catch (bytes memory reason) {\n if (reason.length == 0) {\n revert(\"ERC721: transfer to non ERC721Receiver implementer\");\n } else {\n assembly {\n revert(add(32, reason), mload(reason))\n }\n }\n }\n } else {\n return true;\n }\n }\n\n /**\n * @dev Hook that is called before any token transfer. This includes minting\n * and burning.\n *\n * Calling conditions:\n *\n * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be\n * transferred to `to`.\n * - When `from` is zero, `tokenId` will be minted for `to`.\n * - When `to` is zero, ``from``'s `tokenId` will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 tokenId\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 tokenId\n ) internal virtual {}\n}\n" + }, + "@openzeppelin/contracts/governance/utils/Votes.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (governance/utils/Votes.sol)\npragma solidity ^0.8.0;\n\nimport \"../../utils/Context.sol\";\nimport \"../../utils/Counters.sol\";\nimport \"../../utils/Checkpoints.sol\";\nimport \"../../utils/cryptography/draft-EIP712.sol\";\nimport \"./IVotes.sol\";\n\n/**\n * @dev This is a base abstract contract that tracks voting units, which are a measure of voting power that can be\n * transferred, and provides a system of vote delegation, where an account can delegate its voting units to a sort of\n * \"representative\" that will pool delegated voting units from different accounts and can then use it to vote in\n * decisions. In fact, voting units _must_ be delegated in order to count as actual votes, and an account has to\n * delegate those votes to itself if it wishes to participate in decisions and does not have a trusted representative.\n *\n * This contract is often combined with a token contract such that voting units correspond to token units. For an\n * example, see {ERC721Votes}.\n *\n * The full history of delegate votes is tracked on-chain so that governance protocols can consider votes as distributed\n * at a particular block number to protect against flash loans and double voting. The opt-in delegate system makes the\n * cost of this history tracking optional.\n *\n * When using this module the derived contract must implement {_getVotingUnits} (for example, make it return\n * {ERC721-balanceOf}), and can use {_transferVotingUnits} to track a change in the distribution of those units (in the\n * previous example, it would be included in {ERC721-_beforeTokenTransfer}).\n *\n * _Available since v4.5._\n */\nabstract contract Votes is IVotes, Context, EIP712 {\n using Checkpoints for Checkpoints.History;\n using Counters for Counters.Counter;\n\n bytes32 private constant _DELEGATION_TYPEHASH =\n keccak256(\"Delegation(address delegatee,uint256 nonce,uint256 expiry)\");\n\n mapping(address => address) private _delegation;\n mapping(address => Checkpoints.History) private _delegateCheckpoints;\n Checkpoints.History private _totalCheckpoints;\n\n mapping(address => Counters.Counter) private _nonces;\n\n /**\n * @dev Returns the current amount of votes that `account` has.\n */\n function getVotes(address account) public view virtual override returns (uint256) {\n return _delegateCheckpoints[account].latest();\n }\n\n /**\n * @dev Returns the amount of votes that `account` had at the end of a past block (`blockNumber`).\n *\n * Requirements:\n *\n * - `blockNumber` must have been already mined\n */\n function getPastVotes(address account, uint256 blockNumber) public view virtual override returns (uint256) {\n return _delegateCheckpoints[account].getAtBlock(blockNumber);\n }\n\n /**\n * @dev Returns the total supply of votes available at the end of a past block (`blockNumber`).\n *\n * NOTE: This value is the sum of all available votes, which is not necessarily the sum of all delegated votes.\n * Votes that have not been delegated are still part of total supply, even though they would not participate in a\n * vote.\n *\n * Requirements:\n *\n * - `blockNumber` must have been already mined\n */\n function getPastTotalSupply(uint256 blockNumber) public view virtual override returns (uint256) {\n require(blockNumber < block.number, \"Votes: block not yet mined\");\n return _totalCheckpoints.getAtBlock(blockNumber);\n }\n\n /**\n * @dev Returns the current total supply of votes.\n */\n function _getTotalSupply() internal view virtual returns (uint256) {\n return _totalCheckpoints.latest();\n }\n\n /**\n * @dev Returns the delegate that `account` has chosen.\n */\n function delegates(address account) public view virtual override returns (address) {\n return _delegation[account];\n }\n\n /**\n * @dev Delegates votes from the sender to `delegatee`.\n */\n function delegate(address delegatee) public virtual override {\n address account = _msgSender();\n _delegate(account, delegatee);\n }\n\n /**\n * @dev Delegates votes from signer to `delegatee`.\n */\n function delegateBySig(\n address delegatee,\n uint256 nonce,\n uint256 expiry,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) public virtual override {\n require(block.timestamp <= expiry, \"Votes: signature expired\");\n address signer = ECDSA.recover(\n _hashTypedDataV4(keccak256(abi.encode(_DELEGATION_TYPEHASH, delegatee, nonce, expiry))),\n v,\n r,\n s\n );\n require(nonce == _useNonce(signer), \"Votes: invalid nonce\");\n _delegate(signer, delegatee);\n }\n\n /**\n * @dev Delegate all of `account`'s voting units to `delegatee`.\n *\n * Emits events {DelegateChanged} and {DelegateVotesChanged}.\n */\n function _delegate(address account, address delegatee) internal virtual {\n address oldDelegate = delegates(account);\n _delegation[account] = delegatee;\n\n emit DelegateChanged(account, oldDelegate, delegatee);\n _moveDelegateVotes(oldDelegate, delegatee, _getVotingUnits(account));\n }\n\n /**\n * @dev Transfers, mints, or burns voting units. To register a mint, `from` should be zero. To register a burn, `to`\n * should be zero. Total supply of voting units will be adjusted with mints and burns.\n */\n function _transferVotingUnits(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n if (from == address(0)) {\n _totalCheckpoints.push(_add, amount);\n }\n if (to == address(0)) {\n _totalCheckpoints.push(_subtract, amount);\n }\n _moveDelegateVotes(delegates(from), delegates(to), amount);\n }\n\n /**\n * @dev Moves delegated votes from one delegate to another.\n */\n function _moveDelegateVotes(\n address from,\n address to,\n uint256 amount\n ) private {\n if (from != to && amount > 0) {\n if (from != address(0)) {\n (uint256 oldValue, uint256 newValue) = _delegateCheckpoints[from].push(_subtract, amount);\n emit DelegateVotesChanged(from, oldValue, newValue);\n }\n if (to != address(0)) {\n (uint256 oldValue, uint256 newValue) = _delegateCheckpoints[to].push(_add, amount);\n emit DelegateVotesChanged(to, oldValue, newValue);\n }\n }\n }\n\n function _add(uint256 a, uint256 b) private pure returns (uint256) {\n return a + b;\n }\n\n function _subtract(uint256 a, uint256 b) private pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Consumes a nonce.\n *\n * Returns the current value and increments nonce.\n */\n function _useNonce(address owner) internal virtual returns (uint256 current) {\n Counters.Counter storage nonce = _nonces[owner];\n current = nonce.current();\n nonce.increment();\n }\n\n /**\n * @dev Returns an address nonce.\n */\n function nonces(address owner) public view virtual returns (uint256) {\n return _nonces[owner].current();\n }\n\n /**\n * @dev Returns the contract's {EIP712} domain separator.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32) {\n return _domainSeparatorV4();\n }\n\n /**\n * @dev Must return the voting units held by an account.\n */\n function _getVotingUnits(address) internal virtual returns (uint256);\n}\n" + }, + "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721Receiver.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @title ERC721 token receiver interface\n * @dev Interface for any contract that wants to support safeTransfers\n * from ERC721 asset contracts.\n */\ninterface IERC721Receiver {\n /**\n * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}\n * by `operator` from `from`, this function is called.\n *\n * It must return its Solidity selector to confirm the token transfer.\n * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.\n *\n * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`.\n */\n function onERC721Received(\n address operator,\n address from,\n uint256 tokenId,\n bytes calldata data\n ) external returns (bytes4);\n}\n" + }, + "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC721.sol\";\n\n/**\n * @title ERC-721 Non-Fungible Token Standard, optional metadata extension\n * @dev See https://eips.ethereum.org/EIPS/eip-721\n */\ninterface IERC721Metadata is IERC721 {\n /**\n * @dev Returns the token collection name.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the token collection symbol.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.\n */\n function tokenURI(uint256 tokenId) external view returns (string memory);\n}\n" + }, + "@openzeppelin/contracts/utils/Checkpoints.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (utils/Checkpoints.sol)\npragma solidity ^0.8.0;\n\nimport \"./math/Math.sol\";\nimport \"./math/SafeCast.sol\";\n\n/**\n * @dev This library defines the `History` struct, for checkpointing values as they change at different points in\n * time, and later looking up past values by block number. See {Votes} as an example.\n *\n * To create a history of checkpoints define a variable type `Checkpoints.History` in your contract, and store a new\n * checkpoint for the current transaction block using the {push} function.\n *\n * _Available since v4.5._\n */\nlibrary Checkpoints {\n struct Checkpoint {\n uint32 _blockNumber;\n uint224 _value;\n }\n\n struct History {\n Checkpoint[] _checkpoints;\n }\n\n /**\n * @dev Returns the value in the latest checkpoint, or zero if there are no checkpoints.\n */\n function latest(History storage self) internal view returns (uint256) {\n uint256 pos = self._checkpoints.length;\n return pos == 0 ? 0 : self._checkpoints[pos - 1]._value;\n }\n\n /**\n * @dev Returns the value at a given block number. If a checkpoint is not available at that block, the closest one\n * before it is returned, or zero otherwise.\n */\n function getAtBlock(History storage self, uint256 blockNumber) internal view returns (uint256) {\n require(blockNumber < block.number, \"Checkpoints: block not yet mined\");\n\n uint256 high = self._checkpoints.length;\n uint256 low = 0;\n while (low < high) {\n uint256 mid = Math.average(low, high);\n if (self._checkpoints[mid]._blockNumber > blockNumber) {\n high = mid;\n } else {\n low = mid + 1;\n }\n }\n return high == 0 ? 0 : self._checkpoints[high - 1]._value;\n }\n\n /**\n * @dev Pushes a value onto a History so that it is stored as the checkpoint for the current block.\n *\n * Returns previous value and new value.\n */\n function push(History storage self, uint256 value) internal returns (uint256, uint256) {\n uint256 pos = self._checkpoints.length;\n uint256 old = latest(self);\n if (pos > 0 && self._checkpoints[pos - 1]._blockNumber == block.number) {\n self._checkpoints[pos - 1]._value = SafeCast.toUint224(value);\n } else {\n self._checkpoints.push(\n Checkpoint({_blockNumber: SafeCast.toUint32(block.number), _value: SafeCast.toUint224(value)})\n );\n }\n return (old, value);\n }\n\n /**\n * @dev Pushes a value onto a History, by updating the latest value using binary operation `op`. The new value will\n * be set to `op(latest, delta)`.\n *\n * Returns previous value and new value.\n */\n function push(\n History storage self,\n function(uint256, uint256) view returns (uint256) op,\n uint256 delta\n ) internal returns (uint256, uint256) {\n return push(self, op(latest(self), delta));\n }\n}\n" + }, + "contracts/JBDirectory.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';\nimport {JBOperatable} from './abstract/JBOperatable.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {JBFundingCycleMetadataResolver} from './libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBOperations} from './libraries/JBOperations.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\n\n/// @notice Keeps a reference of which terminal contracts each project is currently accepting funds through, and which controller contract is managing each project's tokens and funding cycles.\ncontract JBDirectory is JBOperatable, Ownable, IJBDirectory {\n // A library that parses the packed funding cycle metadata into a friendlier format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error DUPLICATE_TERMINALS();\n error INVALID_PROJECT_ID_IN_DIRECTORY();\n error SET_CONTROLLER_NOT_ALLOWED();\n error SET_TERMINALS_NOT_ALLOWED();\n error TOKEN_NOT_ACCEPTED();\n\n //*********************************************************************//\n // --------------------- private stored properties ------------------- //\n //*********************************************************************//\n\n /// @notice For each project ID, the terminals that are currently managing its funds.\n /// @custom:member _projectId The ID of the project to get terminals of.\n mapping(uint256 => IJBPaymentTerminal[]) private _terminalsOf;\n\n /// @notice The project's primary terminal for a token.\n /// @custom:member _projectId The ID of the project to get the primary terminal of.\n /// @custom:member _token The token to get the project's primary terminal of.\n mapping(uint256 => mapping(address => IJBPaymentTerminal)) private _primaryTerminalOf;\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice Mints ERC-721's that represent project ownership and transfers.\n IJBProjects public immutable override projects;\n\n /// @notice The contract storing all funding cycle configurations.\n IJBFundingCycleStore public immutable override fundingCycleStore;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice For each project ID, the controller that manages how terminals interact with tokens and funding cycles.\n /// @custom:member _projectId The ID of the project to get the controller of.\n mapping(uint256 => address) public override controllerOf;\n\n /// @notice Addresses that can set a project's first controller on their behalf. These addresses/contracts have been vetted and verified by this contract's owner.\n /// @custom:param _address The address that is either allowed or not.\n mapping(address => bool) public override isAllowedToSetFirstController;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice For each project ID, the terminals that are currently managing its funds.\n /// @param _projectId The ID of the project to get terminals of.\n /// @return An array of terminal addresses.\n function terminalsOf(uint256 _projectId)\n external\n view\n override\n returns (IJBPaymentTerminal[] memory)\n {\n return _terminalsOf[_projectId];\n }\n\n /// @notice The primary terminal that is managing funds for a project for a specified token.\n /// @dev The zero address is returned if a terminal isn't found for the specified token.\n /// @param _projectId The ID of the project to get a terminal for.\n /// @param _token The token the terminal accepts.\n /// @return The primary terminal for the project for the specified token.\n function primaryTerminalOf(uint256 _projectId, address _token)\n external\n view\n override\n returns (IJBPaymentTerminal)\n {\n // Keep a reference to the primary terminal for the provided project ID and token.\n IJBPaymentTerminal _primaryTerminal = _primaryTerminalOf[_projectId][_token];\n\n // If a primary terminal for the token was specifically set and it's one of the project's terminals, return it.\n if (\n _primaryTerminal != IJBPaymentTerminal(address(0)) &&\n isTerminalOf(_projectId, _primaryTerminal)\n ) return _primaryTerminal;\n\n // Keep a reference to the number of terminals the project has.\n uint256 _numberOfTerminals = _terminalsOf[_projectId].length;\n\n // Return the first terminal which accepts the specified token.\n for (uint256 _i; _i < _numberOfTerminals; ) {\n // Keep a reference to the terminal being iterated on.\n IJBPaymentTerminal _terminal = _terminalsOf[_projectId][_i];\n\n // If the terminal accepts the specified token, return it.\n if (_terminal.acceptsToken(_token, _projectId)) return _terminal;\n\n unchecked {\n ++_i;\n }\n }\n\n // Not found.\n return IJBPaymentTerminal(address(0));\n }\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice Whether or not a specified terminal is a terminal of the specified project.\n /// @param _projectId The ID of the project to check within.\n /// @param _terminal The address of the terminal to check for.\n /// @return A flag indicating whether or not the specified terminal is a terminal of the specified project.\n function isTerminalOf(uint256 _projectId, IJBPaymentTerminal _terminal)\n public\n view\n override\n returns (bool)\n {\n // Keep a reference to the number of terminals the project has.\n uint256 _numberOfTerminals = _terminalsOf[_projectId].length;\n\n // Loop through and return true if the terminal is contained.\n for (uint256 _i; _i < _numberOfTerminals; ) {\n // If the terminal being iterated on matches the provided terminal, return true.\n if (_terminalsOf[_projectId][_i] == _terminal) return true;\n\n unchecked {\n ++_i;\n }\n }\n\n // Otherwise, return false.\n return false;\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _fundingCycleStore A contract storing all funding cycle configurations.\n /// @param _owner The address that will own the contract.\n constructor(\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBFundingCycleStore _fundingCycleStore,\n address _owner\n ) JBOperatable(_operatorStore) {\n projects = _projects;\n fundingCycleStore = _fundingCycleStore;\n\n _transferOwnership(_owner);\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Update the controller that manages how terminals interact with the ecosystem.\n /// @dev A controller can be set if:\n /// @dev - the message sender is the project owner or an operator having the correct authorization.\n /// @dev - the message sender is the project's current controller.\n /// @dev - or, an allowedlisted address is setting a controller for a project that doesn't already have a controller.\n /// @param _projectId The ID of the project to set a new controller for.\n /// @param _controller The new controller to set.\n function setControllerOf(uint256 _projectId, address _controller)\n external\n override\n requirePermissionAllowingOverride(\n projects.ownerOf(_projectId),\n _projectId,\n JBOperations.SET_CONTROLLER,\n (msg.sender == address(controllerOf[_projectId]) ||\n (isAllowedToSetFirstController[msg.sender] && controllerOf[_projectId] == address(0)))\n )\n {\n // The project must exist.\n if (projects.count() < _projectId) revert INVALID_PROJECT_ID_IN_DIRECTORY();\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Setting controller is allowed if called from the current controller, or if the project doesn't have a current controller, or if the project's funding cycle allows setting the controller. Revert otherwise.\n if (\n msg.sender != address(controllerOf[_projectId]) &&\n controllerOf[_projectId] != address(0) &&\n !_fundingCycle.global().allowSetController\n ) revert SET_CONTROLLER_NOT_ALLOWED();\n\n // Set the new controller.\n controllerOf[_projectId] = _controller;\n\n emit SetController(_projectId, _controller, msg.sender);\n }\n\n /// @notice Set a project's terminals.\n /// @dev Only a project owner, an operator, or its controller can set its terminals.\n /// @param _projectId The ID of the project having terminals set.\n /// @param _terminals The terminal to set.\n function setTerminalsOf(uint256 _projectId, IJBPaymentTerminal[] calldata _terminals)\n external\n override\n requirePermissionAllowingOverride(\n projects.ownerOf(_projectId),\n _projectId,\n JBOperations.SET_TERMINALS,\n msg.sender == address(controllerOf[_projectId])\n )\n {\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Setting terminals must be allowed if not called from the current controller.\n if (\n msg.sender != address(controllerOf[_projectId]) && !_fundingCycle.global().allowSetTerminals\n ) revert SET_TERMINALS_NOT_ALLOWED();\n\n // Set the stored terminals for the project.\n _terminalsOf[_projectId] = _terminals;\n\n // Make sure duplicates were not added.\n if (_terminals.length > 1) {\n for (uint256 _i; _i < _terminals.length; ) {\n for (uint256 _j = _i + 1; _j < _terminals.length; ) {\n if (_terminals[_i] == _terminals[_j]) revert DUPLICATE_TERMINALS();\n\n unchecked {\n ++_j;\n }\n }\n\n unchecked {\n ++_i;\n }\n }\n }\n emit SetTerminals(_projectId, _terminals, msg.sender);\n }\n\n /// @notice Project's can set which terminal should be their primary for a particular token. \n /// @dev This is useful in case a project has several terminals connected for a particular token.\n /// @dev The terminal will be set as the primary terminal where ecosystem contracts should route tokens.\n /// @dev If setting a newly added terminal and the funding cycle doesn't allow new terminals, the caller must be the current controller.\n /// @param _projectId The ID of the project for which a primary token is being set.\n /// @param _token The token to set the primary terminal of.\n /// @param _terminal The terminal to make primary.\n function setPrimaryTerminalOf(\n uint256 _projectId,\n address _token,\n IJBPaymentTerminal _terminal\n )\n external\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.SET_PRIMARY_TERMINAL)\n {\n // Can't set the primary terminal for a token if it doesn't accept the token.\n if (!_terminal.acceptsToken(_token, _projectId)) revert TOKEN_NOT_ACCEPTED();\n\n // Add the terminal to the project if it hasn't been already.\n _addTerminalIfNeeded(_projectId, _terminal);\n\n // Store the terminal as the primary for the particular token.\n _primaryTerminalOf[_projectId][_token] = _terminal;\n\n emit SetPrimaryTerminal(_projectId, _token, _terminal, msg.sender);\n }\n\n /// @notice Set a contract to the list of trusted addresses that can set a first controller for any project.\t\n /// @dev The owner can add addresses which are allowed to change projects' first controllers. \n /// @dev These addresses are known and vetted controllers as well as contracts designed to launch new projects. \n /// @dev A project can set its own controller without it being on the allow list.\n /// @dev If you would like an address/contract allowlisted, please reach out to the contract owner.\n /// @param _address The address to allow or revoke allowance from.\n /// @param _flag Whether allowance is being added or revoked.\n function setIsAllowedToSetFirstController(address _address, bool _flag)\n external\n override\n onlyOwner\n {\n // Set the flag in the allowlist.\n isAllowedToSetFirstController[_address] = _flag;\n\n emit SetIsAllowedToSetFirstController(_address, _flag, msg.sender);\n }\n\n //*********************************************************************//\n // --------------------- private helper functions -------------------- //\n //*********************************************************************//\n\n /// @notice Add a terminal to a project's list of terminals if it hasn't been already.\n /// @param _projectId The ID of the project having a terminal added.\n /// @param _terminal The terminal to add.\n function _addTerminalIfNeeded(uint256 _projectId, IJBPaymentTerminal _terminal) private {\n // Check that the terminal has not already been added.\n if (isTerminalOf(_projectId, _terminal)) return;\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Setting terminals must be allowed if not called from the current controller.\n if (\n msg.sender != address(controllerOf[_projectId]) && !_fundingCycle.global().allowSetTerminals\n ) revert SET_TERMINALS_NOT_ALLOWED();\n\n // Add the new terminal.\n _terminalsOf[_projectId].push(_terminal);\n\n emit AddTerminal(_projectId, _terminal, msg.sender);\n }\n}\n" + }, + "contracts/JBSingleTokenPaymentTerminalStore3_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {ReentrancyGuard} from '@openzeppelin/contracts/security/ReentrancyGuard.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {JBBallotState} from './enums/JBBallotState.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBController3_1} from './interfaces/IJBController3_1.sol';\nimport {IJBFundingCycleDataSource} from './interfaces/IJBFundingCycleDataSource.sol';\nimport {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol';\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\nimport {IJBSingleTokenPaymentTerminal} from './interfaces/IJBSingleTokenPaymentTerminal.sol';\nimport {IJBSingleTokenPaymentTerminalStore} from './interfaces/IJBSingleTokenPaymentTerminalStore.sol';\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\nimport {JBConstants} from './libraries/JBConstants.sol';\nimport {JBCurrencies} from './libraries/JBCurrencies.sol';\nimport {JBFixedPointNumber} from './libraries/JBFixedPointNumber.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\nimport {JBFundingCycleMetadataResolver} from './libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBPayDelegateAllocation} from './structs/JBPayDelegateAllocation.sol';\nimport {JBPayParamsData} from './structs/JBPayParamsData.sol';\nimport {JBRedeemParamsData} from './structs/JBRedeemParamsData.sol';\nimport {JBRedemptionDelegateAllocation} from './structs/JBRedemptionDelegateAllocation.sol';\nimport {JBTokenAmount} from './structs/JBTokenAmount.sol';\n\n/// @notice Manages all bookkeeping for inflows and outflows of funds from any ISingleTokenPaymentTerminal.\n/// @dev This Store expects a project's controller to be an IJBController3_1. This is the only difference between this version and the original.\ncontract JBSingleTokenPaymentTerminalStore3_1 is\n ReentrancyGuard,\n IJBSingleTokenPaymentTerminalStore\n{\n // A library that parses the packed funding cycle metadata into a friendlier format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error INVALID_AMOUNT_TO_SEND_DELEGATE();\n error CURRENCY_MISMATCH();\n error DISTRIBUTION_AMOUNT_LIMIT_REACHED();\n error FUNDING_CYCLE_PAYMENT_PAUSED();\n error FUNDING_CYCLE_DISTRIBUTION_PAUSED();\n error FUNDING_CYCLE_REDEEM_PAUSED();\n error INADEQUATE_CONTROLLER_ALLOWANCE();\n error INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n error INSUFFICIENT_TOKENS();\n error INVALID_FUNDING_CYCLE();\n error PAYMENT_TERMINAL_MIGRATION_NOT_ALLOWED();\n\n //*********************************************************************//\n // -------------------------- private constants ---------------------- //\n //*********************************************************************//\n\n /// @notice Ensures a maximum number of decimal points of persisted fidelity on mulDiv operations of fixed point numbers.\n uint256 private constant _MAX_FIXED_POINT_FIDELITY = 18;\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n /// @notice The contract storing all funding cycle configurations.\n IJBFundingCycleStore public immutable override fundingCycleStore;\n\n /// @notice The contract that exposes price feeds.\n IJBPrices public immutable override prices;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The amount of tokens that each project has for each terminal, in terms of the terminal's token.\n /// @dev The used distribution limit is represented as a fixed point number with the same amount of decimals as its relative terminal.\n /// @custom:param _terminal The terminal to which the balance applies.\n /// @custom:param _projectId The ID of the project to get the balance of.\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => uint256)) public override balanceOf;\n\n /// @notice The amount of funds that a project has distributed from its limit during the current funding cycle for each terminal, in terms of the distribution limit's currency.\n /// @dev Increases as projects use their preconfigured distribution limits.\n /// @dev The used distribution limit is represented as a fixed point number with the same amount of decimals as its relative terminal.\n /// @custom:param _terminal The terminal to which the used distribution limit applies.\n /// @custom:param _projectId The ID of the project to get the used distribution limit of.\n /// @custom:param _fundingCycleNumber The number of the funding cycle during which the distribution limit was used.\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => mapping(uint256 => uint256)))\n public\n override usedDistributionLimitOf;\n\n /// @notice The amount of funds that a project has used from its allowance during the current funding cycle configuration for each terminal, in terms of the overflow allowance's currency.\n /// @dev Increases as projects use their allowance.\n /// @dev The used allowance is represented as a fixed point number with the same amount of decimals as its relative terminal.\n /// @custom:param _terminal The terminal to which the overflow allowance applies.\n /// @custom:param _projectId The ID of the project to get the used overflow allowance of.\n /// @custom:param _configuration The configuration of the during which the allowance was used.\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => mapping(uint256 => uint256)))\n public\n override usedOverflowAllowanceOf;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Gets the current overflowed amount in a terminal for a specified project.\n /// @dev The current overflow is represented as a fixed point number with the same amount of decimals as the specified terminal.\n /// @param _terminal The terminal for which the overflow is being calculated.\n /// @param _projectId The ID of the project to get overflow for.\n /// @return The current amount of overflow that project has in the specified terminal.\n function currentOverflowOf(\n IJBSingleTokenPaymentTerminal _terminal,\n uint256 _projectId\n ) external view override returns (uint256) {\n // Return the overflow during the project's current funding cycle.\n return\n _overflowDuring(\n _terminal,\n _projectId,\n fundingCycleStore.currentOf(_projectId),\n _terminal.currency()\n );\n }\n\n /// @notice Gets the current overflowed amount for a specified project across all terminals.\n /// @param _projectId The ID of the project to get total overflow for.\n /// @param _decimals The number of decimals that the fixed point overflow should include.\n /// @param _currency The currency that the total overflow should be in terms of.\n /// @return The current total amount of overflow that project has across all terminals.\n function currentTotalOverflowOf(\n uint256 _projectId,\n uint256 _decimals,\n uint256 _currency\n ) external view override returns (uint256) {\n return _currentTotalOverflowOf(_projectId, _decimals, _currency);\n }\n\n /// @notice The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the total token supply and overflow in the ecosystem.\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\n /// @dev The current reclaimable overflow is returned in terms of the specified terminal's currency.\n /// @dev The reclaimable overflow is represented as a fixed point number with the same amount of decimals as the specified terminal.\n /// @param _terminal The terminal from which the reclaimable amount would come.\n /// @param _projectId The ID of the project to get the reclaimable overflow amount for.\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _useTotalOverflow A flag indicating whether the overflow used in the calculation should be summed from all of the project's terminals. If false, overflow should be limited to the amount in the specified `_terminal`.\n /// @return The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_terminal`.\n function currentReclaimableOverflowOf(\n IJBSingleTokenPaymentTerminal _terminal,\n uint256 _projectId,\n uint256 _tokenCount,\n bool _useTotalOverflow\n ) external view override returns (uint256) {\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Get the amount of current overflow.\n // Use the project's total overflow across all of its terminals if the flag species specifies so. Otherwise, use the overflow local to the specified terminal.\n uint256 _currentOverflow = _useTotalOverflow\n ? _currentTotalOverflowOf(_projectId, _terminal.decimals(), _terminal.currency())\n : _overflowDuring(_terminal, _projectId, _fundingCycle, _terminal.currency());\n\n // If there's no overflow, there's no reclaimable overflow.\n if (_currentOverflow == 0) return 0;\n\n // Get the number of outstanding tokens the project has.\n uint256 _totalSupply = IJBController3_1(directory.controllerOf(_projectId))\n .totalOutstandingTokensOf(_projectId);\n\n // Can't redeem more tokens that is in the supply.\n if (_tokenCount > _totalSupply) return 0;\n\n // Return the reclaimable overflow amount.\n return\n _reclaimableOverflowDuring(\n _projectId,\n _fundingCycle,\n _tokenCount,\n _totalSupply,\n _currentOverflow\n );\n }\n\n /// @notice The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the specified total token supply and overflow amounts.\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\n /// @param _projectId The ID of the project to get the reclaimable overflow amount for.\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _totalSupply The total number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _overflow The amount of overflow to make the calculation with, as a fixed point number.\n /// @return The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_overflow`.\n function currentReclaimableOverflowOf(\n uint256 _projectId,\n uint256 _tokenCount,\n uint256 _totalSupply,\n uint256 _overflow\n ) external view override returns (uint256) {\n // If there's no overflow, there's no reclaimable overflow.\n if (_overflow == 0) return 0;\n\n // Can't redeem more tokens that is in the supply.\n if (_tokenCount > _totalSupply) return 0;\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Return the reclaimable overflow amount.\n return\n _reclaimableOverflowDuring(_projectId, _fundingCycle, _tokenCount, _totalSupply, _overflow);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _fundingCycleStore A contract storing all funding cycle configurations.\n /// @param _prices A contract that exposes price feeds.\n constructor(IJBDirectory _directory, IJBFundingCycleStore _fundingCycleStore, IJBPrices _prices) {\n directory = _directory;\n fundingCycleStore = _fundingCycleStore;\n prices = _prices;\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Records newly contributed tokens to a project.\n /// @dev Mints the project's tokens according to values provided by a configured data source. If no data source is configured, mints tokens proportional to the amount of the contribution.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.sender's tokens.\n /// @param _payer The original address that sent the payment to the terminal.\n /// @param _amount The amount of tokens being paid. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\n /// @param _projectId The ID of the project being paid.\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _beneficiary The specified address that should be the beneficiary of anything that results from the payment.\n /// @param _memo A memo to pass along to the emitted event, and passed along to the funding cycle's data source.\n /// @param _metadata Bytes to send along to the data source, if one is provided.\n /// @return fundingCycle The project's funding cycle during which payment was made.\n /// @return tokenCount The number of project tokens that were minted, as a fixed point number with 18 decimals.\n /// @return delegateAllocations The amount to send to delegates instead of adding to the local balance.\n /// @return memo A memo that should be passed along to the emitted event.\n function recordPaymentFrom(\n address _payer,\n JBTokenAmount calldata _amount,\n uint256 _projectId,\n uint256 _baseWeightCurrency,\n address _beneficiary,\n string calldata _memo,\n bytes memory _metadata\n )\n external\n override\n nonReentrant\n returns (\n JBFundingCycle memory fundingCycle,\n uint256 tokenCount,\n JBPayDelegateAllocation[] memory delegateAllocations,\n string memory memo\n )\n {\n // Get a reference to the current funding cycle for the project.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // The project must have a funding cycle configured.\n if (fundingCycle.number == 0) revert INVALID_FUNDING_CYCLE();\n\n // Must not be paused.\n if (fundingCycle.payPaused()) revert FUNDING_CYCLE_PAYMENT_PAUSED();\n\n // The weight according to which new token supply is to be minted, as a fixed point number with 18 decimals.\n uint256 _weight;\n\n // If the funding cycle has configured a data source, use it to derive a weight and memo.\n if (fundingCycle.useDataSourceForPay() && fundingCycle.dataSource() != address(0)) {\n // Create the params that'll be sent to the data source.\n JBPayParamsData memory _data = JBPayParamsData(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _payer,\n _amount,\n _projectId,\n fundingCycle.configuration,\n _beneficiary,\n fundingCycle.weight,\n fundingCycle.reservedRate(),\n _memo,\n _metadata\n );\n (_weight, memo, delegateAllocations) = IJBFundingCycleDataSource(fundingCycle.dataSource())\n .payParams(_data);\n }\n // Otherwise use the funding cycle's weight\n else {\n _weight = fundingCycle.weight;\n memo = _memo;\n }\n\n // Scoped section prevents stack too deep. `_balanceDiff` only used within scope.\n {\n // Keep a reference to the amount that should be added to the project's balance.\n uint256 _balanceDiff = _amount.value;\n\n // Validate all delegated amounts. This needs to be done before returning the delegate allocations to ensure valid delegated amounts.\n if (delegateAllocations.length != 0) {\n for (uint256 _i; _i < delegateAllocations.length; ) {\n // Get a reference to the amount to be delegated.\n uint256 _delegatedAmount = delegateAllocations[_i].amount;\n\n // Validate if non-zero.\n if (_delegatedAmount != 0) {\n // Can't delegate more than was paid.\n if (_delegatedAmount > _balanceDiff) revert INVALID_AMOUNT_TO_SEND_DELEGATE();\n\n // Decrement the total amount being added to the balance.\n _balanceDiff = _balanceDiff - _delegatedAmount;\n }\n\n unchecked {\n ++_i;\n }\n }\n }\n\n // If there's no amount being recorded, there's nothing left to do.\n if (_amount.value == 0) return (fundingCycle, 0, delegateAllocations, memo);\n\n // Add the correct balance difference to the token balance of the project.\n if (_balanceDiff != 0)\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] +\n _balanceDiff;\n }\n\n // If there's no weight, token count must be 0 so there's nothing left to do.\n if (_weight == 0) return (fundingCycle, 0, delegateAllocations, memo);\n\n // Get a reference to the number of decimals in the amount. (prevents stack too deep).\n uint256 _decimals = _amount.decimals;\n\n // If the terminal should base its weight on a different currency from the terminal's currency, determine the factor.\n // The weight is always a fixed point mumber with 18 decimals. To ensure this, the ratio should use the same number of decimals as the `_amount`.\n uint256 _weightRatio = _amount.currency == _baseWeightCurrency\n ? 10 ** _decimals\n : prices.priceFor(_amount.currency, _baseWeightCurrency, _decimals);\n\n // Find the number of tokens to mint, as a fixed point number with as many decimals as `weight` has.\n tokenCount = PRBMath.mulDiv(_amount.value, _weight, _weightRatio);\n }\n\n /// @notice Records newly redeemed tokens of a project.\n /// @dev Redeems the project's tokens according to values provided by a configured data source. If no data source is configured, redeems tokens along a redemption bonding curve that is a function of the number of tokens being burned.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.senders tokens.\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the data source, if one is provided.\n /// @return fundingCycle The funding cycle during which the redemption was made.\n /// @return reclaimAmount The amount of terminal tokens reclaimed, as a fixed point number with 18 decimals.\n /// @return delegateAllocations The amount to send to delegates instead of sending to the beneficiary.\n /// @return memo A memo that should be passed along to the emitted event.\n function recordRedemptionFor(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n string memory _memo,\n bytes memory _metadata\n )\n external\n override\n nonReentrant\n returns (\n JBFundingCycle memory fundingCycle,\n uint256 reclaimAmount,\n JBRedemptionDelegateAllocation[] memory delegateAllocations,\n string memory memo\n )\n {\n // Get a reference to the project's current funding cycle.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // The current funding cycle must not be paused.\n if (fundingCycle.redeemPaused()) revert FUNDING_CYCLE_REDEEM_PAUSED();\n\n // Scoped section prevents stack too deep. `_reclaimedTokenAmount`, `_currentOverflow`, and `_totalSupply` only used within scope.\n {\n // Get a reference to the reclaimed token amount struct, the current overflow, and the total token supply.\n JBTokenAmount memory _reclaimedTokenAmount;\n uint256 _currentOverflow;\n uint256 _totalSupply;\n\n // Another scoped section prevents stack too deep. `_token`, `_decimals`, and `_currency` only used within scope.\n {\n // Get a reference to the terminal's tokens.\n address _token = IJBSingleTokenPaymentTerminal(msg.sender).token();\n\n // Get a reference to the terminal's decimals.\n uint256 _decimals = IJBSingleTokenPaymentTerminal(msg.sender).decimals();\n\n // Get areference to the terminal's currency.\n uint256 _currency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\n\n // Get the amount of current overflow.\n // Use the local overflow if the funding cycle specifies that it should be used. Otherwise, use the project's total overflow across all of its terminals.\n _currentOverflow = fundingCycle.useTotalOverflowForRedemptions()\n ? _currentTotalOverflowOf(_projectId, _decimals, _currency)\n : _overflowDuring(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _projectId,\n fundingCycle,\n _currency\n );\n\n // Get the number of outstanding tokens the project has.\n _totalSupply = IJBController3_1(directory.controllerOf(_projectId))\n .totalOutstandingTokensOf(_projectId);\n\n // Can't redeem more tokens that is in the supply.\n if (_tokenCount > _totalSupply) revert INSUFFICIENT_TOKENS();\n\n if (_currentOverflow != 0)\n // Calculate reclaim amount using the current overflow amount.\n reclaimAmount = _reclaimableOverflowDuring(\n _projectId,\n fundingCycle,\n _tokenCount,\n _totalSupply,\n _currentOverflow\n );\n\n _reclaimedTokenAmount = JBTokenAmount(_token, reclaimAmount, _decimals, _currency);\n }\n\n // If the funding cycle has configured a data source, use it to derive a claim amount and memo.\n if (fundingCycle.useDataSourceForRedeem() && fundingCycle.dataSource() != address(0)) {\n // Yet another scoped section prevents stack too deep. `_state` only used within scope.\n {\n // Get a reference to the ballot state.\n JBBallotState _state = fundingCycleStore.currentBallotStateOf(_projectId);\n\n // Create the params that'll be sent to the data source.\n JBRedeemParamsData memory _data = JBRedeemParamsData(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _holder,\n _projectId,\n fundingCycle.configuration,\n _tokenCount,\n _totalSupply,\n _currentOverflow,\n _reclaimedTokenAmount,\n fundingCycle.useTotalOverflowForRedemptions(),\n _state == JBBallotState.Active\n ? fundingCycle.ballotRedemptionRate()\n : fundingCycle.redemptionRate(),\n _memo,\n _metadata\n );\n (reclaimAmount, memo, delegateAllocations) = IJBFundingCycleDataSource(\n fundingCycle.dataSource()\n ).redeemParams(_data);\n }\n } else {\n memo = _memo;\n }\n }\n\n // Keep a reference to the amount that should be subtracted from the project's balance.\n uint256 _balanceDiff = reclaimAmount;\n\n if (delegateAllocations.length != 0) {\n // Validate all delegated amounts.\n for (uint256 _i; _i < delegateAllocations.length; ) {\n // Get a reference to the amount to be delegated.\n uint256 _delegatedAmount = delegateAllocations[_i].amount;\n\n // Validate if non-zero.\n if (_delegatedAmount != 0)\n // Increment the total amount being subtracted from the balance.\n _balanceDiff = _balanceDiff + _delegatedAmount;\n\n unchecked {\n ++_i;\n }\n }\n }\n\n // The amount being reclaimed must be within the project's balance.\n if (_balanceDiff > balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId])\n revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n\n // Remove the reclaimed funds from the project's balance.\n if (_balanceDiff != 0) {\n unchecked {\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\n _balanceDiff;\n }\n }\n }\n\n /// @notice Records newly distributed funds for a project.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\n /// @param _projectId The ID of the project that is having funds distributed.\n /// @param _amount The amount to use from the distribution limit, as a fixed point number.\n /// @param _currency The currency of the `_amount`. This must match the project's current funding cycle's currency.\n /// @return fundingCycle The funding cycle during which the distribution was made.\n /// @return distributedAmount The amount of terminal tokens distributed, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordDistributionFor(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency\n )\n external\n override\n nonReentrant\n returns (JBFundingCycle memory fundingCycle, uint256 distributedAmount)\n {\n // Get a reference to the project's current funding cycle.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // The funding cycle must not be configured to have distributions paused.\n if (fundingCycle.distributionsPaused()) revert FUNDING_CYCLE_DISTRIBUTION_PAUSED();\n\n // The new total amount that has been distributed during this funding cycle.\n uint256 _newUsedDistributionLimitOf = usedDistributionLimitOf[\n IJBSingleTokenPaymentTerminal(msg.sender)\n ][_projectId][fundingCycle.number] + _amount;\n\n // Amount must be within what is still distributable.\n (uint256 _distributionLimitOf, uint256 _distributionLimitCurrencyOf) = IJBController3_1(\n directory.controllerOf(_projectId)\n ).fundAccessConstraintsStore().distributionLimitOf(\n _projectId,\n fundingCycle.configuration,\n IJBSingleTokenPaymentTerminal(msg.sender),\n IJBSingleTokenPaymentTerminal(msg.sender).token()\n );\n\n // Make sure the new used amount is within the distribution limit.\n if (_newUsedDistributionLimitOf > _distributionLimitOf || _distributionLimitOf == 0)\n revert DISTRIBUTION_AMOUNT_LIMIT_REACHED();\n\n // Make sure the currencies match.\n if (_currency != _distributionLimitCurrencyOf) revert CURRENCY_MISMATCH();\n\n // Get a reference to the terminal's currency.\n uint256 _balanceCurrency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\n\n // Convert the amount to the balance's currency.\n distributedAmount = (_currency == _balanceCurrency)\n ? _amount\n : PRBMath.mulDiv(\n _amount,\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\n prices.priceFor(_currency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\n );\n\n // The amount being distributed must be available.\n if (distributedAmount > balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId])\n revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n\n // Store the new amount.\n usedDistributionLimitOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId][\n fundingCycle.number\n ] = _newUsedDistributionLimitOf;\n\n // Removed the distributed funds from the project's token balance.\n unchecked {\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\n distributedAmount;\n }\n }\n\n /// @notice Records newly used allowance funds of a project.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\n /// @param _projectId The ID of the project to use the allowance of.\n /// @param _amount The amount to use from the allowance, as a fixed point number.\n /// @param _currency The currency of the `_amount`. Must match the currency of the overflow allowance.\n /// @return fundingCycle The funding cycle during which the overflow allowance is being used.\n /// @return usedAmount The amount of terminal tokens used, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordUsedAllowanceOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency\n )\n external\n override\n nonReentrant\n returns (JBFundingCycle memory fundingCycle, uint256 usedAmount)\n {\n // Get a reference to the project's current funding cycle.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Get a reference to the new used overflow allowance for this funding cycle configuration.\n uint256 _newUsedOverflowAllowanceOf = usedOverflowAllowanceOf[\n IJBSingleTokenPaymentTerminal(msg.sender)\n ][_projectId][fundingCycle.configuration] + _amount;\n\n // There must be sufficient allowance available.\n (uint256 _overflowAllowanceOf, uint256 _overflowAllowanceCurrency) = IJBController3_1(\n directory.controllerOf(_projectId)\n ).fundAccessConstraintsStore().overflowAllowanceOf(\n _projectId,\n fundingCycle.configuration,\n IJBSingleTokenPaymentTerminal(msg.sender),\n IJBSingleTokenPaymentTerminal(msg.sender).token()\n );\n\n // Make sure the new used amount is within the allowance.\n if (_newUsedOverflowAllowanceOf > _overflowAllowanceOf || _overflowAllowanceOf == 0)\n revert INADEQUATE_CONTROLLER_ALLOWANCE();\n\n // Make sure the currencies match.\n if (_currency != _overflowAllowanceCurrency) revert CURRENCY_MISMATCH();\n\n // Get a reference to the terminal's currency.\n uint256 _balanceCurrency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\n\n // Convert the amount to this store's terminal's token.\n usedAmount = (_currency == _balanceCurrency)\n ? _amount\n : PRBMath.mulDiv(\n _amount,\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\n prices.priceFor(_currency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\n );\n\n // The amount being distributed must be available in the overflow.\n if (\n usedAmount >\n _overflowDuring(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _projectId,\n fundingCycle,\n _balanceCurrency\n )\n ) revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n\n // Store the incremented value.\n usedOverflowAllowanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId][\n fundingCycle.configuration\n ] = _newUsedOverflowAllowanceOf;\n\n // Update the project's balance.\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\n usedAmount;\n }\n\n /// @notice Records newly added funds for the project.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\n /// @param _projectId The ID of the project to which the funds being added belong.\n /// @param _amount The amount of terminal tokens added, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordAddedBalanceFor(uint256 _projectId, uint256 _amount) external override {\n // Increment the balance.\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] +\n _amount;\n }\n\n /// @notice Records the migration of funds from this store.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount returned is in terms of the msg.senders tokens.\n /// @param _projectId The ID of the project being migrated.\n /// @return balance The project's migrated balance, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordMigration(\n uint256 _projectId\n ) external override nonReentrant returns (uint256 balance) {\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n // Migration must be allowed.\n if (!_fundingCycle.terminalMigrationAllowed()) revert PAYMENT_TERMINAL_MIGRATION_NOT_ALLOWED();\n\n // Return the current balance.\n balance = balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId];\n\n // Set the balance to 0.\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] = 0;\n }\n\n //*********************************************************************//\n // --------------------- private helper functions -------------------- //\n //*********************************************************************//\n\n /// @notice The amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens when measured from the specified.\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\n /// @param _projectId The ID of the project to get the reclaimable overflow amount for.\n /// @param _fundingCycle The funding cycle during which reclaimable overflow is being calculated.\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _totalSupply The total supply of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _overflow The amount of overflow to make the calculation with.\n /// @return The amount of overflowed tokens that can be reclaimed.\n function _reclaimableOverflowDuring(\n uint256 _projectId,\n JBFundingCycle memory _fundingCycle,\n uint256 _tokenCount,\n uint256 _totalSupply,\n uint256 _overflow\n ) private view returns (uint256) {\n // If the amount being redeemed is the total supply, return the rest of the overflow.\n if (_tokenCount == _totalSupply) return _overflow;\n\n // Use the ballot redemption rate if the queued cycle is pending approval according to the previous funding cycle's ballot.\n uint256 _redemptionRate = fundingCycleStore.currentBallotStateOf(_projectId) ==\n JBBallotState.Active\n ? _fundingCycle.ballotRedemptionRate()\n : _fundingCycle.redemptionRate();\n\n // If the redemption rate is 0, nothing is claimable.\n if (_redemptionRate == 0) return 0;\n\n // Get a reference to the linear proportion.\n uint256 _base = PRBMath.mulDiv(_overflow, _tokenCount, _totalSupply);\n\n // These conditions are all part of the same curve. Edge conditions are separated because fewer operation are necessary.\n if (_redemptionRate == JBConstants.MAX_REDEMPTION_RATE) return _base;\n\n return\n PRBMath.mulDiv(\n _base,\n _redemptionRate +\n PRBMath.mulDiv(\n _tokenCount,\n JBConstants.MAX_REDEMPTION_RATE - _redemptionRate,\n _totalSupply\n ),\n JBConstants.MAX_REDEMPTION_RATE\n );\n }\n\n /// @notice Gets the amount that is overflowing when measured from the specified funding cycle.\n /// @dev This amount changes as the value of the balance changes in relation to the currency being used to measure the distribution limit.\n /// @param _terminal The terminal for which the overflow is being calculated.\n /// @param _fundingCycle The ID of the funding cycle to base the overflow on.\n /// @param _balanceCurrency The currency that the stored balance is expected to be in terms of.\n /// @return overflow The overflow of funds, as a fixed point number with 18 decimals.\n function _overflowDuring(\n IJBSingleTokenPaymentTerminal _terminal,\n uint256 _projectId,\n JBFundingCycle memory _fundingCycle,\n uint256 _balanceCurrency\n ) private view returns (uint256) {\n // Get the current balance of the project.\n uint256 _balanceOf = balanceOf[_terminal][_projectId];\n\n // If there's no balance, there's no overflow.\n if (_balanceOf == 0) return 0;\n\n // Get a reference to the distribution limit during the funding cycle.\n (uint256 _distributionLimit, uint256 _distributionLimitCurrency) = IJBController3_1(\n directory.controllerOf(_projectId)\n ).fundAccessConstraintsStore().distributionLimitOf(\n _projectId,\n _fundingCycle.configuration,\n _terminal,\n _terminal.token()\n );\n\n // Get a reference to the amount still distributable during the funding cycle.\n uint256 _distributionLimitRemaining = _distributionLimit -\n usedDistributionLimitOf[_terminal][_projectId][_fundingCycle.number];\n\n // Convert the _distributionRemaining to be in terms of the provided currency.\n if (_distributionLimitRemaining != 0 && _distributionLimitCurrency != _balanceCurrency)\n _distributionLimitRemaining = PRBMath.mulDiv(\n _distributionLimitRemaining,\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\n prices.priceFor(_distributionLimitCurrency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\n );\n\n // Overflow is the balance of this project minus the amount that can still be distributed.\n unchecked {\n return\n _balanceOf > _distributionLimitRemaining ? _balanceOf - _distributionLimitRemaining : 0;\n }\n }\n\n /// @notice Gets the amount that is currently overflowing across all of a project's terminals.\n /// @dev This amount changes as the value of the balances changes in relation to the currency being used to measure the project's distribution limits.\n /// @param _projectId The ID of the project to get the total overflow for.\n /// @param _decimals The number of decimals that the fixed point overflow should include.\n /// @param _currency The currency that the overflow should be in terms of.\n /// @return overflow The total overflow of a project's funds.\n function _currentTotalOverflowOf(\n uint256 _projectId,\n uint256 _decimals,\n uint256 _currency\n ) private view returns (uint256) {\n // Get a reference to the project's terminals.\n IJBPaymentTerminal[] memory _terminals = directory.terminalsOf(_projectId);\n\n // Keep a reference to the ETH overflow across all terminals, as a fixed point number with 18 decimals.\n uint256 _ethOverflow;\n\n // Add the current ETH overflow for each terminal.\n for (uint256 _i; _i < _terminals.length; ) {\n _ethOverflow = _ethOverflow + _terminals[_i].currentEthOverflowOf(_projectId);\n unchecked {\n ++_i;\n }\n }\n\n // Convert the ETH overflow to the specified currency if needed, maintaining a fixed point number with 18 decimals.\n uint256 _totalOverflow18Decimal = _currency == JBCurrencies.ETH\n ? _ethOverflow\n : PRBMath.mulDiv(_ethOverflow, 10 ** 18, prices.priceFor(JBCurrencies.ETH, _currency, 18));\n\n // Adjust the decimals of the fixed point number if needed to match the target decimals.\n return\n (_decimals == 18)\n ? _totalOverflow18Decimal\n : JBFixedPointNumber.adjustDecimals(_totalOverflow18Decimal, 18, _decimals);\n }\n}\n" + }, + "contracts/interfaces/IJBFundingCycleDataSource.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBPayDelegateAllocation} from './../structs/JBPayDelegateAllocation.sol';\nimport {JBPayParamsData} from './../structs/JBPayParamsData.sol';\nimport {JBRedeemParamsData} from './../structs/JBRedeemParamsData.sol';\nimport {JBRedemptionDelegateAllocation} from './../structs/JBRedemptionDelegateAllocation.sol';\n\n/// @title Datasource\n/// @notice The datasource is called by JBPayoutRedemptionPaymentTerminals on pay and redemption, and provide an extra layer of logic to use a custom weight, a custom memo and/or a pay/redeem delegate\ninterface IJBFundingCycleDataSource is IERC165 {\n /// @notice The datasource implementation for JBPaymentTerminal.pay(..)\n /// @param data the data passed to the data source in terminal.pay(..), as a JBPayParamsData struct:\n /// @return weight the weight to use to override the funding cycle weight\n /// @return memo the memo to override the pay(..) memo\n /// @return delegateAllocations The amount to send to delegates instead of adding to the local balance.\n function payParams(\n JBPayParamsData calldata data\n )\n external\n returns (\n uint256 weight,\n string memory memo,\n JBPayDelegateAllocation[] memory delegateAllocations\n );\n\n /// @notice The datasource implementation for JBPaymentTerminal.redeemTokensOf(..)\n /// @param data the data passed to the data source in terminal.redeemTokensOf(..), as a JBRedeemParamsData struct:\n /// @return reclaimAmount The amount to claim, overriding the terminal logic.\n /// @return memo The memo to override the redeemTokensOf(..) memo.\n /// @return delegateAllocations The amount to send to delegates instead of adding to the beneficiary.\n function redeemParams(\n JBRedeemParamsData calldata data\n )\n external\n returns (\n uint256 reclaimAmount,\n string memory memo,\n JBRedemptionDelegateAllocation[] memory delegateAllocations\n );\n}\n" + }, + "contracts/interfaces/IJBSingleTokenPaymentTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\n\ninterface IJBSingleTokenPaymentTerminal is IJBPaymentTerminal {\n function token() external view returns (address);\n\n function currency() external view returns (uint256);\n\n function decimals() external view returns (uint256);\n}\n" + }, + "contracts/interfaces/IJBSingleTokenPaymentTerminalStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\nimport {JBPayDelegateAllocation} from './../structs/JBPayDelegateAllocation.sol';\nimport {JBRedemptionDelegateAllocation} from './../structs/JBRedemptionDelegateAllocation.sol';\nimport {JBTokenAmount} from './../structs/JBTokenAmount.sol';\nimport {IJBDirectory} from './IJBDirectory.sol';\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\nimport {IJBPrices} from './IJBPrices.sol';\nimport {IJBSingleTokenPaymentTerminal} from './IJBSingleTokenPaymentTerminal.sol';\n\ninterface IJBSingleTokenPaymentTerminalStore {\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\n\n function directory() external view returns (IJBDirectory);\n\n function prices() external view returns (IJBPrices);\n\n function balanceOf(\n IJBSingleTokenPaymentTerminal terminal,\n uint256 projectId\n ) external view returns (uint256);\n\n function usedDistributionLimitOf(\n IJBSingleTokenPaymentTerminal terminal,\n uint256 projectId,\n uint256 fundingCycleNumber\n ) external view returns (uint256);\n\n function usedOverflowAllowanceOf(\n IJBSingleTokenPaymentTerminal terminal,\n uint256 projectId,\n uint256 fundingCycleConfiguration\n ) external view returns (uint256);\n\n function currentOverflowOf(\n IJBSingleTokenPaymentTerminal terminal,\n uint256 projectId\n ) external view returns (uint256);\n\n function currentTotalOverflowOf(\n uint256 projectId,\n uint256 decimals,\n uint256 currency\n ) external view returns (uint256);\n\n function currentReclaimableOverflowOf(\n IJBSingleTokenPaymentTerminal terminal,\n uint256 projectId,\n uint256 tokenCount,\n bool useTotalOverflow\n ) external view returns (uint256);\n\n function currentReclaimableOverflowOf(\n uint256 projectId,\n uint256 tokenCount,\n uint256 totalSupply,\n uint256 overflow\n ) external view returns (uint256);\n\n function recordPaymentFrom(\n address payer,\n JBTokenAmount memory amount,\n uint256 projectId,\n uint256 baseWeightCurrency,\n address beneficiary,\n string calldata inputMemo,\n bytes calldata metadata\n )\n external\n returns (\n JBFundingCycle memory fundingCycle,\n uint256 tokenCount,\n JBPayDelegateAllocation[] memory delegateAllocations,\n string memory outputMemo\n );\n\n function recordRedemptionFor(\n address holder,\n uint256 projectId,\n uint256 tokenCount,\n string calldata inputMemo,\n bytes calldata metadata\n )\n external\n returns (\n JBFundingCycle memory fundingCycle,\n uint256 reclaimAmount,\n JBRedemptionDelegateAllocation[] memory delegateAllocations,\n string memory outputMemo\n );\n\n function recordDistributionFor(\n uint256 projectId,\n uint256 amount,\n uint256 currency\n ) external returns (JBFundingCycle memory fundingCycle, uint256 distributedAmount);\n\n function recordUsedAllowanceOf(\n uint256 projectId,\n uint256 amount,\n uint256 currency\n ) external returns (JBFundingCycle memory fundingCycle, uint256 withdrawnAmount);\n\n function recordAddedBalanceFor(uint256 projectId, uint256 amount) external;\n\n function recordMigration(uint256 projectId) external returns (uint256 balance);\n}\n" + }, + "contracts/interfaces/IJBPrices.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBPriceFeed} from './IJBPriceFeed.sol';\n\ninterface IJBPrices {\n event AddFeed(uint256 indexed currency, uint256 indexed base, IJBPriceFeed feed);\n\n function feedFor(uint256 currency, uint256 base) external view returns (IJBPriceFeed);\n\n function priceFor(\n uint256 currency,\n uint256 base,\n uint256 decimals\n ) external view returns (uint256);\n\n function addFeedFor(uint256 currency, uint256 base, IJBPriceFeed priceFeed) external;\n}\n" + }, + "contracts/libraries/JBCurrencies.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nlibrary JBCurrencies {\n uint256 public constant ETH = 1;\n uint256 public constant USD = 2;\n}\n" + }, + "contracts/libraries/JBFixedPointNumber.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nlibrary JBFixedPointNumber {\n function adjustDecimals(\n uint256 _value,\n uint256 _decimals,\n uint256 _targetDecimals\n ) internal pure returns (uint256) {\n // If decimals need adjusting, multiply or divide the price by the decimal adjuster to get the normalized result.\n if (_targetDecimals == _decimals) return _value;\n else if (_targetDecimals > _decimals) return _value * 10**(_targetDecimals - _decimals);\n else return _value / 10**(_decimals - _targetDecimals);\n }\n}\n" + }, + "contracts/structs/JBPayDelegateAllocation.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBPayDelegate} from '../interfaces/IJBPayDelegate.sol';\n\n/// @custom:member delegate A delegate contract to use for subsequent calls.\n/// @custom:member amount The amount to send to the delegate.\nstruct JBPayDelegateAllocation {\n IJBPayDelegate delegate;\n uint256 amount;\n}\n" + }, + "contracts/structs/JBPayParamsData.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\nimport {JBTokenAmount} from './JBTokenAmount.sol';\n\n/// @custom:member terminal The terminal that is facilitating the payment.\n/// @custom:member payer The address from which the payment originated.\n/// @custom:member amount The amount of the payment. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\n/// @custom:member projectId The ID of the project being paid.\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the payment is being made.\n/// @custom:member beneficiary The specified address that should be the beneficiary of anything that results from the payment.\n/// @custom:member weight The weight of the funding cycle during which the payment is being made.\n/// @custom:member reservedRate The reserved rate of the funding cycle during which the payment is being made.\n/// @custom:member memo The memo that was sent alongside the payment.\n/// @custom:member metadata Extra data provided by the payer.\nstruct JBPayParamsData {\n IJBPaymentTerminal terminal;\n address payer;\n JBTokenAmount amount;\n uint256 projectId;\n uint256 currentFundingCycleConfiguration;\n address beneficiary;\n uint256 weight;\n uint256 reservedRate;\n string memo;\n bytes metadata;\n}\n" + }, + "contracts/structs/JBRedeemParamsData.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\nimport {JBTokenAmount} from './JBTokenAmount.sol';\n\n/// @custom:member terminal The terminal that is facilitating the redemption.\n/// @custom:member holder The holder of the tokens being redeemed.\n/// @custom:member projectId The ID of the project whos tokens are being redeemed.\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the redemption is being made.\n/// @custom:member tokenCount The proposed number of tokens being redeemed, as a fixed point number with 18 decimals.\n/// @custom:member totalSupply The total supply of tokens used in the calculation, as a fixed point number with 18 decimals.\n/// @custom:member overflow The amount of overflow used in the reclaim amount calculation.\n/// @custom:member reclaimAmount The amount that should be reclaimed by the redeemer using the protocol's standard bonding curve redemption formula. Includes the token being reclaimed, the reclaim value, the number of decimals included, and the currency of the reclaim amount.\n/// @custom:member useTotalOverflow If overflow across all of a project's terminals is being used when making redemptions.\n/// @custom:member redemptionRate The redemption rate of the funding cycle during which the redemption is being made.\n/// @custom:member memo The proposed memo that is being emitted alongside the redemption.\n/// @custom:member metadata Extra data provided by the redeemer.\nstruct JBRedeemParamsData {\n IJBPaymentTerminal terminal;\n address holder;\n uint256 projectId;\n uint256 currentFundingCycleConfiguration;\n uint256 tokenCount;\n uint256 totalSupply;\n uint256 overflow;\n JBTokenAmount reclaimAmount;\n bool useTotalOverflow;\n uint256 redemptionRate;\n string memo;\n bytes metadata;\n}\n" + }, + "contracts/structs/JBRedemptionDelegateAllocation.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBRedemptionDelegate} from '../interfaces/IJBRedemptionDelegate.sol';\n\n/// @custom:member delegate A delegate contract to use for subsequent calls.\n/// @custom:member amount The amount to send to the delegate.\nstruct JBRedemptionDelegateAllocation {\n IJBRedemptionDelegate delegate;\n uint256 amount;\n}\n" + }, + "contracts/structs/JBTokenAmount.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @custom:member token The token the payment was made in.\n/// @custom:member value The amount of tokens that was paid, as a fixed point number.\n/// @custom:member decimals The number of decimals included in the value fixed point number.\n/// @custom:member currency The expected currency of the value.\nstruct JBTokenAmount {\n address token;\n uint256 value;\n uint256 decimals;\n uint256 currency;\n}\n" + }, + "contracts/interfaces/IJBPayDelegate.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBDidPayData} from './../structs/JBDidPayData.sol';\n\n/// @title Pay delegate\n/// @notice Delegate called after JBTerminal.pay(..) logic completion (if passed by the funding cycle datasource)\ninterface IJBPayDelegate is IERC165 {\n /// @notice This function is called by JBPaymentTerminal.pay(..), after the execution of its logic\n /// @dev Critical business logic should be protected by an appropriate access control\n /// @param data the data passed by the terminal, as a JBDidPayData struct:\n function didPay(JBDidPayData calldata data) external payable;\n}\n" + }, + "contracts/structs/JBDidPayData.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBTokenAmount} from './JBTokenAmount.sol';\n\n/// @custom:member payer The address from which the payment originated.\n/// @custom:member projectId The ID of the project for which the payment was made.\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the payment is being made.\n/// @custom:member amount The amount of the payment. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\n/// @custom:member forwardedAmount The amount of the payment that is being sent to the delegate. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\n/// @custom:member projectTokenCount The number of project tokens minted for the beneficiary.\n/// @custom:member beneficiary The address to which the tokens were minted.\n/// @custom:member preferClaimedTokens A flag indicating whether the request prefered to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract.\n/// @custom:member memo The memo that is being emitted alongside the payment.\n/// @custom:member metadata Extra data to send to the delegate.\nstruct JBDidPayData {\n address payer;\n uint256 projectId;\n uint256 currentFundingCycleConfiguration;\n JBTokenAmount amount;\n JBTokenAmount forwardedAmount;\n uint256 projectTokenCount;\n address beneficiary;\n bool preferClaimedTokens;\n string memo;\n bytes metadata;\n}\n" + }, + "contracts/interfaces/IJBRedemptionDelegate.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBDidRedeemData} from './../structs/JBDidRedeemData.sol';\n\n/// @title Redemption delegate\n/// @notice Delegate called after JBTerminal.redeemTokensOf(..) logic completion (if passed by the funding cycle datasource)\ninterface IJBRedemptionDelegate is IERC165 {\n /// @notice This function is called by JBPaymentTerminal.redeemTokensOf(..), after the execution of its logic\n /// @dev Critical business logic should be protected by an appropriate access control\n /// @param data the data passed by the terminal, as a JBDidRedeemData struct:\n function didRedeem(JBDidRedeemData calldata data) external payable;\n}\n" + }, + "contracts/structs/JBDidRedeemData.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBTokenAmount} from './JBTokenAmount.sol';\n\n/// @custom:member holder The holder of the tokens being redeemed.\n/// @custom:member projectId The ID of the project with which the redeemed tokens are associated.\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the redemption is being made.\n/// @custom:member projectTokenCount The number of project tokens being redeemed.\n/// @custom:member reclaimedAmount The amount reclaimed from the treasury. Includes the token being reclaimed, the value, the number of decimals included, and the currency of the amount.\n/// @custom:member forwardedAmount The amount of the payment that is being sent to the delegate. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\n/// @custom:member beneficiary The address to which the reclaimed amount will be sent.\n/// @custom:member memo The memo that is being emitted alongside the redemption.\n/// @custom:member metadata Extra data to send to the delegate.\nstruct JBDidRedeemData {\n address holder;\n uint256 projectId;\n uint256 currentFundingCycleConfiguration;\n uint256 projectTokenCount;\n JBTokenAmount reclaimedAmount;\n JBTokenAmount forwardedAmount;\n address payable beneficiary;\n string memo;\n bytes metadata;\n}\n" + }, + "contracts/interfaces/IJBPriceFeed.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBPriceFeed {\n function currentPrice(uint256 targetDecimals) external view returns (uint256);\n}\n" + }, + "contracts/JBSingleTokenPaymentTerminalStore3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {ReentrancyGuard} from '@openzeppelin/contracts/security/ReentrancyGuard.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {JBBallotState} from './enums/JBBallotState.sol';\nimport {IJBController3_1} from './interfaces/IJBController3_1.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBFundingCycleDataSource3_1_1} from './interfaces/IJBFundingCycleDataSource3_1_1.sol';\nimport {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol';\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\nimport {IJBSingleTokenPaymentTerminal} from './interfaces/IJBSingleTokenPaymentTerminal.sol';\nimport {IJBSingleTokenPaymentTerminalStore3_1_1} from './interfaces/IJBSingleTokenPaymentTerminalStore3_1_1.sol';\nimport {JBConstants} from './libraries/JBConstants.sol';\nimport {JBCurrencies} from './libraries/JBCurrencies.sol';\nimport {JBFixedPointNumber} from './libraries/JBFixedPointNumber.sol';\nimport {JBFundingCycleMetadataResolver} from './libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\nimport {JBPayDelegateAllocation3_1_1} from './structs/JBPayDelegateAllocation3_1_1.sol';\nimport {JBPayParamsData} from './structs/JBPayParamsData.sol';\nimport {JBRedeemParamsData} from './structs/JBRedeemParamsData.sol';\nimport {JBRedemptionDelegateAllocation3_1_1} from './structs/JBRedemptionDelegateAllocation3_1_1.sol';\nimport {JBTokenAmount} from './structs/JBTokenAmount.sol';\n\n/// @notice Manages all bookkeeping for inflows and outflows of funds from any ISingleTokenPaymentTerminal.\n/// @dev This Store expects a project's controller to be an IJBController3_1.\ncontract JBSingleTokenPaymentTerminalStore3_1_1 is\n ReentrancyGuard,\n IJBSingleTokenPaymentTerminalStore3_1_1\n{\n // A library that parses the packed funding cycle metadata into a friendlier format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error INVALID_AMOUNT_TO_SEND_DELEGATE();\n error CURRENCY_MISMATCH();\n error DISTRIBUTION_AMOUNT_LIMIT_REACHED();\n error FUNDING_CYCLE_PAYMENT_PAUSED();\n error FUNDING_CYCLE_DISTRIBUTION_PAUSED();\n error FUNDING_CYCLE_REDEEM_PAUSED();\n error INADEQUATE_CONTROLLER_ALLOWANCE();\n error INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n error INSUFFICIENT_TOKENS();\n error INVALID_FUNDING_CYCLE();\n error PAYMENT_TERMINAL_MIGRATION_NOT_ALLOWED();\n\n //*********************************************************************//\n // -------------------------- private constants ---------------------- //\n //*********************************************************************//\n\n /// @notice Ensures a maximum number of decimal points of persisted fidelity on mulDiv operations of fixed point numbers.\n uint256 private constant _MAX_FIXED_POINT_FIDELITY = 18;\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n /// @notice The contract storing all funding cycle configurations.\n IJBFundingCycleStore public immutable override fundingCycleStore;\n\n /// @notice The contract that exposes price feeds.\n IJBPrices public immutable override prices;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The amount of tokens that each project has for each terminal, in terms of the terminal's token.\n /// @dev The balance is represented as a fixed point number with the same amount of decimals as its relative terminal.\n /// @custom:param _terminal The terminal to which the balance applies.\n /// @custom:param _projectId The ID of the project to get the balance of.\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => uint256)) public override balanceOf;\n\n /// @notice The amount of funds that a project has distributed from its limit during the current funding cycle for each terminal, in terms of the distribution limit's currency.\n /// @dev Increases as projects use their preconfigured distribution limits.\n /// @dev The used distribution limit is represented as a fixed point number with the same amount of decimals as its relative terminal.\n /// @custom:param _terminal The terminal to which the used distribution limit applies.\n /// @custom:param _projectId The ID of the project to get the used distribution limit of.\n /// @custom:param _fundingCycleNumber The number of the funding cycle during which the distribution limit was used.\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => mapping(uint256 => uint256)))\n public\n override usedDistributionLimitOf;\n\n /// @notice The amount of funds that a project has used from its allowance during the current funding cycle configuration for each terminal, in terms of the overflow allowance's currency.\n /// @dev Increases as projects use their allowance.\n /// @dev The used allowance is represented as a fixed point number with the same amount of decimals as its relative terminal.\n /// @custom:param _terminal The terminal to which the overflow allowance applies.\n /// @custom:param _projectId The ID of the project to get the used overflow allowance of.\n /// @custom:param _configuration The configuration of the during which the allowance was used.\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => mapping(uint256 => uint256)))\n public\n override usedOverflowAllowanceOf;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Gets the current overflowed amount in a terminal for a specified project.\n /// @dev The current overflow is represented as a fixed point number with the same amount of decimals as the specified terminal.\n /// @param _terminal The terminal for which the overflow is being calculated.\n /// @param _projectId The ID of the project to get overflow for.\n /// @return The current amount of overflow that project has in the specified terminal.\n function currentOverflowOf(\n IJBSingleTokenPaymentTerminal _terminal,\n uint256 _projectId\n ) external view override returns (uint256) {\n // Return the overflow during the project's current funding cycle.\n return\n _overflowDuring(\n _terminal,\n _projectId,\n fundingCycleStore.currentOf(_projectId),\n _terminal.currency()\n );\n }\n\n /// @notice Gets the current overflowed amount for a specified project across all terminals.\n /// @param _projectId The ID of the project to get total overflow for.\n /// @param _decimals The number of decimals that the fixed point overflow should include.\n /// @param _currency The currency that the total overflow should be in terms of.\n /// @return The current total amount of overflow that project has across all terminals.\n function currentTotalOverflowOf(\n uint256 _projectId,\n uint256 _decimals,\n uint256 _currency\n ) external view override returns (uint256) {\n return _currentTotalOverflowOf(_projectId, _decimals, _currency);\n }\n\n /// @notice The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the total token supply and overflow in the ecosystem.\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\n /// @dev The current reclaimable overflow is returned in terms of the specified terminal's currency.\n /// @dev The reclaimable overflow is represented as a fixed point number with the same amount of decimals as the specified terminal.\n /// @param _terminal The terminal from which the reclaimable amount would come.\n /// @param _projectId The ID of the project to get the reclaimable overflow amount for.\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _useTotalOverflow A flag indicating whether the overflow used in the calculation should be summed from all of the project's terminals. If false, overflow should be limited to the amount in the specified `_terminal`.\n /// @return The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_terminal`.\n function currentReclaimableOverflowOf(\n IJBSingleTokenPaymentTerminal _terminal,\n uint256 _projectId,\n uint256 _tokenCount,\n bool _useTotalOverflow\n ) external view override returns (uint256) {\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Get the amount of current overflow.\n // Use the project's total overflow across all of its terminals if the flag species specifies so. Otherwise, use the overflow local to the specified terminal.\n uint256 _currentOverflow = _useTotalOverflow\n ? _currentTotalOverflowOf(_projectId, _terminal.decimals(), _terminal.currency())\n : _overflowDuring(_terminal, _projectId, _fundingCycle, _terminal.currency());\n\n // If there's no overflow, there's no reclaimable overflow.\n if (_currentOverflow == 0) return 0;\n\n // Get the number of outstanding tokens the project has.\n uint256 _totalSupply = IJBController3_1(directory.controllerOf(_projectId))\n .totalOutstandingTokensOf(_projectId);\n\n // Can't redeem more tokens that is in the supply.\n if (_tokenCount > _totalSupply) return 0;\n\n // Return the reclaimable overflow amount.\n return\n _reclaimableOverflowDuring(\n _projectId,\n _fundingCycle,\n _tokenCount,\n _totalSupply,\n _currentOverflow\n );\n }\n\n /// @notice The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the specified total token supply and overflow amounts.\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\n /// @param _projectId The ID of the project to get the reclaimable overflow amount for.\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _totalSupply The total number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _overflow The amount of overflow to make the calculation with, as a fixed point number.\n /// @return The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_overflow`.\n function currentReclaimableOverflowOf(\n uint256 _projectId,\n uint256 _tokenCount,\n uint256 _totalSupply,\n uint256 _overflow\n ) external view override returns (uint256) {\n // If there's no overflow, there's no reclaimable overflow.\n if (_overflow == 0) return 0;\n\n // Can't redeem more tokens that is in the supply.\n if (_tokenCount > _totalSupply) return 0;\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Return the reclaimable overflow amount.\n return\n _reclaimableOverflowDuring(_projectId, _fundingCycle, _tokenCount, _totalSupply, _overflow);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _fundingCycleStore A contract storing all funding cycle configurations.\n /// @param _prices A contract that exposes price feeds.\n constructor(IJBDirectory _directory, IJBFundingCycleStore _fundingCycleStore, IJBPrices _prices) {\n directory = _directory;\n fundingCycleStore = _fundingCycleStore;\n prices = _prices;\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Records newly contributed tokens to a project.\n /// @dev Mints the project's tokens according to values provided by a configured data source. If no data source is configured, mints tokens proportional to the amount of the contribution.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.sender's tokens.\n /// @param _payer The original address that sent the payment to the terminal.\n /// @param _amount The amount of tokens being paid. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\n /// @param _projectId The ID of the project being paid.\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _beneficiary The specified address that should be the beneficiary of anything that results from the payment.\n /// @param _memo A memo to pass along to the emitted event, and passed along to the funding cycle's data source.\n /// @param _metadata Bytes to send along to the data source, if one is provided.\n /// @return fundingCycle The project's funding cycle during which payment was made.\n /// @return tokenCount The number of project tokens that were minted, as a fixed point number with 18 decimals.\n /// @return delegateAllocations The amount to send to delegates instead of adding to the local balance.\n /// @return memo A memo that should be passed along to the emitted event.\n function recordPaymentFrom(\n address _payer,\n JBTokenAmount calldata _amount,\n uint256 _projectId,\n uint256 _baseWeightCurrency,\n address _beneficiary,\n string calldata _memo,\n bytes memory _metadata\n )\n external\n override\n nonReentrant\n returns (\n JBFundingCycle memory fundingCycle,\n uint256 tokenCount,\n JBPayDelegateAllocation3_1_1[] memory delegateAllocations,\n string memory memo\n )\n {\n // Get a reference to the current funding cycle for the project.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // The project must have a funding cycle configured.\n if (fundingCycle.number == 0) revert INVALID_FUNDING_CYCLE();\n\n // Must not be paused.\n if (fundingCycle.payPaused()) revert FUNDING_CYCLE_PAYMENT_PAUSED();\n\n // The weight according to which new token supply is to be minted, as a fixed point number with 18 decimals.\n uint256 _weight;\n\n // If the funding cycle has configured a data source, use it to derive a weight and memo.\n if (fundingCycle.useDataSourceForPay() && fundingCycle.dataSource() != address(0)) {\n // Create the params that'll be sent to the data source.\n JBPayParamsData memory _data = JBPayParamsData(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _payer,\n _amount,\n _projectId,\n fundingCycle.configuration,\n _beneficiary,\n fundingCycle.weight,\n fundingCycle.reservedRate(),\n _memo,\n _metadata\n );\n (_weight, memo, delegateAllocations) = IJBFundingCycleDataSource3_1_1(\n fundingCycle.dataSource()\n ).payParams(_data);\n }\n // Otherwise use the funding cycle's weight\n else {\n _weight = fundingCycle.weight;\n memo = _memo;\n }\n\n // Scoped section prevents stack too deep. `_balanceDiff` only used within scope.\n {\n // Keep a reference to the amount that should be added to the project's balance.\n uint256 _balanceDiff = _amount.value;\n\n // Validate all delegated amounts. This needs to be done before returning the delegate allocations to ensure valid delegated amounts.\n if (delegateAllocations.length != 0) {\n for (uint256 _i; _i < delegateAllocations.length; ) {\n // Get a reference to the amount to be delegated.\n uint256 _delegatedAmount = delegateAllocations[_i].amount;\n\n // Validate if non-zero.\n if (_delegatedAmount != 0) {\n // Can't delegate more than was paid.\n if (_delegatedAmount > _balanceDiff) revert INVALID_AMOUNT_TO_SEND_DELEGATE();\n\n // Decrement the total amount being added to the balance.\n _balanceDiff = _balanceDiff - _delegatedAmount;\n }\n\n unchecked {\n ++_i;\n }\n }\n }\n\n // If there's no amount being recorded, there's nothing left to do.\n if (_amount.value == 0) return (fundingCycle, 0, delegateAllocations, memo);\n\n // Add the correct balance difference to the token balance of the project.\n if (_balanceDiff != 0)\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] +\n _balanceDiff;\n }\n\n // If there's no weight, token count must be 0 so there's nothing left to do.\n if (_weight == 0) return (fundingCycle, 0, delegateAllocations, memo);\n\n // Get a reference to the number of decimals in the amount. (prevents stack too deep).\n uint256 _decimals = _amount.decimals;\n\n // If the terminal should base its weight on a different currency from the terminal's currency, determine the factor.\n // The weight is always a fixed point mumber with 18 decimals. To ensure this, the ratio should use the same number of decimals as the `_amount`.\n uint256 _weightRatio = _amount.currency == _baseWeightCurrency\n ? 10 ** _decimals\n : prices.priceFor(_amount.currency, _baseWeightCurrency, _decimals);\n\n // Find the number of tokens to mint, as a fixed point number with as many decimals as `weight` has.\n tokenCount = PRBMath.mulDiv(_amount.value, _weight, _weightRatio);\n }\n\n /// @notice Records newly redeemed tokens of a project.\n /// @dev Redeems the project's tokens according to values provided by a configured data source. If no data source is configured, redeems tokens along a redemption bonding curve that is a function of the number of tokens being burned.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.senders tokens.\n /// @param _holder The account that is having its tokens redeemed.\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\n /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the data source, if one is provided.\n /// @return fundingCycle The funding cycle during which the redemption was made.\n /// @return reclaimAmount The amount of terminal tokens reclaimed, as a fixed point number with 18 decimals.\n /// @return delegateAllocations The amount to send to delegates instead of sending to the beneficiary.\n /// @return memo A memo that should be passed along to the emitted event.\n function recordRedemptionFor(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n string memory _memo,\n bytes memory _metadata\n )\n external\n override\n nonReentrant\n returns (\n JBFundingCycle memory fundingCycle,\n uint256 reclaimAmount,\n JBRedemptionDelegateAllocation3_1_1[] memory delegateAllocations,\n string memory memo\n )\n {\n // Get a reference to the project's current funding cycle.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // The current funding cycle must not be paused.\n if (fundingCycle.redeemPaused()) revert FUNDING_CYCLE_REDEEM_PAUSED();\n\n // Scoped section prevents stack too deep. `_reclaimedTokenAmount`, `_currentOverflow`, and `_totalSupply` only used within scope.\n {\n // Get a reference to the reclaimed token amount struct, the current overflow, and the total token supply.\n JBTokenAmount memory _reclaimedTokenAmount;\n uint256 _currentOverflow;\n uint256 _totalSupply;\n\n // Another scoped section prevents stack too deep. `_token`, `_decimals`, and `_currency` only used within scope.\n {\n // Get a reference to the terminal's tokens.\n address _token = IJBSingleTokenPaymentTerminal(msg.sender).token();\n\n // Get a reference to the terminal's decimals.\n uint256 _decimals = IJBSingleTokenPaymentTerminal(msg.sender).decimals();\n\n // Get areference to the terminal's currency.\n uint256 _currency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\n\n // Get the amount of current overflow.\n // Use the local overflow if the funding cycle specifies that it should be used. Otherwise, use the project's total overflow across all of its terminals.\n _currentOverflow = fundingCycle.useTotalOverflowForRedemptions()\n ? _currentTotalOverflowOf(_projectId, _decimals, _currency)\n : _overflowDuring(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _projectId,\n fundingCycle,\n _currency\n );\n\n // Get the number of outstanding tokens the project has.\n _totalSupply = IJBController3_1(directory.controllerOf(_projectId))\n .totalOutstandingTokensOf(_projectId);\n\n // Can't redeem more tokens that is in the supply.\n if (_tokenCount > _totalSupply) revert INSUFFICIENT_TOKENS();\n\n if (_currentOverflow != 0)\n // Calculate reclaim amount using the current overflow amount.\n reclaimAmount = _reclaimableOverflowDuring(\n _projectId,\n fundingCycle,\n _tokenCount,\n _totalSupply,\n _currentOverflow\n );\n\n _reclaimedTokenAmount = JBTokenAmount(_token, reclaimAmount, _decimals, _currency);\n }\n\n // If the funding cycle has configured a data source, use it to derive a claim amount and memo.\n if (fundingCycle.useDataSourceForRedeem() && fundingCycle.dataSource() != address(0)) {\n // Yet another scoped section prevents stack too deep. `_state` only used within scope.\n {\n // Get a reference to the ballot state.\n JBBallotState _state = fundingCycleStore.currentBallotStateOf(_projectId);\n\n // Create the params that'll be sent to the data source.\n JBRedeemParamsData memory _data = JBRedeemParamsData(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _holder,\n _projectId,\n fundingCycle.configuration,\n _tokenCount,\n _totalSupply,\n _currentOverflow,\n _reclaimedTokenAmount,\n fundingCycle.useTotalOverflowForRedemptions(),\n _state == JBBallotState.Active\n ? fundingCycle.ballotRedemptionRate()\n : fundingCycle.redemptionRate(),\n _memo,\n _metadata\n );\n (reclaimAmount, memo, delegateAllocations) = IJBFundingCycleDataSource3_1_1(\n fundingCycle.dataSource()\n ).redeemParams(_data);\n }\n } else {\n memo = _memo;\n }\n }\n\n // Keep a reference to the amount that should be subtracted from the project's balance.\n uint256 _balanceDiff = reclaimAmount;\n\n if (delegateAllocations.length != 0) {\n // Validate all delegated amounts.\n for (uint256 _i; _i < delegateAllocations.length; ) {\n // Get a reference to the amount to be delegated.\n uint256 _delegatedAmount = delegateAllocations[_i].amount;\n\n // Validate if non-zero.\n if (_delegatedAmount != 0)\n // Increment the total amount being subtracted from the balance.\n _balanceDiff = _balanceDiff + _delegatedAmount;\n\n unchecked {\n ++_i;\n }\n }\n }\n\n // The amount being reclaimed must be within the project's balance.\n if (_balanceDiff > balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId])\n revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n\n // Remove the reclaimed funds from the project's balance.\n if (_balanceDiff != 0) {\n unchecked {\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\n _balanceDiff;\n }\n }\n }\n\n /// @notice Records newly distributed funds for a project.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\n /// @param _projectId The ID of the project that is having funds distributed.\n /// @param _amount The amount to use from the distribution limit, as a fixed point number.\n /// @param _currency The currency of the `_amount`. This must match the project's current funding cycle's currency.\n /// @return fundingCycle The funding cycle during which the distribution was made.\n /// @return distributedAmount The amount of terminal tokens distributed, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordDistributionFor(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency\n )\n external\n override\n nonReentrant\n returns (JBFundingCycle memory fundingCycle, uint256 distributedAmount)\n {\n // Get a reference to the project's current funding cycle.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // The funding cycle must not be configured to have distributions paused.\n if (fundingCycle.distributionsPaused()) revert FUNDING_CYCLE_DISTRIBUTION_PAUSED();\n\n // The new total amount that has been distributed during this funding cycle.\n uint256 _newUsedDistributionLimitOf = usedDistributionLimitOf[\n IJBSingleTokenPaymentTerminal(msg.sender)\n ][_projectId][fundingCycle.number] + _amount;\n\n // Amount must be within what is still distributable.\n (uint256 _distributionLimitOf, uint256 _distributionLimitCurrencyOf) = IJBController3_1(\n directory.controllerOf(_projectId)\n ).fundAccessConstraintsStore().distributionLimitOf(\n _projectId,\n fundingCycle.configuration,\n IJBSingleTokenPaymentTerminal(msg.sender),\n IJBSingleTokenPaymentTerminal(msg.sender).token()\n );\n\n // Make sure the new used amount is within the distribution limit.\n if (_newUsedDistributionLimitOf > _distributionLimitOf || _distributionLimitOf == 0)\n revert DISTRIBUTION_AMOUNT_LIMIT_REACHED();\n\n // Make sure the currencies match.\n if (_currency != _distributionLimitCurrencyOf) revert CURRENCY_MISMATCH();\n\n // Get a reference to the terminal's currency.\n uint256 _balanceCurrency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\n\n // Convert the amount to the balance's currency.\n distributedAmount = (_currency == _balanceCurrency)\n ? _amount\n : PRBMath.mulDiv(\n _amount,\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\n prices.priceFor(_currency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\n );\n\n // The amount being distributed must be available.\n if (distributedAmount > balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId])\n revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n\n // Store the new amount.\n usedDistributionLimitOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId][\n fundingCycle.number\n ] = _newUsedDistributionLimitOf;\n\n // Removed the distributed funds from the project's token balance.\n unchecked {\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\n distributedAmount;\n }\n }\n\n /// @notice Records newly used allowance funds of a project.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\n /// @param _projectId The ID of the project to use the allowance of.\n /// @param _amount The amount to use from the allowance, as a fixed point number.\n /// @param _currency The currency of the `_amount`. Must match the currency of the overflow allowance.\n /// @return fundingCycle The funding cycle during which the overflow allowance is being used.\n /// @return usedAmount The amount of terminal tokens used, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordUsedAllowanceOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency\n )\n external\n override\n nonReentrant\n returns (JBFundingCycle memory fundingCycle, uint256 usedAmount)\n {\n // Get a reference to the project's current funding cycle.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Get a reference to the new used overflow allowance for this funding cycle configuration.\n uint256 _newUsedOverflowAllowanceOf = usedOverflowAllowanceOf[\n IJBSingleTokenPaymentTerminal(msg.sender)\n ][_projectId][fundingCycle.configuration] + _amount;\n\n // There must be sufficient allowance available.\n (uint256 _overflowAllowanceOf, uint256 _overflowAllowanceCurrency) = IJBController3_1(\n directory.controllerOf(_projectId)\n ).fundAccessConstraintsStore().overflowAllowanceOf(\n _projectId,\n fundingCycle.configuration,\n IJBSingleTokenPaymentTerminal(msg.sender),\n IJBSingleTokenPaymentTerminal(msg.sender).token()\n );\n\n // Make sure the new used amount is within the allowance.\n if (_newUsedOverflowAllowanceOf > _overflowAllowanceOf || _overflowAllowanceOf == 0)\n revert INADEQUATE_CONTROLLER_ALLOWANCE();\n\n // Make sure the currencies match.\n if (_currency != _overflowAllowanceCurrency) revert CURRENCY_MISMATCH();\n\n // Get a reference to the terminal's currency.\n uint256 _balanceCurrency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\n\n // Convert the amount to this store's terminal's token.\n usedAmount = (_currency == _balanceCurrency)\n ? _amount\n : PRBMath.mulDiv(\n _amount,\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\n prices.priceFor(_currency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\n );\n\n // The amount being distributed must be available in the overflow.\n if (\n usedAmount >\n _overflowDuring(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _projectId,\n fundingCycle,\n _balanceCurrency\n )\n ) revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n\n // Store the incremented value.\n usedOverflowAllowanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId][\n fundingCycle.configuration\n ] = _newUsedOverflowAllowanceOf;\n\n // Update the project's balance.\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\n usedAmount;\n }\n\n /// @notice Records newly added funds for the project.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\n /// @param _projectId The ID of the project to which the funds being added belong.\n /// @param _amount The amount of terminal tokens added, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordAddedBalanceFor(uint256 _projectId, uint256 _amount) external override {\n // Increment the balance.\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] +\n _amount;\n }\n\n /// @notice Records the migration of funds from this store.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount returned is in terms of the msg.senders tokens.\n /// @param _projectId The ID of the project being migrated.\n /// @return balance The project's migrated balance, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordMigration(\n uint256 _projectId\n ) external override nonReentrant returns (uint256 balance) {\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Migration must be allowed.\n if (!_fundingCycle.terminalMigrationAllowed()) revert PAYMENT_TERMINAL_MIGRATION_NOT_ALLOWED();\n\n // Return the current balance.\n balance = balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId];\n\n // Set the balance to 0.\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] = 0;\n }\n\n //*********************************************************************//\n // --------------------- private helper functions -------------------- //\n //*********************************************************************//\n\n /// @notice The amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens when measured from the specified.\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\n /// @param _projectId The ID of the project to get the reclaimable overflow amount for.\n /// @param _fundingCycle The funding cycle during which reclaimable overflow is being calculated.\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _totalSupply The total supply of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _overflow The amount of overflow to make the calculation with.\n /// @return The amount of overflowed tokens that can be reclaimed.\n function _reclaimableOverflowDuring(\n uint256 _projectId,\n JBFundingCycle memory _fundingCycle,\n uint256 _tokenCount,\n uint256 _totalSupply,\n uint256 _overflow\n ) private view returns (uint256) {\n // If the amount being redeemed is the total supply, return the rest of the overflow.\n if (_tokenCount == _totalSupply) return _overflow;\n\n // Use the ballot redemption rate if the queued cycle is pending approval according to the previous funding cycle's ballot.\n uint256 _redemptionRate = fundingCycleStore.currentBallotStateOf(_projectId) ==\n JBBallotState.Active\n ? _fundingCycle.ballotRedemptionRate()\n : _fundingCycle.redemptionRate();\n\n // If the redemption rate is 0, nothing is claimable.\n if (_redemptionRate == 0) return 0;\n\n // Get a reference to the linear proportion.\n uint256 _base = PRBMath.mulDiv(_overflow, _tokenCount, _totalSupply);\n\n // These conditions are all part of the same curve. Edge conditions are separated because fewer operation are necessary.\n if (_redemptionRate == JBConstants.MAX_REDEMPTION_RATE) return _base;\n\n return\n PRBMath.mulDiv(\n _base,\n _redemptionRate +\n PRBMath.mulDiv(\n _tokenCount,\n JBConstants.MAX_REDEMPTION_RATE - _redemptionRate,\n _totalSupply\n ),\n JBConstants.MAX_REDEMPTION_RATE\n );\n }\n\n /// @notice Gets the amount that is overflowing when measured from the specified funding cycle.\n /// @dev This amount changes as the value of the balance changes in relation to the currency being used to measure the distribution limit.\n /// @param _terminal The terminal for which the overflow is being calculated.\n /// @param _projectId The ID of the project to get overflow for.\n /// @param _fundingCycle The ID of the funding cycle to base the overflow on.\n /// @param _balanceCurrency The currency that the stored balance is expected to be in terms of.\n /// @return overflow The overflow of funds, as a fixed point number with 18 decimals.\n function _overflowDuring(\n IJBSingleTokenPaymentTerminal _terminal,\n uint256 _projectId,\n JBFundingCycle memory _fundingCycle,\n uint256 _balanceCurrency\n ) private view returns (uint256) {\n // Get the current balance of the project.\n uint256 _balanceOf = balanceOf[_terminal][_projectId];\n\n // If there's no balance, there's no overflow.\n if (_balanceOf == 0) return 0;\n\n // Get a reference to the distribution limit during the funding cycle.\n (uint256 _distributionLimit, uint256 _distributionLimitCurrency) = IJBController3_1(\n directory.controllerOf(_projectId)\n ).fundAccessConstraintsStore().distributionLimitOf(\n _projectId,\n _fundingCycle.configuration,\n _terminal,\n _terminal.token()\n );\n\n // Get a reference to the amount still distributable during the funding cycle.\n uint256 _distributionLimitRemaining = _distributionLimit -\n usedDistributionLimitOf[_terminal][_projectId][_fundingCycle.number];\n\n // Convert the _distributionRemaining to be in terms of the provided currency.\n if (_distributionLimitRemaining != 0 && _distributionLimitCurrency != _balanceCurrency)\n _distributionLimitRemaining = PRBMath.mulDiv(\n _distributionLimitRemaining,\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\n prices.priceFor(_distributionLimitCurrency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\n );\n\n // Overflow is the balance of this project minus the amount that can still be distributed.\n unchecked {\n return\n _balanceOf > _distributionLimitRemaining ? _balanceOf - _distributionLimitRemaining : 0;\n }\n }\n\n /// @notice Gets the amount that is currently overflowing across all of a project's terminals.\n /// @dev This amount changes as the value of the balances changes in relation to the currency being used to measure the project's distribution limits.\n /// @param _projectId The ID of the project to get the total overflow for.\n /// @param _decimals The number of decimals that the fixed point overflow should include.\n /// @param _currency The currency that the overflow should be in terms of.\n /// @return overflow The total overflow of a project's funds.\n function _currentTotalOverflowOf(\n uint256 _projectId,\n uint256 _decimals,\n uint256 _currency\n ) private view returns (uint256) {\n // Get a reference to the project's terminals.\n IJBPaymentTerminal[] memory _terminals = directory.terminalsOf(_projectId);\n\n // Keep a reference to the ETH overflow across all terminals, as a fixed point number with 18 decimals.\n uint256 _ethOverflow;\n\n // Add the current ETH overflow for each terminal.\n for (uint256 _i; _i < _terminals.length; ) {\n _ethOverflow = _ethOverflow + _terminals[_i].currentEthOverflowOf(_projectId);\n unchecked {\n ++_i;\n }\n }\n\n // Convert the ETH overflow to the specified currency if needed, maintaining a fixed point number with 18 decimals.\n uint256 _totalOverflow18Decimal = _currency == JBCurrencies.ETH\n ? _ethOverflow\n : PRBMath.mulDiv(_ethOverflow, 10 ** 18, prices.priceFor(JBCurrencies.ETH, _currency, 18));\n\n // Adjust the decimals of the fixed point number if needed to match the target decimals.\n return\n (_decimals == 18)\n ? _totalOverflow18Decimal\n : JBFixedPointNumber.adjustDecimals(_totalOverflow18Decimal, 18, _decimals);\n }\n}\n" + }, + "contracts/interfaces/IJBFundingCycleDataSource3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBPayDelegateAllocation3_1_1} from './../structs/JBPayDelegateAllocation3_1_1.sol';\nimport {JBPayParamsData} from './../structs/JBPayParamsData.sol';\nimport {JBRedeemParamsData} from './../structs/JBRedeemParamsData.sol';\nimport {JBRedemptionDelegateAllocation3_1_1} from './../structs/JBRedemptionDelegateAllocation3_1_1.sol';\n\n/// @title Datasource\n/// @notice The datasource is called by JBPayoutRedemptionPaymentTerminals on pay and redemption, and provide an extra layer of logic to use a custom weight, a custom memo and/or a pay/redeem delegate\ninterface IJBFundingCycleDataSource3_1_1 is IERC165 {\n /// @notice The datasource implementation for JBPaymentTerminal.pay(..)\n /// @param data the data passed to the data source in terminal.pay(..), as a JBPayParamsData struct:\n /// @return weight the weight to use to override the funding cycle weight\n /// @return memo the memo to override the pay(..) memo\n /// @return delegateAllocations The amount to send to delegates instead of adding to the local balance.\n function payParams(\n JBPayParamsData calldata data\n )\n external\n returns (\n uint256 weight,\n string memory memo,\n JBPayDelegateAllocation3_1_1[] memory delegateAllocations\n );\n\n /// @notice The datasource implementation for JBPaymentTerminal.redeemTokensOf(..)\n /// @param data the data passed to the data source in terminal.redeemTokensOf(..), as a JBRedeemParamsData struct:\n /// @return reclaimAmount The amount to claim, overriding the terminal logic.\n /// @return memo The memo to override the redeemTokensOf(..) memo.\n /// @return delegateAllocations The amount to send to delegates instead of adding to the beneficiary.\n function redeemParams(\n JBRedeemParamsData calldata data\n )\n external\n returns (\n uint256 reclaimAmount,\n string memory memo,\n JBRedemptionDelegateAllocation3_1_1[] memory delegateAllocations\n );\n}\n" + }, + "contracts/interfaces/IJBSingleTokenPaymentTerminalStore3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\nimport {JBPayDelegateAllocation3_1_1} from './../structs/JBPayDelegateAllocation3_1_1.sol';\nimport {JBRedemptionDelegateAllocation3_1_1} from './../structs/JBRedemptionDelegateAllocation3_1_1.sol';\nimport {JBTokenAmount} from './../structs/JBTokenAmount.sol';\nimport {IJBDirectory} from './IJBDirectory.sol';\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\nimport {IJBPrices} from './IJBPrices.sol';\nimport {IJBSingleTokenPaymentTerminal} from './IJBSingleTokenPaymentTerminal.sol';\n\ninterface IJBSingleTokenPaymentTerminalStore3_1_1 {\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\n\n function directory() external view returns (IJBDirectory);\n\n function prices() external view returns (IJBPrices);\n\n function balanceOf(\n IJBSingleTokenPaymentTerminal terminal,\n uint256 projectId\n ) external view returns (uint256);\n\n function usedDistributionLimitOf(\n IJBSingleTokenPaymentTerminal terminal,\n uint256 projectId,\n uint256 fundingCycleNumber\n ) external view returns (uint256);\n\n function usedOverflowAllowanceOf(\n IJBSingleTokenPaymentTerminal terminal,\n uint256 projectId,\n uint256 fundingCycleConfiguration\n ) external view returns (uint256);\n\n function currentOverflowOf(\n IJBSingleTokenPaymentTerminal terminal,\n uint256 projectId\n ) external view returns (uint256);\n\n function currentTotalOverflowOf(\n uint256 projectId,\n uint256 decimals,\n uint256 currency\n ) external view returns (uint256);\n\n function currentReclaimableOverflowOf(\n IJBSingleTokenPaymentTerminal terminal,\n uint256 projectId,\n uint256 tokenCount,\n bool useTotalOverflow\n ) external view returns (uint256);\n\n function currentReclaimableOverflowOf(\n uint256 projectId,\n uint256 tokenCount,\n uint256 totalSupply,\n uint256 overflow\n ) external view returns (uint256);\n\n function recordPaymentFrom(\n address payer,\n JBTokenAmount memory amount,\n uint256 projectId,\n uint256 baseWeightCurrency,\n address beneficiary,\n string calldata inputMemo,\n bytes calldata metadata\n )\n external\n returns (\n JBFundingCycle memory fundingCycle,\n uint256 tokenCount,\n JBPayDelegateAllocation3_1_1[] memory delegateAllocations,\n string memory outputMemo\n );\n\n function recordRedemptionFor(\n address holder,\n uint256 projectId,\n uint256 tokenCount,\n string calldata inputMemo,\n bytes calldata metadata\n )\n external\n returns (\n JBFundingCycle memory fundingCycle,\n uint256 reclaimAmount,\n JBRedemptionDelegateAllocation3_1_1[] memory delegateAllocations,\n string memory outputMemo\n );\n\n function recordDistributionFor(\n uint256 projectId,\n uint256 amount,\n uint256 currency\n ) external returns (JBFundingCycle memory fundingCycle, uint256 distributedAmount);\n\n function recordUsedAllowanceOf(\n uint256 projectId,\n uint256 amount,\n uint256 currency\n ) external returns (JBFundingCycle memory fundingCycle, uint256 withdrawnAmount);\n\n function recordAddedBalanceFor(uint256 projectId, uint256 amount) external;\n\n function recordMigration(uint256 projectId) external returns (uint256 balance);\n}\n" + }, + "contracts/structs/JBPayDelegateAllocation3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBPayDelegate3_1_1} from '../interfaces/IJBPayDelegate3_1_1.sol';\n\n/// @custom:member delegate A delegate contract to use for subsequent calls.\n/// @custom:member amount The amount to send to the delegate.\n/// @custom:member metadata Metadata to pass the delegate.\nstruct JBPayDelegateAllocation3_1_1 {\n IJBPayDelegate3_1_1 delegate;\n uint256 amount;\n bytes metadata;\n}\n" + }, + "contracts/structs/JBRedemptionDelegateAllocation3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBRedemptionDelegate3_1_1} from '../interfaces/IJBRedemptionDelegate3_1_1.sol';\n\n/// @custom:member delegate A delegate contract to use for subsequent calls.\n/// @custom:member amount The amount to send to the delegate.\n/// @custom:member metadata Metadata to pass the delegate.\nstruct JBRedemptionDelegateAllocation3_1_1 {\n IJBRedemptionDelegate3_1_1 delegate;\n uint256 amount;\n bytes metadata;\n}\n" + }, + "contracts/interfaces/IJBPayDelegate3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBDidPayData3_1_1} from './../structs/JBDidPayData3_1_1.sol';\n\n/// @title Pay delegate\n/// @notice Delegate called after JBTerminal.pay(..) logic completion (if passed by the funding cycle datasource)\ninterface IJBPayDelegate3_1_1 is IERC165 {\n /// @notice This function is called by JBPaymentTerminal.pay(..), after the execution of its logic\n /// @dev Critical business logic should be protected by an appropriate access control\n /// @param data the data passed by the terminal, as a JBDidPayData3_1_1 struct:\n function didPay(JBDidPayData3_1_1 calldata data) external payable;\n}\n" + }, + "contracts/structs/JBDidPayData3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBTokenAmount} from './JBTokenAmount.sol';\n\n/// @custom:member payer The address from which the payment originated.\n/// @custom:member projectId The ID of the project for which the payment was made.\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the payment is being made.\n/// @custom:member amount The amount of the payment. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\n/// @custom:member forwardedAmount The amount of the payment that is being sent to the delegate. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\n/// @custom:member projectTokenCount The number of project tokens minted for the beneficiary.\n/// @custom:member beneficiary The address to which the tokens were minted.\n/// @custom:member preferClaimedTokens A flag indicating whether the request prefered to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract.\n/// @custom:member memo The memo that is being emitted alongside the payment.\n/// @custom:member dataSourceMetadata Extra data to send to the delegate sent by the data source.\n/// @custom:member payerMetadata Extra data to send to the delegate sent by the payer.\nstruct JBDidPayData3_1_1 {\n address payer;\n uint256 projectId;\n uint256 currentFundingCycleConfiguration;\n JBTokenAmount amount;\n JBTokenAmount forwardedAmount;\n uint256 projectTokenCount;\n address beneficiary;\n bool preferClaimedTokens;\n string memo;\n bytes dataSourceMetadata;\n bytes payerMetadata;\n}\n" + }, + "contracts/interfaces/IJBRedemptionDelegate3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBDidRedeemData3_1_1} from './../structs/JBDidRedeemData3_1_1.sol';\n\n/// @title Redemption delegate\n/// @notice Delegate called after JBTerminal.redeemTokensOf(..) logic completion (if passed by the funding cycle datasource)\ninterface IJBRedemptionDelegate3_1_1 is IERC165 {\n /// @notice This function is called by JBPaymentTerminal.redeemTokensOf(..), after the execution of its logic\n /// @dev Critical business logic should be protected by an appropriate access control\n /// @param data the data passed by the terminal, as a JBDidRedeemData struct:\n function didRedeem(JBDidRedeemData3_1_1 calldata data) external payable;\n}\n" + }, + "contracts/structs/JBDidRedeemData3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBTokenAmount} from './JBTokenAmount.sol';\n\n/// @custom:member holder The holder of the tokens being redeemed.\n/// @custom:member projectId The ID of the project with which the redeemed tokens are associated.\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the redemption is being made.\n/// @custom:member projectTokenCount The number of project tokens being redeemed.\n/// @custom:member reclaimedAmount The amount reclaimed from the treasury. Includes the token being reclaimed, the value, the number of decimals included, and the currency of the amount.\n/// @custom:member forwardedAmount The amount of the payment that is being sent to the delegate. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\n/// @custom:member beneficiary The address to which the reclaimed amount will be sent.\n/// @custom:member memo The memo that is being emitted alongside the redemption.\n/// @custom:member dataSourceMetadata Extra data to send to the delegate sent by the data source.\n/// @custom:member redeemerMetadata Extra data to send to the delegate sent by the redeemer.\nstruct JBDidRedeemData3_1_1 {\n address holder;\n uint256 projectId;\n uint256 currentFundingCycleConfiguration;\n uint256 projectTokenCount;\n JBTokenAmount reclaimedAmount;\n JBTokenAmount forwardedAmount;\n address payable beneficiary;\n string memo;\n bytes dataSourceMetadata;\n bytes redeemerMetadata;\n}\n" + }, + "contracts/JBSingleTokenPaymentTerminalStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {ReentrancyGuard} from '@openzeppelin/contracts/security/ReentrancyGuard.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {JBBallotState} from './enums/JBBallotState.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBController} from './interfaces/IJBController.sol';\nimport {IJBFundingCycleDataSource} from './interfaces/IJBFundingCycleDataSource.sol';\nimport {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol';\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\nimport {IJBSingleTokenPaymentTerminal} from './interfaces/IJBSingleTokenPaymentTerminal.sol';\nimport {IJBSingleTokenPaymentTerminalStore} from './interfaces/IJBSingleTokenPaymentTerminalStore.sol';\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\nimport {JBConstants} from './libraries/JBConstants.sol';\nimport {JBCurrencies} from './libraries/JBCurrencies.sol';\nimport {JBFixedPointNumber} from './libraries/JBFixedPointNumber.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\nimport {JBFundingCycleMetadataResolver} from './libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBPayDelegateAllocation} from './structs/JBPayDelegateAllocation.sol';\nimport {JBPayParamsData} from './structs/JBPayParamsData.sol';\nimport {JBRedeemParamsData} from './structs/JBRedeemParamsData.sol';\nimport {JBRedemptionDelegateAllocation} from './structs/JBRedemptionDelegateAllocation.sol';\nimport {JBTokenAmount} from './structs/JBTokenAmount.sol';\n\n/// @notice Manages all bookkeeping for inflows and outflows of funds from any ISingleTokenPaymentTerminal.\ncontract JBSingleTokenPaymentTerminalStore is ReentrancyGuard, IJBSingleTokenPaymentTerminalStore {\n // A library that parses the packed funding cycle metadata into a friendlier format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error INVALID_AMOUNT_TO_SEND_DELEGATE();\n error CURRENCY_MISMATCH();\n error DISTRIBUTION_AMOUNT_LIMIT_REACHED();\n error FUNDING_CYCLE_PAYMENT_PAUSED();\n error FUNDING_CYCLE_DISTRIBUTION_PAUSED();\n error FUNDING_CYCLE_REDEEM_PAUSED();\n error INADEQUATE_CONTROLLER_ALLOWANCE();\n error INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n error INSUFFICIENT_TOKENS();\n error INVALID_FUNDING_CYCLE();\n error PAYMENT_TERMINAL_MIGRATION_NOT_ALLOWED();\n\n //*********************************************************************//\n // -------------------------- private constants ---------------------- //\n //*********************************************************************//\n\n /// @notice Ensures a maximum number of decimal points of persisted fidelity on mulDiv operations of fixed point numbers.\n uint256 private constant _MAX_FIXED_POINT_FIDELITY = 18;\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n /// @notice The contract storing all funding cycle configurations.\n IJBFundingCycleStore public immutable override fundingCycleStore;\n\n /// @notice The contract that exposes price feeds.\n IJBPrices public immutable override prices;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The amount of tokens that each project has for each terminal, in terms of the terminal's token.\n /// @dev The used distribution limit is represented as a fixed point number with the same amount of decimals as its relative terminal.\n /// @custom:param _terminal The terminal to which the balance applies.\n /// @custom:param _projectId The ID of the project to get the balance of.\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => uint256)) public override balanceOf;\n\n /// @notice The amount of funds that a project has distributed from its limit during the current funding cycle for each terminal, in terms of the distribution limit's currency.\n /// @dev Increases as projects use their preconfigured distribution limits.\n /// @dev The used distribution limit is represented as a fixed point number with the same amount of decimals as its relative terminal.\n /// @custom:param _terminal The terminal to which the used distribution limit applies.\n /// @custom:param _projectId The ID of the project to get the used distribution limit of.\n /// @custom:param _fundingCycleNumber The number of the funding cycle during which the distribution limit was used.\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => mapping(uint256 => uint256)))\n public\n override usedDistributionLimitOf;\n\n /// @notice The amount of funds that a project has used from its allowance during the current funding cycle configuration for each terminal, in terms of the overflow allowance's currency.\n /// @dev Increases as projects use their allowance.\n /// @dev The used allowance is represented as a fixed point number with the same amount of decimals as its relative terminal.\n /// @custom:param _terminal The terminal to which the overflow allowance applies.\n /// @custom:param _projectId The ID of the project to get the used overflow allowance of.\n /// @custom:param _configuration The configuration of the during which the allowance was used.\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => mapping(uint256 => uint256)))\n public\n override usedOverflowAllowanceOf;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Gets the current overflowed amount in a terminal for a specified project.\n /// @dev The current overflow is represented as a fixed point number with the same amount of decimals as the specified terminal.\n /// @param _terminal The terminal for which the overflow is being calculated.\n /// @param _projectId The ID of the project to get overflow for.\n /// @return The current amount of overflow that project has in the specified terminal.\n function currentOverflowOf(\n IJBSingleTokenPaymentTerminal _terminal,\n uint256 _projectId\n ) external view override returns (uint256) {\n // Return the overflow during the project's current funding cycle.\n return\n _overflowDuring(\n _terminal,\n _projectId,\n fundingCycleStore.currentOf(_projectId),\n _terminal.currency()\n );\n }\n\n /// @notice Gets the current overflowed amount for a specified project across all terminals.\n /// @param _projectId The ID of the project to get total overflow for.\n /// @param _decimals The number of decimals that the fixed point overflow should include.\n /// @param _currency The currency that the total overflow should be in terms of.\n /// @return The current total amount of overflow that project has across all terminals.\n function currentTotalOverflowOf(\n uint256 _projectId,\n uint256 _decimals,\n uint256 _currency\n ) external view override returns (uint256) {\n return _currentTotalOverflowOf(_projectId, _decimals, _currency);\n }\n\n /// @notice The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the total token supply and overflow in the ecosystem.\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\n /// @dev The current reclaimable overflow is returned in terms of the specified terminal's currency.\n /// @dev The reclaimable overflow is represented as a fixed point number with the same amount of decimals as the specified terminal.\n /// @param _terminal The terminal from which the reclaimable amount would come.\n /// @param _projectId The ID of the project to get the reclaimable overflow amount for.\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _useTotalOverflow A flag indicating whether the overflow used in the calculation should be summed from all of the project's terminals. If false, overflow should be limited to the amount in the specified `_terminal`.\n /// @return The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_terminal`.\n function currentReclaimableOverflowOf(\n IJBSingleTokenPaymentTerminal _terminal,\n uint256 _projectId,\n uint256 _tokenCount,\n bool _useTotalOverflow\n ) external view override returns (uint256) {\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Get the amount of current overflow.\n // Use the project's total overflow across all of its terminals if the flag species specifies so. Otherwise, use the overflow local to the specified terminal.\n uint256 _currentOverflow = _useTotalOverflow\n ? _currentTotalOverflowOf(_projectId, _terminal.decimals(), _terminal.currency())\n : _overflowDuring(_terminal, _projectId, _fundingCycle, _terminal.currency());\n\n // If there's no overflow, there's no reclaimable overflow.\n if (_currentOverflow == 0) return 0;\n\n // Get the number of outstanding tokens the project has.\n uint256 _totalSupply = IJBController(directory.controllerOf(_projectId))\n .totalOutstandingTokensOf(_projectId, _fundingCycle.reservedRate());\n\n // Can't redeem more tokens that is in the supply.\n if (_tokenCount > _totalSupply) return 0;\n\n // Return the reclaimable overflow amount.\n return\n _reclaimableOverflowDuring(\n _projectId,\n _fundingCycle,\n _tokenCount,\n _totalSupply,\n _currentOverflow\n );\n }\n\n /// @notice The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the specified total token supply and overflow amounts.\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\n /// @param _projectId The ID of the project for which the reclaimable overflow applies.\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _totalSupply The total number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _overflow The amount of overflow to make the calculation with, as a fixed point number.\n /// @return The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_overflow`.\n function currentReclaimableOverflowOf(\n uint256 _projectId,\n uint256 _tokenCount,\n uint256 _totalSupply,\n uint256 _overflow\n ) external view override returns (uint256) {\n // If there's no overflow, there's no reclaimable overflow.\n if (_overflow == 0) return 0;\n\n // Can't redeem more tokens that is in the supply.\n if (_tokenCount > _totalSupply) return 0;\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Return the reclaimable overflow amount.\n return\n _reclaimableOverflowDuring(_projectId, _fundingCycle, _tokenCount, _totalSupply, _overflow);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _fundingCycleStore A contract storing all funding cycle configurations.\n /// @param _prices A contract that exposes price feeds.\n constructor(IJBDirectory _directory, IJBFundingCycleStore _fundingCycleStore, IJBPrices _prices) {\n directory = _directory;\n fundingCycleStore = _fundingCycleStore;\n prices = _prices;\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Records newly contributed tokens to a project.\n /// @dev Mints the project's tokens according to values provided by a configured data source. If no data source is configured, mints tokens proportional to the amount of the contribution.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.sender's tokens.\n /// @param _payer The original address that sent the payment to the terminal.\n /// @param _amount The amount of tokens being paid. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\n /// @param _projectId The ID of the project being paid.\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _beneficiary The specified address that should be the beneficiary of anything that results from the payment.\n /// @param _memo A memo to pass along to the emitted event, and passed along to the funding cycle's data source.\n /// @param _metadata Bytes to send along to the data source, if one is provided.\n /// @return fundingCycle The project's funding cycle during which payment was made.\n /// @return tokenCount The number of project tokens that were minted, as a fixed point number with 18 decimals.\n /// @return delegateAllocations The amount to send to delegates instead of adding to the local balance.\n /// @return memo A memo that should be passed along to the emitted event.\n function recordPaymentFrom(\n address _payer,\n JBTokenAmount calldata _amount,\n uint256 _projectId,\n uint256 _baseWeightCurrency,\n address _beneficiary,\n string calldata _memo,\n bytes memory _metadata\n )\n external\n override\n nonReentrant\n returns (\n JBFundingCycle memory fundingCycle,\n uint256 tokenCount,\n JBPayDelegateAllocation[] memory delegateAllocations,\n string memory memo\n )\n {\n // Get a reference to the current funding cycle for the project.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // The project must have a funding cycle configured.\n if (fundingCycle.number == 0) revert INVALID_FUNDING_CYCLE();\n\n // Must not be paused.\n if (fundingCycle.payPaused()) revert FUNDING_CYCLE_PAYMENT_PAUSED();\n\n // The weight according to which new token supply is to be minted, as a fixed point number with 18 decimals.\n uint256 _weight;\n\n // If the funding cycle has configured a data source, use it to derive a weight and memo.\n if (fundingCycle.useDataSourceForPay() && fundingCycle.dataSource() != address(0)) {\n // Create the params that'll be sent to the data source.\n JBPayParamsData memory _data = JBPayParamsData(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _payer,\n _amount,\n _projectId,\n fundingCycle.configuration,\n _beneficiary,\n fundingCycle.weight,\n fundingCycle.reservedRate(),\n _memo,\n _metadata\n );\n (_weight, memo, delegateAllocations) = IJBFundingCycleDataSource(fundingCycle.dataSource())\n .payParams(_data);\n }\n // Otherwise use the funding cycle's weight\n else {\n _weight = fundingCycle.weight;\n memo = _memo;\n }\n\n // Scoped section prevents stack too deep. `_balanceDiff` only used within scope.\n {\n // Keep a reference to the amount that should be added to the project's balance.\n uint256 _balanceDiff = _amount.value;\n\n // Validate all delegated amounts. This needs to be done before returning the delegate allocations to ensure valid delegated amounts.\n if (delegateAllocations.length != 0) {\n for (uint256 _i; _i < delegateAllocations.length; ) {\n // Get a reference to the amount to be delegated.\n uint256 _delegatedAmount = delegateAllocations[_i].amount;\n\n // Validate if non-zero.\n if (_delegatedAmount != 0) {\n // Can't delegate more than was paid.\n if (_delegatedAmount > _balanceDiff) revert INVALID_AMOUNT_TO_SEND_DELEGATE();\n\n // Decrement the total amount being added to the balance.\n _balanceDiff = _balanceDiff - _delegatedAmount;\n }\n\n unchecked {\n ++_i;\n }\n }\n }\n\n // If there's no amount being recorded, there's nothing left to do.\n if (_amount.value == 0) return (fundingCycle, 0, delegateAllocations, memo);\n\n // Add the correct balance difference to the token balance of the project.\n if (_balanceDiff != 0)\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] +\n _balanceDiff;\n }\n\n // If there's no weight, token count must be 0 so there's nothing left to do.\n if (_weight == 0) return (fundingCycle, 0, delegateAllocations, memo);\n\n // Get a reference to the number of decimals in the amount. (prevents stack too deep).\n uint256 _decimals = _amount.decimals;\n\n // If the terminal should base its weight on a different currency from the terminal's currency, determine the factor.\n // The weight is always a fixed point mumber with 18 decimals. To ensure this, the ratio should use the same number of decimals as the `_amount`.\n uint256 _weightRatio = _amount.currency == _baseWeightCurrency\n ? 10 ** _decimals\n : prices.priceFor(_amount.currency, _baseWeightCurrency, _decimals);\n\n // Find the number of tokens to mint, as a fixed point number with as many decimals as `weight` has.\n tokenCount = PRBMath.mulDiv(_amount.value, _weight, _weightRatio);\n }\n\n /// @notice Records newly redeemed tokens of a project.\n /// @dev Redeems the project's tokens according to values provided by a configured data source. If no data source is configured, redeems tokens along a redemption bonding curve that is a function of the number of tokens being burned.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.senders tokens.\n /// @param _holder The account that is having its tokens redeemed.\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\n /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the data source, if one is provided.\n /// @return fundingCycle The funding cycle during which the redemption was made.\n /// @return reclaimAmount The amount of terminal tokens reclaimed, as a fixed point number with 18 decimals.\n /// @return delegateAllocations The amount to send to delegates instead of sending to the beneficiary.\n /// @return memo A memo that should be passed along to the emitted event.\n function recordRedemptionFor(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n string memory _memo,\n bytes memory _metadata\n )\n external\n override\n nonReentrant\n returns (\n JBFundingCycle memory fundingCycle,\n uint256 reclaimAmount,\n JBRedemptionDelegateAllocation[] memory delegateAllocations,\n string memory memo\n )\n {\n // Get a reference to the project's current funding cycle.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // The current funding cycle must not be paused.\n if (fundingCycle.redeemPaused()) revert FUNDING_CYCLE_REDEEM_PAUSED();\n\n // Scoped section prevents stack too deep. `_reclaimedTokenAmount`, `_currentOverflow`, and `_totalSupply` only used within scope.\n {\n // Get a reference to the reclaimed token amount struct, the current overflow, and the total token supply.\n JBTokenAmount memory _reclaimedTokenAmount;\n uint256 _currentOverflow;\n uint256 _totalSupply;\n\n // Another scoped section prevents stack too deep. `_token`, `_decimals`, and `_currency` only used within scope.\n {\n // Get a reference to the terminal's tokens.\n address _token = IJBSingleTokenPaymentTerminal(msg.sender).token();\n\n // Get a reference to the terminal's decimals.\n uint256 _decimals = IJBSingleTokenPaymentTerminal(msg.sender).decimals();\n\n // Get areference to the terminal's currency.\n uint256 _currency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\n\n // Get the amount of current overflow.\n // Use the local overflow if the funding cycle specifies that it should be used. Otherwise, use the project's total overflow across all of its terminals.\n _currentOverflow = fundingCycle.useTotalOverflowForRedemptions()\n ? _currentTotalOverflowOf(_projectId, _decimals, _currency)\n : _overflowDuring(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _projectId,\n fundingCycle,\n _currency\n );\n\n // Get the number of outstanding tokens the project has.\n _totalSupply = IJBController(directory.controllerOf(_projectId)).totalOutstandingTokensOf(\n _projectId,\n fundingCycle.reservedRate()\n );\n\n // Can't redeem more tokens that is in the supply.\n if (_tokenCount > _totalSupply) revert INSUFFICIENT_TOKENS();\n\n if (_currentOverflow != 0)\n // Calculate reclaim amount using the current overflow amount.\n reclaimAmount = _reclaimableOverflowDuring(\n _projectId,\n fundingCycle,\n _tokenCount,\n _totalSupply,\n _currentOverflow\n );\n\n _reclaimedTokenAmount = JBTokenAmount(_token, reclaimAmount, _decimals, _currency);\n }\n\n // If the funding cycle has configured a data source, use it to derive a claim amount and memo.\n if (fundingCycle.useDataSourceForRedeem() && fundingCycle.dataSource() != address(0)) {\n // Yet another scoped section prevents stack too deep. `_state` only used within scope.\n {\n // Get a reference to the ballot state.\n JBBallotState _state = fundingCycleStore.currentBallotStateOf(_projectId);\n\n // Create the params that'll be sent to the data source.\n JBRedeemParamsData memory _data = JBRedeemParamsData(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _holder,\n _projectId,\n fundingCycle.configuration,\n _tokenCount,\n _totalSupply,\n _currentOverflow,\n _reclaimedTokenAmount,\n fundingCycle.useTotalOverflowForRedemptions(),\n _state == JBBallotState.Active\n ? fundingCycle.ballotRedemptionRate()\n : fundingCycle.redemptionRate(),\n _memo,\n _metadata\n );\n (reclaimAmount, memo, delegateAllocations) = IJBFundingCycleDataSource(\n fundingCycle.dataSource()\n ).redeemParams(_data);\n }\n } else {\n memo = _memo;\n }\n }\n\n // Keep a reference to the amount that should be subtracted from the project's balance.\n uint256 _balanceDiff = reclaimAmount;\n\n if (delegateAllocations.length != 0) {\n // Validate all delegated amounts.\n for (uint256 _i; _i < delegateAllocations.length; ) {\n // Get a reference to the amount to be delegated.\n uint256 _delegatedAmount = delegateAllocations[_i].amount;\n\n // Validate if non-zero.\n if (_delegatedAmount != 0)\n // Increment the total amount being subtracted from the balance.\n _balanceDiff = _balanceDiff + _delegatedAmount;\n\n unchecked {\n ++_i;\n }\n }\n }\n\n // The amount being reclaimed must be within the project's balance.\n if (_balanceDiff > balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId])\n revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n\n // Remove the reclaimed funds from the project's balance.\n if (_balanceDiff != 0) {\n unchecked {\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\n _balanceDiff;\n }\n }\n }\n\n /// @notice Records newly distributed funds for a project.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\n /// @param _projectId The ID of the project that is having funds distributed.\n /// @param _amount The amount to use from the distribution limit, as a fixed point number.\n /// @param _currency The currency of the `_amount`. This must match the project's current funding cycle's currency.\n /// @return fundingCycle The funding cycle during which the distribution was made.\n /// @return distributedAmount The amount of terminal tokens distributed, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordDistributionFor(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency\n )\n external\n override\n nonReentrant\n returns (JBFundingCycle memory fundingCycle, uint256 distributedAmount)\n {\n // Get a reference to the project's current funding cycle.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // The funding cycle must not be configured to have distributions paused.\n if (fundingCycle.distributionsPaused()) revert FUNDING_CYCLE_DISTRIBUTION_PAUSED();\n\n // The new total amount that has been distributed during this funding cycle.\n uint256 _newUsedDistributionLimitOf = usedDistributionLimitOf[\n IJBSingleTokenPaymentTerminal(msg.sender)\n ][_projectId][fundingCycle.number] + _amount;\n\n // Amount must be within what is still distributable.\n (uint256 _distributionLimitOf, uint256 _distributionLimitCurrencyOf) = IJBController(\n directory.controllerOf(_projectId)\n ).distributionLimitOf(\n _projectId,\n fundingCycle.configuration,\n IJBSingleTokenPaymentTerminal(msg.sender),\n IJBSingleTokenPaymentTerminal(msg.sender).token()\n );\n\n // Make sure the new used amount is within the distribution limit.\n if (_newUsedDistributionLimitOf > _distributionLimitOf || _distributionLimitOf == 0)\n revert DISTRIBUTION_AMOUNT_LIMIT_REACHED();\n\n // Make sure the currencies match.\n if (_currency != _distributionLimitCurrencyOf) revert CURRENCY_MISMATCH();\n\n // Get a reference to the terminal's currency.\n uint256 _balanceCurrency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\n\n // Convert the amount to the balance's currency.\n distributedAmount = (_currency == _balanceCurrency)\n ? _amount\n : PRBMath.mulDiv(\n _amount,\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\n prices.priceFor(_currency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\n );\n\n // The amount being distributed must be available.\n if (distributedAmount > balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId])\n revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n\n // Store the new amount.\n usedDistributionLimitOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId][\n fundingCycle.number\n ] = _newUsedDistributionLimitOf;\n\n // Removed the distributed funds from the project's token balance.\n unchecked {\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\n distributedAmount;\n }\n }\n\n /// @notice Records newly used allowance funds of a project.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\n /// @param _projectId The ID of the project to use the allowance of.\n /// @param _amount The amount to use from the allowance, as a fixed point number.\n /// @param _currency The currency of the `_amount`. Must match the currency of the overflow allowance.\n /// @return fundingCycle The funding cycle during which the overflow allowance is being used.\n /// @return usedAmount The amount of terminal tokens used, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordUsedAllowanceOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency\n )\n external\n override\n nonReentrant\n returns (JBFundingCycle memory fundingCycle, uint256 usedAmount)\n {\n // Get a reference to the project's current funding cycle.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Get a reference to the new used overflow allowance for this funding cycle configuration.\n uint256 _newUsedOverflowAllowanceOf = usedOverflowAllowanceOf[\n IJBSingleTokenPaymentTerminal(msg.sender)\n ][_projectId][fundingCycle.configuration] + _amount;\n\n // There must be sufficient allowance available.\n (uint256 _overflowAllowanceOf, uint256 _overflowAllowanceCurrency) = IJBController(\n directory.controllerOf(_projectId)\n ).overflowAllowanceOf(\n _projectId,\n fundingCycle.configuration,\n IJBSingleTokenPaymentTerminal(msg.sender),\n IJBSingleTokenPaymentTerminal(msg.sender).token()\n );\n\n // Make sure the new used amount is within the allowance.\n if (_newUsedOverflowAllowanceOf > _overflowAllowanceOf || _overflowAllowanceOf == 0)\n revert INADEQUATE_CONTROLLER_ALLOWANCE();\n\n // Make sure the currencies match.\n if (_currency != _overflowAllowanceCurrency) revert CURRENCY_MISMATCH();\n\n // Get a reference to the terminal's currency.\n uint256 _balanceCurrency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\n\n // Convert the amount to this store's terminal's token.\n usedAmount = (_currency == _balanceCurrency)\n ? _amount\n : PRBMath.mulDiv(\n _amount,\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\n prices.priceFor(_currency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\n );\n\n // The amount being distributed must be available in the overflow.\n if (\n usedAmount >\n _overflowDuring(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _projectId,\n fundingCycle,\n _balanceCurrency\n )\n ) revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n\n // Store the incremented value.\n usedOverflowAllowanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId][\n fundingCycle.configuration\n ] = _newUsedOverflowAllowanceOf;\n\n // Update the project's balance.\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\n usedAmount;\n }\n\n /// @notice Records newly added funds for the project.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\n /// @param _projectId The ID of the project to which the funds being added belong.\n /// @param _amount The amount of terminal tokens added, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordAddedBalanceFor(uint256 _projectId, uint256 _amount) external override {\n // Increment the balance.\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] +\n _amount;\n }\n\n /// @notice Records the migration of funds from this store.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount returned is in terms of the msg.senders tokens.\n /// @param _projectId The ID of the project being migrated.\n /// @return balance The project's migrated balance, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordMigration(\n uint256 _projectId\n ) external override nonReentrant returns (uint256 balance) {\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Migration must be allowed.\n if (!_fundingCycle.terminalMigrationAllowed()) revert PAYMENT_TERMINAL_MIGRATION_NOT_ALLOWED();\n\n // Return the current balance.\n balance = balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId];\n\n // Set the balance to 0.\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] = 0;\n }\n\n //*********************************************************************//\n // --------------------- private helper functions -------------------- //\n //*********************************************************************//\n\n /// @notice The amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens when measured from the specified.\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\n /// @param _projectId The ID of the project to get the reclaimable overflow amount for.\n /// @param _fundingCycle The funding cycle during which reclaimable overflow is being calculated.\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _totalSupply The total supply of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _overflow The amount of overflow to make the calculation with.\n /// @return The amount of overflowed tokens that can be reclaimed.\n function _reclaimableOverflowDuring(\n uint256 _projectId,\n JBFundingCycle memory _fundingCycle,\n uint256 _tokenCount,\n uint256 _totalSupply,\n uint256 _overflow\n ) private view returns (uint256) {\n // If the amount being redeemed is the total supply, return the rest of the overflow.\n if (_tokenCount == _totalSupply) return _overflow;\n\n // Use the ballot redemption rate if the queued cycle is pending approval according to the previous funding cycle's ballot.\n uint256 _redemptionRate = fundingCycleStore.currentBallotStateOf(_projectId) ==\n JBBallotState.Active\n ? _fundingCycle.ballotRedemptionRate()\n : _fundingCycle.redemptionRate();\n\n // If the redemption rate is 0, nothing is claimable.\n if (_redemptionRate == 0) return 0;\n\n // Get a reference to the linear proportion.\n uint256 _base = PRBMath.mulDiv(_overflow, _tokenCount, _totalSupply);\n\n // These conditions are all part of the same curve. Edge conditions are separated because fewer operation are necessary.\n if (_redemptionRate == JBConstants.MAX_REDEMPTION_RATE) return _base;\n\n return\n PRBMath.mulDiv(\n _base,\n _redemptionRate +\n PRBMath.mulDiv(\n _tokenCount,\n JBConstants.MAX_REDEMPTION_RATE - _redemptionRate,\n _totalSupply\n ),\n JBConstants.MAX_REDEMPTION_RATE\n );\n }\n\n /// @notice Gets the amount that is overflowing when measured from the specified funding cycle.\n /// @dev This amount changes as the value of the balance changes in relation to the currency being used to measure the distribution limit.\n /// @param _terminal The terminal for which the overflow is being calculated.\n /// @param _projectId The ID of the project to get overflow for.\n /// @param _fundingCycle The ID of the funding cycle to base the overflow on.\n /// @param _balanceCurrency The currency that the stored balance is expected to be in terms of.\n /// @return overflow The overflow of funds, as a fixed point number with 18 decimals.\n function _overflowDuring(\n IJBSingleTokenPaymentTerminal _terminal,\n uint256 _projectId,\n JBFundingCycle memory _fundingCycle,\n uint256 _balanceCurrency\n ) private view returns (uint256) {\n // Get the current balance of the project.\n uint256 _balanceOf = balanceOf[_terminal][_projectId];\n\n // If there's no balance, there's no overflow.\n if (_balanceOf == 0) return 0;\n\n // Get a reference to the distribution limit during the funding cycle.\n (uint256 _distributionLimit, uint256 _distributionLimitCurrency) = IJBController(\n directory.controllerOf(_projectId)\n ).distributionLimitOf(_projectId, _fundingCycle.configuration, _terminal, _terminal.token());\n\n // Get a reference to the amount still distributable during the funding cycle.\n uint256 _distributionLimitRemaining = _distributionLimit -\n usedDistributionLimitOf[_terminal][_projectId][_fundingCycle.number];\n\n // Convert the _distributionRemaining to be in terms of the provided currency.\n if (_distributionLimitRemaining != 0 && _distributionLimitCurrency != _balanceCurrency)\n _distributionLimitRemaining = PRBMath.mulDiv(\n _distributionLimitRemaining,\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\n prices.priceFor(_distributionLimitCurrency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\n );\n\n // Overflow is the balance of this project minus the amount that can still be distributed.\n unchecked {\n return\n _balanceOf > _distributionLimitRemaining ? _balanceOf - _distributionLimitRemaining : 0;\n }\n }\n\n /// @notice Gets the amount that is currently overflowing across all of a project's terminals.\n /// @dev This amount changes as the value of the balances changes in relation to the currency being used to measure the project's distribution limits.\n /// @param _projectId The ID of the project to get the total overflow for.\n /// @param _decimals The number of decimals that the fixed point overflow should include.\n /// @param _currency The currency that the overflow should be in terms of.\n /// @return overflow The total overflow of a project's funds.\n function _currentTotalOverflowOf(\n uint256 _projectId,\n uint256 _decimals,\n uint256 _currency\n ) private view returns (uint256) {\n // Get a reference to the project's terminals.\n IJBPaymentTerminal[] memory _terminals = directory.terminalsOf(_projectId);\n\n // Keep a reference to the ETH overflow across all terminals, as a fixed point number with 18 decimals.\n uint256 _ethOverflow;\n\n // Add the current ETH overflow for each terminal.\n for (uint256 _i; _i < _terminals.length; ) {\n _ethOverflow = _ethOverflow + _terminals[_i].currentEthOverflowOf(_projectId);\n unchecked {\n ++_i;\n }\n }\n\n // Convert the ETH overflow to the specified currency if needed, maintaining a fixed point number with 18 decimals.\n uint256 _totalOverflow18Decimal = _currency == JBCurrencies.ETH\n ? _ethOverflow\n : PRBMath.mulDiv(_ethOverflow, 10 ** 18, prices.priceFor(JBCurrencies.ETH, _currency, 18));\n\n // Adjust the decimals of the fixed point number if needed to match the target decimals.\n return\n (_decimals == 18)\n ? _totalOverflow18Decimal\n : JBFixedPointNumber.adjustDecimals(_totalOverflow18Decimal, 18, _decimals);\n }\n}\n" + }, + "contracts/JBMigrationOperator.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {IJBController} from './interfaces/IJBController.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBMigratable} from './interfaces/IJBMigratable.sol';\nimport {IJBPayoutRedemptionPaymentTerminal} from './interfaces/IJBPayoutRedemptionPaymentTerminal.sol';\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\n\n/// @notice Allows projects to migrate their controller & terminal to 3.1 version\ncontract JBMigrationOperator {\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error UNAUTHORIZED();\n\n //*********************************************************************//\n // --------------- public immutable stored properties ---------------- //\n //*********************************************************************//\n\n /// @notice directory instance which keeps a track of which controller is linked to which project.\n IJBDirectory public immutable directory;\n\n /// @notice The NFT granting ownership to a Juicebox project\n IJBProjects public immutable projects;\n\n //*********************************************************************//\n // ---------------------------- constructor -------------------------- //\n //*********************************************************************//\n\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n constructor(IJBDirectory _directory) {\n directory = _directory;\n projects = IJBProjects(_directory.projects());\n }\n\n //*********************************************************************//\n // --------------------- external transactions ----------------------- //\n //*********************************************************************//\n\n /// @notice Allows project owners to migrate the controller & terminal linked to their project to the latest version.\n /// @param _projectId The project id whose controller & terminal are to be migrated\n /// @param _newController Controller 3.1 address to migrate to.\n /// @param _newJbTerminal Terminal 3.1 address to migrate to.\n /// @param _oldJbTerminal Old terminal address to migrate from.\n function migrate(\n uint256 _projectId,\n IJBMigratable _newController,\n IJBPaymentTerminal _newJbTerminal,\n IJBPayoutRedemptionPaymentTerminal _oldJbTerminal\n ) external {\n // Only allow the project owner to migrate\n if (projects.ownerOf(_projectId) != msg.sender) revert UNAUTHORIZED();\n\n // controller migration\n address _oldController = directory.controllerOf(_projectId);\n\n // assuming the project owner has reconfigured the funding cycle with allowControllerMigration\n IJBController(_oldController).migrate(_projectId, _newController);\n\n // terminal migration\n IJBPaymentTerminal[] memory _newTerminals = new IJBPaymentTerminal[](1);\n _newTerminals[0] = IJBPaymentTerminal(address(_newJbTerminal));\n\n // assuming the project owner has reconfigured the funding cycle with allowTerminalMigration & global.allowSetTerminals\n directory.setTerminalsOf(_projectId, _newTerminals);\n _oldJbTerminal.migrate(_projectId, _newJbTerminal);\n }\n}\n" + }, + "contracts/interfaces/IJBPayoutRedemptionPaymentTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBFee} from './../structs/JBFee.sol';\nimport {IJBAllowanceTerminal} from './IJBAllowanceTerminal.sol';\nimport {IJBDirectory} from './IJBDirectory.sol';\nimport {IJBPayDelegate} from './IJBPayDelegate.sol';\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\nimport {IJBPayoutTerminal} from './IJBPayoutTerminal.sol';\nimport {IJBPrices} from './IJBPrices.sol';\nimport {IJBProjects} from './IJBProjects.sol';\nimport {IJBRedemptionDelegate} from './IJBRedemptionDelegate.sol';\nimport {IJBRedemptionTerminal} from './IJBRedemptionTerminal.sol';\nimport {IJBSplitsStore} from './IJBSplitsStore.sol';\nimport {JBDidPayData} from './../structs/JBDidPayData.sol';\nimport {JBDidRedeemData} from './../structs/JBDidRedeemData.sol';\nimport {JBSplit} from './../structs/JBSplit.sol';\n\ninterface IJBPayoutRedemptionPaymentTerminal is\n IJBPaymentTerminal,\n IJBPayoutTerminal,\n IJBAllowanceTerminal,\n IJBRedemptionTerminal\n{\n event AddToBalance(\n uint256 indexed projectId,\n uint256 amount,\n uint256 refundedFees,\n string memo,\n bytes metadata,\n address caller\n );\n\n event Migrate(\n uint256 indexed projectId,\n IJBPaymentTerminal indexed to,\n uint256 amount,\n address caller\n );\n\n event DistributePayouts(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n address beneficiary,\n uint256 amount,\n uint256 distributedAmount,\n uint256 fee,\n uint256 beneficiaryDistributionAmount,\n string memo,\n address caller\n );\n\n event UseAllowance(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n address beneficiary,\n uint256 amount,\n uint256 distributedAmount,\n uint256 netDistributedamount,\n string memo,\n address caller\n );\n\n event HoldFee(\n uint256 indexed projectId,\n uint256 indexed amount,\n uint256 indexed fee,\n uint256 feeDiscount,\n address beneficiary,\n address caller\n );\n\n event ProcessFee(\n uint256 indexed projectId,\n uint256 indexed amount,\n bool indexed wasHeld,\n address beneficiary,\n address caller\n );\n\n event RefundHeldFees(\n uint256 indexed projectId,\n uint256 indexed amount,\n uint256 indexed refundedFees,\n uint256 leftoverAmount,\n address caller\n );\n\n event Pay(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n address payer,\n address beneficiary,\n uint256 amount,\n uint256 beneficiaryTokenCount,\n string memo,\n bytes metadata,\n address caller\n );\n\n event DelegateDidPay(\n IJBPayDelegate indexed delegate,\n JBDidPayData data,\n uint256 delegatedAmount,\n address caller\n );\n\n event RedeemTokens(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n address holder,\n address beneficiary,\n uint256 tokenCount,\n uint256 reclaimedAmount,\n string memo,\n bytes metadata,\n address caller\n );\n\n event DelegateDidRedeem(\n IJBRedemptionDelegate indexed delegate,\n JBDidRedeemData data,\n uint256 delegatedAmount,\n address caller\n );\n\n event DistributeToPayoutSplit(\n uint256 indexed projectId,\n uint256 indexed domain,\n uint256 indexed group,\n JBSplit split,\n uint256 amount,\n address caller\n );\n\n event SetFee(uint256 fee, address caller);\n\n event SetFeeGauge(address indexed feeGauge, address caller);\n\n event SetFeelessAddress(address indexed addrs, bool indexed flag, address caller);\n\n function projects() external view returns (IJBProjects);\n\n function splitsStore() external view returns (IJBSplitsStore);\n\n function directory() external view returns (IJBDirectory);\n\n function prices() external view returns (IJBPrices);\n\n function store() external view returns (address);\n\n function baseWeightCurrency() external view returns (uint256);\n\n function payoutSplitsGroup() external view returns (uint256);\n\n function heldFeesOf(uint256 projectId) external view returns (JBFee[] memory);\n\n function fee() external view returns (uint256);\n\n function feeGauge() external view returns (address);\n\n function isFeelessAddress(address account) external view returns (bool);\n\n function migrate(uint256 projectId, IJBPaymentTerminal _to) external returns (uint256 balance);\n\n function processFees(uint256 projectId) external;\n\n function setFee(uint256 fee) external;\n\n function setFeeGauge(address feeGauge) external;\n\n function setFeelessAddress(address account, bool flag) external;\n}\n" + }, + "contracts/structs/JBFee.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @custom:member amount The total amount the fee was taken from, as a fixed point number with the same number of decimals as the terminal in which this struct was created.\n/// @custom:member fee The percent of the fee, out of MAX_FEE.\n/// @custom:member feeDiscount The discount of the fee.\n/// @custom:member beneficiary The address that will receive the tokens that are minted as a result of the fee payment.\nstruct JBFee {\n uint256 amount;\n uint32 fee;\n uint32 feeDiscount;\n address beneficiary;\n}\n" + }, + "contracts/interfaces/IJBAllowanceTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBAllowanceTerminal {\n function useAllowanceOf(\n uint256 projectId,\n uint256 amount,\n uint256 currency,\n address token,\n uint256 minReturnedTokens,\n address payable beneficiary,\n string calldata memo\n ) external returns (uint256 netDistributedAmount);\n}\n" + }, + "contracts/interfaces/IJBPayoutTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBPayoutTerminal {\n function distributePayoutsOf(\n uint256 projectId,\n uint256 amount,\n uint256 currency,\n address token,\n uint256 minReturnedTokens,\n string calldata memo\n ) external returns (uint256 netLeftoverDistributionAmount);\n}\n" + }, + "contracts/interfaces/IJBRedemptionTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBRedemptionTerminal {\n function redeemTokensOf(\n address holder,\n uint256 projectId,\n uint256 tokenCount,\n address token,\n uint256 minReturnedTokens,\n address payable beneficiary,\n string calldata memo,\n bytes calldata metadata\n ) external returns (uint256 reclaimAmount);\n}\n" + }, + "contracts/JBETHPaymentTerminal3_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Address} from '@openzeppelin/contracts/utils/Address.sol';\nimport {JBPayoutRedemptionPaymentTerminal3_1} from './abstract/JBPayoutRedemptionPaymentTerminal3_1.sol';\nimport {JBSplitsGroups} from './libraries/JBSplitsGroups.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {JBCurrencies} from './libraries/JBCurrencies.sol';\nimport {JBTokens} from './libraries/JBTokens.sol';\n\n/// @notice Manages all inflows and outflows of ETH funds into the protocol ecosystem.\ncontract JBETHPaymentTerminal3_1 is JBPayoutRedemptionPaymentTerminal3_1 {\n //*********************************************************************//\n // -------------------------- internal views ------------------------- //\n //*********************************************************************//\n\n /// @notice Checks the balance of tokens in this contract.\n /// @return The contract's balance, as a fixed point number with the same amount of decimals as this terminal.\n function _balance() internal view override returns (uint256) {\n return address(this).balance;\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _prices A contract that exposes price feeds.\n /// @param _store A contract that stores the terminal's data.\n /// @param _owner The address that will own this contract.\n constructor(\n uint256 _baseWeightCurrency,\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBSplitsStore _splitsStore,\n IJBPrices _prices,\n address _store,\n address _owner\n )\n JBPayoutRedemptionPaymentTerminal3_1(\n JBTokens.ETH,\n 18, // 18 decimals.\n JBCurrencies.ETH,\n _baseWeightCurrency,\n JBSplitsGroups.ETH_PAYOUT,\n _operatorStore,\n _projects,\n _directory,\n _splitsStore,\n _prices,\n _store,\n _owner\n )\n // solhint-disable-next-line no-empty-blocks\n {\n\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Transfers tokens.\n /// @param _from The address from which the transfer should originate.\n /// @param _to The address to which the transfer should go.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _transferFrom(address _from, address payable _to, uint256 _amount) internal override {\n _from; // Prevents unused var compiler and natspec complaints.\n\n Address.sendValue(_to, _amount);\n }\n}\n" + }, + "contracts/abstract/JBPayoutRedemptionPaymentTerminal3_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {ERC165Checker} from '@openzeppelin/contracts/utils/introspection/ERC165Checker.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {IJBAllowanceTerminal3_1} from './../interfaces/IJBAllowanceTerminal3_1.sol';\nimport {IJBController} from './../interfaces/IJBController.sol';\nimport {IJBDirectory} from './../interfaces/IJBDirectory.sol';\nimport {IJBFeeGauge} from './../interfaces/IJBFeeGauge.sol';\nimport {IJBPayoutRedemptionPaymentTerminal3_1} from './../interfaces/IJBPayoutRedemptionPaymentTerminal3_1.sol';\nimport {IJBSplitAllocator} from './../interfaces/IJBSplitAllocator.sol';\nimport {IJBOperatable} from './../interfaces/IJBOperatable.sol';\nimport {IJBOperatorStore} from './../interfaces/IJBOperatorStore.sol';\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\nimport {IJBPayoutTerminal3_1} from './../interfaces/IJBPayoutTerminal3_1.sol';\nimport {IJBPrices} from './../interfaces/IJBPrices.sol';\nimport {IJBProjects} from './../interfaces/IJBProjects.sol';\nimport {IJBRedemptionTerminal} from './../interfaces/IJBRedemptionTerminal.sol';\nimport {IJBSingleTokenPaymentTerminalStore} from './../interfaces/IJBSingleTokenPaymentTerminalStore.sol';\nimport {IJBSplitsStore} from './../interfaces/IJBSplitsStore.sol';\nimport {JBConstants} from './../libraries/JBConstants.sol';\nimport {JBCurrencies} from './../libraries/JBCurrencies.sol';\nimport {JBFixedPointNumber} from './../libraries/JBFixedPointNumber.sol';\nimport {JBFundingCycleMetadataResolver} from './../libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBOperations} from './../libraries/JBOperations.sol';\nimport {JBTokens} from './../libraries/JBTokens.sol';\nimport {JBDidPayData} from './../structs/JBDidPayData.sol';\nimport {JBDidRedeemData} from './../structs/JBDidRedeemData.sol';\nimport {JBFee} from './../structs/JBFee.sol';\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\nimport {JBPayDelegateAllocation} from './../structs/JBPayDelegateAllocation.sol';\nimport {JBTokenAmount} from './../structs/JBTokenAmount.sol';\nimport {JBRedemptionDelegateAllocation} from './../structs/JBRedemptionDelegateAllocation.sol';\nimport {JBSplit} from './../structs/JBSplit.sol';\nimport {JBSplitAllocationData} from './../structs/JBSplitAllocationData.sol';\nimport {JBOperatable} from './JBOperatable.sol';\nimport {JBSingleTokenPaymentTerminal} from './JBSingleTokenPaymentTerminal.sol';\n\n/// @notice Generic terminal managing all inflows and outflows of funds into the protocol ecosystem.\nabstract contract JBPayoutRedemptionPaymentTerminal3_1 is\n JBSingleTokenPaymentTerminal,\n JBOperatable,\n Ownable,\n IJBPayoutRedemptionPaymentTerminal3_1\n{\n // A library that parses the packed funding cycle metadata into a friendlier format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error FEE_TOO_HIGH();\n error INADEQUATE_DISTRIBUTION_AMOUNT();\n error INADEQUATE_RECLAIM_AMOUNT();\n error INADEQUATE_TOKEN_COUNT();\n error NO_MSG_VALUE_ALLOWED();\n error PAY_TO_ZERO_ADDRESS();\n error PROJECT_TERMINAL_MISMATCH();\n error REDEEM_TO_ZERO_ADDRESS();\n error TERMINAL_IN_SPLIT_ZERO_ADDRESS();\n error TERMINAL_TOKENS_INCOMPATIBLE();\n\n //*********************************************************************//\n // ---------------------------- modifiers ---------------------------- //\n //*********************************************************************//\n\n /// @notice A modifier that verifies this terminal is a terminal of provided project ID.\n modifier isTerminalOf(uint256 _projectId) {\n if (!directory.isTerminalOf(_projectId, this)) revert PROJECT_TERMINAL_MISMATCH();\n _;\n }\n\n //*********************************************************************//\n // --------------------- internal stored constants ------------------- //\n //*********************************************************************//\n\n /// @notice Maximum fee that can be set for a funding cycle configuration.\n /// @dev Out of MAX_FEE (50_000_000 / 1_000_000_000).\n uint256 internal constant _FEE_CAP = 50_000_000;\n\n /// @notice The fee beneficiary project ID is 1, as it should be the first project launched during the deployment process.\n uint256 internal constant _FEE_BENEFICIARY_PROJECT_ID = 1;\n\n //*********************************************************************//\n // --------------------- internal stored properties ------------------ //\n //*********************************************************************//\n\n /// @notice Fees that are being held to be processed later.\n /// @custom:param _projectId The ID of the project for which fees are being held.\n mapping(uint256 => JBFee[]) internal _heldFeesOf;\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice Mints ERC-721's that represent project ownership and transfers.\n IJBProjects public immutable override projects;\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n /// @notice The contract that stores splits for each project.\n IJBSplitsStore public immutable override splitsStore;\n\n /// @notice The contract that exposes price feeds.\n IJBPrices public immutable override prices;\n\n /// @notice The contract that stores and manages the terminal's data.\n address public immutable override store;\n\n /// @notice The currency to base token issuance on.\n /// @dev If this differs from `currency`, there must be a price feed available to convert `currency` to `baseWeightCurrency`.\n uint256 public immutable override baseWeightCurrency;\n\n /// @notice The group that payout splits coming from this terminal are identified by.\n uint256 public immutable override payoutSplitsGroup;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The platform fee percent.\n /// @dev Out of MAX_FEE (25_000_000 / 1_000_000_000)\n uint256 public override fee = 25_000_000; // 2.5%\n\n /// @notice The data source that returns a discount to apply to a project's fee.\n address public override feeGauge;\n\n /// @notice Addresses that can be paid towards from this terminal without incurring a fee.\n /// @dev Only addresses that are considered to be contained within the ecosystem can be feeless. Funds sent outside the ecosystem may incur fees despite being stored as feeless.\n /// @custom:param _address The address that can be paid toward.\n mapping(address => bool) public override isFeelessAddress;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Gets the current overflowed amount in this terminal for a specified project, in terms of ETH.\n /// @dev The current overflow is represented as a fixed point number with 18 decimals.\n /// @param _projectId The ID of the project to get overflow for.\n /// @return The current amount of ETH overflow that project has in this terminal, as a fixed point number with 18 decimals.\n function currentEthOverflowOf(\n uint256 _projectId\n ) external view virtual override returns (uint256) {\n // Get this terminal's current overflow.\n uint256 _overflow = IJBSingleTokenPaymentTerminalStore(store).currentOverflowOf(\n this,\n _projectId\n );\n\n // Adjust the decimals of the fixed point number if needed to have 18 decimals.\n uint256 _adjustedOverflow = (decimals == 18)\n ? _overflow\n : JBFixedPointNumber.adjustDecimals(_overflow, decimals, 18);\n\n // Return the amount converted to ETH.\n return\n (currency == JBCurrencies.ETH)\n ? _adjustedOverflow\n : PRBMath.mulDiv(\n _adjustedOverflow,\n 10 ** decimals,\n prices.priceFor(currency, JBCurrencies.ETH, decimals)\n );\n }\n\n /// @notice The fees that are currently being held to be processed later for each project.\n /// @param _projectId The ID of the project for which fees are being held.\n /// @return An array of fees that are being held.\n function heldFeesOf(uint256 _projectId) external view override returns (JBFee[] memory) {\n return _heldFeesOf[_projectId];\n }\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if the provided interface ID is supported.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(JBSingleTokenPaymentTerminal, IERC165) returns (bool) {\n return\n _interfaceId == type(IJBPayoutRedemptionPaymentTerminal3_1).interfaceId ||\n _interfaceId == type(IJBPayoutTerminal3_1).interfaceId ||\n _interfaceId == type(IJBAllowanceTerminal3_1).interfaceId ||\n _interfaceId == type(IJBRedemptionTerminal).interfaceId ||\n _interfaceId == type(IJBOperatable).interfaceId ||\n super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // -------------------------- internal views ------------------------- //\n //*********************************************************************//\n\n /// @notice Checks the balance of tokens in this contract.\n /// @return The contract's balance.\n function _balance() internal view virtual returns (uint256);\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _decimals The number of decimals the token fixed point amounts are expected to have.\n /// @param _currency The currency that this terminal's token adheres to for price feeds.\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _payoutSplitsGroup The group that denotes payout splits from this terminal in the splits store.\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _prices A contract that exposes price feeds.\n /// @param _store A contract that stores the terminal's data.\n /// @param _owner The address that will own this contract.\n constructor(\n // payable constructor save the gas used to check msg.value==0\n address _token,\n uint256 _decimals,\n uint256 _currency,\n uint256 _baseWeightCurrency,\n uint256 _payoutSplitsGroup,\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBSplitsStore _splitsStore,\n IJBPrices _prices,\n address _store,\n address _owner\n )\n payable\n JBSingleTokenPaymentTerminal(_token, _decimals, _currency)\n JBOperatable(_operatorStore)\n {\n baseWeightCurrency = _baseWeightCurrency;\n payoutSplitsGroup = _payoutSplitsGroup;\n projects = _projects;\n directory = _directory;\n splitsStore = _splitsStore;\n prices = _prices;\n store = _store;\n\n transferOwnership(_owner);\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Contribute tokens to a project.\n /// @param _projectId The ID of the project being paid.\n /// @param _amount The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place.\n /// @param _token The token being paid. This terminal ignores this property since it only manages one token.\n /// @param _beneficiary The address to mint tokens for and pass along to the funding cycle's data source and delegate.\n /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\n /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals.\n function pay(\n uint256 _projectId,\n uint256 _amount,\n address _token,\n address _beneficiary,\n uint256 _minReturnedTokens,\n bool _preferClaimedTokens,\n string calldata _memo,\n bytes calldata _metadata\n ) external payable virtual override isTerminalOf(_projectId) returns (uint256) {\n _token; // Prevents unused var compiler and natspec complaints.\n\n // ETH shouldn't be sent if this terminal's token isn't ETH.\n if (token != JBTokens.ETH) {\n if (msg.value > 0) revert NO_MSG_VALUE_ALLOWED();\n\n // Get a reference to the balance before receiving tokens.\n uint256 _balanceBefore = _balance();\n\n // Transfer tokens to this terminal from the msg sender.\n _transferFrom(msg.sender, payable(address(this)), _amount);\n\n // The amount should reflect the change in balance.\n _amount = _balance() - _balanceBefore;\n }\n // If this terminal's token is ETH, override _amount with msg.value.\n else _amount = msg.value;\n\n return\n _pay(\n _amount,\n msg.sender,\n _projectId,\n _beneficiary,\n _minReturnedTokens,\n _preferClaimedTokens,\n _memo,\n _metadata\n );\n }\n\n /// @notice Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source.\n /// @dev Only a token holder or a designated operator can redeem its tokens.\n /// @param _holder The account to redeem tokens for.\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\n /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals.\n /// @param _token The token being reclaimed. This terminal ignores this property since it only manages one token.\n /// @param _minReturnedTokens The minimum amount of terminal tokens expected in return, as a fixed point number with the same amount of decimals as the terminal.\n /// @param _beneficiary The address to send the terminal tokens to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return reclaimAmount The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals.\n function redeemTokensOf(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n address _token,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo,\n bytes memory _metadata\n )\n external\n virtual\n override\n requirePermission(_holder, _projectId, JBOperations.REDEEM)\n returns (uint256 reclaimAmount)\n {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return\n _redeemTokensOf(\n _holder,\n _projectId,\n _tokenCount,\n _minReturnedTokens,\n _beneficiary,\n _memo,\n _metadata\n );\n }\n\n /// @notice Distributes payouts for a project with the distribution limit of its current funding cycle.\n /// @dev Payouts are sent to the preprogrammed splits. Any leftover is sent to the project's owner.\n /// @dev 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.\n /// @dev All funds distributed outside of this contract or any feeless terminals incure the protocol fee.\n /// @param _projectId The ID of the project having its payouts distributed.\n /// @param _amount The amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency.\n /// @param _token The token being distributed. This terminal ignores this property since it only manages one token.\n /// @param _minReturnedTokens 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.\n /// @param _metadata Bytes to send along to the emitted event, if provided.\n /// @return netLeftoverDistributionAmount The amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal.\n function distributePayoutsOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n address _token,\n uint256 _minReturnedTokens,\n bytes calldata _metadata\n ) external virtual override returns (uint256 netLeftoverDistributionAmount) {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return _distributePayoutsOf(_projectId, _amount, _currency, _minReturnedTokens, _metadata);\n }\n\n /// @notice Only a project's owner or a designated operator can use its allowance.\n /// @dev Incurs the protocol fee.\n /// @param _projectId The ID of the project to use the allowance of.\n /// @param _amount The amount of terminal tokens to use from this project's current allowance, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's overflow allowance currency.\n /// @param _token The token being distributed. This terminal ignores this property since it only manages one token.\n /// @param _minReturnedTokens The minimum number of tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with 18 decimals.\n /// @param _beneficiary The address to send the funds to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the emitted event, if provided.\n /// @return netDistributedAmount The amount of tokens that was distributed to the beneficiary, as a fixed point number with the same amount of decimals as the terminal.\n function useAllowanceOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n address _token,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo,\n bytes calldata _metadata\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.USE_ALLOWANCE)\n returns (uint256 netDistributedAmount)\n {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return\n _useAllowanceOf(\n _projectId,\n _amount,\n _currency,\n _minReturnedTokens,\n _beneficiary,\n _memo,\n _metadata\n );\n }\n\n /// @notice Allows a project owner to migrate its funds and operations to a new terminal that accepts the same token type.\n /// @dev Only a project's owner or a designated operator can migrate it.\n /// @param _projectId The ID of the project being migrated.\n /// @param _to The terminal contract that will gain the project's funds.\n /// @return balance The amount of funds that were migrated, as a fixed point number with the same amount of decimals as this terminal.\n function migrate(\n uint256 _projectId,\n IJBPaymentTerminal _to\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.MIGRATE_TERMINAL)\n returns (uint256 balance)\n {\n // The terminal being migrated to must accept the same token as this terminal.\n if (!_to.acceptsToken(token, _projectId)) revert TERMINAL_TOKENS_INCOMPATIBLE();\n\n // Record the migration in the store.\n balance = IJBSingleTokenPaymentTerminalStore(store).recordMigration(_projectId);\n\n // Transfer the balance if needed.\n if (balance > 0) {\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_to), balance);\n\n // If this terminal's token is ETH, send it in msg.value.\n uint256 _payableValue = token == JBTokens.ETH ? balance : 0;\n\n // Withdraw the balance to transfer to the new terminal;\n _to.addToBalanceOf{value: _payableValue}(_projectId, balance, token, '', bytes(''));\n }\n\n emit Migrate(_projectId, _to, balance, msg.sender);\n }\n\n /// @notice Receives funds belonging to the specified project.\n /// @param _projectId The ID of the project to which the funds received belong.\n /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\n /// @param _token The token being paid. This terminal ignores this property since it only manages one currency.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the emitted event.\n function addToBalanceOf(\n uint256 _projectId,\n uint256 _amount,\n address _token,\n string calldata _memo,\n bytes calldata _metadata\n ) external payable virtual override isTerminalOf(_projectId) {\n // Do not refund held fees by default.\n addToBalanceOf(_projectId, _amount, _token, false, _memo, _metadata);\n }\n\n /// @notice Process any fees that are being held for the project.\n /// @dev Only a project owner, an operator, or the contract's owner can process held fees.\n /// @param _projectId The ID of the project whos held fees should be processed.\n function processFees(\n uint256 _projectId\n )\n external\n virtual\n override\n requirePermissionAllowingOverride(\n projects.ownerOf(_projectId),\n _projectId,\n JBOperations.PROCESS_FEES,\n msg.sender == owner()\n )\n {\n // Get a reference to the project's held fees.\n JBFee[] memory _heldFees = _heldFeesOf[_projectId];\n\n // Delete the held fees.\n delete _heldFeesOf[_projectId];\n\n // Push array length in stack\n uint256 _heldFeeLength = _heldFees.length;\n\n // Process each fee.\n for (uint256 _i; _i < _heldFeeLength; ) {\n // Get the fee amount.\n uint256 _amount = _feeAmount(\n _heldFees[_i].amount,\n _heldFees[_i].fee,\n _heldFees[_i].feeDiscount\n );\n\n // Process the fee.\n _processFee(_amount, _heldFees[_i].beneficiary, _projectId);\n\n emit ProcessFee(_projectId, _amount, true, _heldFees[_i].beneficiary, msg.sender);\n\n unchecked {\n ++_i;\n }\n }\n }\n\n /// @notice Allows the fee to be updated.\n /// @dev Only the owner of this contract can change the fee.\n /// @param _fee The new fee, out of MAX_FEE.\n function setFee(uint256 _fee) external virtual override onlyOwner {\n // The provided fee must be within the max.\n if (_fee > _FEE_CAP) revert FEE_TOO_HIGH();\n\n // Store the new fee.\n fee = _fee;\n\n emit SetFee(_fee, msg.sender);\n }\n\n /// @notice Allows the fee gauge to be updated.\n /// @dev Only the owner of this contract can change the fee gauge.\n /// @param _feeGauge The new fee gauge.\n function setFeeGauge(address _feeGauge) external virtual override onlyOwner {\n // Store the new fee gauge.\n feeGauge = _feeGauge;\n\n emit SetFeeGauge(_feeGauge, msg.sender);\n }\n\n /// @notice Sets whether projects operating on this terminal can pay towards the specified address without incurring a fee.\n /// @param _address The address that can be paid towards while still bypassing fees.\n /// @param _flag A flag indicating whether the terminal should be feeless or not.\n function setFeelessAddress(address _address, bool _flag) external virtual override onlyOwner {\n // Set the flag value.\n isFeelessAddress[_address] = _flag;\n\n emit SetFeelessAddress(_address, _flag, msg.sender);\n }\n\n //*********************************************************************//\n // ----------------------- public transactions ----------------------- //\n //*********************************************************************//\n\n /// @notice Receives funds belonging to the specified project.\n /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\n /// @param _token The token being paid. This terminal ignores this property since it only manages one currency.\n /// @param _shouldRefundHeldFees A flag indicating if held fees should be refunded based on the amount being added.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the emitted event.\n function addToBalanceOf(\n uint256 _projectId,\n uint256 _amount,\n address _token,\n bool _shouldRefundHeldFees,\n string calldata _memo,\n bytes calldata _metadata\n ) public payable virtual override isTerminalOf(_projectId) {\n _token; // Prevents unused var compiler and natspec complaints.\n\n // If this terminal's token isn't ETH, make sure no msg.value was sent, then transfer the tokens in from msg.sender.\n if (token != JBTokens.ETH) {\n // Amount must be greater than 0.\n if (msg.value > 0) revert NO_MSG_VALUE_ALLOWED();\n\n // Get a reference to the balance before receiving tokens.\n uint256 _balanceBefore = _balance();\n\n // Transfer tokens to this terminal from the msg sender.\n _transferFrom(msg.sender, payable(address(this)), _amount);\n\n // The amount should reflect the change in balance.\n _amount = _balance() - _balanceBefore;\n }\n // If the terminal's token is ETH, override `_amount` with msg.value.\n else _amount = msg.value;\n\n // Add to balance.\n _addToBalanceOf(_projectId, _amount, _shouldRefundHeldFees, _memo, _metadata);\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Transfers tokens.\n /// @param _from The address from which the transfer should originate.\n /// @param _to The address to which the transfer should go.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _transferFrom(address _from, address payable _to, uint256 _amount) internal virtual {\n _from; // Prevents unused var compiler and natspec complaints.\n _to; // Prevents unused var compiler and natspec complaints.\n _amount; // Prevents unused var compiler and natspec complaints.\n }\n\n /// @notice Logic to be triggered before transferring tokens from this terminal.\n /// @param _to The address to which the transfer is going.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _beforeTransferTo(address _to, uint256 _amount) internal virtual {\n _to; // Prevents unused var compiler and natspec complaints.\n _amount; // Prevents unused var compiler and natspec complaints.\n }\n\n /// @notice Logic to be triggered if a transfer should be undone\n /// @param _to The address to which the transfer went.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _cancelTransferTo(address _to, uint256 _amount) internal virtual {\n _to; // Prevents unused var compiler and natspec complaints.\n _amount; // Prevents unused var compiler and natspec complaints.\n }\n\n /// @notice Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source.\n /// @dev Only a token holder or a designated operator can redeem its tokens.\n /// @param _holder The account to redeem tokens for.\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\n /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals.\n /// @param _minReturnedTokens The minimum amount of terminal tokens expected in return, as a fixed point number with the same amount of decimals as the terminal.\n /// @param _beneficiary The address to send the terminal tokens to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return reclaimAmount The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals.\n function _redeemTokensOf(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo,\n bytes memory _metadata\n ) internal returns (uint256 reclaimAmount) {\n // Can't send reclaimed funds to the zero address.\n if (_beneficiary == address(0)) revert REDEEM_TO_ZERO_ADDRESS();\n\n // Define variables that will be needed outside the scoped section below.\n // Keep a reference to the funding cycle during which the redemption is being made.\n JBFundingCycle memory _fundingCycle;\n\n // Scoped section prevents stack too deep. `_delegateAllocations` only used within scope.\n {\n JBRedemptionDelegateAllocation[] memory _delegateAllocations;\n\n // Record the redemption.\n (\n _fundingCycle,\n reclaimAmount,\n _delegateAllocations,\n _memo\n ) = IJBSingleTokenPaymentTerminalStore(store).recordRedemptionFor(\n _holder,\n _projectId,\n _tokenCount,\n _memo,\n _metadata\n );\n\n // The amount being reclaimed must be at least as much as was expected.\n if (reclaimAmount < _minReturnedTokens) revert INADEQUATE_RECLAIM_AMOUNT();\n\n // Burn the project tokens.\n if (_tokenCount > 0)\n IJBController(directory.controllerOf(_projectId)).burnTokensOf(\n _holder,\n _projectId,\n _tokenCount,\n '',\n false\n );\n\n // If delegate allocations were specified by the data source, fulfill them.\n if (_delegateAllocations.length != 0) {\n // Keep a reference to the token amount being forwarded to the delegate.\n JBTokenAmount memory _forwardedAmount = JBTokenAmount(token, 0, decimals, currency);\n\n JBDidRedeemData memory _data = JBDidRedeemData(\n _holder,\n _projectId,\n _fundingCycle.configuration,\n _tokenCount,\n JBTokenAmount(token, reclaimAmount, decimals, currency),\n _forwardedAmount,\n _beneficiary,\n _memo,\n _metadata\n );\n\n uint256 _numDelegates = _delegateAllocations.length;\n\n for (uint256 _i; _i < _numDelegates; ) {\n // Get a reference to the delegate being iterated on.\n JBRedemptionDelegateAllocation memory _delegateAllocation = _delegateAllocations[_i];\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_delegateAllocation.delegate), _delegateAllocation.amount);\n\n // Keep track of the msg.value to use in the delegate call\n uint256 _payableValue;\n\n // If this terminal's token is ETH, send it in msg.value.\n if (token == JBTokens.ETH) _payableValue = _delegateAllocation.amount;\n\n // Pass the correct token forwardedAmount to the delegate\n _data.forwardedAmount.value = _delegateAllocation.amount;\n\n _delegateAllocation.delegate.didRedeem{value: _payableValue}(_data);\n\n emit DelegateDidRedeem(\n _delegateAllocation.delegate,\n _data,\n _delegateAllocation.amount,\n msg.sender\n );\n unchecked {\n ++_i;\n }\n }\n }\n }\n\n // Send the reclaimed funds to the beneficiary.\n if (reclaimAmount > 0) _transferFrom(address(this), _beneficiary, reclaimAmount);\n\n emit RedeemTokens(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _holder,\n _beneficiary,\n _tokenCount,\n reclaimAmount,\n _memo,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Distributes payouts for a project with the distribution limit of its current funding cycle.\n /// @dev Payouts are sent to the preprogrammed splits. Any leftover is sent to the project's owner.\n /// @dev 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.\n /// @dev All funds distributed outside of this contract or any feeless terminals incure the protocol fee.\n /// @param _projectId The ID of the project having its payouts distributed.\n /// @param _amount The amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency.\n /// @param _minReturnedTokens 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.\n /// @param _metadata Bytes to send along to the emitted event, if provided.\n /// @return netLeftoverDistributionAmount The amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal.\n function _distributePayoutsOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n uint256 _minReturnedTokens,\n bytes calldata _metadata\n ) internal returns (uint256 netLeftoverDistributionAmount) {\n // Record the distribution.\n (\n JBFundingCycle memory _fundingCycle,\n uint256 _distributedAmount\n ) = IJBSingleTokenPaymentTerminalStore(store).recordDistributionFor(\n _projectId,\n _amount,\n _currency\n );\n\n // The amount being distributed must be at least as much as was expected.\n if (_distributedAmount < _minReturnedTokens) revert INADEQUATE_DISTRIBUTION_AMOUNT();\n\n // Get a reference to the project owner, which will receive tokens from paying the platform fee\n // and receive any extra distributable funds not allocated to payout splits.\n address payable _projectOwner = payable(projects.ownerOf(_projectId));\n\n // Define variables that will be needed outside the scoped section below.\n // Keep a reference to the fee amount that was paid.\n uint256 _fee;\n\n // Scoped section prevents stack too deep. `_feeDiscount`, `_feeEligibleDistributionAmount`, and `_leftoverDistributionAmount` only used within scope.\n {\n // Get the amount of discount that should be applied to any fees taken.\n // If the fee is zero, set the discount to 100% for convenience.\n uint256 _feeDiscount = fee == 0\n ? JBConstants.MAX_FEE_DISCOUNT\n : _currentFeeDiscount(_projectId);\n\n // The amount distributed that is eligible for incurring fees.\n uint256 _feeEligibleDistributionAmount;\n\n // The amount leftover after distributing to the splits.\n uint256 _leftoverDistributionAmount;\n\n // Payout to splits and get a reference to the leftover transfer amount after all splits have been paid.\n // Also get a reference to the amount that was distributed to splits from which fees should be taken.\n (_leftoverDistributionAmount, _feeEligibleDistributionAmount) = _distributeToPayoutSplitsOf(\n _projectId,\n _fundingCycle.configuration,\n payoutSplitsGroup,\n _distributedAmount,\n _feeDiscount\n );\n\n if (_feeDiscount != JBConstants.MAX_FEE_DISCOUNT) {\n // Leftover distribution amount is also eligible for a fee since the funds are going out of the ecosystem to _beneficiary.\n unchecked {\n _feeEligibleDistributionAmount += _leftoverDistributionAmount;\n }\n }\n\n // Take the fee.\n _fee = _feeEligibleDistributionAmount != 0\n ? _takeFeeFrom(\n _projectId,\n _fundingCycle,\n _feeEligibleDistributionAmount,\n _projectOwner,\n _feeDiscount\n )\n : 0;\n\n // Transfer any remaining balance to the project owner and update returned leftover accordingly.\n if (_leftoverDistributionAmount != 0) {\n // Subtract the fee from the net leftover amount.\n netLeftoverDistributionAmount =\n _leftoverDistributionAmount -\n _feeAmount(_leftoverDistributionAmount, fee, _feeDiscount);\n\n // Transfer the amount to the project owner.\n _transferFrom(address(this), _projectOwner, netLeftoverDistributionAmount);\n }\n }\n\n emit DistributePayouts(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _projectOwner,\n _amount,\n _distributedAmount,\n _fee,\n netLeftoverDistributionAmount,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Allows a project to send funds from its overflow up to the preconfigured allowance.\n /// @dev Only a project's owner or a designated operator can use its allowance.\n /// @dev Incurs the protocol fee.\n /// @param _projectId The ID of the project to use the allowance of.\n /// @param _amount The amount of terminal tokens to use from this project's current allowance, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's overflow allowance currency.\n /// @param _minReturnedTokens The minimum number of tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with 18 decimals.\n /// @param _beneficiary The address to send the funds to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the emitted event, if provided.\n /// @return netDistributedAmount The amount of tokens that was distributed to the beneficiary, as a fixed point number with the same amount of decimals as the terminal.\n function _useAllowanceOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo,\n bytes calldata _metadata\n ) internal returns (uint256 netDistributedAmount) {\n // Record the use of the allowance.\n (\n JBFundingCycle memory _fundingCycle,\n uint256 _distributedAmount\n ) = IJBSingleTokenPaymentTerminalStore(store).recordUsedAllowanceOf(\n _projectId,\n _amount,\n _currency\n );\n\n // The amount being withdrawn must be at least as much as was expected.\n if (_distributedAmount < _minReturnedTokens) revert INADEQUATE_DISTRIBUTION_AMOUNT();\n\n // Scoped section prevents stack too deep. `_fee`, `_projectOwner`, `_feeDiscount`, and `_netAmount` only used within scope.\n {\n // Keep a reference to the fee amount that was paid.\n uint256 _fee;\n\n // Get a reference to the project owner, which will receive tokens from paying the platform fee.\n address _projectOwner = projects.ownerOf(_projectId);\n\n // Get the amount of discount that should be applied to any fees taken.\n // 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.\n uint256 _feeDiscount = fee == 0 || isFeelessAddress[msg.sender]\n ? JBConstants.MAX_FEE_DISCOUNT\n : _currentFeeDiscount(_projectId);\n\n // Take a fee from the `_distributedAmount`, if needed.\n _fee = _feeDiscount == JBConstants.MAX_FEE_DISCOUNT\n ? 0\n : _takeFeeFrom(_projectId, _fundingCycle, _distributedAmount, _projectOwner, _feeDiscount);\n\n unchecked {\n // The net amount is the withdrawn amount without the fee.\n netDistributedAmount = _distributedAmount - _fee;\n }\n\n // Transfer any remaining balance to the beneficiary.\n if (netDistributedAmount > 0)\n _transferFrom(address(this), _beneficiary, netDistributedAmount);\n }\n\n emit UseAllowance(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _beneficiary,\n _amount,\n _distributedAmount,\n netDistributedAmount,\n _memo,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Pays out splits for a project's funding cycle configuration.\n /// @param _projectId The ID of the project for which payout splits are being distributed.\n /// @param _domain The domain of the splits to distribute the payout between.\n /// @param _group The group of the splits to distribute the payout between.\n /// @param _amount The total amount being distributed, as a fixed point number with the same number of decimals as this terminal.\n /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE.\n /// @return leftoverAmount If the leftover amount if the splits don't add up to 100%.\n /// @return feeEligibleDistributionAmount The total amount of distributions that are eligible to have fees taken from.\n function _distributeToPayoutSplitsOf(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group,\n uint256 _amount,\n uint256 _feeDiscount\n ) internal returns (uint256 leftoverAmount, uint256 feeEligibleDistributionAmount) {\n // Set the leftover amount to the initial amount.\n leftoverAmount = _amount;\n // The total percentage available to split\n uint256 leftoverPercentage = JBConstants.SPLITS_TOTAL_PERCENT;\n\n // Get a reference to the project's payout splits.\n JBSplit[] memory _splits = splitsStore.splitsOf(_projectId, _domain, _group);\n\n // Transfer between all splits.\n for (uint256 _i; _i < _splits.length; ) {\n // Get a reference to the split being iterated on.\n JBSplit memory _split = _splits[_i];\n\n // The amount to send towards the split.\n uint256 _payoutAmount = _split.percent == leftoverPercentage\n ? leftoverAmount\n : PRBMath.mulDiv(_amount, _split.percent, JBConstants.SPLITS_TOTAL_PERCENT);\n\n // Decrement the leftover percentage.\n leftoverPercentage -= _split.percent;\n\n // The payout amount substracting any applicable incurred fees.\n uint256 _netPayoutAmount = _distributeToPayoutSplit(\n _split,\n _projectId,\n _group,\n _payoutAmount,\n _feeDiscount\n );\n\n // If the split allocator is set as feeless, this distribution is not eligible for a fee.\n if (_netPayoutAmount != 0 && _netPayoutAmount != _payoutAmount)\n feeEligibleDistributionAmount += _payoutAmount;\n\n if (_payoutAmount > 0) {\n // Subtract from the amount to be sent to the beneficiary.\n unchecked {\n leftoverAmount = leftoverAmount - _payoutAmount;\n }\n }\n\n emit DistributeToPayoutSplit(\n _projectId,\n _domain,\n _group,\n _split,\n _payoutAmount,\n _netPayoutAmount,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n\n /// @notice Pays out a split for a project's funding cycle configuration.\n /// @param _split The split to distribute payouts to.\n /// @param _amount The total amount being distributed to the split, as a fixed point number with the same number of decimals as this terminal.\n /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE.\n /// @return netPayoutAmount The amount sent to the split after subtracting fees.\n function _distributeToPayoutSplit(\n JBSplit memory _split,\n uint256 _projectId,\n uint256 _group,\n uint256 _amount,\n uint256 _feeDiscount\n ) internal returns (uint256 netPayoutAmount) {\n // If there's an allocator set, transfer to its `allocate` function.\n if (_split.allocator != IJBSplitAllocator(address(0))) {\n // If the split allocator is set as feeless, this distribution is not eligible for a fee.\n if (\n _feeDiscount == JBConstants.MAX_FEE_DISCOUNT || isFeelessAddress[address(_split.allocator)]\n )\n netPayoutAmount = _amount;\n // This distribution is eligible for a fee since the funds are leaving this contract and the allocator isn't listed as feeless.\n else {\n unchecked {\n netPayoutAmount = _amount - _feeAmount(_amount, fee, _feeDiscount);\n }\n }\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_split.allocator), netPayoutAmount);\n\n // Create the data to send to the allocator.\n JBSplitAllocationData memory _data = JBSplitAllocationData(\n token,\n netPayoutAmount,\n decimals,\n _projectId,\n _group,\n _split\n );\n\n // Trigger the allocator's `allocate` function.\n uint256 _error;\n bytes memory _reason;\n\n if (\n ERC165Checker.supportsInterface(\n address(_split.allocator),\n type(IJBSplitAllocator).interfaceId\n )\n )\n // If this terminal's token is ETH, send it in msg.value.\n try\n _split.allocator.allocate{value: token == JBTokens.ETH ? netPayoutAmount : 0}(_data)\n {} catch (bytes memory reason) {\n _reason = reason;\n _error = 1;\n }\n else _error = 2;\n\n if (_error != 0) {\n // Trigger any inhereted post-transfer cancelation logic.\n _cancelTransferTo(address(_split.allocator), netPayoutAmount);\n\n // Set the net payout amount to 0 to signal the reversion.\n netPayoutAmount = 0;\n\n // Add undistributed amount back to project's balance.\n IJBSingleTokenPaymentTerminalStore(store).recordAddedBalanceFor(_projectId, _amount);\n\n emit PayoutReverted(\n _projectId,\n _split,\n _amount,\n _error == 1 ? _reason : abi.encode('IERC165 fail'),\n msg.sender\n );\n }\n\n // Otherwise, if a project is specified, make a payment to it.\n } else if (_split.projectId != 0) {\n // Get a reference to the Juicebox terminal being used.\n IJBPaymentTerminal _terminal = directory.primaryTerminalOf(_split.projectId, token);\n\n // The project must have a terminal to send funds to.\n if (_terminal == IJBPaymentTerminal(address(0))) revert TERMINAL_IN_SPLIT_ZERO_ADDRESS();\n\n // If the terminal is set as feeless, this distribution is not eligible for a fee.\n if (\n _terminal == this ||\n _feeDiscount == JBConstants.MAX_FEE_DISCOUNT ||\n isFeelessAddress[address(_terminal)]\n )\n netPayoutAmount = _amount;\n // This distribution is eligible for a fee since the funds are leaving this contract and the terminal isn't listed as feeless.\n else {\n unchecked {\n netPayoutAmount = _amount - _feeAmount(_amount, fee, _feeDiscount);\n }\n }\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_terminal), netPayoutAmount);\n\n // Send the projectId in the metadata.\n bytes memory _projectMetadata = new bytes(32);\n _projectMetadata = bytes(abi.encodePacked(_projectId));\n\n // Add to balance if prefered.\n if (_split.preferAddToBalance)\n try\n _terminal.addToBalanceOf{value: token == JBTokens.ETH ? netPayoutAmount : 0}(\n _split.projectId,\n netPayoutAmount,\n token,\n '',\n _projectMetadata\n )\n {} catch (bytes memory reason) {\n // Trigger any inhereted post-transfer cancelation logic.\n _cancelTransferTo(address(_terminal), netPayoutAmount);\n\n // Set the net payout amount to 0 to signal the reversion.\n netPayoutAmount = 0;\n\n // Add undistributed amount back to project's balance.\n IJBSingleTokenPaymentTerminalStore(store).recordAddedBalanceFor(_projectId, _amount);\n\n emit PayoutReverted(_projectId, _split, _amount, reason, msg.sender);\n }\n else\n try\n _terminal.pay{value: token == JBTokens.ETH ? netPayoutAmount : 0}(\n _split.projectId,\n netPayoutAmount,\n token,\n _split.beneficiary != address(0) ? _split.beneficiary : msg.sender,\n 0,\n _split.preferClaimed,\n '',\n _projectMetadata\n )\n {} catch (bytes memory reason) {\n // Trigger any inhereted post-transfer cancelation logic.\n _cancelTransferTo(address(_terminal), netPayoutAmount);\n\n // Set the net payout amount to 0 to signal the reversion.\n netPayoutAmount = 0;\n\n // Add undistributed amount back to project's balance.\n IJBSingleTokenPaymentTerminalStore(store).recordAddedBalanceFor(_projectId, _amount);\n\n emit PayoutReverted(_projectId, _split, _amount, reason, msg.sender);\n }\n } else {\n // Keep a reference to the beneficiary.\n address payable _beneficiary = _split.beneficiary != address(0)\n ? _split.beneficiary\n : payable(msg.sender);\n\n // If there's a full discount, this distribution is not eligible for a fee.\n // Don't enforce feeless address for the beneficiary since the funds are leaving the ecosystem.\n if (_feeDiscount == JBConstants.MAX_FEE_DISCOUNT)\n netPayoutAmount = _amount;\n // This distribution is eligible for a fee since the funds are leaving this contract and the beneficiary isn't listed as feeless.\n else {\n unchecked {\n netPayoutAmount = _amount - _feeAmount(_amount, fee, _feeDiscount);\n }\n }\n\n // If there's a beneficiary, send the funds directly to the beneficiary. Otherwise send to the msg.sender.\n _transferFrom(address(this), _beneficiary, netPayoutAmount);\n }\n }\n\n /// @notice Takes a fee into the platform's project, which has an id of _FEE_BENEFICIARY_PROJECT_ID.\n /// @param _projectId The ID of the project having fees taken from.\n /// @param _fundingCycle The funding cycle during which the fee is being taken.\n /// @param _amount The amount of the fee to take, as a floating point number with 18 decimals.\n /// @param _beneficiary The address to mint the platforms tokens for.\n /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE.\n /// @return feeAmount The amount of the fee taken.\n function _takeFeeFrom(\n uint256 _projectId,\n JBFundingCycle memory _fundingCycle,\n uint256 _amount,\n address _beneficiary,\n uint256 _feeDiscount\n ) internal returns (uint256 feeAmount) {\n feeAmount = _feeAmount(_amount, fee, _feeDiscount);\n\n if (_fundingCycle.shouldHoldFees()) {\n // Store the held fee.\n _heldFeesOf[_projectId].push(JBFee(_amount, uint32(fee), uint32(_feeDiscount), _beneficiary));\n\n emit HoldFee(_projectId, _amount, fee, _feeDiscount, _beneficiary, msg.sender);\n } else {\n // Process the fee.\n _processFee(feeAmount, _beneficiary, _projectId); // Take the fee.\n\n emit ProcessFee(_projectId, feeAmount, false, _beneficiary, msg.sender);\n }\n }\n\n /// @notice Process a fee of the specified amount.\n /// @param _amount The fee amount, as a floating point number with 18 decimals.\n /// @param _beneficiary The address to mint the platform's tokens for.\n /// @param _from The project ID the fee is being paid from.\n function _processFee(uint256 _amount, address _beneficiary, uint256 _from) internal {\n // Get the terminal for the protocol project.\n IJBPaymentTerminal _terminal = directory.primaryTerminalOf(_FEE_BENEFICIARY_PROJECT_ID, token);\n\n // If this terminal's token is ETH, send it in msg.value.\n uint256 _payableValue = token == JBTokens.ETH ? _amount : 0;\n\n // Send the projectId in the metadata.\n bytes memory _projectMetadata = new bytes(32);\n _projectMetadata = bytes(abi.encodePacked(_from));\n\n // Trigger any inherited pre-transfer logic if funds will be transferred.\n if (address(_terminal) != address(this)) _beforeTransferTo(address(_terminal), _amount);\n\n try\n // Send the fee.\n _terminal.pay{value: _payableValue}(\n _FEE_BENEFICIARY_PROJECT_ID,\n _amount,\n token,\n _beneficiary,\n 0,\n false,\n '',\n _projectMetadata\n )\n {} catch (bytes memory reason) {\n // Trigger any inhereted post-transfer cancelation logic if the pre-transfer logic was triggered.\n if (address(_terminal) != address(this)) _cancelTransferTo(address(_terminal), _amount);\n\n // Add fee amount back to project's balance.\n IJBSingleTokenPaymentTerminalStore(store).recordAddedBalanceFor(_from, _amount);\n\n emit FeeReverted(_from, _FEE_BENEFICIARY_PROJECT_ID, _amount, reason, msg.sender);\n }\n }\n\n /// @notice Contribute tokens to a project.\n /// @param _amount The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place.\n /// @param _payer The address making the payment.\n /// @param _projectId The ID of the project being paid.\n /// @param _beneficiary The address to mint tokens for and pass along to the funding cycle's data source and delegate.\n /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\n /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return beneficiaryTokenCount The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals.\n function _pay(\n uint256 _amount,\n address _payer,\n uint256 _projectId,\n address _beneficiary,\n uint256 _minReturnedTokens,\n bool _preferClaimedTokens,\n string memory _memo,\n bytes memory _metadata\n ) internal returns (uint256 beneficiaryTokenCount) {\n // Cant send tokens to the zero address.\n if (_beneficiary == address(0)) revert PAY_TO_ZERO_ADDRESS();\n\n // Define variables that will be needed outside the scoped section below.\n // Keep a reference to the funding cycle during which the payment is being made.\n JBFundingCycle memory _fundingCycle;\n\n // Scoped section prevents stack too deep. `_delegateAllocations` and `_tokenCount` only used within scope.\n {\n JBPayDelegateAllocation[] memory _delegateAllocations;\n uint256 _tokenCount;\n\n // Bundle the amount info into a JBTokenAmount struct.\n JBTokenAmount memory _bundledAmount = JBTokenAmount(token, _amount, decimals, currency);\n\n // Record the payment.\n (\n _fundingCycle,\n _tokenCount,\n _delegateAllocations,\n _memo\n ) = IJBSingleTokenPaymentTerminalStore(store).recordPaymentFrom(\n _payer,\n _bundledAmount,\n _projectId,\n baseWeightCurrency,\n _beneficiary,\n _memo,\n _metadata\n );\n\n // Mint the tokens if needed.\n if (_tokenCount > 0)\n // Set token count to be the number of tokens minted for the beneficiary instead of the total amount.\n beneficiaryTokenCount = IJBController(directory.controllerOf(_projectId)).mintTokensOf(\n _projectId,\n _tokenCount,\n _beneficiary,\n '',\n _preferClaimedTokens,\n true\n );\n\n // The token count for the beneficiary must be greater than or equal to the minimum expected.\n if (beneficiaryTokenCount < _minReturnedTokens) revert INADEQUATE_TOKEN_COUNT();\n\n // If delegate allocations were specified by the data source, fulfill them.\n if (_delegateAllocations.length != 0) {\n // Keep a reference to the token amount being forwarded to the delegate.\n JBTokenAmount memory _forwardedAmount = JBTokenAmount(token, _amount, decimals, currency);\n\n JBDidPayData memory _data = JBDidPayData(\n _payer,\n _projectId,\n _fundingCycle.configuration,\n _bundledAmount,\n _forwardedAmount,\n beneficiaryTokenCount,\n _beneficiary,\n _preferClaimedTokens,\n _memo,\n _metadata\n );\n\n // Get a reference to the number of delegates to allocate to.\n uint256 _numDelegates = _delegateAllocations.length;\n\n for (uint256 _i; _i < _numDelegates; ) {\n // Get a reference to the delegate being iterated on.\n JBPayDelegateAllocation memory _delegateAllocation = _delegateAllocations[_i];\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_delegateAllocation.delegate), _delegateAllocation.amount);\n\n // Keep track of the msg.value to use in the delegate call\n uint256 _payableValue;\n\n // If this terminal's token is ETH, send it in msg.value.\n if (token == JBTokens.ETH) _payableValue = _delegateAllocation.amount;\n\n // Pass the correct token forwardedAmount to the delegate\n _data.forwardedAmount.value = _delegateAllocation.amount;\n\n _delegateAllocation.delegate.didPay{value: _payableValue}(_data);\n\n emit DelegateDidPay(\n _delegateAllocation.delegate,\n _data,\n _delegateAllocation.amount,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n }\n\n emit Pay(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _payer,\n _beneficiary,\n _amount,\n beneficiaryTokenCount,\n _memo,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Receives funds belonging to the specified project.\n /// @param _projectId The ID of the project to which the funds received belong.\n /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\n /// @param _shouldRefundHeldFees A flag indicating if held fees should be refunded based on the amount being added.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the emitted event.\n function _addToBalanceOf(\n uint256 _projectId,\n uint256 _amount,\n bool _shouldRefundHeldFees,\n string memory _memo,\n bytes memory _metadata\n ) internal {\n // Refund any held fees to make sure the project doesn't pay double for funds going in and out of the protocol.\n uint256 _refundedFees = _shouldRefundHeldFees ? _refundHeldFees(_projectId, _amount) : 0;\n\n // Record the added funds with any refunded fees.\n IJBSingleTokenPaymentTerminalStore(store).recordAddedBalanceFor(\n _projectId,\n _amount + _refundedFees\n );\n\n emit AddToBalance(_projectId, _amount, _refundedFees, _memo, _metadata, msg.sender);\n }\n\n /// @notice Refund fees based on the specified amount.\n /// @param _projectId The project for which fees are being refunded.\n /// @param _amount The amount to base the refund on, as a fixed point number with the same amount of decimals as this terminal.\n /// @return refundedFees How much fees were refunded, as a fixed point number with the same number of decimals as this terminal\n function _refundHeldFees(\n uint256 _projectId,\n uint256 _amount\n ) internal returns (uint256 refundedFees) {\n // Get a reference to the project's held fees.\n JBFee[] memory _heldFees = _heldFeesOf[_projectId];\n\n // Delete the current held fees.\n delete _heldFeesOf[_projectId];\n\n // Get a reference to the leftover amount once all fees have been settled.\n uint256 leftoverAmount = _amount;\n\n // Push length in stack\n uint256 _heldFeesLength = _heldFees.length;\n\n // Process each fee.\n for (uint256 _i; _i < _heldFeesLength; ) {\n if (leftoverAmount == 0) _heldFeesOf[_projectId].push(_heldFees[_i]);\n else if (leftoverAmount >= _heldFees[_i].amount) {\n unchecked {\n leftoverAmount = leftoverAmount - _heldFees[_i].amount;\n refundedFees += _feeAmount(\n _heldFees[_i].amount,\n _heldFees[_i].fee,\n _heldFees[_i].feeDiscount\n );\n }\n } else {\n unchecked {\n _heldFeesOf[_projectId].push(\n JBFee(\n _heldFees[_i].amount - leftoverAmount,\n _heldFees[_i].fee,\n _heldFees[_i].feeDiscount,\n _heldFees[_i].beneficiary\n )\n );\n refundedFees += _feeAmount(leftoverAmount, _heldFees[_i].fee, _heldFees[_i].feeDiscount);\n }\n leftoverAmount = 0;\n }\n\n unchecked {\n ++_i;\n }\n }\n\n emit RefundHeldFees(_projectId, _amount, refundedFees, leftoverAmount, msg.sender);\n }\n\n /// @notice Returns the fee amount based on the provided amount for the specified project.\n /// @param _amount The amount that the fee is based on, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _fee The percentage of the fee, out of MAX_FEE.\n /// @param _feeDiscount The percentage discount that should be applied out of the max amount, out of MAX_FEE_DISCOUNT.\n /// @return The amount of the fee, as a fixed point number with the same amount of decimals as this terminal.\n function _feeAmount(\n uint256 _amount,\n uint256 _fee,\n uint256 _feeDiscount\n ) internal pure returns (uint256) {\n // Calculate the discounted fee.\n uint256 _discountedFee = _fee -\n PRBMath.mulDiv(_fee, _feeDiscount, JBConstants.MAX_FEE_DISCOUNT);\n\n // The amount of tokens from the `_amount` to pay as a fee.\n return\n _amount - PRBMath.mulDiv(_amount, JBConstants.MAX_FEE, _discountedFee + JBConstants.MAX_FEE);\n }\n\n /// @notice Get the fee discount from the fee gauge for the specified project.\n /// @param _projectId The ID of the project to get a fee discount for.\n /// @return feeDiscount The fee discount, which should be interpreted as a percentage out MAX_FEE_DISCOUNT.\n function _currentFeeDiscount(uint256 _projectId) internal view returns (uint256) {\n // Can't take a fee if the protocol project doesn't have a terminal that accepts the token.\n if (\n directory.primaryTerminalOf(_FEE_BENEFICIARY_PROJECT_ID, token) ==\n IJBPaymentTerminal(address(0))\n ) return JBConstants.MAX_FEE_DISCOUNT;\n\n // Get the fee discount.\n if (feeGauge != address(0))\n // If the guage reverts, keep the discount at 0.\n try IJBFeeGauge(feeGauge).currentDiscountFor(_projectId) returns (uint256 discount) {\n // If the fee discount is greater than the max, we ignore the return value\n if (discount <= JBConstants.MAX_FEE_DISCOUNT) return discount;\n } catch {\n return 0;\n }\n\n return 0;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165Checker.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC165.sol\";\n\n/**\n * @dev Library used to query support of an interface declared via {IERC165}.\n *\n * Note that these functions return the actual result of the query: they do not\n * `revert` if an interface is not supported. It is up to the caller to decide\n * what to do in these cases.\n */\nlibrary ERC165Checker {\n // As per the EIP-165 spec, no interface should ever match 0xffffffff\n bytes4 private constant _INTERFACE_ID_INVALID = 0xffffffff;\n\n /**\n * @dev Returns true if `account` supports the {IERC165} interface,\n */\n function supportsERC165(address account) internal view returns (bool) {\n // Any contract that implements ERC165 must explicitly indicate support of\n // InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid\n return\n _supportsERC165Interface(account, type(IERC165).interfaceId) &&\n !_supportsERC165Interface(account, _INTERFACE_ID_INVALID);\n }\n\n /**\n * @dev Returns true if `account` supports the interface defined by\n * `interfaceId`. Support for {IERC165} itself is queried automatically.\n *\n * See {IERC165-supportsInterface}.\n */\n function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) {\n // query support of both ERC165 as per the spec and support of _interfaceId\n return supportsERC165(account) && _supportsERC165Interface(account, interfaceId);\n }\n\n /**\n * @dev Returns a boolean array where each value corresponds to the\n * interfaces passed in and whether they're supported or not. This allows\n * you to batch check interfaces for a contract where your expectation\n * is that some interfaces may not be supported.\n *\n * See {IERC165-supportsInterface}.\n *\n * _Available since v3.4._\n */\n function getSupportedInterfaces(address account, bytes4[] memory interfaceIds)\n internal\n view\n returns (bool[] memory)\n {\n // an array of booleans corresponding to interfaceIds and whether they're supported or not\n bool[] memory interfaceIdsSupported = new bool[](interfaceIds.length);\n\n // query support of ERC165 itself\n if (supportsERC165(account)) {\n // query support of each interface in interfaceIds\n for (uint256 i = 0; i < interfaceIds.length; i++) {\n interfaceIdsSupported[i] = _supportsERC165Interface(account, interfaceIds[i]);\n }\n }\n\n return interfaceIdsSupported;\n }\n\n /**\n * @dev Returns true if `account` supports all the interfaces defined in\n * `interfaceIds`. Support for {IERC165} itself is queried automatically.\n *\n * Batch-querying can lead to gas savings by skipping repeated checks for\n * {IERC165} support.\n *\n * See {IERC165-supportsInterface}.\n */\n function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) {\n // query support of ERC165 itself\n if (!supportsERC165(account)) {\n return false;\n }\n\n // query support of each interface in _interfaceIds\n for (uint256 i = 0; i < interfaceIds.length; i++) {\n if (!_supportsERC165Interface(account, interfaceIds[i])) {\n return false;\n }\n }\n\n // all interfaces supported\n return true;\n }\n\n /**\n * @notice Query if a contract implements an interface, does not check ERC165 support\n * @param account The address of the contract to query for support of an interface\n * @param interfaceId The interface identifier, as specified in ERC-165\n * @return true if the contract at account indicates support of the interface with\n * identifier interfaceId, false otherwise\n * @dev Assumes that account contains a contract that supports ERC165, otherwise\n * the behavior of this method is undefined. This precondition can be checked\n * with {supportsERC165}.\n * Interface identification is specified in ERC-165.\n */\n function _supportsERC165Interface(address account, bytes4 interfaceId) private view returns (bool) {\n bytes memory encodedParams = abi.encodeWithSelector(IERC165.supportsInterface.selector, interfaceId);\n (bool success, bytes memory result) = account.staticcall{gas: 30000}(encodedParams);\n if (result.length < 32) return false;\n return success && abi.decode(result, (bool));\n }\n}\n" + }, + "contracts/interfaces/IJBAllowanceTerminal3_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBAllowanceTerminal3_1 {\n function useAllowanceOf(\n uint256 projectId,\n uint256 amount,\n uint256 currency,\n address token,\n uint256 minReturnedTokens,\n address payable beneficiary,\n string calldata memo,\n bytes calldata metadata\n ) external returns (uint256 netDistributedAmount);\n}\n" + }, + "contracts/interfaces/IJBFeeGauge.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBFeeGauge {\n function currentDiscountFor(uint256 projectId) external view returns (uint256);\n}\n" + }, + "contracts/interfaces/IJBPayoutRedemptionPaymentTerminal3_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBFee} from './../structs/JBFee.sol';\nimport {IJBAllowanceTerminal3_1} from './IJBAllowanceTerminal3_1.sol';\nimport {IJBDirectory} from './IJBDirectory.sol';\nimport {IJBFeeHoldingTerminal} from './IJBFeeHoldingTerminal.sol';\nimport {IJBPayDelegate} from './IJBPayDelegate.sol';\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\nimport {IJBPayoutTerminal3_1} from './IJBPayoutTerminal3_1.sol';\nimport {IJBPrices} from './IJBPrices.sol';\nimport {IJBProjects} from './IJBProjects.sol';\nimport {IJBRedemptionDelegate} from './IJBRedemptionDelegate.sol';\nimport {IJBRedemptionTerminal} from './IJBRedemptionTerminal.sol';\nimport {IJBSplitsStore} from './IJBSplitsStore.sol';\nimport {JBDidPayData} from './../structs/JBDidPayData.sol';\nimport {JBDidRedeemData} from './../structs/JBDidRedeemData.sol';\nimport {JBSplit} from './../structs/JBSplit.sol';\n\ninterface IJBPayoutRedemptionPaymentTerminal3_1 is\n IJBPaymentTerminal,\n IJBPayoutTerminal3_1,\n IJBAllowanceTerminal3_1,\n IJBRedemptionTerminal,\n IJBFeeHoldingTerminal\n{\n event AddToBalance(\n uint256 indexed projectId,\n uint256 amount,\n uint256 refundedFees,\n string memo,\n bytes metadata,\n address caller\n );\n\n event Migrate(\n uint256 indexed projectId,\n IJBPaymentTerminal indexed to,\n uint256 amount,\n address caller\n );\n\n event DistributePayouts(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n address beneficiary,\n uint256 amount,\n uint256 distributedAmount,\n uint256 fee,\n uint256 beneficiaryDistributionAmount,\n bytes metadata,\n address caller\n );\n\n event UseAllowance(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n address beneficiary,\n uint256 amount,\n uint256 distributedAmount,\n uint256 netDistributedamount,\n string memo,\n bytes metadata,\n address caller\n );\n\n event HoldFee(\n uint256 indexed projectId,\n uint256 indexed amount,\n uint256 indexed fee,\n uint256 feeDiscount,\n address beneficiary,\n address caller\n );\n\n event ProcessFee(\n uint256 indexed projectId,\n uint256 indexed amount,\n bool indexed wasHeld,\n address beneficiary,\n address caller\n );\n\n event RefundHeldFees(\n uint256 indexed projectId,\n uint256 indexed amount,\n uint256 indexed refundedFees,\n uint256 leftoverAmount,\n address caller\n );\n\n event Pay(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n address payer,\n address beneficiary,\n uint256 amount,\n uint256 beneficiaryTokenCount,\n string memo,\n bytes metadata,\n address caller\n );\n\n event DelegateDidPay(\n IJBPayDelegate indexed delegate,\n JBDidPayData data,\n uint256 delegatedAmount,\n address caller\n );\n\n event RedeemTokens(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n address holder,\n address beneficiary,\n uint256 tokenCount,\n uint256 reclaimedAmount,\n string memo,\n bytes metadata,\n address caller\n );\n\n event DelegateDidRedeem(\n IJBRedemptionDelegate indexed delegate,\n JBDidRedeemData data,\n uint256 delegatedAmount,\n address caller\n );\n\n event DistributeToPayoutSplit(\n uint256 indexed projectId,\n uint256 indexed domain,\n uint256 indexed group,\n JBSplit split,\n uint256 amount,\n uint256 netAmount,\n address caller\n );\n\n event SetFee(uint256 fee, address caller);\n\n event SetFeeGauge(address indexed feeGauge, address caller);\n\n event SetFeelessAddress(address indexed addrs, bool indexed flag, address caller);\n\n event PayoutReverted(\n uint256 indexed projectId,\n JBSplit split,\n uint256 amount,\n bytes reason,\n address caller\n );\n\n event FeeReverted(\n uint256 indexed projectId,\n uint256 indexed feeProjectId,\n uint256 amount,\n bytes reason,\n address caller\n );\n\n function projects() external view returns (IJBProjects);\n\n function splitsStore() external view returns (IJBSplitsStore);\n\n function directory() external view returns (IJBDirectory);\n\n function prices() external view returns (IJBPrices);\n\n function store() external view returns (address);\n\n function baseWeightCurrency() external view returns (uint256);\n\n function payoutSplitsGroup() external view returns (uint256);\n\n function heldFeesOf(uint256 projectId) external view returns (JBFee[] memory);\n\n function fee() external view returns (uint256);\n\n function feeGauge() external view returns (address);\n\n function isFeelessAddress(address account) external view returns (bool);\n\n function migrate(uint256 projectId, IJBPaymentTerminal to) external returns (uint256 balance);\n\n function processFees(uint256 projectId) external;\n\n function setFee(uint256 fee) external;\n\n function setFeeGauge(address feeGauge) external;\n\n function setFeelessAddress(address account, bool flag) external;\n}\n" + }, + "contracts/interfaces/IJBPayoutTerminal3_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBPayoutTerminal3_1 {\n function distributePayoutsOf(\n uint256 projectId,\n uint256 amount,\n uint256 currency,\n address token,\n uint256 minReturnedTokens,\n bytes calldata metadata\n ) external returns (uint256 netLeftoverDistributionAmount);\n}\n" + }, + "contracts/abstract/JBSingleTokenPaymentTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {ERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol';\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\nimport {IJBSingleTokenPaymentTerminal} from './../interfaces/IJBSingleTokenPaymentTerminal.sol';\n\n/// @notice Generic terminal managing all inflows of funds into the protocol ecosystem for one token.\nabstract contract JBSingleTokenPaymentTerminal is ERC165, IJBSingleTokenPaymentTerminal {\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice The token that this terminal accepts.\n address public immutable override token;\n\n /// @notice The number of decimals the token fixed point amounts are expected to have.\n uint256 public immutable override decimals;\n\n /// @notice The currency to use when resolving price feeds for this terminal.\n uint256 public immutable override currency;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice A flag indicating if this terminal accepts the specified token.\n /// @param _token The token to check if this terminal accepts or not.\n /// @param _projectId The project ID to check for token acceptance.\n /// @return The flag.\n function acceptsToken(address _token, uint256 _projectId) external view override returns (bool) {\n _projectId; // Prevents unused var compiler and natspec complaints.\n\n return _token == token;\n }\n\n /// @notice The decimals that should be used in fixed number accounting for the specified token.\n /// @param _token The token to check for the decimals of.\n /// @return The number of decimals for the token.\n function decimalsForToken(address _token) external view override returns (uint256) {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return decimals;\n }\n\n /// @notice The currency that should be used for the specified token.\n /// @param _token The token to check for the currency of.\n /// @return The currency index.\n function currencyForToken(address _token) external view override returns (uint256) {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return currency;\n }\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if the provided interface ID is supported.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(ERC165, IERC165) returns (bool) {\n return\n _interfaceId == type(IJBPaymentTerminal).interfaceId ||\n _interfaceId == type(IJBSingleTokenPaymentTerminal).interfaceId ||\n super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _token The token that this terminal manages.\n /// @param _decimals The number of decimals the token fixed point amounts are expected to have.\n /// @param _currency The currency that this terminal's token adheres to for price feeds.\n constructor(address _token, uint256 _decimals, uint256 _currency) {\n token = _token;\n decimals = _decimals;\n currency = _currency;\n }\n}\n" + }, + "contracts/interfaces/IJBFeeHoldingTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBFeeHoldingTerminal {\n function addToBalanceOf(\n uint256 projectId,\n uint256 amount,\n address token,\n bool shouldRefundHeldFees,\n string calldata memo,\n bytes calldata metadata\n ) external payable;\n}\n" + }, + "contracts/JBETHPaymentTerminal3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Address} from '@openzeppelin/contracts/utils/Address.sol';\nimport {JBPayoutRedemptionPaymentTerminal3_1_1} from './abstract/JBPayoutRedemptionPaymentTerminal3_1_1.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\nimport {JBCurrencies} from './libraries/JBCurrencies.sol';\nimport {JBSplitsGroups} from './libraries/JBSplitsGroups.sol';\nimport {JBTokens} from './libraries/JBTokens.sol';\n\n/// @notice Manages all inflows and outflows of ETH funds into the protocol ecosystem.\ncontract JBETHPaymentTerminal3_1_1 is JBPayoutRedemptionPaymentTerminal3_1_1 {\n //*********************************************************************//\n // -------------------------- internal views ------------------------- //\n //*********************************************************************//\n\n /// @notice Checks the balance of tokens in this contract.\n /// @return The contract's balance, as a fixed point number with the same amount of decimals as this terminal.\n function _balance() internal view override returns (uint256) {\n return address(this).balance;\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _prices A contract that exposes price feeds.\n /// @param _store A contract that stores the terminal's data.\n /// @param _owner The address that will own this contract.\n constructor(\n uint256 _baseWeightCurrency,\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBSplitsStore _splitsStore,\n IJBPrices _prices,\n address _store,\n address _owner\n )\n JBPayoutRedemptionPaymentTerminal3_1_1(\n JBTokens.ETH,\n 18, // 18 decimals.\n JBCurrencies.ETH,\n _baseWeightCurrency,\n JBSplitsGroups.ETH_PAYOUT,\n _operatorStore,\n _projects,\n _directory,\n _splitsStore,\n _prices,\n _store,\n _owner\n )\n // solhint-disable-next-line no-empty-blocks\n {\n\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Transfers tokens.\n /// @param _from The address from which the transfer should originate.\n /// @param _to The address to which the transfer should go.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _transferFrom(address _from, address payable _to, uint256 _amount) internal override {\n _from; // Prevents unused var compiler and natspec complaints.\n\n Address.sendValue(_to, _amount);\n }\n}\n" + }, + "contracts/abstract/JBPayoutRedemptionPaymentTerminal3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {ERC165Checker} from '@openzeppelin/contracts/utils/introspection/ERC165Checker.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {JBFeeType} from './../enums/JBFeeType.sol';\nimport {IJBAllowanceTerminal3_1} from './../interfaces/IJBAllowanceTerminal3_1.sol';\nimport {IJBController} from './../interfaces/IJBController.sol';\nimport {IJBDirectory} from './../interfaces/IJBDirectory.sol';\nimport {IJBPayoutRedemptionPaymentTerminal3_1} from './../interfaces/IJBPayoutRedemptionPaymentTerminal3_1.sol';\nimport {IJBPayoutRedemptionPaymentTerminal3_1_1} from './../interfaces/IJBPayoutRedemptionPaymentTerminal3_1_1.sol';\nimport {IJBSplitsStore} from './../interfaces/IJBSplitsStore.sol';\nimport {IJBFeeGauge3_1} from './../interfaces/IJBFeeGauge3_1.sol';\nimport {IJBOperatable} from './../interfaces/IJBOperatable.sol';\nimport {IJBOperatorStore} from './../interfaces/IJBOperatorStore.sol';\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\nimport {IJBPayoutTerminal3_1} from './../interfaces/IJBPayoutTerminal3_1.sol';\nimport {IJBPrices} from './../interfaces/IJBPrices.sol';\nimport {IJBProjects} from './../interfaces/IJBProjects.sol';\nimport {IJBRedemptionTerminal} from './../interfaces/IJBRedemptionTerminal.sol';\nimport {IJBSingleTokenPaymentTerminalStore3_1_1} from './../interfaces/IJBSingleTokenPaymentTerminalStore3_1_1.sol';\nimport {IJBSplitAllocator} from './../interfaces/IJBSplitAllocator.sol';\nimport {JBConstants} from './../libraries/JBConstants.sol';\nimport {JBCurrencies} from './../libraries/JBCurrencies.sol';\nimport {JBFixedPointNumber} from './../libraries/JBFixedPointNumber.sol';\nimport {JBFundingCycleMetadataResolver} from './../libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBOperations} from './../libraries/JBOperations.sol';\nimport {JBTokens} from './../libraries/JBTokens.sol';\nimport {JBDidRedeemData3_1_1} from './../structs/JBDidRedeemData3_1_1.sol';\nimport {JBDidPayData3_1_1} from './../structs/JBDidPayData3_1_1.sol';\nimport {JBFee} from './../structs/JBFee.sol';\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\nimport {JBPayDelegateAllocation3_1_1} from './../structs/JBPayDelegateAllocation3_1_1.sol';\nimport {JBRedemptionDelegateAllocation3_1_1} from './../structs/JBRedemptionDelegateAllocation3_1_1.sol';\nimport {JBSplit} from './../structs/JBSplit.sol';\nimport {JBSplitAllocationData} from './../structs/JBSplitAllocationData.sol';\nimport {JBTokenAmount} from './../structs/JBTokenAmount.sol';\nimport {JBOperatable} from './JBOperatable.sol';\nimport {JBSingleTokenPaymentTerminal} from './JBSingleTokenPaymentTerminal.sol';\n\n/// @notice Generic terminal managing all inflows and outflows of funds into the protocol ecosystem.\nabstract contract JBPayoutRedemptionPaymentTerminal3_1_1 is\n JBSingleTokenPaymentTerminal,\n JBOperatable,\n Ownable,\n IJBPayoutRedemptionPaymentTerminal3_1,\n IJBPayoutRedemptionPaymentTerminal3_1_1\n{\n // A library that parses the packed funding cycle metadata into a friendlier format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error FEE_TOO_HIGH();\n error INADEQUATE_DISTRIBUTION_AMOUNT();\n error INADEQUATE_RECLAIM_AMOUNT();\n error INADEQUATE_TOKEN_COUNT();\n error NO_MSG_VALUE_ALLOWED();\n error PAY_TO_ZERO_ADDRESS();\n error PROJECT_TERMINAL_MISMATCH();\n error REDEEM_TO_ZERO_ADDRESS();\n error TERMINAL_TOKENS_INCOMPATIBLE();\n\n //*********************************************************************//\n // --------------------- internal stored constants ------------------- //\n //*********************************************************************//\n\n /// @notice Maximum fee that can be set for a funding cycle configuration.\n /// @dev Out of MAX_FEE (50_000_000 / 1_000_000_000).\n uint256 internal constant _FEE_CAP = 50_000_000;\n\n /// @notice The fee beneficiary project ID is 1, as it should be the first project launched during the deployment process.\n uint256 internal constant _FEE_BENEFICIARY_PROJECT_ID = 1;\n\n //*********************************************************************//\n // --------------------- internal stored properties ------------------ //\n //*********************************************************************//\n\n /// @notice Fees that are being held to be processed later.\n /// @custom:param _projectId The ID of the project for which fees are being held.\n mapping(uint256 => JBFee[]) internal _heldFeesOf;\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice Mints ERC-721's that represent project ownership and transfers.\n IJBProjects public immutable override projects;\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n /// @notice The contract that stores splits for each project.\n IJBSplitsStore public immutable override splitsStore;\n\n /// @notice The contract that exposes price feeds.\n IJBPrices public immutable override prices;\n\n /// @notice The contract that stores and manages the terminal's data.\n address public immutable override store;\n\n /// @notice The currency to base token issuance on.\n /// @dev If this differs from `currency`, there must be a price feed available to convert `currency` to `baseWeightCurrency`.\n uint256 public immutable override baseWeightCurrency;\n\n /// @notice The group that payout splits coming from this terminal are identified by.\n uint256 public immutable override payoutSplitsGroup;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The platform fee percent.\n /// @dev Out of MAX_FEE (25_000_000 / 1_000_000_000)\n uint256 public override fee = 25_000_000; // 2.5%\n\n /// @notice The data source that returns a discount to apply to a project's fee.\n address public override feeGauge;\n\n /// @notice Addresses that can be paid towards from this terminal without incurring a fee.\n /// @dev Only addresses that are considered to be contained within the ecosystem can be feeless. Funds sent outside the ecosystem may incur fees despite being stored as feeless.\n /// @custom:param _address The address that can be paid toward.\n mapping(address => bool) public override isFeelessAddress;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Gets the current overflowed amount in this terminal for a specified project, in terms of ETH.\n /// @dev The current overflow is represented as a fixed point number with 18 decimals.\n /// @param _projectId The ID of the project to get overflow for.\n /// @return The current amount of ETH overflow that project has in this terminal, as a fixed point number with 18 decimals.\n function currentEthOverflowOf(\n uint256 _projectId\n ) external view virtual override returns (uint256) {\n // Get this terminal's current overflow.\n uint256 _overflow = IJBSingleTokenPaymentTerminalStore3_1_1(store).currentOverflowOf(\n this,\n _projectId\n );\n\n // Adjust the decimals of the fixed point number if needed to have 18 decimals.\n uint256 _adjustedOverflow = (decimals == 18)\n ? _overflow\n : JBFixedPointNumber.adjustDecimals(_overflow, decimals, 18);\n\n // Return the amount converted to ETH.\n return\n (currency == JBCurrencies.ETH)\n ? _adjustedOverflow\n : PRBMath.mulDiv(\n _adjustedOverflow,\n 10 ** decimals,\n prices.priceFor(currency, JBCurrencies.ETH, decimals)\n );\n }\n\n /// @notice The fees that are currently being held to be processed later for each project.\n /// @param _projectId The ID of the project for which fees are being held.\n /// @return An array of fees that are being held.\n function heldFeesOf(uint256 _projectId) external view override returns (JBFee[] memory) {\n return _heldFeesOf[_projectId];\n }\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if the provided interface ID is supported.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(JBSingleTokenPaymentTerminal, IERC165) returns (bool) {\n return\n _interfaceId == type(IJBPayoutRedemptionPaymentTerminal3_1_1).interfaceId ||\n _interfaceId == type(IJBPayoutRedemptionPaymentTerminal3_1).interfaceId ||\n _interfaceId == type(IJBPayoutTerminal3_1).interfaceId ||\n _interfaceId == type(IJBAllowanceTerminal3_1).interfaceId ||\n _interfaceId == type(IJBRedemptionTerminal).interfaceId ||\n _interfaceId == type(IJBOperatable).interfaceId ||\n super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // -------------------------- internal views ------------------------- //\n //*********************************************************************//\n\n /// @notice Checks the balance of tokens in this contract.\n /// @return The contract's balance.\n function _balance() internal view virtual returns (uint256);\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _token The token that this terminal manages.\n /// @param _decimals The number of decimals the token fixed point amounts are expected to have.\n /// @param _currency The currency that this terminal's token adheres to for price feeds.\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _payoutSplitsGroup The group that denotes payout splits from this terminal in the splits store.\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _prices A contract that exposes price feeds.\n /// @param _store A contract that stores the terminal's data.\n /// @param _owner The address that will own this contract.\n constructor(\n // payable constructor save the gas used to check msg.value==0\n address _token,\n uint256 _decimals,\n uint256 _currency,\n uint256 _baseWeightCurrency,\n uint256 _payoutSplitsGroup,\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBSplitsStore _splitsStore,\n IJBPrices _prices,\n address _store,\n address _owner\n )\n payable\n JBSingleTokenPaymentTerminal(_token, _decimals, _currency)\n JBOperatable(_operatorStore)\n {\n baseWeightCurrency = _baseWeightCurrency;\n payoutSplitsGroup = _payoutSplitsGroup;\n projects = _projects;\n directory = _directory;\n splitsStore = _splitsStore;\n prices = _prices;\n store = _store;\n\n transferOwnership(_owner);\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Contribute tokens to a project.\n /// @param _projectId The ID of the project being paid.\n /// @param _amount The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place.\n /// @param _token The token being paid. This terminal ignores this property since it only manages one token.\n /// @param _beneficiary The address to mint tokens for and pass along to the funding cycle's data source and delegate.\n /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\n /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals.\n function pay(\n uint256 _projectId,\n uint256 _amount,\n address _token,\n address _beneficiary,\n uint256 _minReturnedTokens,\n bool _preferClaimedTokens,\n string calldata _memo,\n bytes calldata _metadata\n ) external payable virtual override returns (uint256) {\n _token; // Prevents unused var compiler and natspec complaints.\n\n // valid terminal check\n _isTerminalOf(_projectId);\n\n // ETH shouldn't be sent if this terminal's token isn't ETH.\n if (token != JBTokens.ETH) {\n if (msg.value != 0) revert NO_MSG_VALUE_ALLOWED();\n\n // Get a reference to the balance before receiving tokens.\n uint256 _balanceBefore = _balance();\n\n // Transfer tokens to this terminal from the msg sender.\n _transferFrom(msg.sender, payable(address(this)), _amount);\n\n // The amount should reflect the change in balance.\n _amount = _balance() - _balanceBefore;\n }\n // If this terminal's token is ETH, override _amount with msg.value.\n else _amount = msg.value;\n\n return\n _pay(\n _amount,\n msg.sender,\n _projectId,\n _beneficiary,\n _minReturnedTokens,\n _preferClaimedTokens,\n _memo,\n _metadata\n );\n }\n\n /// @notice Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source.\n /// @dev Only a token holder or a designated operator can redeem its tokens.\n /// @param _holder The account to redeem tokens for.\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\n /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals.\n /// @param _token The token being reclaimed. This terminal ignores this property since it only manages one token.\n /// @param _minReturnedTokens The minimum amount of terminal tokens expected in return, as a fixed point number with the same amount of decimals as the terminal.\n /// @param _beneficiary The address to send the terminal tokens to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return reclaimAmount The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals.\n function redeemTokensOf(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n address _token,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo,\n bytes memory _metadata\n )\n external\n virtual\n override\n requirePermission(_holder, _projectId, JBOperations.REDEEM)\n returns (uint256 reclaimAmount)\n {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return\n _redeemTokensOf(\n _holder,\n _projectId,\n _tokenCount,\n _minReturnedTokens,\n _beneficiary,\n _memo,\n _metadata\n );\n }\n\n /// @notice Distributes payouts for a project with the distribution limit of its current funding cycle.\n /// @dev Payouts are sent to the preprogrammed splits. Any leftover is sent to the project's owner.\n /// @dev 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.\n /// @dev All funds distributed outside of this contract or any feeless terminals incure the protocol fee.\n /// @param _projectId The ID of the project having its payouts distributed.\n /// @param _amount The amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency.\n /// @param _token The token being distributed. This terminal ignores this property since it only manages one token.\n /// @param _minReturnedTokens 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.\n /// @param _metadata Bytes to send along to the emitted event, if provided.\n /// @return netLeftoverDistributionAmount The amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal.\n function distributePayoutsOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n address _token,\n uint256 _minReturnedTokens,\n bytes calldata _metadata\n ) external virtual override returns (uint256 netLeftoverDistributionAmount) {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return _distributePayoutsOf(_projectId, _amount, _currency, _minReturnedTokens, _metadata);\n }\n\n /// @notice Allows a project to send funds from its overflow up to the preconfigured allowance.\n /// @dev Only a project's owner or a designated operator can use its allowance.\n /// @dev Incurs the protocol fee.\n /// @param _projectId The ID of the project to use the allowance of.\n /// @param _amount The amount of terminal tokens to use from this project's current allowance, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's overflow allowance currency.\n /// @param _token The token being distributed. This terminal ignores this property since it only manages one token.\n /// @param _minReturnedTokens The minimum number of tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with 18 decimals.\n /// @param _beneficiary The address to send the funds to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the emitted event, if provided.\n /// @return netDistributedAmount The amount of tokens that was distributed to the beneficiary, as a fixed point number with the same amount of decimals as the terminal.\n function useAllowanceOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n address _token,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo,\n bytes calldata _metadata\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.USE_ALLOWANCE)\n returns (uint256 netDistributedAmount)\n {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return\n _useAllowanceOf(\n _projectId,\n _amount,\n _currency,\n _minReturnedTokens,\n _beneficiary,\n _memo,\n _metadata\n );\n }\n\n /// @notice Allows a project owner to migrate its funds and operations to a new terminal that accepts the same token type.\n /// @dev Only a project's owner or a designated operator can migrate it.\n /// @param _projectId The ID of the project being migrated.\n /// @param _to The terminal contract that will gain the project's funds.\n /// @return balance The amount of funds that were migrated, as a fixed point number with the same amount of decimals as this terminal.\n function migrate(\n uint256 _projectId,\n IJBPaymentTerminal _to\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.MIGRATE_TERMINAL)\n returns (uint256 balance)\n {\n // The terminal being migrated to must accept the same token as this terminal.\n if (!_to.acceptsToken(token, _projectId)) revert TERMINAL_TOKENS_INCOMPATIBLE();\n\n // Record the migration in the store.\n balance = IJBSingleTokenPaymentTerminalStore3_1_1(store).recordMigration(_projectId);\n\n // Transfer the balance if needed.\n if (balance != 0) {\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_to), balance);\n\n // If this terminal's token is ETH, send it in msg.value.\n uint256 _payableValue = token == JBTokens.ETH ? balance : 0;\n\n // Withdraw the balance to transfer to the new terminal;\n _to.addToBalanceOf{value: _payableValue}(_projectId, balance, token, '', bytes(''));\n }\n\n emit Migrate(_projectId, _to, balance, msg.sender);\n }\n\n /// @notice Receives funds belonging to the specified project.\n /// @param _projectId The ID of the project to which the funds received belong.\n /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\n /// @param _token The token being paid. This terminal ignores this property since it only manages one currency.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the emitted event.\n function addToBalanceOf(\n uint256 _projectId,\n uint256 _amount,\n address _token,\n string calldata _memo,\n bytes calldata _metadata\n ) external payable virtual override {\n // valid terminal check\n _isTerminalOf(_projectId);\n\n // Do not refund held fees by default.\n addToBalanceOf(_projectId, _amount, _token, false, _memo, _metadata);\n }\n\n /// @notice Process any fees that are being held for the project.\n /// @dev Only a project owner, an operator, or the contract's owner can process held fees.\n /// @param _projectId The ID of the project whos held fees should be processed.\n function processFees(\n uint256 _projectId\n )\n external\n virtual\n override\n requirePermissionAllowingOverride(\n projects.ownerOf(_projectId),\n _projectId,\n JBOperations.PROCESS_FEES,\n msg.sender == owner()\n )\n {\n // Get a reference to the project's held fees.\n JBFee[] memory _heldFees = _heldFeesOf[_projectId];\n\n // Delete the held fees.\n delete _heldFeesOf[_projectId];\n\n // Push array length in stack\n uint256 _heldFeeLength = _heldFees.length;\n\n // Keep a reference to the amount.\n uint256 _amount;\n\n // Process each fee.\n for (uint256 _i; _i < _heldFeeLength; ) {\n // Get the fee amount.\n _amount = (\n _heldFees[_i].fee == 0 || _heldFees[_i].feeDiscount == JBConstants.MAX_FEE_DISCOUNT\n ? 0\n : _feeAmount(_heldFees[_i].amount, _heldFees[_i].fee, _heldFees[_i].feeDiscount)\n );\n\n // Process the fee.\n _processFee(_amount, _heldFees[_i].beneficiary, _projectId);\n\n emit ProcessFee(_projectId, _amount, true, _heldFees[_i].beneficiary, msg.sender);\n\n unchecked {\n ++_i;\n }\n }\n }\n\n /// @notice Allows the fee to be updated.\n /// @dev Only the owner of this contract can change the fee.\n /// @param _fee The new fee, out of MAX_FEE.\n function setFee(uint256 _fee) external virtual override onlyOwner {\n // The provided fee must be within the max.\n if (_fee > _FEE_CAP) revert FEE_TOO_HIGH();\n\n // Store the new fee.\n fee = _fee;\n\n emit SetFee(_fee, msg.sender);\n }\n\n /// @notice Allows the fee gauge to be updated.\n /// @dev Only the owner of this contract can change the fee gauge.\n /// @param _feeGauge The new fee gauge.\n function setFeeGauge(address _feeGauge) external virtual override onlyOwner {\n // Store the new fee gauge.\n feeGauge = _feeGauge;\n\n emit SetFeeGauge(_feeGauge, msg.sender);\n }\n\n /// @notice Sets whether projects operating on this terminal can pay towards the specified address without incurring a fee.\n /// @dev Only the owner of this contract can set addresses as feeless.\n /// @param _address The address that can be paid towards while still bypassing fees.\n /// @param _flag A flag indicating whether the terminal should be feeless or not.\n function setFeelessAddress(address _address, bool _flag) external virtual override onlyOwner {\n // Set the flag value.\n isFeelessAddress[_address] = _flag;\n\n emit SetFeelessAddress(_address, _flag, msg.sender);\n }\n\n //*********************************************************************//\n // ----------------------- public transactions ----------------------- //\n //*********************************************************************//\n\n /// @notice Receives funds belonging to the specified project.\n /// @param _projectId The ID of the project to which the funds received belong.\n /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\n /// @param _token The token being paid. This terminal ignores this property since it only manages one currency.\n /// @param _shouldRefundHeldFees A flag indicating if held fees should be refunded based on the amount being added.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the emitted event.\n function addToBalanceOf(\n uint256 _projectId,\n uint256 _amount,\n address _token,\n bool _shouldRefundHeldFees,\n string calldata _memo,\n bytes calldata _metadata\n ) public payable virtual override {\n // valid terminal check\n _isTerminalOf(_projectId);\n\n _token; // Prevents unused var compiler and natspec complaints.\n\n // If this terminal's token isn't ETH, make sure no msg.value was sent, then transfer the tokens in from msg.sender.\n if (token != JBTokens.ETH) {\n // Amount must be greater than 0.\n if (msg.value != 0) revert NO_MSG_VALUE_ALLOWED();\n\n // Get a reference to the balance before receiving tokens.\n uint256 _balanceBefore = _balance();\n\n // Transfer tokens to this terminal from the msg sender.\n _transferFrom(msg.sender, payable(address(this)), _amount);\n\n // The amount should reflect the change in balance.\n _amount = _balance() - _balanceBefore;\n }\n // If the terminal's token is ETH, override `_amount` with msg.value.\n else _amount = msg.value;\n\n // Add to balance.\n _addToBalanceOf(_projectId, _amount, _shouldRefundHeldFees, _memo, _metadata);\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Transfers tokens.\n /// @param _from The address from which the transfer should originate.\n /// @param _to The address to which the transfer should go.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _transferFrom(address _from, address payable _to, uint256 _amount) internal virtual {\n _from; // Prevents unused var compiler and natspec complaints.\n _to; // Prevents unused var compiler and natspec complaints.\n _amount; // Prevents unused var compiler and natspec complaints.\n }\n\n /// @notice Logic to be triggered before transferring tokens from this terminal.\n /// @param _to The address to which the transfer is going.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _beforeTransferTo(address _to, uint256 _amount) internal virtual {\n _to; // Prevents unused var compiler and natspec complaints.\n _amount; // Prevents unused var compiler and natspec complaints.\n }\n\n /// @notice Logic to be triggered if a transfer should be undone\n /// @param _to The address to which the transfer went.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _cancelTransferTo(address _to, uint256 _amount) internal virtual {\n _to; // Prevents unused var compiler and natspec complaints.\n _amount; // Prevents unused var compiler and natspec complaints.\n }\n\n /// @notice Verifies this terminal is a terminal of provided project ID.\n /// @param _projectId The ID of the project to check if this contract is a terminal of.\n function _isTerminalOf(uint256 _projectId) internal view {\n if (!directory.isTerminalOf(_projectId, this)) revert PROJECT_TERMINAL_MISMATCH();\n }\n\n /// @notice Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source.\n /// @dev Only a token holder or a designated operator can redeem its tokens.\n /// @param _holder The account to redeem tokens for.\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\n /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals.\n /// @param _minReturnedTokens The minimum amount of terminal tokens expected in return, as a fixed point number with the same amount of decimals as the terminal.\n /// @param _beneficiary The address to send the terminal tokens to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return reclaimAmount The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals.\n function _redeemTokensOf(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo,\n bytes memory _metadata\n ) internal returns (uint256 reclaimAmount) {\n // Can't send reclaimed funds to the zero address.\n if (_beneficiary == address(0)) revert REDEEM_TO_ZERO_ADDRESS();\n\n // Define variables that will be needed outside the scoped section below.\n // Keep a reference to the funding cycle during which the redemption is being made.\n JBFundingCycle memory _fundingCycle;\n\n // Scoped section prevents stack too deep. `_feeEligibleDistributionAmount`, `_feeDiscount` and `_feePercent` only used within scope.\n {\n // Keep a reference to the amount being reclaimed that should have fees withheld from.\n uint256 _feeEligibleDistributionAmount;\n\n // Keep a reference to the amount of discount to apply to the fee.\n uint256 _feeDiscount;\n\n // Keep a reference to the fee.\n uint256 _feePercent = fee;\n\n // Scoped section prevents stack too deep. `_delegateAllocations` only used within scope.\n {\n JBRedemptionDelegateAllocation3_1_1[] memory _delegateAllocations;\n\n // Record the redemption.\n (\n _fundingCycle,\n reclaimAmount,\n _delegateAllocations,\n _memo\n ) = IJBSingleTokenPaymentTerminalStore3_1_1(store).recordRedemptionFor(\n _holder,\n _projectId,\n _tokenCount,\n _memo,\n _metadata\n );\n\n // Set the reference to the fee discount to apply. No fee if the beneficiary is feeless or if the redemption rate is at its max.\n _feeDiscount = isFeelessAddress[_beneficiary] ||\n (_fundingCycle.redemptionRate() == JBConstants.MAX_REDEMPTION_RATE &&\n _fundingCycle.ballotRedemptionRate() == JBConstants.MAX_REDEMPTION_RATE) ||\n _feePercent == 0\n ? JBConstants.MAX_FEE_DISCOUNT\n : _currentFeeDiscount(_projectId, JBFeeType.REDEMPTION);\n\n // The amount being reclaimed must be at least as much as was expected.\n if (reclaimAmount < _minReturnedTokens) revert INADEQUATE_RECLAIM_AMOUNT();\n\n // Burn the project tokens.\n if (_tokenCount != 0)\n IJBController(directory.controllerOf(_projectId)).burnTokensOf(\n _holder,\n _projectId,\n _tokenCount,\n '',\n false\n );\n\n // If delegate allocations were specified by the data source, fulfill them.\n if (_delegateAllocations.length != 0) {\n JBDidRedeemData3_1_1 memory _data = JBDidRedeemData3_1_1(\n _holder,\n _projectId,\n _fundingCycle.configuration,\n _tokenCount,\n JBTokenAmount(token, reclaimAmount, decimals, currency),\n JBTokenAmount(token, 0, decimals, currency),\n _beneficiary,\n _memo,\n bytes(''),\n _metadata\n );\n\n // Keep a reference to the allocation.\n JBRedemptionDelegateAllocation3_1_1 memory _delegateAllocation;\n\n // Keep a reference to the fee.\n uint256 _delegatedAmountFee;\n\n // Keep a reference to the number of allocations.\n uint256 _numDelegates = _delegateAllocations.length;\n\n for (uint256 _i; _i < _numDelegates; ) {\n // Get a reference to the delegate being iterated on.\n _delegateAllocation = _delegateAllocations[_i];\n\n // Get the fee for the delegated amount.\n _delegatedAmountFee = _feePercent == 0\n ? 0\n : _feeAmount(_delegateAllocation.amount, _feePercent, _feeDiscount);\n\n // Add the delegated amount to the amount eligible for having a fee taken.\n if (_delegatedAmountFee != 0) {\n _feeEligibleDistributionAmount += _delegateAllocation.amount;\n _delegateAllocation.amount -= _delegatedAmountFee;\n }\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_delegateAllocation.delegate), _delegateAllocation.amount);\n\n // Pass the correct token forwardedAmount to the delegate\n _data.forwardedAmount.value = _delegateAllocation.amount;\n\n // Pass the correct metadata from the data source.\n _data.dataSourceMetadata = _delegateAllocation.metadata;\n\n _delegateAllocation.delegate.didRedeem{\n value: token == JBTokens.ETH ? _delegateAllocation.amount : 0\n }(_data);\n\n emit DelegateDidRedeem(\n _delegateAllocation.delegate,\n _data,\n _delegateAllocation.amount,\n _delegatedAmountFee,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n }\n\n // Send the reclaimed funds to the beneficiary.\n if (reclaimAmount != 0) {\n // Get the fee for the reclaimed amount.\n uint256 _reclaimAmountFee = _feeDiscount == JBConstants.MAX_FEE_DISCOUNT\n ? 0\n : _feeAmount(reclaimAmount, _feePercent, _feeDiscount);\n\n if (_reclaimAmountFee != 0) {\n _feeEligibleDistributionAmount += reclaimAmount;\n reclaimAmount -= _reclaimAmountFee;\n }\n\n // Subtract the fee from the reclaim amount.\n if (reclaimAmount != 0) _transferFrom(address(this), _beneficiary, reclaimAmount);\n }\n\n // Take the fee from all outbound reclaimations.\n _feeEligibleDistributionAmount != 0\n ? _takeFeeFrom(\n _projectId,\n false,\n _feeEligibleDistributionAmount,\n _feePercent,\n _beneficiary,\n _feeDiscount\n )\n : 0;\n }\n\n emit RedeemTokens(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _holder,\n _beneficiary,\n _tokenCount,\n reclaimAmount,\n _memo,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Distributes payouts for a project with the distribution limit of its current funding cycle.\n /// @dev Payouts are sent to the preprogrammed splits. Any leftover is sent to the project's owner.\n /// @dev 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.\n /// @dev All funds distributed outside of this contract or any feeless terminals incure the protocol fee.\n /// @param _projectId The ID of the project having its payouts distributed.\n /// @param _amount The amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency.\n /// @param _minReturnedTokens 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.\n /// @param _metadata Bytes to send along to the emitted event, if provided.\n /// @return netLeftoverDistributionAmount The amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal.\n function _distributePayoutsOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n uint256 _minReturnedTokens,\n bytes calldata _metadata\n ) internal returns (uint256 netLeftoverDistributionAmount) {\n // Record the distribution.\n (\n JBFundingCycle memory _fundingCycle,\n uint256 _distributedAmount\n ) = IJBSingleTokenPaymentTerminalStore3_1_1(store).recordDistributionFor(\n _projectId,\n _amount,\n _currency\n );\n\n // The amount being distributed must be at least as much as was expected.\n if (_distributedAmount < _minReturnedTokens) revert INADEQUATE_DISTRIBUTION_AMOUNT();\n\n // Get a reference to the project owner, which will receive tokens from paying the platform fee\n // and receive any extra distributable funds not allocated to payout splits.\n address payable _projectOwner = payable(projects.ownerOf(_projectId));\n\n // Define variables that will be needed outside the scoped section below.\n // Keep a reference to the fee amount that was paid.\n uint256 _feeTaken;\n\n // Scoped section prevents stack too deep. `_feePercent`, `_feeDiscount`, `_feeEligibleDistributionAmount`, and `_leftoverDistributionAmount` only used within scope.\n {\n // Keep a reference to the fee.\n uint256 _feePercent = fee;\n\n // Get the amount of discount that should be applied to any fees taken.\n // If the fee is zero, set the discount to 100% for convenience.\n uint256 _feeDiscount = _feePercent == 0\n ? JBConstants.MAX_FEE_DISCOUNT\n : _currentFeeDiscount(_projectId, JBFeeType.PAYOUT);\n\n // The amount distributed that is eligible for incurring fees.\n uint256 _feeEligibleDistributionAmount;\n\n // The amount leftover after distributing to the splits.\n uint256 _leftoverDistributionAmount;\n\n // Payout to splits and get a reference to the leftover transfer amount after all splits have been paid.\n // Also get a reference to the amount that was distributed to splits from which fees should be taken.\n (_leftoverDistributionAmount, _feeEligibleDistributionAmount) = _distributeToPayoutSplitsOf(\n _projectId,\n _fundingCycle.configuration,\n payoutSplitsGroup,\n _distributedAmount,\n _feePercent,\n _feeDiscount\n );\n\n if (_feeDiscount != JBConstants.MAX_FEE_DISCOUNT) {\n // Leftover distribution amount is also eligible for a fee since the funds are going out of the ecosystem to _beneficiary.\n unchecked {\n _feeEligibleDistributionAmount += _leftoverDistributionAmount;\n }\n }\n\n // Take the fee.\n _feeTaken = _feeEligibleDistributionAmount != 0\n ? _takeFeeFrom(\n _projectId,\n _fundingCycle.shouldHoldFees(),\n _feeEligibleDistributionAmount,\n _feePercent,\n _projectOwner,\n _feeDiscount\n )\n : 0;\n\n // Transfer any remaining balance to the project owner and update returned leftover accordingly.\n if (_leftoverDistributionAmount != 0) {\n // Subtract the fee from the net leftover amount.\n netLeftoverDistributionAmount =\n _leftoverDistributionAmount -\n (\n _feeDiscount == JBConstants.MAX_FEE_DISCOUNT\n ? 0\n : _feeAmount(_leftoverDistributionAmount, _feePercent, _feeDiscount)\n );\n\n // Transfer the amount to the project owner.\n _transferFrom(address(this), _projectOwner, netLeftoverDistributionAmount);\n }\n }\n\n emit DistributePayouts(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _projectOwner,\n _amount,\n _distributedAmount,\n _feeTaken,\n netLeftoverDistributionAmount,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Allows a project to send funds from its overflow up to the preconfigured allowance.\n /// @dev Only a project's owner or a designated operator can use its allowance.\n /// @dev Incurs the protocol fee.\n /// @param _projectId The ID of the project to use the allowance of.\n /// @param _amount The amount of terminal tokens to use from this project's current allowance, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's overflow allowance currency.\n /// @param _minReturnedTokens The minimum number of tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with 18 decimals.\n /// @param _beneficiary The address to send the funds to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the emitted event, if provided.\n /// @return netDistributedAmount The amount of tokens that was distributed to the beneficiary, as a fixed point number with the same amount of decimals as the terminal.\n function _useAllowanceOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo,\n bytes calldata _metadata\n ) internal returns (uint256 netDistributedAmount) {\n // Record the use of the allowance.\n (\n JBFundingCycle memory _fundingCycle,\n uint256 _distributedAmount\n ) = IJBSingleTokenPaymentTerminalStore3_1_1(store).recordUsedAllowanceOf(\n _projectId,\n _amount,\n _currency\n );\n\n // The amount being withdrawn must be at least as much as was expected.\n if (_distributedAmount < _minReturnedTokens) revert INADEQUATE_DISTRIBUTION_AMOUNT();\n\n // Scoped section prevents stack too deep. `_fee`, `_projectOwner`, `_feeDiscount`, and `_netAmount` only used within scope.\n {\n // Keep a reference to the fee amount that was paid.\n uint256 _feeTaken;\n\n // Keep a reference to the fee.\n uint256 _feePercent = fee;\n\n // Get a reference to the project owner, which will receive tokens from paying the platform fee.\n address _projectOwner = projects.ownerOf(_projectId);\n\n // Get the amount of discount that should be applied to any fees taken.\n // 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.\n uint256 _feeDiscount = _feePercent == 0 || isFeelessAddress[msg.sender]\n ? JBConstants.MAX_FEE_DISCOUNT\n : _currentFeeDiscount(_projectId, JBFeeType.ALLOWANCE);\n\n // Take a fee from the `_distributedAmount`, if needed.\n _feeTaken = _feeDiscount == JBConstants.MAX_FEE_DISCOUNT\n ? 0\n : _takeFeeFrom(\n _projectId,\n _fundingCycle.shouldHoldFees(),\n _distributedAmount,\n _feePercent,\n _projectOwner,\n _feeDiscount\n );\n\n unchecked {\n // The net amount is the withdrawn amount without the fee.\n netDistributedAmount = _distributedAmount - _feeTaken;\n }\n\n // Transfer any remaining balance to the beneficiary.\n if (netDistributedAmount != 0)\n _transferFrom(address(this), _beneficiary, netDistributedAmount);\n }\n\n emit UseAllowance(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _beneficiary,\n _amount,\n _distributedAmount,\n netDistributedAmount,\n _memo,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Pays out splits for a project's funding cycle configuration.\n /// @param _projectId The ID of the project for which payout splits are being distributed.\n /// @param _domain The domain of the splits to distribute the payout between.\n /// @param _group The group of the splits to distribute the payout between.\n /// @param _amount The total amount being distributed, as a fixed point number with the same number of decimals as this terminal.\n /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE.\n /// @param _feePercent The percent of fees to take, out of MAX_FEE.\n /// @return If the leftover amount if the splits don't add up to 100%.\n /// @return feeEligibleDistributionAmount The total amount of distributions that are eligible to have fees taken from.\n function _distributeToPayoutSplitsOf(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group,\n uint256 _amount,\n uint256 _feePercent,\n uint256 _feeDiscount\n ) internal returns (uint256, uint256 feeEligibleDistributionAmount) {\n // The total percentage available to split\n uint256 _leftoverPercentage = JBConstants.SPLITS_TOTAL_PERCENT;\n\n // Get a reference to the project's payout splits.\n JBSplit[] memory _splits = splitsStore.splitsOf(_projectId, _domain, _group);\n\n // Keep a reference to the split being iterated on.\n JBSplit memory _split;\n\n // Transfer between all splits.\n for (uint256 _i; _i < _splits.length; ) {\n // Get a reference to the split being iterated on.\n _split = _splits[_i];\n\n // The amount to send towards the split.\n uint256 _payoutAmount = PRBMath.mulDiv(_amount, _split.percent, _leftoverPercentage);\n\n // The payout amount substracting any applicable incurred fees.\n uint256 _netPayoutAmount = _distributeToPayoutSplit(\n _split,\n _projectId,\n _group,\n _payoutAmount,\n _feePercent,\n _feeDiscount\n );\n\n // If the split allocator is set as feeless, this distribution is not eligible for a fee.\n if (_netPayoutAmount != 0 && _netPayoutAmount != _payoutAmount)\n feeEligibleDistributionAmount += _payoutAmount;\n\n if (_payoutAmount != 0) {\n // Subtract from the amount to be sent to the beneficiary.\n unchecked {\n _amount -= _payoutAmount;\n }\n }\n\n unchecked {\n // Decrement the leftover percentage.\n _leftoverPercentage -= _split.percent;\n }\n\n emit DistributeToPayoutSplit(\n _projectId,\n _domain,\n _group,\n _split,\n _payoutAmount,\n _netPayoutAmount,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n\n return (_amount, feeEligibleDistributionAmount);\n }\n\n /// @notice Pays out a split for a project's funding cycle configuration.\n /// @param _split The split to distribute payouts to.\n /// @param _amount The total amount being distributed to the split, as a fixed point number with the same number of decimals as this terminal.\n /// @param _feePercent The percent of fees to take, out of MAX_FEE.\n /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE.\n /// @return netPayoutAmount The amount sent to the split after subtracting fees.\n function _distributeToPayoutSplit(\n JBSplit memory _split,\n uint256 _projectId,\n uint256 _group,\n uint256 _amount,\n uint256 _feePercent,\n uint256 _feeDiscount\n ) internal returns (uint256 netPayoutAmount) {\n // By default, the net payout amount is the full amount. This will be adjusted if fees are taken.\n netPayoutAmount = _amount;\n\n // If there's an allocator set, transfer to its `allocate` function.\n if (_split.allocator != IJBSplitAllocator(address(0))) {\n // This distribution is eligible for a fee since the funds are leaving this contract and the allocator isn't listed as feeless.\n if (\n _feeDiscount != JBConstants.MAX_FEE_DISCOUNT && !isFeelessAddress[address(_split.allocator)]\n ) {\n unchecked {\n netPayoutAmount -= _feeAmount(_amount, _feePercent, _feeDiscount);\n }\n }\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_split.allocator), netPayoutAmount);\n\n // Create the data to send to the allocator.\n JBSplitAllocationData memory _data = JBSplitAllocationData(\n token,\n netPayoutAmount,\n decimals,\n _projectId,\n _group,\n _split\n );\n\n // Trigger the allocator's `allocate` function.\n bytes memory _reason;\n\n if (\n ERC165Checker.supportsInterface(\n address(_split.allocator),\n type(IJBSplitAllocator).interfaceId\n )\n )\n // If this terminal's token is ETH, send it in msg.value.\n try\n _split.allocator.allocate{value: token == JBTokens.ETH ? netPayoutAmount : 0}(_data)\n {} catch (bytes memory __reason) {\n _reason = __reason.length == 0 ? abi.encode('Allocate fail') : __reason;\n }\n else {\n _reason = abi.encode('IERC165 fail');\n }\n\n if (_reason.length != 0) {\n // Revert the payout.\n _revertTransferFrom(_projectId, address(_split.allocator), netPayoutAmount, _amount);\n\n // Set the net payout amount to 0 to signal the reversion.\n netPayoutAmount = 0;\n\n emit PayoutReverted(_projectId, _split, _amount, _reason, msg.sender);\n }\n\n // Otherwise, if a project is specified, make a payment to it.\n } else if (_split.projectId != 0) {\n // Get a reference to the Juicebox terminal being used.\n IJBPaymentTerminal _terminal = directory.primaryTerminalOf(_split.projectId, token);\n\n // The project must have a terminal to send funds to.\n if (_terminal == IJBPaymentTerminal(address(0))) {\n // Set the net payout amount to 0 to signal the reversion.\n netPayoutAmount = 0;\n\n // Revert the payout.\n _revertTransferFrom(_projectId, address(0), 0, _amount);\n\n emit PayoutReverted(_projectId, _split, _amount, 'Terminal not found', msg.sender);\n } else {\n // This distribution is eligible for a fee since the funds are leaving this contract and the terminal isn't listed as feeless.\n if (\n _terminal != this &&\n _feeDiscount != JBConstants.MAX_FEE_DISCOUNT &&\n !isFeelessAddress[address(_terminal)]\n ) {\n unchecked {\n netPayoutAmount -= _feeAmount(_amount, _feePercent, _feeDiscount);\n }\n }\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_terminal), netPayoutAmount);\n\n // Add to balance if prefered.\n if (_split.preferAddToBalance)\n try\n _terminal.addToBalanceOf{value: token == JBTokens.ETH ? netPayoutAmount : 0}(\n _split.projectId,\n netPayoutAmount,\n token,\n '',\n // Send the projectId in the metadata as a referral.\n bytes(abi.encodePacked(_projectId))\n )\n {} catch (bytes memory _reason) {\n // Revert the payout.\n _revertTransferFrom(_projectId, address(_terminal), netPayoutAmount, _amount);\n\n // Set the net payout amount to 0 to signal the reversion.\n netPayoutAmount = 0;\n\n emit PayoutReverted(_projectId, _split, _amount, _reason, msg.sender);\n }\n else\n try\n _terminal.pay{value: token == JBTokens.ETH ? netPayoutAmount : 0}(\n _split.projectId,\n netPayoutAmount,\n token,\n _split.beneficiary != address(0) ? _split.beneficiary : msg.sender,\n 0,\n _split.preferClaimed,\n '',\n // Send the projectId in the metadata as a referral.\n bytes(abi.encodePacked(_projectId))\n )\n {} catch (bytes memory _reason) {\n // Revert the payout.\n _revertTransferFrom(_projectId, address(_terminal), netPayoutAmount, _amount);\n\n // Set the net payout amount to 0 to signal the reversion.\n netPayoutAmount = 0;\n\n emit PayoutReverted(_projectId, _split, _amount, _reason, msg.sender);\n }\n }\n } else {\n // This distribution is eligible for a fee since the funds are leaving this contract and the beneficiary isn't listed as feeless.\n // Don't enforce feeless address for the beneficiary since the funds are leaving the ecosystem.\n if (_feeDiscount != JBConstants.MAX_FEE_DISCOUNT) {\n unchecked {\n netPayoutAmount -= _feeAmount(_amount, _feePercent, _feeDiscount);\n }\n }\n\n // If there's a beneficiary, send the funds directly to the beneficiary. Otherwise send to the msg.sender.\n _transferFrom(\n address(this),\n _split.beneficiary != address(0) ? _split.beneficiary : payable(msg.sender),\n netPayoutAmount\n );\n }\n }\n\n /// @notice Takes a fee into the platform's project, which has an id of _FEE_BENEFICIARY_PROJECT_ID.\n /// @param _projectId The ID of the project having fees taken from.\n /// @param _shouldHoldFees If fees should be tracked and held back.\n /// @param _feePercent The percent of fees to take, out of MAX_FEE.\n /// @param _amount The amount of the fee to take, as a floating point number with 18 decimals.\n /// @param _beneficiary The address to mint the platforms tokens for.\n /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE.\n /// @return feeAmount The amount of the fee taken.\n function _takeFeeFrom(\n uint256 _projectId,\n bool _shouldHoldFees,\n uint256 _amount,\n uint256 _feePercent,\n address _beneficiary,\n uint256 _feeDiscount\n ) internal returns (uint256 feeAmount) {\n feeAmount = _feeAmount(_amount, _feePercent, _feeDiscount);\n\n if (_shouldHoldFees) {\n // Store the held fee.\n _heldFeesOf[_projectId].push(JBFee(_amount, uint32(fee), uint32(_feeDiscount), _beneficiary));\n\n emit HoldFee(_projectId, _amount, _feePercent, _feeDiscount, _beneficiary, msg.sender);\n } else {\n // Process the fee.\n _processFee(feeAmount, _beneficiary, _projectId); // Take the fee.\n\n emit ProcessFee(_projectId, feeAmount, false, _beneficiary, msg.sender);\n }\n }\n\n /// @notice Process a fee of the specified amount.\n /// @param _amount The fee amount, as a floating point number with 18 decimals.\n /// @param _beneficiary The address to mint the platform's tokens for.\n /// @param _from The project ID the fee is being paid from.\n function _processFee(uint256 _amount, address _beneficiary, uint256 _from) internal {\n // Get the terminal for the protocol project.\n IJBPaymentTerminal _terminal = directory.primaryTerminalOf(_FEE_BENEFICIARY_PROJECT_ID, token);\n\n // Trigger any inherited pre-transfer logic if funds will be transferred.\n if (address(_terminal) != address(this)) _beforeTransferTo(address(_terminal), _amount);\n\n try\n // Send the fee.\n // If this terminal's token is ETH, send it in msg.value.\n _terminal.pay{value: token == JBTokens.ETH ? _amount : 0}(\n _FEE_BENEFICIARY_PROJECT_ID,\n _amount,\n token,\n _beneficiary,\n 0,\n false,\n '',\n // Send the projectId in the metadata.\n bytes(abi.encodePacked(_from))\n )\n {} catch (bytes memory _reason) {\n _revertTransferFrom(\n _from,\n address(_terminal) != address(this) ? address(_terminal) : address(0),\n address(_terminal) != address(this) ? _amount : 0,\n _amount\n );\n emit FeeReverted(_from, _FEE_BENEFICIARY_PROJECT_ID, _amount, _reason, msg.sender);\n }\n }\n\n /// @notice Reverts an expected payout.\n /// @param _projectId The ID of the project having paying out.\n /// @param _expectedDestination The address the payout was expected to go to.\n /// @param _allowanceAmount The amount that the destination has been allowed to use.\n /// @param _depositAmount The amount of the payout as debited from the project's balance.\n function _revertTransferFrom(\n uint256 _projectId,\n address _expectedDestination,\n uint256 _allowanceAmount,\n uint256 _depositAmount\n ) internal {\n // Cancel allowance if needed.\n if (_allowanceAmount != 0) _cancelTransferTo(_expectedDestination, _allowanceAmount);\n\n // Add undistributed amount back to project's balance.\n IJBSingleTokenPaymentTerminalStore3_1_1(store).recordAddedBalanceFor(\n _projectId,\n _depositAmount\n );\n }\n\n /// @notice Contribute tokens to a project.\n /// @param _amount The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place.\n /// @param _payer The address making the payment.\n /// @param _projectId The ID of the project being paid.\n /// @param _beneficiary The address to mint tokens for and pass along to the funding cycle's data source and delegate.\n /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\n /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return beneficiaryTokenCount The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals.\n function _pay(\n uint256 _amount,\n address _payer,\n uint256 _projectId,\n address _beneficiary,\n uint256 _minReturnedTokens,\n bool _preferClaimedTokens,\n string memory _memo,\n bytes memory _metadata\n ) internal returns (uint256 beneficiaryTokenCount) {\n // Cant send tokens to the zero address.\n if (_beneficiary == address(0)) revert PAY_TO_ZERO_ADDRESS();\n\n // Define variables that will be needed outside the scoped section below.\n // Keep a reference to the funding cycle during which the payment is being made.\n JBFundingCycle memory _fundingCycle;\n\n // Scoped section prevents stack too deep. `_delegateAllocations` and `_tokenCount` only used within scope.\n {\n JBPayDelegateAllocation3_1_1[] memory _delegateAllocations;\n uint256 _tokenCount;\n\n // Bundle the amount info into a JBTokenAmount struct.\n JBTokenAmount memory _bundledAmount = JBTokenAmount(token, _amount, decimals, currency);\n\n // Record the payment.\n (\n _fundingCycle,\n _tokenCount,\n _delegateAllocations,\n _memo\n ) = IJBSingleTokenPaymentTerminalStore3_1_1(store).recordPaymentFrom(\n _payer,\n _bundledAmount,\n _projectId,\n baseWeightCurrency,\n _beneficiary,\n _memo,\n _metadata\n );\n\n // Mint the tokens if needed.\n if (_tokenCount != 0)\n // Set token count to be the number of tokens minted for the beneficiary instead of the total amount.\n beneficiaryTokenCount = IJBController(directory.controllerOf(_projectId)).mintTokensOf(\n _projectId,\n _tokenCount,\n _beneficiary,\n '',\n _preferClaimedTokens,\n true\n );\n\n // The token count for the beneficiary must be greater than or equal to the minimum expected.\n if (beneficiaryTokenCount < _minReturnedTokens) revert INADEQUATE_TOKEN_COUNT();\n\n // If delegate allocations were specified by the data source, fulfill them.\n if (_delegateAllocations.length != 0) {\n JBDidPayData3_1_1 memory _data = JBDidPayData3_1_1(\n _payer,\n _projectId,\n _fundingCycle.configuration,\n _bundledAmount,\n JBTokenAmount(token, 0, decimals, currency),\n beneficiaryTokenCount,\n _beneficiary,\n _preferClaimedTokens,\n _memo,\n bytes(''),\n _metadata\n );\n\n // Get a reference to the number of delegates to allocate to.\n uint256 _numDelegates = _delegateAllocations.length;\n\n // Keep a reference to the allocation.\n JBPayDelegateAllocation3_1_1 memory _delegateAllocation;\n\n for (uint256 _i; _i < _numDelegates; ) {\n // Get a reference to the delegate being iterated on.\n _delegateAllocation = _delegateAllocations[_i];\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_delegateAllocation.delegate), _delegateAllocation.amount);\n\n // Pass the correct token forwardedAmount to the delegate\n _data.forwardedAmount.value = _delegateAllocation.amount;\n\n // Pass the correct metadata from the data source.\n _data.dataSourceMetadata = _delegateAllocation.metadata;\n\n _delegateAllocation.delegate.didPay{\n value: token == JBTokens.ETH ? _delegateAllocation.amount : 0\n }(_data);\n\n emit DelegateDidPay(\n _delegateAllocation.delegate,\n _data,\n _delegateAllocation.amount,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n }\n\n emit Pay(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _payer,\n _beneficiary,\n _amount,\n beneficiaryTokenCount,\n _memo,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Receives funds belonging to the specified project.\n /// @param _projectId The ID of the project to which the funds received belong.\n /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\n /// @param _shouldRefundHeldFees A flag indicating if held fees should be refunded based on the amount being added.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the emitted event.\n function _addToBalanceOf(\n uint256 _projectId,\n uint256 _amount,\n bool _shouldRefundHeldFees,\n string memory _memo,\n bytes memory _metadata\n ) internal {\n // Refund any held fees to make sure the project doesn't pay double for funds going in and out of the protocol.\n uint256 _refundedFees = _shouldRefundHeldFees ? _refundHeldFees(_projectId, _amount) : 0;\n\n // Record the added funds with any refunded fees.\n IJBSingleTokenPaymentTerminalStore3_1_1(store).recordAddedBalanceFor(\n _projectId,\n _amount + _refundedFees\n );\n\n emit AddToBalance(_projectId, _amount, _refundedFees, _memo, _metadata, msg.sender);\n }\n\n /// @notice Refund fees based on the specified amount.\n /// @param _projectId The project for which fees are being refunded.\n /// @param _amount The amount to base the refund on, as a fixed point number with the same amount of decimals as this terminal.\n /// @return refundedFees How much fees were refunded, as a fixed point number with the same number of decimals as this terminal\n function _refundHeldFees(\n uint256 _projectId,\n uint256 _amount\n ) internal returns (uint256 refundedFees) {\n // Get a reference to the project's held fees.\n JBFee[] memory _heldFees = _heldFeesOf[_projectId];\n\n // Delete the current held fees.\n delete _heldFeesOf[_projectId];\n\n // Get a reference to the leftover amount once all fees have been settled.\n uint256 leftoverAmount = _amount;\n\n // Push length in stack\n uint256 _heldFeesLength = _heldFees.length;\n\n // Process each fee.\n for (uint256 _i; _i < _heldFeesLength; ) {\n if (leftoverAmount == 0) _heldFeesOf[_projectId].push(_heldFees[_i]);\n else if (leftoverAmount >= _heldFees[_i].amount) {\n unchecked {\n leftoverAmount = leftoverAmount - _heldFees[_i].amount;\n refundedFees += (\n _heldFees[_i].fee == 0 || _heldFees[_i].feeDiscount == JBConstants.MAX_FEE_DISCOUNT\n ? 0\n : _feeAmount(_heldFees[_i].amount, _heldFees[_i].fee, _heldFees[_i].feeDiscount)\n );\n }\n } else {\n unchecked {\n _heldFeesOf[_projectId].push(\n JBFee(\n _heldFees[_i].amount - leftoverAmount,\n _heldFees[_i].fee,\n _heldFees[_i].feeDiscount,\n _heldFees[_i].beneficiary\n )\n );\n refundedFees += (\n _heldFees[_i].fee == 0 || _heldFees[_i].feeDiscount == JBConstants.MAX_FEE_DISCOUNT\n ? 0\n : _feeAmount(leftoverAmount, _heldFees[_i].fee, _heldFees[_i].feeDiscount)\n );\n }\n leftoverAmount = 0;\n }\n\n unchecked {\n ++_i;\n }\n }\n\n emit RefundHeldFees(_projectId, _amount, refundedFees, leftoverAmount, msg.sender);\n }\n\n /// @notice Returns the fee amount based on the provided amount for the specified project.\n /// @param _amount The amount that the fee is based on, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _fee The percentage of the fee, out of MAX_FEE.\n /// @param _feeDiscount The percentage discount that should be applied out of the max amount, out of MAX_FEE_DISCOUNT.\n /// @return The amount of the fee, as a fixed point number with the same amount of decimals as this terminal.\n function _feeAmount(\n uint256 _amount,\n uint256 _fee,\n uint256 _feeDiscount\n ) internal pure returns (uint256) {\n // Calculate the discounted fee.\n uint256 _discountedFee = _fee -\n PRBMath.mulDiv(_fee, _feeDiscount, JBConstants.MAX_FEE_DISCOUNT);\n\n // The amount of tokens from the `_amount` to pay as a fee.\n return\n _amount - PRBMath.mulDiv(_amount, JBConstants.MAX_FEE, _discountedFee + JBConstants.MAX_FEE);\n }\n\n /// @notice Get the fee discount from the fee gauge for the specified project.\n /// @param _projectId The ID of the project to get a fee discount for.\n /// @param _feeType The type of fee the discount is being applied to.\n /// @return feeDiscount The fee discount, which should be interpreted as a percentage out MAX_FEE_DISCOUNT.\n function _currentFeeDiscount(\n uint256 _projectId,\n JBFeeType _feeType\n ) internal view returns (uint256) {\n // Can't take a fee if the protocol project doesn't have a terminal that accepts the token.\n if (\n directory.primaryTerminalOf(_FEE_BENEFICIARY_PROJECT_ID, token) ==\n IJBPaymentTerminal(address(0))\n ) return JBConstants.MAX_FEE_DISCOUNT;\n\n // Get the fee discount.\n if (feeGauge != address(0))\n // If the guage reverts, keep the discount at 0.\n try IJBFeeGauge3_1(feeGauge).currentDiscountFor(_projectId, _feeType) returns (\n uint256 discount\n ) {\n // If the fee discount is greater than the max, we ignore the return value\n if (discount <= JBConstants.MAX_FEE_DISCOUNT) return discount;\n } catch {\n return 0;\n }\n\n return 0;\n }\n}\n" + }, + "contracts/enums/JBFeeType.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nenum JBFeeType {\n PAYOUT,\n ALLOWANCE,\n REDEMPTION\n}\n" + }, + "contracts/interfaces/IJBPayoutRedemptionPaymentTerminal3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBFee} from './../structs/JBFee.sol';\nimport {JBDidRedeemData3_1_1} from './../structs/JBDidRedeemData3_1_1.sol';\nimport {JBDidPayData3_1_1} from './../structs/JBDidPayData3_1_1.sol';\nimport {IJBPayDelegate3_1_1} from './IJBPayDelegate3_1_1.sol';\nimport {IJBRedemptionDelegate3_1_1} from './IJBRedemptionDelegate3_1_1.sol';\n\ninterface IJBPayoutRedemptionPaymentTerminal3_1_1 {\n event DelegateDidRedeem(\n IJBRedemptionDelegate3_1_1 indexed delegate,\n JBDidRedeemData3_1_1 data,\n uint256 delegatedAmount,\n uint256 fee,\n address caller\n );\n\n event DelegateDidPay(\n IJBPayDelegate3_1_1 indexed delegate,\n JBDidPayData3_1_1 data,\n uint256 delegatedAmount,\n address caller\n );\n}\n" + }, + "contracts/interfaces/IJBFeeGauge3_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBFeeType} from './../enums/JBFeeType.sol';\n\ninterface IJBFeeGauge3_1 {\n function currentDiscountFor(uint256 projectId, JBFeeType feeType) external view returns (uint256);\n}\n" + }, + "contracts/JBETHPaymentTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Address} from '@openzeppelin/contracts/utils/Address.sol';\nimport {JBPayoutRedemptionPaymentTerminal} from './abstract/JBPayoutRedemptionPaymentTerminal.sol';\nimport {JBSplitsGroups} from './libraries/JBSplitsGroups.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {JBCurrencies} from './libraries/JBCurrencies.sol';\nimport {JBTokens} from './libraries/JBTokens.sol';\n\n/// @notice Manages all inflows and outflows of ETH funds into the protocol ecosystem.\ncontract JBETHPaymentTerminal is JBPayoutRedemptionPaymentTerminal {\n //*********************************************************************//\n // -------------------------- internal views ------------------------- //\n //*********************************************************************//\n\n /// @notice Checks the balance of tokens in this contract.\n /// @return The contract's balance, as a fixed point number with the same amount of decimals as this terminal.\n function _balance() internal view override returns (uint256) {\n return address(this).balance;\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _prices A contract that exposes price feeds.\n /// @param _store A contract that stores the terminal's data.\n /// @param _owner The address that will own this contract.\n constructor(\n uint256 _baseWeightCurrency,\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBSplitsStore _splitsStore,\n IJBPrices _prices,\n address _store,\n address _owner\n )\n JBPayoutRedemptionPaymentTerminal(\n JBTokens.ETH,\n 18, // 18 decimals.\n JBCurrencies.ETH,\n _baseWeightCurrency,\n JBSplitsGroups.ETH_PAYOUT,\n _operatorStore,\n _projects,\n _directory,\n _splitsStore,\n _prices,\n _store,\n _owner\n )\n // solhint-disable-next-line no-empty-blocks\n {\n\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Transfers tokens.\n /// @param _from The address from which the transfer should originate.\n /// @param _to The address to which the transfer should go.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _transferFrom(address _from, address payable _to, uint256 _amount) internal override {\n _from; // Prevents unused var compiler and natspec complaints.\n\n Address.sendValue(_to, _amount);\n }\n}\n" + }, + "contracts/abstract/JBPayoutRedemptionPaymentTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {IJBAllowanceTerminal} from './../interfaces/IJBAllowanceTerminal.sol';\nimport {IJBController} from './../interfaces/IJBController.sol';\nimport {IJBDirectory} from './../interfaces/IJBDirectory.sol';\nimport {IJBPayoutRedemptionPaymentTerminal} from './../interfaces/IJBPayoutRedemptionPaymentTerminal.sol';\nimport {IJBSplitAllocator} from './../interfaces/IJBSplitAllocator.sol';\nimport {IJBFeeGauge} from './../interfaces/IJBFeeGauge.sol';\nimport {IJBOperatable} from './../interfaces/IJBOperatable.sol';\nimport {IJBOperatorStore} from './../interfaces/IJBOperatorStore.sol';\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\nimport {IJBPayoutTerminal} from './../interfaces/IJBPayoutTerminal.sol';\nimport {IJBPrices} from './../interfaces/IJBPrices.sol';\nimport {IJBProjects} from './../interfaces/IJBProjects.sol';\nimport {IJBRedemptionTerminal} from './../interfaces/IJBRedemptionTerminal.sol';\nimport {IJBSingleTokenPaymentTerminalStore} from './../interfaces/IJBSingleTokenPaymentTerminalStore.sol';\nimport {IJBSplitsStore} from './../interfaces/IJBSplitsStore.sol';\nimport {JBConstants} from './../libraries/JBConstants.sol';\nimport {JBCurrencies} from './../libraries/JBCurrencies.sol';\nimport {JBFixedPointNumber} from './../libraries/JBFixedPointNumber.sol';\nimport {JBFundingCycleMetadataResolver} from './../libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBOperations} from './../libraries/JBOperations.sol';\nimport {JBTokens} from './../libraries/JBTokens.sol';\nimport {JBDidPayData} from './../structs/JBDidPayData.sol';\nimport {JBDidRedeemData} from './../structs/JBDidRedeemData.sol';\nimport {JBFee} from './../structs/JBFee.sol';\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\nimport {JBPayDelegateAllocation} from './../structs/JBPayDelegateAllocation.sol';\nimport {JBTokenAmount} from './../structs/JBTokenAmount.sol';\nimport {JBRedemptionDelegateAllocation} from './../structs/JBRedemptionDelegateAllocation.sol';\nimport {JBSplit} from './../structs/JBSplit.sol';\nimport {JBSplitAllocationData} from './../structs/JBSplitAllocationData.sol';\nimport {JBOperatable} from './JBOperatable.sol';\nimport {JBSingleTokenPaymentTerminal} from './JBSingleTokenPaymentTerminal.sol';\n\n/// @notice Generic terminal managing all inflows and outflows of funds into the protocol ecosystem.\n/// A project can transfer its funds, along with the power to reconfigure and mint/burn their tokens, from this contract to another allowed terminal of the same token type contract at any time.\nabstract contract JBPayoutRedemptionPaymentTerminal is\n JBSingleTokenPaymentTerminal,\n JBOperatable,\n Ownable,\n IJBPayoutRedemptionPaymentTerminal\n{\n // A library that parses the packed funding cycle metadata into a friendlier format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error FEE_TOO_HIGH();\n error INADEQUATE_DISTRIBUTION_AMOUNT();\n error INADEQUATE_RECLAIM_AMOUNT();\n error INADEQUATE_TOKEN_COUNT();\n error NO_MSG_VALUE_ALLOWED();\n error PAY_TO_ZERO_ADDRESS();\n error PROJECT_TERMINAL_MISMATCH();\n error REDEEM_TO_ZERO_ADDRESS();\n error TERMINAL_IN_SPLIT_ZERO_ADDRESS();\n error TERMINAL_TOKENS_INCOMPATIBLE();\n\n //*********************************************************************//\n // ---------------------------- modifiers ---------------------------- //\n //*********************************************************************//\n\n /// @notice A modifier that verifies this terminal is a terminal of provided project ID.\n modifier isTerminalOf(uint256 _projectId) {\n if (!directory.isTerminalOf(_projectId, this)) revert PROJECT_TERMINAL_MISMATCH();\n _;\n }\n\n //*********************************************************************//\n // --------------------- internal stored constants ------------------- //\n //*********************************************************************//\n\n /// @notice Maximum fee that can be set for a funding cycle configuration.\n /// @dev Out of MAX_FEE (50_000_000 / 1_000_000_000).\n uint256 internal constant _FEE_CAP = 50_000_000;\n\n /// @notice The fee beneficiary project ID is 1, as it should be the first project launched during the deployment process.\n uint256 internal constant _FEE_BENEFICIARY_PROJECT_ID = 1;\n\n //*********************************************************************//\n // --------------------- internal stored properties ------------------ //\n //*********************************************************************//\n\n /// @notice Fees that are being held to be processed later.\n /// @custom:param _projectId The ID of the project for which fees are being held.\n mapping(uint256 => JBFee[]) internal _heldFeesOf;\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice Mints ERC-721's that represent project ownership and transfers.\n IJBProjects public immutable override projects;\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n /// @notice The contract that stores splits for each project.\n IJBSplitsStore public immutable override splitsStore;\n\n /// @notice The contract that exposes price feeds.\n IJBPrices public immutable override prices;\n\n /// @notice The contract that stores and manages the terminal's data.\n address public immutable override store;\n\n /// @notice The currency to base token issuance on.\n /// @dev If this differs from `currency`, there must be a price feed available to convert `currency` to `baseWeightCurrency`.\n uint256 public immutable override baseWeightCurrency;\n\n /// @notice The group that payout splits coming from this terminal are identified by.\n uint256 public immutable override payoutSplitsGroup;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The platform fee percent.\n /// @dev Out of MAX_FEE (25_000_000 / 1_000_000_000)\n uint256 public override fee = 25_000_000; // 2.5%\n\n /// @notice The data source that returns a discount to apply to a project's fee.\n address public override feeGauge;\n\n /// @notice Addresses that can be paid towards from this terminal without incurring a fee.\n /// @dev Only addresses that are considered to be contained within the ecosystem can be feeless. Funds sent outside the ecosystem may incur fees despite being stored as feeless.\n /// @custom:param _address The address that can be paid toward.\n mapping(address => bool) public override isFeelessAddress;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Gets the current overflowed amount in this terminal for a specified project, in terms of ETH.\n /// @dev The current overflow is represented as a fixed point number with 18 decimals.\n /// @param _projectId The ID of the project to get overflow for.\n /// @return The current amount of ETH overflow that project has in this terminal, as a fixed point number with 18 decimals.\n function currentEthOverflowOf(\n uint256 _projectId\n ) external view virtual override returns (uint256) {\n // Get this terminal's current overflow.\n uint256 _overflow = IJBSingleTokenPaymentTerminalStore(store).currentOverflowOf(\n this,\n _projectId\n );\n\n // Adjust the decimals of the fixed point number if needed to have 18 decimals.\n uint256 _adjustedOverflow = (decimals == 18)\n ? _overflow\n : JBFixedPointNumber.adjustDecimals(_overflow, decimals, 18);\n\n // Return the amount converted to ETH.\n return\n (currency == JBCurrencies.ETH)\n ? _adjustedOverflow\n : PRBMath.mulDiv(\n _adjustedOverflow,\n 10 ** decimals,\n prices.priceFor(currency, JBCurrencies.ETH, decimals)\n );\n }\n\n /// @notice The fees that are currently being held to be processed later for each project.\n /// @param _projectId The ID of the project for which fees are being held.\n /// @return An array of fees that are being held.\n function heldFeesOf(uint256 _projectId) external view override returns (JBFee[] memory) {\n return _heldFeesOf[_projectId];\n }\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if the provided interface ID is supported.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(JBSingleTokenPaymentTerminal, IERC165) returns (bool) {\n return\n _interfaceId == type(IJBPayoutRedemptionPaymentTerminal).interfaceId ||\n _interfaceId == type(IJBPayoutTerminal).interfaceId ||\n _interfaceId == type(IJBAllowanceTerminal).interfaceId ||\n _interfaceId == type(IJBRedemptionTerminal).interfaceId ||\n _interfaceId == type(IJBOperatable).interfaceId ||\n super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // -------------------------- internal views ------------------------- //\n //*********************************************************************//\n\n /// @notice Checks the balance of tokens in this contract.\n /// @return The contract's balance.\n function _balance() internal view virtual returns (uint256);\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _token The token that this terminal manages.\n /// @param _decimals The number of decimals the token fixed point amounts are expected to have.\n /// @param _currency The currency that this terminal's token adheres to for price feeds.\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _payoutSplitsGroup The group that denotes payout splits from this terminal in the splits store.\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _prices A contract that exposes price feeds.\n /// @param _store A contract that stores the terminal's data.\n /// @param _owner The address that will own this contract.\n constructor(\n // payable constructor save the gas used to check msg.value==0\n address _token,\n uint256 _decimals,\n uint256 _currency,\n uint256 _baseWeightCurrency,\n uint256 _payoutSplitsGroup,\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBSplitsStore _splitsStore,\n IJBPrices _prices,\n address _store,\n address _owner\n )\n payable\n JBSingleTokenPaymentTerminal(_token, _decimals, _currency)\n JBOperatable(_operatorStore)\n {\n baseWeightCurrency = _baseWeightCurrency;\n payoutSplitsGroup = _payoutSplitsGroup;\n projects = _projects;\n directory = _directory;\n splitsStore = _splitsStore;\n prices = _prices;\n store = _store;\n\n transferOwnership(_owner);\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Contribute tokens to a project.\n /// @param _projectId The ID of the project being paid.\n /// @param _amount The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place.\n /// @param _token The token being paid. This terminal ignores this property since it only manages one token.\n /// @param _beneficiary The address to mint tokens for and pass along to the funding cycle's data source and delegate.\n /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\n /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals.\n function pay(\n uint256 _projectId,\n uint256 _amount,\n address _token,\n address _beneficiary,\n uint256 _minReturnedTokens,\n bool _preferClaimedTokens,\n string calldata _memo,\n bytes calldata _metadata\n ) external payable virtual override isTerminalOf(_projectId) returns (uint256) {\n _token; // Prevents unused var compiler and natspec complaints.\n\n // ETH shouldn't be sent if this terminal's token isn't ETH.\n if (token != JBTokens.ETH) {\n if (msg.value > 0) revert NO_MSG_VALUE_ALLOWED();\n\n // Get a reference to the balance before receiving tokens.\n uint256 _balanceBefore = _balance();\n\n // Transfer tokens to this terminal from the msg sender.\n _transferFrom(msg.sender, payable(address(this)), _amount);\n\n // The amount should reflect the change in balance.\n _amount = _balance() - _balanceBefore;\n }\n // If this terminal's token is ETH, override _amount with msg.value.\n else _amount = msg.value;\n\n return\n _pay(\n _amount,\n msg.sender,\n _projectId,\n _beneficiary,\n _minReturnedTokens,\n _preferClaimedTokens,\n _memo,\n _metadata\n );\n }\n\n /// @notice Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source.\n /// @dev Only a token holder or a designated operator can redeem its tokens.\n /// @param _holder The account to redeem tokens for.\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\n /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals.\n /// @param _token The token being reclaimed. This terminal ignores this property since it only manages one token.\n /// @param _minReturnedTokens The minimum amount of terminal tokens expected in return, as a fixed point number with the same amount of decimals as the terminal.\n /// @param _beneficiary The address to send the terminal tokens to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return reclaimAmount The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals.\n function redeemTokensOf(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n address _token,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo,\n bytes memory _metadata\n )\n external\n virtual\n override\n requirePermission(_holder, _projectId, JBOperations.REDEEM)\n returns (uint256 reclaimAmount)\n {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return\n _redeemTokensOf(\n _holder,\n _projectId,\n _tokenCount,\n _minReturnedTokens,\n _beneficiary,\n _memo,\n _metadata\n );\n }\n\n /// @notice Distributes payouts for a project with the distribution limit of its current funding cycle.\n /// @dev Payouts are sent to the preprogrammed splits. Any leftover is sent to the project's owner.\n /// @dev 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.\n /// @dev All funds distributed outside of this contract or any feeless terminals incure the protocol fee.\n /// @param _projectId The ID of the project having its payouts distributed.\n /// @param _amount The amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency.\n /// @param _token The token being distributed. This terminal ignores this property since it only manages one token.\n /// @param _minReturnedTokens 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.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return netLeftoverDistributionAmount The amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal.\n function distributePayoutsOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n address _token,\n uint256 _minReturnedTokens,\n string calldata _memo\n ) external virtual override returns (uint256 netLeftoverDistributionAmount) {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return _distributePayoutsOf(_projectId, _amount, _currency, _minReturnedTokens, _memo);\n }\n\n /// @notice Allows a project to send funds from its overflow up to the preconfigured allowance.\n /// @dev Only a project's owner or a designated operator can use its allowance.\n /// @dev Incurs the protocol fee.\n /// @param _projectId The ID of the project to use the allowance of.\n /// @param _amount The amount of terminal tokens to use from this project's current allowance, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's overflow allowance currency.\n /// @param _token The token being distributed. This terminal ignores this property since it only manages one token.\n /// @param _minReturnedTokens The minimum number of tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with 18 decimals.\n /// @param _beneficiary The address to send the funds to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return netDistributedAmount The amount of tokens that was distributed to the beneficiary, as a fixed point number with the same amount of decimals as the terminal.\n function useAllowanceOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n address _token,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.USE_ALLOWANCE)\n returns (uint256 netDistributedAmount)\n {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return _useAllowanceOf(_projectId, _amount, _currency, _minReturnedTokens, _beneficiary, _memo);\n }\n\n /// @notice Allows a project owner to migrate its funds and operations to a new terminal that accepts the same token type.\n /// @dev Only a project's owner or a designated operator can migrate it.\n /// @param _projectId The ID of the project being migrated.\n /// @param _to The terminal contract that will gain the project's funds.\n /// @return balance The amount of funds that were migrated, as a fixed point number with the same amount of decimals as this terminal.\n function migrate(\n uint256 _projectId,\n IJBPaymentTerminal _to\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.MIGRATE_TERMINAL)\n returns (uint256 balance)\n {\n // The terminal being migrated to must accept the same token as this terminal.\n if (!_to.acceptsToken(token, _projectId)) revert TERMINAL_TOKENS_INCOMPATIBLE();\n\n // Record the migration in the store.\n balance = IJBSingleTokenPaymentTerminalStore(store).recordMigration(_projectId);\n\n // Transfer the balance if needed.\n if (balance > 0) {\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_to), balance);\n\n // If this terminal's token is ETH, send it in msg.value.\n uint256 _payableValue = token == JBTokens.ETH ? balance : 0;\n\n // Withdraw the balance to transfer to the new terminal;\n _to.addToBalanceOf{value: _payableValue}(_projectId, balance, token, '', bytes(''));\n }\n\n emit Migrate(_projectId, _to, balance, msg.sender);\n }\n\n /// @notice Receives funds belonging to the specified project.\n /// @param _projectId The ID of the project to which the funds received belong.\n /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\n /// @param _token The token being paid. This terminal ignores this property since it only manages one currency.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the emitted event.\n function addToBalanceOf(\n uint256 _projectId,\n uint256 _amount,\n address _token,\n string calldata _memo,\n bytes calldata _metadata\n ) external payable virtual override isTerminalOf(_projectId) {\n _token; // Prevents unused var compiler and natspec complaints.\n\n // If this terminal's token isn't ETH, make sure no msg.value was sent, then transfer the tokens in from msg.sender.\n if (token != JBTokens.ETH) {\n // Amount must be greater than 0.\n if (msg.value > 0) revert NO_MSG_VALUE_ALLOWED();\n\n // Get a reference to the balance before receiving tokens.\n uint256 _balanceBefore = _balance();\n\n // Transfer tokens to this terminal from the msg sender.\n _transferFrom(msg.sender, payable(address(this)), _amount);\n\n // The amount should reflect the change in balance.\n _amount = _balance() - _balanceBefore;\n }\n // If the terminal's token is ETH, override `_amount` with msg.value.\n else _amount = msg.value;\n\n // Add to balance while only refunding held fees if the funds aren't originating from a feeless terminal.\n _addToBalanceOf(_projectId, _amount, !isFeelessAddress[msg.sender], _memo, _metadata);\n }\n\n /// @notice Process any fees that are being held for the project.\n /// @dev Only a project owner, an operator, or the contract's owner can process held fees.\n /// @param _projectId The ID of the project whos held fees should be processed.\n function processFees(\n uint256 _projectId\n )\n external\n virtual\n override\n requirePermissionAllowingOverride(\n projects.ownerOf(_projectId),\n _projectId,\n JBOperations.PROCESS_FEES,\n msg.sender == owner()\n )\n {\n // Get a reference to the project's held fees.\n JBFee[] memory _heldFees = _heldFeesOf[_projectId];\n\n // Delete the held fees.\n delete _heldFeesOf[_projectId];\n\n // Push array length in stack\n uint256 _heldFeeLength = _heldFees.length;\n\n // Process each fee.\n for (uint256 _i; _i < _heldFeeLength; ) {\n // Get the fee amount.\n uint256 _amount = _feeAmount(\n _heldFees[_i].amount,\n _heldFees[_i].fee,\n _heldFees[_i].feeDiscount\n );\n\n // Process the fee.\n _processFee(_amount, _heldFees[_i].beneficiary);\n\n emit ProcessFee(_projectId, _amount, true, _heldFees[_i].beneficiary, msg.sender);\n\n unchecked {\n ++_i;\n }\n }\n }\n\n /// @notice Allows the fee to be updated.\n /// @dev Only the owner of this contract can change the fee.\n /// @param _fee The new fee, out of MAX_FEE.\n function setFee(uint256 _fee) external virtual override onlyOwner {\n // The provided fee must be within the max.\n if (_fee > _FEE_CAP) revert FEE_TOO_HIGH();\n\n // Store the new fee.\n fee = _fee;\n\n emit SetFee(_fee, msg.sender);\n }\n\n /// @notice Allows the fee gauge to be updated.\n /// @dev Only the owner of this contract can change the fee gauge.\n /// @param _feeGauge The new fee gauge.\n function setFeeGauge(address _feeGauge) external virtual override onlyOwner {\n // Store the new fee gauge.\n feeGauge = _feeGauge;\n\n emit SetFeeGauge(_feeGauge, msg.sender);\n }\n\n /// @notice Sets whether projects operating on this terminal can pay towards the specified address without incurring a fee.\n /// @dev Only the owner of this contract can set addresses as feeless.\n /// @param _address The address that can be paid towards while still bypassing fees.\n /// @param _flag A flag indicating whether the terminal should be feeless or not.\n function setFeelessAddress(address _address, bool _flag) external virtual override onlyOwner {\n // Set the flag value.\n isFeelessAddress[_address] = _flag;\n\n emit SetFeelessAddress(_address, _flag, msg.sender);\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Transfers tokens.\n /// @param _from The address from which the transfer should originate.\n /// @param _to The address to which the transfer should go.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _transferFrom(address _from, address payable _to, uint256 _amount) internal virtual {\n _from; // Prevents unused var compiler and natspec complaints.\n _to; // Prevents unused var compiler and natspec complaints.\n _amount; // Prevents unused var compiler and natspec complaints.\n }\n\n /// @notice Logic to be triggered before transferring tokens from this terminal.\n /// @param _to The address to which the transfer is going.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _beforeTransferTo(address _to, uint256 _amount) internal virtual {\n _to; // Prevents unused var compiler and natspec complaints.\n _amount; // Prevents unused var compiler and natspec complaints.\n }\n\n /// @notice Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source.\n /// @dev Only a token holder or a designated operator can redeem its tokens.\n /// @param _holder The account to redeem tokens for.\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\n /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals.\n /// @param _minReturnedTokens The minimum amount of terminal tokens expected in return, as a fixed point number with the same amount of decimals as the terminal.\n /// @param _beneficiary The address to send the terminal tokens to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return reclaimAmount The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals.\n function _redeemTokensOf(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo,\n bytes memory _metadata\n ) internal returns (uint256 reclaimAmount) {\n // Can't send reclaimed funds to the zero address.\n if (_beneficiary == address(0)) revert REDEEM_TO_ZERO_ADDRESS();\n\n // Define variables that will be needed outside the scoped section below.\n // Keep a reference to the funding cycle during which the redemption is being made.\n JBFundingCycle memory _fundingCycle;\n\n // Scoped section prevents stack too deep. `_delegateAllocations` only used within scope.\n {\n JBRedemptionDelegateAllocation[] memory _delegateAllocations;\n\n // Record the redemption.\n (\n _fundingCycle,\n reclaimAmount,\n _delegateAllocations,\n _memo\n ) = IJBSingleTokenPaymentTerminalStore(store).recordRedemptionFor(\n _holder,\n _projectId,\n _tokenCount,\n _memo,\n _metadata\n );\n\n // The amount being reclaimed must be at least as much as was expected.\n if (reclaimAmount < _minReturnedTokens) revert INADEQUATE_RECLAIM_AMOUNT();\n\n // Burn the project tokens.\n if (_tokenCount > 0)\n IJBController(directory.controllerOf(_projectId)).burnTokensOf(\n _holder,\n _projectId,\n _tokenCount,\n '',\n false\n );\n\n // If delegate allocations were specified by the data source, fulfill them.\n if (_delegateAllocations.length != 0) {\n // Keep a reference to the token amount being forwarded to the delegate.\n JBTokenAmount memory _forwardedAmount = JBTokenAmount(token, 0, decimals, currency);\n\n JBDidRedeemData memory _data = JBDidRedeemData(\n _holder,\n _projectId,\n _fundingCycle.configuration,\n _tokenCount,\n JBTokenAmount(token, reclaimAmount, decimals, currency),\n _forwardedAmount,\n _beneficiary,\n _memo,\n _metadata\n );\n\n uint256 _numDelegates = _delegateAllocations.length;\n\n for (uint256 _i; _i < _numDelegates; ) {\n // Get a reference to the delegate being iterated on.\n JBRedemptionDelegateAllocation memory _delegateAllocation = _delegateAllocations[_i];\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_delegateAllocation.delegate), _delegateAllocation.amount);\n\n // Keep track of the msg.value to use in the delegate call\n uint256 _payableValue;\n\n // If this terminal's token is ETH, send it in msg.value.\n if (token == JBTokens.ETH) _payableValue = _delegateAllocation.amount;\n\n // Pass the correct token forwardedAmount to the delegate\n _data.forwardedAmount.value = _delegateAllocation.amount;\n\n _delegateAllocation.delegate.didRedeem{value: _payableValue}(_data);\n\n emit DelegateDidRedeem(\n _delegateAllocation.delegate,\n _data,\n _delegateAllocation.amount,\n msg.sender\n );\n unchecked {\n ++_i;\n }\n }\n }\n }\n\n // Send the reclaimed funds to the beneficiary.\n if (reclaimAmount > 0) _transferFrom(address(this), _beneficiary, reclaimAmount);\n\n emit RedeemTokens(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _holder,\n _beneficiary,\n _tokenCount,\n reclaimAmount,\n _memo,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Distributes payouts for a project with the distribution limit of its current funding cycle.\n /// @dev Payouts are sent to the preprogrammed splits. Any leftover is sent to the project's owner.\n /// @dev 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.\n /// @dev All funds distributed outside of this contract or any feeless terminals incure the protocol fee.\n /// @param _projectId The ID of the project having its payouts distributed.\n /// @param _amount The amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency.\n /// @param _minReturnedTokens 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.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return netLeftoverDistributionAmount The amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal.\n function _distributePayoutsOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n uint256 _minReturnedTokens,\n string calldata _memo\n ) internal returns (uint256 netLeftoverDistributionAmount) {\n // Record the distribution.\n (\n JBFundingCycle memory _fundingCycle,\n uint256 _distributedAmount\n ) = IJBSingleTokenPaymentTerminalStore(store).recordDistributionFor(\n _projectId,\n _amount,\n _currency\n );\n\n // The amount being distributed must be at least as much as was expected.\n if (_distributedAmount < _minReturnedTokens) revert INADEQUATE_DISTRIBUTION_AMOUNT();\n\n // Get a reference to the project owner, which will receive tokens from paying the platform fee\n // and receive any extra distributable funds not allocated to payout splits.\n address payable _projectOwner = payable(projects.ownerOf(_projectId));\n\n // Define variables that will be needed outside the scoped section below.\n // Keep a reference to the fee amount that was paid.\n uint256 _fee;\n\n // Scoped section prevents stack too deep. `_feeDiscount`, `_feeEligibleDistributionAmount`, and `_leftoverDistributionAmount` only used within scope.\n {\n // Get the amount of discount that should be applied to any fees taken.\n // If the fee is zero, set the discount to 100% for convenience.\n uint256 _feeDiscount = fee == 0\n ? JBConstants.MAX_FEE_DISCOUNT\n : _currentFeeDiscount(_projectId);\n\n // The amount distributed that is eligible for incurring fees.\n uint256 _feeEligibleDistributionAmount;\n\n // The amount leftover after distributing to the splits.\n uint256 _leftoverDistributionAmount;\n\n // Payout to splits and get a reference to the leftover transfer amount after all splits have been paid.\n // Also get a reference to the amount that was distributed to splits from which fees should be taken.\n (_leftoverDistributionAmount, _feeEligibleDistributionAmount) = _distributeToPayoutSplitsOf(\n _projectId,\n _fundingCycle.configuration,\n payoutSplitsGroup,\n _distributedAmount,\n _feeDiscount\n );\n\n if (_feeDiscount != JBConstants.MAX_FEE_DISCOUNT) {\n // Leftover distribution amount is also eligible for a fee since the funds are going out of the ecosystem to _beneficiary.\n unchecked {\n _feeEligibleDistributionAmount += _leftoverDistributionAmount;\n }\n }\n\n // Take the fee.\n _fee = _feeEligibleDistributionAmount != 0\n ? _takeFeeFrom(\n _projectId,\n _fundingCycle,\n _feeEligibleDistributionAmount,\n _projectOwner,\n _feeDiscount\n )\n : 0;\n\n // Transfer any remaining balance to the project owner and update returned leftover accordingly.\n if (_leftoverDistributionAmount != 0) {\n // Subtract the fee from the net leftover amount.\n netLeftoverDistributionAmount =\n _leftoverDistributionAmount -\n _feeAmount(_leftoverDistributionAmount, fee, _feeDiscount);\n\n // Transfer the amount to the project owner.\n _transferFrom(address(this), _projectOwner, netLeftoverDistributionAmount);\n }\n }\n\n emit DistributePayouts(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _projectOwner,\n _amount,\n _distributedAmount,\n _fee,\n netLeftoverDistributionAmount,\n _memo,\n msg.sender\n );\n }\n\n /// @notice Allows a project to send funds from its overflow up to the preconfigured allowance.\n /// @dev Only a project's owner or a designated operator can use its allowance.\n /// @dev Incurs the protocol fee.\n /// @param _projectId The ID of the project to use the allowance of.\n /// @param _amount The amount of terminal tokens to use from this project's current allowance, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's overflow allowance currency.\n /// @param _minReturnedTokens The minimum number of tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with 18 decimals.\n /// @param _beneficiary The address to send the funds to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return netDistributedAmount The amount of tokens that was distributed to the beneficiary, as a fixed point number with the same amount of decimals as the terminal.\n function _useAllowanceOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo\n ) internal returns (uint256 netDistributedAmount) {\n // Record the use of the allowance.\n (\n JBFundingCycle memory _fundingCycle,\n uint256 _distributedAmount\n ) = IJBSingleTokenPaymentTerminalStore(store).recordUsedAllowanceOf(\n _projectId,\n _amount,\n _currency\n );\n\n // The amount being withdrawn must be at least as much as was expected.\n if (_distributedAmount < _minReturnedTokens) revert INADEQUATE_DISTRIBUTION_AMOUNT();\n\n // Scoped section prevents stack too deep. `_fee`, `_projectOwner`, `_feeDiscount`, and `_netAmount` only used within scope.\n {\n // Keep a reference to the fee amount that was paid.\n uint256 _fee;\n\n // Get a reference to the project owner, which will receive tokens from paying the platform fee.\n address _projectOwner = projects.ownerOf(_projectId);\n\n // Get the amount of discount that should be applied to any fees taken.\n // 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.\n uint256 _feeDiscount = fee == 0 || isFeelessAddress[msg.sender]\n ? JBConstants.MAX_FEE_DISCOUNT\n : _currentFeeDiscount(_projectId);\n\n // Take a fee from the `_distributedAmount`, if needed.\n _fee = _feeDiscount == JBConstants.MAX_FEE_DISCOUNT\n ? 0\n : _takeFeeFrom(_projectId, _fundingCycle, _distributedAmount, _projectOwner, _feeDiscount);\n\n unchecked {\n // The net amount is the withdrawn amount without the fee.\n netDistributedAmount = _distributedAmount - _fee;\n }\n\n // Transfer any remaining balance to the beneficiary.\n if (netDistributedAmount > 0)\n _transferFrom(address(this), _beneficiary, netDistributedAmount);\n }\n\n emit UseAllowance(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _beneficiary,\n _amount,\n _distributedAmount,\n netDistributedAmount,\n _memo,\n msg.sender\n );\n }\n\n /// @notice Pays out splits for a project's funding cycle configuration.\n /// @param _projectId The ID of the project for which payout splits are being distributed.\n /// @param _domain The domain of the splits to distribute the payout between.\n /// @param _group The group of the splits to distribute the payout between.\n /// @param _amount The total amount being distributed, as a fixed point number with the same number of decimals as this terminal.\n /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE.\n /// @return leftoverAmount If the leftover amount if the splits don't add up to 100%.\n /// @return feeEligibleDistributionAmount The total amount of distributions that are eligible to have fees taken from.\n function _distributeToPayoutSplitsOf(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group,\n uint256 _amount,\n uint256 _feeDiscount\n ) internal returns (uint256 leftoverAmount, uint256 feeEligibleDistributionAmount) {\n // Set the leftover amount to the initial amount.\n leftoverAmount = _amount;\n // The total percentage available to split\n uint256 leftoverPercentage = JBConstants.SPLITS_TOTAL_PERCENT;\n\n // Get a reference to the project's payout splits.\n JBSplit[] memory _splits = splitsStore.splitsOf(_projectId, _domain, _group);\n\n // Transfer between all splits.\n for (uint256 _i; _i < _splits.length; ) {\n // Get a reference to the split being iterated on.\n JBSplit memory _split = _splits[_i];\n\n // The amount to send towards the split.\n uint256 _payoutAmount = _split.percent == leftoverPercentage\n ? leftoverAmount\n : PRBMath.mulDiv(_amount, _split.percent, JBConstants.SPLITS_TOTAL_PERCENT);\n\n // Decrement the leftover percentage.\n leftoverPercentage -= _split.percent;\n\n // The payout amount substracting any applicable incurred fees.\n uint256 _netPayoutAmount;\n\n if (_payoutAmount > 0) {\n // Transfer tokens to the split.\n // If there's an allocator set, transfer to its `allocate` function.\n if (_split.allocator != IJBSplitAllocator(address(0))) {\n // If the split allocator is set as feeless, this distribution is not eligible for a fee.\n if (\n _feeDiscount == JBConstants.MAX_FEE_DISCOUNT ||\n isFeelessAddress[address(_split.allocator)]\n )\n _netPayoutAmount = _payoutAmount;\n // This distribution is eligible for a fee since the funds are leaving this contract and the allocator isn't listed as feeless.\n else {\n unchecked {\n _netPayoutAmount = _payoutAmount - _feeAmount(_payoutAmount, fee, _feeDiscount);\n }\n\n // This distribution is eligible for a fee since the funds are leaving the ecosystem.\n feeEligibleDistributionAmount += _payoutAmount;\n }\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_split.allocator), _netPayoutAmount);\n\n // Create the data to send to the allocator.\n JBSplitAllocationData memory _data = JBSplitAllocationData(\n token,\n _netPayoutAmount,\n decimals,\n _projectId,\n _group,\n _split\n );\n\n // Trigger the allocator's `allocate` function.\n // If this terminal's token is ETH, send it in msg.value.\n _split.allocator.allocate{value: token == JBTokens.ETH ? _netPayoutAmount : 0}(_data);\n\n // Otherwise, if a project is specified, make a payment to it.\n } else if (_split.projectId != 0) {\n // Get a reference to the Juicebox terminal being used.\n IJBPaymentTerminal _terminal = directory.primaryTerminalOf(_split.projectId, token);\n\n // The project must have a terminal to send funds to.\n if (_terminal == IJBPaymentTerminal(address(0))) revert TERMINAL_IN_SPLIT_ZERO_ADDRESS();\n\n // Save gas if this contract is being used as the terminal.\n if (_terminal == this) {\n // This distribution does not incur a fee.\n _netPayoutAmount = _payoutAmount;\n\n // Send the projectId in the metadata.\n bytes memory _projectMetadata = new bytes(32);\n _projectMetadata = bytes(abi.encodePacked(_projectId));\n\n // Add to balance if prefered.\n if (_split.preferAddToBalance)\n _addToBalanceOf(_split.projectId, _netPayoutAmount, false, '', _projectMetadata);\n else\n _pay(\n _netPayoutAmount,\n address(this),\n _split.projectId,\n (_split.beneficiary != address(0)) ? _split.beneficiary : msg.sender,\n 0,\n _split.preferClaimed,\n '',\n _projectMetadata\n );\n } else {\n // If the terminal is set as feeless, this distribution is not eligible for a fee.\n if (\n _feeDiscount == JBConstants.MAX_FEE_DISCOUNT || isFeelessAddress[address(_terminal)]\n )\n _netPayoutAmount = _payoutAmount;\n // This distribution is eligible for a fee since the funds are leaving this contract and the terminal isn't listed as feeless.\n else {\n unchecked {\n _netPayoutAmount = _payoutAmount - _feeAmount(_payoutAmount, fee, _feeDiscount);\n }\n\n feeEligibleDistributionAmount += _payoutAmount;\n }\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_terminal), _netPayoutAmount);\n\n // If this terminal's token is ETH, send it in msg.value.\n uint256 _payableValue = token == JBTokens.ETH ? _netPayoutAmount : 0;\n\n // Send the projectId in the metadata.\n bytes memory _projectMetadata = new bytes(32);\n _projectMetadata = bytes(abi.encodePacked(_projectId));\n\n // Add to balance if prefered.\n if (_split.preferAddToBalance)\n _terminal.addToBalanceOf{value: _payableValue}(\n _split.projectId,\n _netPayoutAmount,\n token,\n '',\n _projectMetadata\n );\n else\n _terminal.pay{value: _payableValue}(\n _split.projectId,\n _netPayoutAmount,\n token,\n _split.beneficiary != address(0) ? _split.beneficiary : msg.sender,\n 0,\n _split.preferClaimed,\n '',\n _projectMetadata\n );\n }\n } else {\n // Keep a reference to the beneficiary.\n address payable _beneficiary = _split.beneficiary != address(0)\n ? _split.beneficiary\n : payable(msg.sender);\n\n // If there's a full discount, this distribution is not eligible for a fee.\n // Don't enforce feeless address for the beneficiary since the funds are leaving the ecosystem.\n if (_feeDiscount == JBConstants.MAX_FEE_DISCOUNT)\n _netPayoutAmount = _payoutAmount;\n // This distribution is eligible for a fee since the funds are leaving this contract and the beneficiary isn't listed as feeless.\n else {\n unchecked {\n _netPayoutAmount = _payoutAmount - _feeAmount(_payoutAmount, fee, _feeDiscount);\n }\n\n feeEligibleDistributionAmount += _payoutAmount;\n }\n\n // If there's a beneficiary, send the funds directly to the beneficiary. Otherwise send to the msg.sender.\n _transferFrom(address(this), _beneficiary, _netPayoutAmount);\n }\n\n // Subtract from the amount to be sent to the beneficiary.\n unchecked {\n leftoverAmount = leftoverAmount - _payoutAmount;\n }\n }\n\n emit DistributeToPayoutSplit(\n _projectId,\n _domain,\n _group,\n _split,\n _netPayoutAmount,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n\n /// @notice Takes a fee into the platform's project, which has an id of _FEE_BENEFICIARY_PROJECT_ID.\n /// @param _projectId The ID of the project having fees taken from.\n /// @param _fundingCycle The funding cycle during which the fee is being taken.\n /// @param _amount The amount of the fee to take, as a floating point number with 18 decimals.\n /// @param _beneficiary The address to mint the platforms tokens for.\n /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE.\n /// @return feeAmount The amount of the fee taken.\n function _takeFeeFrom(\n uint256 _projectId,\n JBFundingCycle memory _fundingCycle,\n uint256 _amount,\n address _beneficiary,\n uint256 _feeDiscount\n ) internal returns (uint256 feeAmount) {\n feeAmount = _feeAmount(_amount, fee, _feeDiscount);\n\n if (_fundingCycle.shouldHoldFees()) {\n // Store the held fee.\n _heldFeesOf[_projectId].push(JBFee(_amount, uint32(fee), uint32(_feeDiscount), _beneficiary));\n\n emit HoldFee(_projectId, _amount, fee, _feeDiscount, _beneficiary, msg.sender);\n } else {\n // Process the fee.\n _processFee(feeAmount, _beneficiary); // Take the fee.\n\n emit ProcessFee(_projectId, feeAmount, false, _beneficiary, msg.sender);\n }\n }\n\n /// @notice Process a fee of the specified amount.\n /// @param _amount The fee amount, as a floating point number with 18 decimals.\n /// @param _beneficiary The address to mint the platform's tokens for.\n function _processFee(uint256 _amount, address _beneficiary) internal {\n // Get the terminal for the protocol project.\n IJBPaymentTerminal _terminal = directory.primaryTerminalOf(_FEE_BENEFICIARY_PROJECT_ID, token);\n\n // When processing the admin fee, save gas if the admin is using this contract as its terminal.\n if (_terminal == this)\n _pay(\n _amount,\n address(this),\n _FEE_BENEFICIARY_PROJECT_ID,\n _beneficiary,\n 0,\n false,\n '',\n bytes('')\n ); // Use the local pay call.\n else {\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_terminal), _amount);\n\n // If this terminal's token is ETH, send it in msg.value.\n uint256 _payableValue = token == JBTokens.ETH ? _amount : 0;\n\n // Send the payment.\n _terminal.pay{value: _payableValue}(\n _FEE_BENEFICIARY_PROJECT_ID,\n _amount,\n token,\n _beneficiary,\n 0,\n false,\n '',\n bytes('')\n ); // Use the external pay call of the correct terminal.\n }\n }\n\n /// @notice Contribute tokens to a project.\n /// @param _amount The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place.\n /// @param _payer The address making the payment.\n /// @param _projectId The ID of the project being paid.\n /// @param _beneficiary The address to mint tokens for and pass along to the funding cycle's data source and delegate.\n /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\n /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return beneficiaryTokenCount The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals.\n function _pay(\n uint256 _amount,\n address _payer,\n uint256 _projectId,\n address _beneficiary,\n uint256 _minReturnedTokens,\n bool _preferClaimedTokens,\n string memory _memo,\n bytes memory _metadata\n ) internal returns (uint256 beneficiaryTokenCount) {\n // Cant send tokens to the zero address.\n if (_beneficiary == address(0)) revert PAY_TO_ZERO_ADDRESS();\n\n // Define variables that will be needed outside the scoped section below.\n // Keep a reference to the funding cycle during which the payment is being made.\n JBFundingCycle memory _fundingCycle;\n\n // Scoped section prevents stack too deep. `_delegateAllocations` and `_tokenCount` only used within scope.\n {\n JBPayDelegateAllocation[] memory _delegateAllocations;\n uint256 _tokenCount;\n\n // Bundle the amount info into a JBTokenAmount struct.\n JBTokenAmount memory _bundledAmount = JBTokenAmount(token, _amount, decimals, currency);\n\n // Record the payment.\n (\n _fundingCycle,\n _tokenCount,\n _delegateAllocations,\n _memo\n ) = IJBSingleTokenPaymentTerminalStore(store).recordPaymentFrom(\n _payer,\n _bundledAmount,\n _projectId,\n baseWeightCurrency,\n _beneficiary,\n _memo,\n _metadata\n );\n\n // Mint the tokens if needed.\n if (_tokenCount > 0)\n // Set token count to be the number of tokens minted for the beneficiary instead of the total amount.\n beneficiaryTokenCount = IJBController(directory.controllerOf(_projectId)).mintTokensOf(\n _projectId,\n _tokenCount,\n _beneficiary,\n '',\n _preferClaimedTokens,\n true\n );\n\n // The token count for the beneficiary must be greater than or equal to the minimum expected.\n if (beneficiaryTokenCount < _minReturnedTokens) revert INADEQUATE_TOKEN_COUNT();\n\n // If delegate allocations were specified by the data source, fulfill them.\n if (_delegateAllocations.length != 0) {\n // Keep a reference to the token amount being forwarded to the delegate.\n JBTokenAmount memory _forwardedAmount = JBTokenAmount(token, _amount, decimals, currency);\n\n JBDidPayData memory _data = JBDidPayData(\n _payer,\n _projectId,\n _fundingCycle.configuration,\n _bundledAmount,\n _forwardedAmount,\n beneficiaryTokenCount,\n _beneficiary,\n _preferClaimedTokens,\n _memo,\n _metadata\n );\n\n // Get a reference to the number of delegates to allocate to.\n uint256 _numDelegates = _delegateAllocations.length;\n\n for (uint256 _i; _i < _numDelegates; ) {\n // Get a reference to the delegate being iterated on.\n JBPayDelegateAllocation memory _delegateAllocation = _delegateAllocations[_i];\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_delegateAllocation.delegate), _delegateAllocation.amount);\n\n // Keep track of the msg.value to use in the delegate call\n uint256 _payableValue;\n\n // If this terminal's token is ETH, send it in msg.value.\n if (token == JBTokens.ETH) _payableValue = _delegateAllocation.amount;\n\n // Pass the correct token forwardedAmount to the delegate\n _data.forwardedAmount.value = _delegateAllocation.amount;\n\n _delegateAllocation.delegate.didPay{value: _payableValue}(_data);\n\n emit DelegateDidPay(\n _delegateAllocation.delegate,\n _data,\n _delegateAllocation.amount,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n }\n\n emit Pay(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _payer,\n _beneficiary,\n _amount,\n beneficiaryTokenCount,\n _memo,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Receives funds belonging to the specified project.\n /// @param _projectId The ID of the project to which the funds received belong.\n /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\n /// @param _shouldRefundHeldFees A flag indicating if held fees should be refunded based on the amount being added.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the emitted event.\n function _addToBalanceOf(\n uint256 _projectId,\n uint256 _amount,\n bool _shouldRefundHeldFees,\n string memory _memo,\n bytes memory _metadata\n ) internal {\n // Refund any held fees to make sure the project doesn't pay double for funds going in and out of the protocol.\n uint256 _refundedFees = _shouldRefundHeldFees ? _refundHeldFees(_projectId, _amount) : 0;\n\n // Record the added funds with any refunded fees.\n IJBSingleTokenPaymentTerminalStore(store).recordAddedBalanceFor(\n _projectId,\n _amount + _refundedFees\n );\n\n emit AddToBalance(_projectId, _amount, _refundedFees, _memo, _metadata, msg.sender);\n }\n\n /// @notice Refund fees based on the specified amount.\n /// @param _projectId The project for which fees are being refunded.\n /// @param _amount The amount to base the refund on, as a fixed point number with the same amount of decimals as this terminal.\n /// @return refundedFees How much fees were refunded, as a fixed point number with the same number of decimals as this terminal\n function _refundHeldFees(\n uint256 _projectId,\n uint256 _amount\n ) internal returns (uint256 refundedFees) {\n // Get a reference to the project's held fees.\n JBFee[] memory _heldFees = _heldFeesOf[_projectId];\n\n // Delete the current held fees.\n delete _heldFeesOf[_projectId];\n\n // Get a reference to the leftover amount once all fees have been settled.\n uint256 leftoverAmount = _amount;\n\n // Push length in stack\n uint256 _heldFeesLength = _heldFees.length;\n\n // Process each fee.\n for (uint256 _i; _i < _heldFeesLength; ) {\n if (leftoverAmount == 0) _heldFeesOf[_projectId].push(_heldFees[_i]);\n else if (leftoverAmount >= _heldFees[_i].amount) {\n unchecked {\n leftoverAmount = leftoverAmount - _heldFees[_i].amount;\n refundedFees += _feeAmount(\n _heldFees[_i].amount,\n _heldFees[_i].fee,\n _heldFees[_i].feeDiscount\n );\n }\n } else {\n unchecked {\n _heldFeesOf[_projectId].push(\n JBFee(\n _heldFees[_i].amount - leftoverAmount,\n _heldFees[_i].fee,\n _heldFees[_i].feeDiscount,\n _heldFees[_i].beneficiary\n )\n );\n refundedFees += _feeAmount(leftoverAmount, _heldFees[_i].fee, _heldFees[_i].feeDiscount);\n }\n leftoverAmount = 0;\n }\n\n unchecked {\n ++_i;\n }\n }\n\n emit RefundHeldFees(_projectId, _amount, refundedFees, leftoverAmount, msg.sender);\n }\n\n /// @notice Returns the fee amount based on the provided amount for the specified project.\n /// @param _amount The amount that the fee is based on, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _fee The percentage of the fee, out of MAX_FEE.\n /// @param _feeDiscount The percentage discount that should be applied out of the max amount, out of MAX_FEE_DISCOUNT.\n /// @return The amount of the fee, as a fixed point number with the same amount of decimals as this terminal.\n function _feeAmount(\n uint256 _amount,\n uint256 _fee,\n uint256 _feeDiscount\n ) internal pure returns (uint256) {\n // Calculate the discounted fee.\n uint256 _discountedFee = _fee -\n PRBMath.mulDiv(_fee, _feeDiscount, JBConstants.MAX_FEE_DISCOUNT);\n\n // The amount of tokens from the `_amount` to pay as a fee.\n return\n _amount - PRBMath.mulDiv(_amount, JBConstants.MAX_FEE, _discountedFee + JBConstants.MAX_FEE);\n }\n\n /// @notice Get the fee discount from the fee gauge for the specified project.\n /// @param _projectId The ID of the project to get a fee discount for.\n /// @return feeDiscount The fee discount, which should be interpreted as a percentage out MAX_FEE_DISCOUNT.\n function _currentFeeDiscount(uint256 _projectId) internal view returns (uint256) {\n // Can't take a fee if the protocol project doesn't have a terminal that accepts the token.\n if (\n directory.primaryTerminalOf(_FEE_BENEFICIARY_PROJECT_ID, token) ==\n IJBPaymentTerminal(address(0))\n ) return JBConstants.MAX_FEE_DISCOUNT;\n\n // Get the fee discount.\n if (feeGauge != address(0))\n // If the guage reverts, keep the discount at 0.\n try IJBFeeGauge(feeGauge).currentDiscountFor(_projectId) returns (uint256 discount) {\n // If the fee discount is greater than the max, we ignore the return value\n if (discount <= JBConstants.MAX_FEE_DISCOUNT) return discount;\n } catch {\n return 0;\n }\n\n return 0;\n }\n}\n" + }, + "contracts/JBERC20PaymentTerminal3_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';\nimport {IERC20Metadata} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol';\nimport {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';\nimport {JBPayoutRedemptionPaymentTerminal3_1} from './abstract/JBPayoutRedemptionPaymentTerminal3_1.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\n\n/// @notice Manages the inflows and outflows of an ERC-20 token.\ncontract JBERC20PaymentTerminal3_1 is JBPayoutRedemptionPaymentTerminal3_1 {\n using SafeERC20 for IERC20;\n\n //*********************************************************************//\n // -------------------------- internal views ------------------------- //\n //*********************************************************************//\n\n /// @notice Checks the balance of tokens in this contract.\n /// @return The contract's balance, as a fixed point number with the same amount of decimals as this terminal.\n function _balance() internal view override returns (uint256) {\n return IERC20(token).balanceOf(address(this));\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _token The token that this terminal manages.\n /// @param _currency The currency that this terminal's token adheres to for price feeds.\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _payoutSplitsGroup The group that denotes payout splits from this terminal in the splits store.\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _prices A contract that exposes price feeds.\n /// @param _store A contract that stores the terminal's data.\n /// @param _owner The address that will own this contract.\n constructor(\n IERC20Metadata _token,\n uint256 _currency,\n uint256 _baseWeightCurrency,\n uint256 _payoutSplitsGroup,\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBSplitsStore _splitsStore,\n IJBPrices _prices,\n address _store,\n address _owner\n )\n JBPayoutRedemptionPaymentTerminal3_1(\n address(_token),\n _token.decimals(),\n _currency,\n _baseWeightCurrency,\n _payoutSplitsGroup,\n _operatorStore,\n _projects,\n _directory,\n _splitsStore,\n _prices,\n _store,\n _owner\n )\n // solhint-disable-next-line no-empty-blocks\n {\n\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Transfers tokens.\n /// @param _from The address from which the transfer should originate.\n /// @param _to The address to which the transfer should go.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _transferFrom(address _from, address payable _to, uint256 _amount) internal override {\n _from == address(this)\n ? IERC20(token).safeTransfer(_to, _amount)\n : IERC20(token).safeTransferFrom(_from, _to, _amount);\n }\n\n /// @notice Logic to be triggered before transferring tokens from this terminal.\n /// @param _to The address to which the transfer is going.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _beforeTransferTo(address _to, uint256 _amount) internal override {\n IERC20(token).safeIncreaseAllowance(_to, _amount);\n }\n\n /// @notice Logic to be triggered if a transfer should be undone\n /// @param _to The address to which the transfer went.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _cancelTransferTo(address _to, uint256 _amount) internal override {\n IERC20(token).safeDecreaseAllowance(_to, _amount);\n }\n}\n" + }, + "contracts/JBPrices.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {IJBPriceFeed} from './interfaces/IJBPriceFeed.sol';\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\n\n/// @notice Manages and normalizes price feeds.\ncontract JBPrices is Ownable, IJBPrices {\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error PRICE_FEED_ALREADY_EXISTS();\n error PRICE_FEED_NOT_FOUND();\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The available price feeds.\n /// @dev The feed returns the number of `_currency` units that can be converted to 1 `_base` unit.\n /// @custom:param _currency The currency units the feed's resulting price is in terms of.\n /// @custom:param _base The base currency unit being priced by the feed.\n mapping(uint256 => mapping(uint256 => IJBPriceFeed)) public override feedFor;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Gets the number of `_currency` units that can be converted to 1 `_base` unit.\n /// @param _currency The currency units the resulting price is in terms of.\n /// @param _base The base currency unit being priced.\n /// @param _decimals The number of decimals the returned fixed point price should include.\n /// @return The price of the currency in terms of the base, as a fixed point number with the specified number of decimals.\n function priceFor(\n uint256 _currency,\n uint256 _base,\n uint256 _decimals\n ) external view override returns (uint256) {\n // If the currency is the base, return 1 since they are priced the same. Include the desired number of decimals.\n if (_currency == _base) return 10 ** _decimals;\n\n // Get a reference to the feed.\n IJBPriceFeed _feed = feedFor[_currency][_base];\n\n // If it exists, return the price.\n if (_feed != IJBPriceFeed(address(0))) return _feed.currentPrice(_decimals);\n\n // Get the inverse feed.\n _feed = feedFor[_base][_currency];\n\n // If it exists, return the inverse price.\n if (_feed != IJBPriceFeed(address(0)))\n return PRBMath.mulDiv(10 ** _decimals, 10 ** _decimals, _feed.currentPrice(_decimals));\n\n // No price feed available, revert.\n revert PRICE_FEED_NOT_FOUND();\n }\n\n //*********************************************************************//\n // ---------------------------- constructor -------------------------- //\n //*********************************************************************//\n\n /// @param _owner The address that will own the contract.\n constructor(address _owner) {\n // Transfer the ownership.\n transferOwnership(_owner);\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Add a price feed for a currency in terms of the provided base currency.\n /// @dev Current feeds can't be modified.\n /// @param _currency The currency units the feed's resulting price is in terms of.\n /// @param _base The base currency unit being priced by the feed.\n /// @param _feed The price feed being added.\n function addFeedFor(\n uint256 _currency,\n uint256 _base,\n IJBPriceFeed _feed\n ) external override onlyOwner {\n // There can't already be a feed for the specified currency.\n if (\n feedFor[_currency][_base] != IJBPriceFeed(address(0)) ||\n feedFor[_base][_currency] != IJBPriceFeed(address(0))\n ) revert PRICE_FEED_ALREADY_EXISTS();\n\n // Store the feed.\n feedFor[_currency][_base] = _feed;\n\n emit AddFeed(_currency, _base, _feed);\n }\n}\n" + }, + "contracts/JBChainlinkV3PriceFeed.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {AggregatorV3Interface} from '@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol';\nimport {IJBPriceFeed} from './interfaces/IJBPriceFeed.sol';\nimport {JBFixedPointNumber} from './libraries/JBFixedPointNumber.sol';\n\n/// @notice A generalized price feed for the Chainlink AggregatorV3Interface.\ncontract JBChainlinkV3PriceFeed is IJBPriceFeed {\n // A library that provides utility for fixed point numbers.\n using JBFixedPointNumber for uint256;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error STALE_PRICE();\n error INCOMPLETE_ROUND();\n error NEGATIVE_PRICE();\n\n //*********************************************************************//\n // ---------------- public stored immutable properties --------------- //\n //*********************************************************************//\n\n /// @notice The feed that prices are reported from.\n AggregatorV3Interface public immutable feed;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Gets the current price from the feed, normalized to the specified number of decimals.\n /// @param _decimals The number of decimals the returned fixed point price should include.\n /// @return The current price of the feed, as a fixed point number with the specified number of decimals.\n function currentPrice(uint256 _decimals) external view override returns (uint256) {\n // Get the latest round information.\n (uint80 roundId, int256 _price, , uint256 updatedAt, uint80 answeredInRound) = feed\n .latestRoundData();\n\n // Make sure the price isn't stale.\n if (answeredInRound < roundId) revert STALE_PRICE();\n\n // Make sure the round is finished.\n if (updatedAt == 0) revert INCOMPLETE_ROUND();\n\n // Make sure the price is positive.\n if (_price < 0) revert NEGATIVE_PRICE();\n\n // Get a reference to the number of decimals the feed uses.\n uint256 _feedDecimals = feed.decimals();\n\n // Return the price, adjusted to the target decimals.\n return uint256(_price).adjustDecimals(_feedDecimals, _decimals);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _feed The feed to report prices from.\n constructor(AggregatorV3Interface _feed) {\n feed = _feed;\n }\n}\n" + }, + "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface AggregatorV3Interface {\n\n function decimals()\n external\n view\n returns (\n uint8\n );\n\n function description()\n external\n view\n returns (\n string memory\n );\n\n function version()\n external\n view\n returns (\n uint256\n );\n\n // getRoundData and latestRoundData should both raise \"No data present\"\n // if they do not have data to report, instead of returning unset values\n // which could be misinterpreted as actual reported values.\n function getRoundData(\n uint80 _roundId\n )\n external\n view\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n );\n\n function latestRoundData()\n external\n view\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n );\n\n}\n" + }, + "contracts/JBERC20PaymentTerminal3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';\nimport {IERC20Metadata} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol';\nimport {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';\nimport {JBPayoutRedemptionPaymentTerminal3_1_1} from './abstract/JBPayoutRedemptionPaymentTerminal3_1_1.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\n\n/// @notice Manages the inflows and outflows of an ERC-20 token.\ncontract JBERC20PaymentTerminal3_1_1 is JBPayoutRedemptionPaymentTerminal3_1_1 {\n using SafeERC20 for IERC20;\n\n //*********************************************************************//\n // -------------------------- internal views ------------------------- //\n //*********************************************************************//\n\n /// @notice Checks the balance of tokens in this contract.\n /// @return The contract's balance, as a fixed point number with the same amount of decimals as this terminal.\n function _balance() internal view override returns (uint256) {\n return IERC20(token).balanceOf(address(this));\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _token The token that this terminal manages.\n /// @param _currency The currency that this terminal's token adheres to for price feeds.\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _payoutSplitsGroup The group that denotes payout splits from this terminal in the splits store.\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _prices A contract that exposes price feeds.\n /// @param _store A contract that stores the terminal's data.\n /// @param _owner The address that will own this contract.\n constructor(\n IERC20Metadata _token,\n uint256 _currency,\n uint256 _baseWeightCurrency,\n uint256 _payoutSplitsGroup,\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBSplitsStore _splitsStore,\n IJBPrices _prices,\n address _store,\n address _owner\n )\n JBPayoutRedemptionPaymentTerminal3_1_1(\n address(_token),\n _token.decimals(),\n _currency,\n _baseWeightCurrency,\n _payoutSplitsGroup,\n _operatorStore,\n _projects,\n _directory,\n _splitsStore,\n _prices,\n _store,\n _owner\n )\n // solhint-disable-next-line no-empty-blocks\n {\n\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Transfers tokens.\n /// @param _from The address from which the transfer should originate.\n /// @param _to The address to which the transfer should go.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _transferFrom(address _from, address payable _to, uint256 _amount) internal override {\n _from == address(this)\n ? IERC20(token).safeTransfer(_to, _amount)\n : IERC20(token).safeTransferFrom(_from, _to, _amount);\n }\n\n /// @notice Logic to be triggered before transferring tokens from this terminal.\n /// @param _to The address to which the transfer is going.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _beforeTransferTo(address _to, uint256 _amount) internal override {\n IERC20(token).safeIncreaseAllowance(_to, _amount);\n }\n\n /// @notice Logic to be triggered if a transfer should be undone\n /// @param _to The address to which the transfer went.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _cancelTransferTo(address _to, uint256 _amount) internal override {\n IERC20(token).safeDecreaseAllowance(_to, _amount);\n }\n}\n" + }, + "contracts/JBERC20PaymentTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';\nimport {IERC20Metadata} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol';\nimport {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';\nimport {JBPayoutRedemptionPaymentTerminal} from './abstract/JBPayoutRedemptionPaymentTerminal.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\n\n/// @notice Manages the inflows and outflows of an ERC-20 token.\ncontract JBERC20PaymentTerminal is JBPayoutRedemptionPaymentTerminal {\n using SafeERC20 for IERC20;\n\n //*********************************************************************//\n // -------------------------- internal views ------------------------- //\n //*********************************************************************//\n\n /// @notice Checks the balance of tokens in this contract.\n /// @return The contract's balance, as a fixed point number with the same amount of decimals as this terminal.\n function _balance() internal view override returns (uint256) {\n return IERC20(token).balanceOf(address(this));\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _token The token that this terminal manages.\n /// @param _currency The currency that this terminal's token adheres to for price feeds.\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _payoutSplitsGroup The group that denotes payout splits from this terminal in the splits store.\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _prices A contract that exposes price feeds.\n /// @param _store A contract that stores the terminal's data.\n /// @param _owner The address that will own this contract.\n constructor(\n IERC20Metadata _token,\n uint256 _currency,\n uint256 _baseWeightCurrency,\n uint256 _payoutSplitsGroup,\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBSplitsStore _splitsStore,\n IJBPrices _prices,\n address _store,\n address _owner\n )\n JBPayoutRedemptionPaymentTerminal(\n address(_token),\n _token.decimals(),\n _currency,\n _baseWeightCurrency,\n _payoutSplitsGroup,\n _operatorStore,\n _projects,\n _directory,\n _splitsStore,\n _prices,\n _store,\n _owner\n )\n // solhint-disable-next-line no-empty-blocks\n {\n\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Transfers tokens.\n /// @param _from The address from which the transfer should originate.\n /// @param _to The address to which the transfer should go.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _transferFrom(address _from, address payable _to, uint256 _amount) internal override {\n _from == address(this)\n ? IERC20(token).safeTransfer(_to, _amount)\n : IERC20(token).safeTransferFrom(_from, _to, _amount);\n }\n\n /// @notice Logic to be triggered before transferring tokens from this terminal.\n /// @param _to The address to which the transfer is going.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _beforeTransferTo(address _to, uint256 _amount) internal override {\n IERC20(token).safeApprove(_to, _amount);\n }\n}\n" + }, + "contracts/JBFundingCycleStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {JBControllerUtility} from './abstract/JBControllerUtility.sol';\nimport {JBBallotState} from './enums/JBBallotState.sol';\nimport {JBConstants} from './libraries/JBConstants.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBFundingCycleBallot} from './interfaces/IJBFundingCycleBallot.sol';\nimport {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\nimport {JBFundingCycleData} from './structs/JBFundingCycleData.sol';\n\n/// @notice Manages funding cycle configurations and scheduling.\ncontract JBFundingCycleStore is JBControllerUtility, IJBFundingCycleStore {\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error INVALID_BALLOT();\n error INVALID_DISCOUNT_RATE();\n error INVALID_DURATION();\n error INVALID_TIMEFRAME();\n error INVALID_WEIGHT();\n error NO_SAME_BLOCK_RECONFIGURATION();\n\n //*********************************************************************//\n // --------------------- private stored properties ------------------- //\n //*********************************************************************//\n\n /// @notice Stores the user defined properties of each funding cycle, packed into one storage slot.\n /// @custom:param _projectId The ID of the project to get properties of.\n /// @custom:param _configuration The funding cycle configuration to get properties of.\n mapping(uint256 => mapping(uint256 => uint256)) private _packedUserPropertiesOf;\n\n /// @notice Stores the properties added by the mechanism to manage and schedule each funding cycle, packed into one storage slot.\n /// @custom:param _projectId The ID of the project to get instrinsic properties of.\n /// @custom:param _configuration The funding cycle configuration to get properties of.\n mapping(uint256 => mapping(uint256 => uint256)) private _packedIntrinsicPropertiesOf;\n\n /// @notice Stores the metadata for each funding cycle configuration, packed into one storage slot.\n /// @custom:param _projectId The ID of the project to get metadata of.\n /// @custom:param _configuration The funding cycle configuration to get metadata of.\n mapping(uint256 => mapping(uint256 => uint256)) private _metadataOf;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The latest funding cycle configuration for each project.\n /// @custom:param _projectId The ID of the project to get the latest funding cycle configuration of.\n mapping(uint256 => uint256) public override latestConfigurationOf;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Get the funding cycle with the given configuration for the specified project.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @param _configuration The configuration of the funding cycle to get.\n /// @return fundingCycle The funding cycle.\n function get(\n uint256 _projectId,\n uint256 _configuration\n ) external view override returns (JBFundingCycle memory fundingCycle) {\n return _getStructFor(_projectId, _configuration);\n }\n\n /// @notice The latest funding cycle to be configured for the specified project, and its current ballot state.\n /// @param _projectId The ID of the project to get the latest configured funding cycle of.\n /// @return fundingCycle The project's queued funding cycle.\n /// @return ballotState The state of the ballot for the reconfiguration.\n function latestConfiguredOf(\n uint256 _projectId\n ) external view override returns (JBFundingCycle memory fundingCycle, JBBallotState ballotState) {\n // Get a reference to the latest funding cycle configuration.\n uint256 _fundingCycleConfiguration = latestConfigurationOf[_projectId];\n\n // Resolve the funding cycle for the latest configuration.\n fundingCycle = _getStructFor(_projectId, _fundingCycleConfiguration);\n\n // Resolve the ballot state.\n ballotState = _ballotStateOf(\n _projectId,\n fundingCycle.configuration,\n fundingCycle.start,\n fundingCycle.basedOn\n );\n }\n\n /// @notice The funding cycle that's next up for the specified project.\n /// @dev If a queued funding cycle of the project is not found, returns an empty funding cycle with all properties set to 0.\n /// @param _projectId The ID of the project to get the queued funding cycle of.\n /// @return fundingCycle The project's queued funding cycle.\n function queuedOf(\n uint256 _projectId\n ) external view override returns (JBFundingCycle memory fundingCycle) {\n // If the project does not have a funding cycle, return an empty struct.\n if (latestConfigurationOf[_projectId] == 0) return _getStructFor(0, 0);\n\n // Get a reference to the configuration of the standby funding cycle.\n uint256 _standbyFundingCycleConfiguration = _standbyOf(_projectId);\n\n // If it exists, return its funding cycle if it is approved.\n if (_standbyFundingCycleConfiguration > 0) {\n fundingCycle = _getStructFor(_projectId, _standbyFundingCycleConfiguration);\n\n if (_isApproved(_projectId, fundingCycle)) return fundingCycle;\n\n // Resolve the funding cycle for the latest configured funding cycle.\n fundingCycle = _getStructFor(_projectId, fundingCycle.basedOn);\n } else {\n // Resolve the funding cycle for the latest configured funding cycle.\n fundingCycle = _getStructFor(_projectId, latestConfigurationOf[_projectId]);\n\n // If the latest funding cycle starts in the future, it must start in the distant future\n // since its not in standby. In this case base the queued cycles on the base cycle.\n if (fundingCycle.start > block.timestamp)\n fundingCycle = _getStructFor(_projectId, fundingCycle.basedOn);\n }\n\n // There's no queued if the current has a duration of 0.\n if (fundingCycle.duration == 0) return _getStructFor(0, 0);\n\n // Check to see if this funding cycle's ballot is approved.\n // If so, return a funding cycle based on it.\n if (_isApproved(_projectId, fundingCycle)) return _mockFundingCycleBasedOn(fundingCycle, false);\n\n // Get the funding cycle of its base funding cycle, which carries the last approved configuration.\n fundingCycle = _getStructFor(_projectId, fundingCycle.basedOn);\n\n // There's no queued if the base, which must still be the current, has a duration of 0.\n if (fundingCycle.duration == 0) return _getStructFor(0, 0);\n\n // Return a mock of the next up funding cycle.\n return _mockFundingCycleBasedOn(fundingCycle, false);\n }\n\n /// @notice The funding cycle that is currently active for the specified project.\n /// @dev If a current funding cycle of the project is not found, returns an empty funding cycle with all properties set to 0.\n /// @param _projectId The ID of the project to get the current funding cycle of.\n /// @return fundingCycle The project's current funding cycle.\n function currentOf(\n uint256 _projectId\n ) external view override returns (JBFundingCycle memory fundingCycle) {\n // If the project does not have a funding cycle, return an empty struct.\n if (latestConfigurationOf[_projectId] == 0) return _getStructFor(0, 0);\n\n // Get a reference to the configuration of the eligible funding cycle.\n uint256 _fundingCycleConfiguration = _eligibleOf(_projectId);\n\n // Keep a reference to the eligible funding cycle.\n JBFundingCycle memory _fundingCycle;\n\n // If an eligible funding cycle exists...\n if (_fundingCycleConfiguration > 0) {\n // Resolve the funding cycle for the eligible configuration.\n _fundingCycle = _getStructFor(_projectId, _fundingCycleConfiguration);\n\n // Check to see if this funding cycle's ballot is approved.\n // If so, return it.\n if (_isApproved(_projectId, _fundingCycle)) return _fundingCycle;\n\n // If it hasn't been approved, set the funding cycle configuration to be the configuration of the funding cycle that it's based on,\n // which carries the last approved configuration.\n _fundingCycleConfiguration = _fundingCycle.basedOn;\n } else {\n // No upcoming funding cycle found that is eligible to become active,\n // so use the last configuration.\n _fundingCycleConfiguration = latestConfigurationOf[_projectId];\n\n // Get the funding cycle for the latest ID.\n _fundingCycle = _getStructFor(_projectId, _fundingCycleConfiguration);\n\n // If it's not approved or if it hasn't yet started, get a reference to the funding cycle that the latest is based on, which has the latest approved configuration.\n if (!_isApproved(_projectId, _fundingCycle) || block.timestamp < _fundingCycle.start)\n _fundingCycleConfiguration = _fundingCycle.basedOn;\n }\n\n // If there is not funding cycle to base the current one on, there can't be a current one.\n if (_fundingCycleConfiguration == 0) return _getStructFor(0, 0);\n\n // The funding cycle to base a current one on.\n _fundingCycle = _getStructFor(_projectId, _fundingCycleConfiguration);\n\n // If the base has no duration, it's still the current one.\n if (_fundingCycle.duration == 0) return _fundingCycle;\n\n // Return a mock of the current funding cycle.\n return _mockFundingCycleBasedOn(_fundingCycle, true);\n }\n\n /// @notice The current ballot state of the project.\n /// @param _projectId The ID of the project to check the ballot state of.\n /// @return The project's current ballot's state.\n function currentBallotStateOf(uint256 _projectId) external view override returns (JBBallotState) {\n // Get a reference to the latest funding cycle configuration.\n uint256 _fundingCycleConfiguration = latestConfigurationOf[_projectId];\n\n // Resolve the funding cycle for the latest configuration.\n JBFundingCycle memory _fundingCycle = _getStructFor(_projectId, _fundingCycleConfiguration);\n\n return\n _ballotStateOf(\n _projectId,\n _fundingCycle.configuration,\n _fundingCycle.start,\n _fundingCycle.basedOn\n );\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n // solhint-disable-next-line no-empty-blocks\n constructor(IJBDirectory _directory) JBControllerUtility(_directory) {}\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Configures the next eligible funding cycle for the specified project.\n /// @dev Only a project's current controller can configure its funding cycles.\n /// @param _projectId The ID of the project being configured.\n /// @param _data The funding cycle configuration data.\n /// @param _metadata Arbitrary extra data to associate with this funding cycle configuration that's not used within.\n /// @param _mustStartAtOrAfter The time before which the initialized funding cycle cannot start.\n /// @return The funding cycle that the configuration will take effect during.\n function configureFor(\n uint256 _projectId,\n JBFundingCycleData calldata _data,\n uint256 _metadata,\n uint256 _mustStartAtOrAfter\n ) external override onlyController(_projectId) returns (JBFundingCycle memory) {\n // Duration must fit in a uint32.\n if (_data.duration > type(uint32).max) revert INVALID_DURATION();\n\n // Discount rate must be less than or equal to 100%.\n if (_data.discountRate > JBConstants.MAX_DISCOUNT_RATE) revert INVALID_DISCOUNT_RATE();\n\n // Weight must fit into a uint88.\n if (_data.weight > type(uint88).max) revert INVALID_WEIGHT();\n\n // If the start date is in the past, set it to be the current timestamp.\n if (_mustStartAtOrAfter < block.timestamp) _mustStartAtOrAfter = block.timestamp;\n\n // Make sure the min start date fits in a uint56, and that the start date of an upcoming cycle also starts within the max.\n if (_mustStartAtOrAfter + _data.duration > type(uint56).max) revert INVALID_TIMEFRAME();\n\n // Ballot should be a valid contract, supporting the correct interface\n if (_data.ballot != IJBFundingCycleBallot(address(0))) {\n address _ballot = address(_data.ballot);\n\n // No contract at the address ?\n if (_ballot.code.length == 0) revert INVALID_BALLOT();\n\n // Make sure the ballot supports the expected interface.\n try _data.ballot.supportsInterface(type(IJBFundingCycleBallot).interfaceId) returns (\n bool _supports\n ) {\n if (!_supports) revert INVALID_BALLOT(); // Contract exists at the address but with the wrong interface\n } catch {\n revert INVALID_BALLOT(); // No ERC165 support\n }\n }\n\n // The configuration timestamp is now.\n uint256 _configuration = block.timestamp;\n\n // Set up a reconfiguration by configuring intrinsic properties.\n _configureIntrinsicPropertiesFor(_projectId, _configuration, _data.weight, _mustStartAtOrAfter);\n\n // Efficiently stores a funding cycles provided user defined properties.\n // If all user config properties are zero, no need to store anything as the default value will have the same outcome.\n if (\n _data.ballot != IJBFundingCycleBallot(address(0)) ||\n _data.duration > 0 ||\n _data.discountRate > 0\n ) {\n // ballot in bits 0-159 bytes.\n uint256 packed = uint160(address(_data.ballot));\n\n // duration in bits 160-191 bytes.\n packed |= _data.duration << 160;\n\n // discountRate in bits 192-223 bytes.\n packed |= _data.discountRate << 192;\n\n // Set in storage.\n _packedUserPropertiesOf[_projectId][_configuration] = packed;\n }\n\n // Set the metadata if needed.\n if (_metadata > 0) _metadataOf[_projectId][_configuration] = _metadata;\n\n emit Configure(_configuration, _projectId, _data, _metadata, _mustStartAtOrAfter, msg.sender);\n\n // Return the funding cycle for the new configuration.\n return _getStructFor(_projectId, _configuration);\n }\n\n //*********************************************************************//\n // --------------------- private helper functions -------------------- //\n //*********************************************************************//\n\n /// @notice Updates the configurable funding cycle for this project if it exists, otherwise creates one.\n /// @param _projectId The ID of the project to find a configurable funding cycle for.\n /// @param _configuration The time at which the funding cycle was configured.\n /// @param _weight The weight to store in the configured funding cycle.\n /// @param _mustStartAtOrAfter The time before which the initialized funding cycle can't start.\n function _configureIntrinsicPropertiesFor(\n uint256 _projectId,\n uint256 _configuration,\n uint256 _weight,\n uint256 _mustStartAtOrAfter\n ) private {\n // If there's not yet a funding cycle for the project, initialize one.\n if (latestConfigurationOf[_projectId] == 0)\n // Use an empty funding cycle as the base.\n return\n _initFor(_projectId, _getStructFor(0, 0), _configuration, _mustStartAtOrAfter, _weight);\n\n // Get the active funding cycle's configuration.\n uint256 _currentConfiguration = _eligibleOf(_projectId);\n\n // If an eligible funding cycle does not exist, get a reference to the latest funding cycle configuration for the project.\n if (_currentConfiguration == 0)\n // Get the latest funding cycle's configuration.\n _currentConfiguration = latestConfigurationOf[_projectId];\n\n // Get a reference to the funding cycle.\n JBFundingCycle memory _baseFundingCycle = _getStructFor(_projectId, _currentConfiguration);\n\n if (!_isApproved(_projectId, _baseFundingCycle) || block.timestamp < _baseFundingCycle.start)\n // If it hasn't been approved or hasn't yet started, set the ID to be the funding cycle it's based on,\n // which carries the latest approved configuration.\n _baseFundingCycle = _getStructFor(_projectId, _baseFundingCycle.basedOn);\n\n // The configuration can't be the same as the base configuration.\n if (_baseFundingCycle.configuration == _configuration) revert NO_SAME_BLOCK_RECONFIGURATION();\n\n // The time after the ballot of the provided funding cycle has expired.\n // If the provided funding cycle has no ballot, return the current timestamp.\n uint256 _timestampAfterBallot = _baseFundingCycle.ballot == IJBFundingCycleBallot(address(0))\n ? 0\n : _configuration + _baseFundingCycle.ballot.duration();\n\n _initFor(\n _projectId,\n _baseFundingCycle,\n _configuration,\n // Can only start after the ballot.\n _timestampAfterBallot > _mustStartAtOrAfter ? _timestampAfterBallot : _mustStartAtOrAfter,\n _weight\n );\n }\n\n /// @notice Initializes a funding cycle with the specified properties.\n /// @param _projectId The ID of the project to which the funding cycle being initialized belongs.\n /// @param _baseFundingCycle The funding cycle to base the initialized one on.\n /// @param _configuration The configuration of the funding cycle being initialized.\n /// @param _mustStartAtOrAfter The time before which the initialized funding cycle cannot start.\n /// @param _weight The weight to give the newly initialized funding cycle.\n function _initFor(\n uint256 _projectId,\n JBFundingCycle memory _baseFundingCycle,\n uint256 _configuration,\n uint256 _mustStartAtOrAfter,\n uint256 _weight\n ) private {\n // If there is no base, initialize a first cycle.\n if (_baseFundingCycle.number == 0) {\n // The first number is 1.\n uint256 _number = 1;\n\n // Set fresh intrinsic properties.\n _packAndStoreIntrinsicPropertiesOf(\n _configuration,\n _projectId,\n _number,\n _weight,\n _baseFundingCycle.configuration,\n _mustStartAtOrAfter\n );\n } else {\n // Derive the correct next start time from the base.\n uint256 _start = _deriveStartFrom(_baseFundingCycle, _mustStartAtOrAfter);\n\n // A weight of 1 is treated as a weight of 0.\n // This is to allow a weight of 0 (default) to represent inheriting the discounted weight of the previous funding cycle.\n _weight = _weight > 0\n ? (_weight == 1 ? 0 : _weight)\n : _deriveWeightFrom(_baseFundingCycle, _start);\n\n // Derive the correct number.\n uint256 _number = _deriveNumberFrom(_baseFundingCycle, _start);\n\n // Update the intrinsic properties.\n _packAndStoreIntrinsicPropertiesOf(\n _configuration,\n _projectId,\n _number,\n _weight,\n _baseFundingCycle.configuration,\n _start\n );\n }\n\n // Set the project's latest funding cycle configuration.\n latestConfigurationOf[_projectId] = _configuration;\n\n emit Init(_configuration, _projectId, _baseFundingCycle.configuration);\n }\n\n /// @notice Efficiently stores a funding cycle's provided intrinsic properties.\n /// @param _configuration The configuration of the funding cycle to pack and store.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @param _number The number of the funding cycle.\n /// @param _weight The weight of the funding cycle.\n /// @param _basedOn The configuration of the base funding cycle.\n /// @param _start The start time of this funding cycle.\n function _packAndStoreIntrinsicPropertiesOf(\n uint256 _configuration,\n uint256 _projectId,\n uint256 _number,\n uint256 _weight,\n uint256 _basedOn,\n uint256 _start\n ) private {\n // weight in bits 0-87.\n uint256 packed = _weight;\n\n // basedOn in bits 88-143.\n packed |= _basedOn << 88;\n\n // start in bits 144-199.\n packed |= _start << 144;\n\n // number in bits 200-255.\n packed |= _number << 200;\n\n // Store the packed value.\n _packedIntrinsicPropertiesOf[_projectId][_configuration] = packed;\n }\n\n /// @notice The project's stored funding cycle that hasn't yet started and should be used next, if one exists.\n /// @dev A value of 0 is returned if no funding cycle was found.\n /// @dev Assumes the project has a latest configuration.\n /// @param _projectId The ID of a project to look through for a standby cycle.\n /// @return configuration The configuration of the standby funding cycle if one exists, or 0 if one doesn't exist.\n function _standbyOf(uint256 _projectId) private view returns (uint256 configuration) {\n // Get a reference to the project's latest funding cycle.\n configuration = latestConfigurationOf[_projectId];\n\n // Get the necessary properties for the latest funding cycle.\n JBFundingCycle memory _fundingCycle = _getStructFor(_projectId, configuration);\n\n // There is no upcoming funding cycle if the latest funding cycle has already started.\n if (block.timestamp >= _fundingCycle.start) return 0;\n\n // If this is the first funding cycle, it is queued.\n if (_fundingCycle.number == 1) return configuration;\n\n // Get the necessary properties for the base funding cycle.\n JBFundingCycle memory _baseFundingCycle = _getStructFor(_projectId, _fundingCycle.basedOn);\n\n // If the latest configuration doesn't start until after another base cycle, return 0.\n if (\n _baseFundingCycle.duration > 0 &&\n block.timestamp < _fundingCycle.start - _baseFundingCycle.duration\n ) return 0;\n }\n\n /// @notice The project's stored funding cycle that has started and hasn't yet expired.\n /// @dev A value of 0 is returned if no funding cycle was found.\n /// @dev Assumes the project has a latest configuration.\n /// @param _projectId The ID of the project to look through.\n /// @return configuration The configuration of an eligible funding cycle if one exists, or 0 if one doesn't exist.\n function _eligibleOf(uint256 _projectId) private view returns (uint256 configuration) {\n // Get a reference to the project's latest funding cycle.\n configuration = latestConfigurationOf[_projectId];\n\n // Get the latest funding cycle.\n JBFundingCycle memory _fundingCycle = _getStructFor(_projectId, configuration);\n\n // If the latest is expired, return an empty funding cycle.\n // A duration of 0 cannot be expired.\n if (\n _fundingCycle.duration > 0 && block.timestamp >= _fundingCycle.start + _fundingCycle.duration\n ) return 0;\n\n // Return the funding cycle's configuration if it has started.\n if (block.timestamp >= _fundingCycle.start) return _fundingCycle.configuration;\n\n // Get a reference to the cycle's base configuration.\n JBFundingCycle memory _baseFundingCycle = _getStructFor(_projectId, _fundingCycle.basedOn);\n\n // If the base cycle isn't eligible, the project has no eligible cycle.\n // A duration of 0 is always eligible.\n if (\n _baseFundingCycle.duration > 0 &&\n block.timestamp >= _baseFundingCycle.start + _baseFundingCycle.duration\n ) return 0;\n\n // Return the configuration that the latest funding cycle is based on.\n configuration = _fundingCycle.basedOn;\n }\n\n /// @notice A view of the funding cycle that would be created based on the provided one if the project doesn't make a reconfiguration.\n /// @dev Returns an empty funding cycle if there can't be a mock funding cycle based on the provided one.\n /// @dev Assumes a funding cycle with a duration of 0 will never be asked to be the base of a mock.\n /// @param _baseFundingCycle The funding cycle that the resulting funding cycle should follow.\n /// @param _allowMidCycle A flag indicating if the mocked funding cycle is allowed to already be mid cycle.\n /// @return A mock of what the next funding cycle will be.\n function _mockFundingCycleBasedOn(\n JBFundingCycle memory _baseFundingCycle,\n bool _allowMidCycle\n ) private view returns (JBFundingCycle memory) {\n // Get the distance of the current time to the start of the next possible funding cycle.\n // If the returned mock cycle must not yet have started, the start time of the mock must be in the future.\n uint256 _mustStartAtOrAfter = !_allowMidCycle\n ? block.timestamp + 1\n : block.timestamp - _baseFundingCycle.duration + 1;\n\n // Derive what the start time should be.\n uint256 _start = _deriveStartFrom(_baseFundingCycle, _mustStartAtOrAfter);\n\n // Derive what the number should be.\n uint256 _number = _deriveNumberFrom(_baseFundingCycle, _start);\n\n return\n JBFundingCycle(\n _number,\n _baseFundingCycle.configuration,\n _baseFundingCycle.basedOn,\n _start,\n _baseFundingCycle.duration,\n _deriveWeightFrom(_baseFundingCycle, _start),\n _baseFundingCycle.discountRate,\n _baseFundingCycle.ballot,\n _baseFundingCycle.metadata\n );\n }\n\n /// @notice The date that is the nearest multiple of the specified funding cycle's duration from its end.\n /// @param _baseFundingCycle The funding cycle to base the calculation on.\n /// @param _mustStartAtOrAfter A date that the derived start must be on or come after.\n /// @return start The next start time.\n function _deriveStartFrom(\n JBFundingCycle memory _baseFundingCycle,\n uint256 _mustStartAtOrAfter\n ) private pure returns (uint256 start) {\n // A subsequent cycle to one with a duration of 0 should start as soon as possible.\n if (_baseFundingCycle.duration == 0) return _mustStartAtOrAfter;\n\n // The time when the funding cycle immediately after the specified funding cycle starts.\n uint256 _nextImmediateStart = _baseFundingCycle.start + _baseFundingCycle.duration;\n\n // If the next immediate start is now or in the future, return it.\n if (_nextImmediateStart >= _mustStartAtOrAfter) return _nextImmediateStart;\n\n // The amount of seconds since the `_mustStartAtOrAfter` time which results in a start time that might satisfy the specified constraints.\n uint256 _timeFromImmediateStartMultiple = (_mustStartAtOrAfter - _nextImmediateStart) %\n _baseFundingCycle.duration;\n\n // A reference to the first possible start timestamp.\n start = _mustStartAtOrAfter - _timeFromImmediateStartMultiple;\n\n // Add increments of duration as necessary to satisfy the threshold.\n while (_mustStartAtOrAfter > start) start = start + _baseFundingCycle.duration;\n }\n\n /// @notice The accumulated weight change since the specified funding cycle.\n /// @param _baseFundingCycle The funding cycle to base the calculation on.\n /// @param _start The start time of the funding cycle to derive a number for.\n /// @return weight The derived weight, as a fixed point number with 18 decimals.\n function _deriveWeightFrom(\n JBFundingCycle memory _baseFundingCycle,\n uint256 _start\n ) private pure returns (uint256 weight) {\n // A subsequent cycle to one with a duration of 0 should have the next possible weight.\n if (_baseFundingCycle.duration == 0)\n return\n PRBMath.mulDiv(\n _baseFundingCycle.weight,\n JBConstants.MAX_DISCOUNT_RATE - _baseFundingCycle.discountRate,\n JBConstants.MAX_DISCOUNT_RATE\n );\n\n // The weight should be based off the base funding cycle's weight.\n weight = _baseFundingCycle.weight;\n\n // If the discount is 0, the weight doesn't change.\n if (_baseFundingCycle.discountRate == 0) return weight;\n\n // The difference between the start of the base funding cycle and the proposed start.\n uint256 _startDistance = _start - _baseFundingCycle.start;\n\n // Apply the base funding cycle's discount rate for each cycle that has passed.\n uint256 _discountMultiple;\n unchecked {\n _discountMultiple = _startDistance / _baseFundingCycle.duration; // Non-null duration is excluded above\n }\n\n for (uint256 _i; _i < _discountMultiple; ) {\n // The number of times to apply the discount rate.\n // Base the new weight on the specified funding cycle's weight.\n weight = PRBMath.mulDiv(\n weight,\n JBConstants.MAX_DISCOUNT_RATE - _baseFundingCycle.discountRate,\n JBConstants.MAX_DISCOUNT_RATE\n );\n\n // The calculation doesn't need to continue if the weight is 0.\n if (weight == 0) break;\n\n unchecked {\n ++_i;\n }\n }\n }\n\n /// @notice The number of the next funding cycle given the specified funding cycle.\n /// @param _baseFundingCycle The funding cycle to base the calculation on.\n /// @param _start The start time of the funding cycle to derive a number for.\n /// @return The funding cycle number.\n function _deriveNumberFrom(\n JBFundingCycle memory _baseFundingCycle,\n uint256 _start\n ) private pure returns (uint256) {\n // A subsequent cycle to one with a duration of 0 should be the next number.\n if (_baseFundingCycle.duration == 0) return _baseFundingCycle.number + 1;\n\n // The difference between the start of the base funding cycle and the proposed start.\n uint256 _startDistance = _start - _baseFundingCycle.start;\n\n // Find the number of base cycles that fit in the start distance.\n return _baseFundingCycle.number + (_startDistance / _baseFundingCycle.duration);\n }\n\n /// @notice Checks to see if the provided funding cycle is approved according to the correct ballot.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @param _fundingCycle The funding cycle to get an approval flag for.\n /// @return The approval flag.\n function _isApproved(\n uint256 _projectId,\n JBFundingCycle memory _fundingCycle\n ) private view returns (bool) {\n return\n _ballotStateOf(\n _projectId,\n _fundingCycle.configuration,\n _fundingCycle.start,\n _fundingCycle.basedOn\n ) == JBBallotState.Approved;\n }\n\n /// @notice A project's latest funding cycle configuration approval status.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @param _configuration The funding cycle configuration to get the ballot state of.\n /// @param _start The start time of the funding cycle configuration to get the ballot state of.\n /// @param _ballotFundingCycleConfiguration The configuration of the funding cycle which is configured with the ballot that should be used.\n /// @return The ballot state of the project.\n function _ballotStateOf(\n uint256 _projectId,\n uint256 _configuration,\n uint256 _start,\n uint256 _ballotFundingCycleConfiguration\n ) private view returns (JBBallotState) {\n // If there is no ballot funding cycle, implicitly approve.\n if (_ballotFundingCycleConfiguration == 0) return JBBallotState.Approved;\n\n // Get the ballot funding cycle.\n JBFundingCycle memory _ballotFundingCycle = _getStructFor(\n _projectId,\n _ballotFundingCycleConfiguration\n );\n\n // If there is no ballot, the ID is auto approved.\n if (_ballotFundingCycle.ballot == IJBFundingCycleBallot(address(0)))\n return JBBallotState.Approved;\n\n // Return the ballot's state\n return _ballotFundingCycle.ballot.stateOf(_projectId, _configuration, _start);\n }\n\n /// @notice Unpack a funding cycle's packed stored values into an easy-to-work-with funding cycle struct.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @param _configuration The funding cycle configuration to get the full struct for.\n /// @return fundingCycle A funding cycle struct.\n function _getStructFor(\n uint256 _projectId,\n uint256 _configuration\n ) private view returns (JBFundingCycle memory fundingCycle) {\n // Return an empty funding cycle if the configuration specified is 0.\n if (_configuration == 0) return fundingCycle;\n\n fundingCycle.configuration = _configuration;\n\n uint256 _packedIntrinsicProperties = _packedIntrinsicPropertiesOf[_projectId][_configuration];\n\n // weight in bits 0-87 bits.\n fundingCycle.weight = uint256(uint88(_packedIntrinsicProperties));\n // basedOn in bits 88-143 bits.\n fundingCycle.basedOn = uint256(uint56(_packedIntrinsicProperties >> 88));\n // start in bits 144-199 bits.\n fundingCycle.start = uint256(uint56(_packedIntrinsicProperties >> 144));\n // number in bits 200-255 bits.\n fundingCycle.number = uint256(uint56(_packedIntrinsicProperties >> 200));\n\n uint256 _packedUserProperties = _packedUserPropertiesOf[_projectId][_configuration];\n\n // ballot in bits 0-159 bits.\n fundingCycle.ballot = IJBFundingCycleBallot(address(uint160(_packedUserProperties)));\n // duration in bits 160-191 bits.\n fundingCycle.duration = uint256(uint32(_packedUserProperties >> 160));\n // discountRate in bits 192-223 bits.\n fundingCycle.discountRate = uint256(uint32(_packedUserProperties >> 192));\n\n fundingCycle.metadata = _metadataOf[_projectId][_configuration];\n }\n}\n" + }, + "contracts/JBController.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {ERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {SafeCast} from '@openzeppelin/contracts/utils/math/SafeCast.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {JBOperatable} from './abstract/JBOperatable.sol';\nimport {JBBallotState} from './enums/JBBallotState.sol';\nimport {IJBController} from './interfaces/IJBController.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol';\nimport {IJBMigratable} from './interfaces/IJBMigratable.sol';\nimport {IJBOperatable} from './interfaces/IJBOperatable.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {IJBSplitAllocator} from './interfaces/IJBSplitAllocator.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {IJBTokenStore} from './interfaces/IJBTokenStore.sol';\nimport {JBConstants} from './libraries/JBConstants.sol';\nimport {JBFundingCycleMetadataResolver} from './libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBOperations} from './libraries/JBOperations.sol';\nimport {JBSplitsGroups} from './libraries/JBSplitsGroups.sol';\nimport {JBSplitAllocationData} from './structs/JBSplitAllocationData.sol';\nimport {JBFundAccessConstraints} from './structs/JBFundAccessConstraints.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\nimport {JBFundingCycleData} from './structs/JBFundingCycleData.sol';\nimport {JBFundingCycleMetadata} from './structs/JBFundingCycleMetadata.sol';\nimport {JBGroupedSplits} from './structs/JBGroupedSplits.sol';\nimport {JBProjectMetadata} from './structs/JBProjectMetadata.sol';\nimport {JBSplit} from './structs/JBSplit.sol';\n\n/// @notice Stitches together funding cycles and project tokens, making sure all activity is accounted for and correct.\ncontract JBController is JBOperatable, ERC165, IJBController, IJBMigratable {\n // A library that parses the packed funding cycle metadata into a more friendly format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error BURN_PAUSED_AND_SENDER_NOT_VALID_TERMINAL_DELEGATE();\n error CANT_MIGRATE_TO_CURRENT_CONTROLLER();\n error FUNDING_CYCLE_ALREADY_LAUNCHED();\n error INVALID_BALLOT_REDEMPTION_RATE();\n error INVALID_DISTRIBUTION_LIMIT();\n error INVALID_DISTRIBUTION_LIMIT_CURRENCY();\n error INVALID_OVERFLOW_ALLOWANCE();\n error INVALID_OVERFLOW_ALLOWANCE_CURRENCY();\n error INVALID_REDEMPTION_RATE();\n error INVALID_RESERVED_RATE();\n error MIGRATION_NOT_ALLOWED();\n error MINT_NOT_ALLOWED_AND_NOT_TERMINAL_DELEGATE();\n error NO_BURNABLE_TOKENS();\n error NOT_CURRENT_CONTROLLER();\n error ZERO_TOKENS_TO_MINT();\n\n //*********************************************************************//\n // --------------------- internal stored properties ------------------ //\n //*********************************************************************//\n\n /// @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.\n /// @custom:param _projectId The ID of the project to get the tracker of.\n mapping(uint256 => int256) internal _processedTokenTrackerOf;\n\n /// @notice Data regarding the distribution limit of a project during a configuration.\n /// @dev bits 0-231: The amount of token that a project can distribute per funding cycle.\n /// @dev bits 232-255: The currency of amount that a project can distribute.\n /// @custom:param _projectId The ID of the project to get the packed distribution limit data of.\n /// @custom:param _configuration The configuration during which the packed distribution limit data applies.\n /// @custom:param _terminal The terminal from which distributions are being limited.\n /// @custom:param _token The token for which distributions are being limited.\n mapping(uint256 => mapping(uint256 => mapping(IJBPaymentTerminal => mapping(address => uint256))))\n internal _packedDistributionLimitDataOf;\n\n /// @notice Data regarding the overflow allowance of a project during a configuration.\n /// @dev bits 0-231: The amount of overflow that a project is allowed to tap into on-demand throughout the configuration.\n /// @dev bits 232-255: The currency of the amount of overflow that a project is allowed to tap.\n /// @custom:param _projectId The ID of the project to get the packed overflow allowance data of.\n /// @custom:param _configuration The configuration during which the packed overflow allowance data applies.\n /// @custom:param _terminal The terminal managing the overflow.\n /// @custom:param _token The token for which overflow is being allowed.\n mapping(uint256 => mapping(uint256 => mapping(IJBPaymentTerminal => mapping(address => uint256))))\n internal _packedOverflowAllowanceDataOf;\n\n //*********************************************************************//\n // --------------- public immutable stored properties ---------------- //\n //*********************************************************************//\n\n /// @notice Mints ERC-721's that represent project ownership.\n IJBProjects public immutable override projects;\n\n /// @notice The contract storing all funding cycle configurations.\n IJBFundingCycleStore public immutable override fundingCycleStore;\n\n /// @notice The contract that manages token minting and burning.\n IJBTokenStore public immutable override tokenStore;\n\n /// @notice The contract that stores splits for each project.\n IJBSplitsStore public immutable override splitsStore;\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice The amount of token that a project can distribute per funding cycle, and the currency it's in terms of.\n /// @dev The number of decimals in the returned fixed point amount is the same as that of the specified terminal.\n /// @param _projectId The ID of the project to get the distribution limit of.\n /// @param _configuration The configuration during which the distribution limit applies.\n /// @param _terminal The terminal from which distributions are being limited.\n /// @param _token The token for which the distribution limit applies.\n /// @return The distribution limit, as a fixed point number with the same number of decimals as the provided terminal.\n /// @return The currency of the distribution limit.\n function distributionLimitOf(\n uint256 _projectId,\n uint256 _configuration,\n IJBPaymentTerminal _terminal,\n address _token\n ) external view override returns (uint256, uint256) {\n // Get a reference to the packed data.\n uint256 _data = _packedDistributionLimitDataOf[_projectId][_configuration][_terminal][_token];\n\n // The limit is in bits 0-231. The currency is in bits 232-255.\n return (uint256(uint232(_data)), _data >> 232);\n }\n\n /// @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.\n /// @dev The number of decimals in the returned fixed point amount is the same as that of the specified terminal.\n /// @param _projectId The ID of the project to get the overflow allowance of.\n /// @param _configuration The configuration of the during which the allowance applies.\n /// @param _terminal The terminal managing the overflow.\n /// @param _token The token for which the overflow allowance applies.\n /// @return The overflow allowance, as a fixed point number with the same number of decimals as the provided terminal.\n /// @return The currency of the overflow allowance.\n function overflowAllowanceOf(\n uint256 _projectId,\n uint256 _configuration,\n IJBPaymentTerminal _terminal,\n address _token\n ) external view override returns (uint256, uint256) {\n // Get a reference to the packed data.\n uint256 _data = _packedOverflowAllowanceDataOf[_projectId][_configuration][_terminal][_token];\n\n // The allowance is in bits 0-231. The currency is in bits 232-255.\n return (uint256(uint232(_data)), _data >> 232);\n }\n\n /// @notice Gets the amount of reserved tokens that a project has available to distribute.\n /// @param _projectId The ID of the project to get a reserved token balance of.\n /// @param _reservedRate The reserved rate to use when making the calculation.\n /// @return The current amount of reserved tokens.\n function reservedTokenBalanceOf(\n uint256 _projectId,\n uint256 _reservedRate\n ) external view override returns (uint256) {\n return\n _reservedTokenAmountFrom(\n _processedTokenTrackerOf[_projectId],\n _reservedRate,\n tokenStore.totalSupplyOf(_projectId)\n );\n }\n\n /// @notice Gets the current total amount of outstanding tokens for a project, given a reserved rate.\n /// @param _projectId The ID of the project to get total outstanding tokens of.\n /// @param _reservedRate The reserved rate to use when making the calculation.\n /// @return The current total amount of outstanding tokens for the project.\n function totalOutstandingTokensOf(\n uint256 _projectId,\n uint256 _reservedRate\n ) external view override returns (uint256) {\n // Get the total number of tokens in circulation.\n uint256 _totalSupply = tokenStore.totalSupplyOf(_projectId);\n\n // Get the number of reserved tokens the project has.\n uint256 _reservedTokenAmount = _reservedTokenAmountFrom(\n _processedTokenTrackerOf[_projectId],\n _reservedRate,\n _totalSupply\n );\n\n // Add the reserved tokens to the total supply.\n return _totalSupply + _reservedTokenAmount;\n }\n\n /// @notice A project's funding cycle for the specified configuration along with its metadata.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The funding cycle.\n /// @return metadata The funding cycle's metadata.\n function getFundingCycleOf(\n uint256 _projectId,\n uint256 _configuration\n )\n external\n view\n override\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata)\n {\n fundingCycle = fundingCycleStore.get(_projectId, _configuration);\n metadata = fundingCycle.expandMetadata();\n }\n\n /// @notice A project's latest configured funding cycle along with its metadata and the ballot state of the configuration.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The latest configured funding cycle.\n /// @return metadata The latest configured funding cycle's metadata.\n /// @return ballotState The state of the configuration.\n function latestConfiguredFundingCycleOf(\n uint256 _projectId\n )\n external\n view\n override\n returns (\n JBFundingCycle memory fundingCycle,\n JBFundingCycleMetadata memory metadata,\n JBBallotState ballotState\n )\n {\n (fundingCycle, ballotState) = fundingCycleStore.latestConfiguredOf(_projectId);\n metadata = fundingCycle.expandMetadata();\n }\n\n /// @notice A project's current funding cycle along with its metadata.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The current funding cycle.\n /// @return metadata The current funding cycle's metadata.\n function currentFundingCycleOf(\n uint256 _projectId\n )\n external\n view\n override\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata)\n {\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n metadata = fundingCycle.expandMetadata();\n }\n\n /// @notice A project's queued funding cycle along with its metadata.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The queued funding cycle.\n /// @return metadata The queued funding cycle's metadata.\n function queuedFundingCycleOf(\n uint256 _projectId\n )\n external\n view\n override\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata)\n {\n fundingCycle = fundingCycleStore.queuedOf(_projectId);\n metadata = fundingCycle.expandMetadata();\n }\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if the provided interface ID is supported.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(ERC165, IERC165) returns (bool) {\n return\n _interfaceId == type(IJBController).interfaceId ||\n _interfaceId == type(IJBMigratable).interfaceId ||\n _interfaceId == type(IJBOperatable).interfaceId ||\n super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // ---------------------------- constructor -------------------------- //\n //*********************************************************************//\n\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _fundingCycleStore A contract storing all funding cycle configurations.\n /// @param _tokenStore A contract that manages token minting and burning.\n /// @param _splitsStore A contract that stores splits for each project.\n constructor(\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBFundingCycleStore _fundingCycleStore,\n IJBTokenStore _tokenStore,\n IJBSplitsStore _splitsStore\n ) JBOperatable(_operatorStore) {\n projects = _projects;\n directory = _directory;\n fundingCycleStore = _fundingCycleStore;\n tokenStore = _tokenStore;\n splitsStore = _splitsStore;\n }\n\n //*********************************************************************//\n // --------------------- external transactions ----------------------- //\n //*********************************************************************//\n\n /// @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.\n /// @dev Each operation within this transaction can be done in sequence separately.\n /// @dev Anyone can deploy a project on an owner's behalf.\n /// @param _owner The address to set as the owner of the project. The project ERC-721 will be owned by this address.\n /// @param _projectMetadata Metadata to associate with the project within a particular domain. This can be updated any time by the owner of the project.\n /// @param _data Data that defines the project's first funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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`.\n /// @param _terminals Payment terminals to add for the project.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return projectId The ID of the project.\n function launchProjectFor(\n address _owner,\n JBProjectMetadata calldata _projectMetadata,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] calldata _groupedSplits,\n JBFundAccessConstraints[] calldata _fundAccessConstraints,\n IJBPaymentTerminal[] memory _terminals,\n string memory _memo\n ) external virtual override returns (uint256 projectId) {\n // Keep a reference to the directory.\n IJBDirectory _directory = directory;\n\n // Mint the project into the wallet of the owner.\n projectId = projects.createFor(_owner, _projectMetadata);\n\n // Set this contract as the project's controller in the directory.\n _directory.setControllerOf(projectId, address(this));\n\n // Configure the first funding cycle.\n uint256 _configuration = _configure(\n projectId,\n _data,\n _metadata,\n _mustStartAtOrAfter,\n _groupedSplits,\n _fundAccessConstraints\n );\n\n // Add the provided terminals to the list of terminals.\n if (_terminals.length > 0) _directory.setTerminalsOf(projectId, _terminals);\n\n emit LaunchProject(_configuration, projectId, _memo, msg.sender);\n }\n\n /// @notice Creates a funding cycle for an already existing project ERC-721.\n /// @dev Each operation within this transaction can be done in sequence separately.\n /// @dev Only a project owner or operator can launch its funding cycles.\n /// @param _projectId The ID of the project to launch funding cycles for.\n /// @param _data Data that defines the project's first funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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`.\n /// @param _terminals Payment terminals to add for the project.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return configuration The configuration of the funding cycle that was successfully created.\n function launchFundingCyclesFor(\n uint256 _projectId,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] calldata _groupedSplits,\n JBFundAccessConstraints[] memory _fundAccessConstraints,\n IJBPaymentTerminal[] memory _terminals,\n string memory _memo\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.RECONFIGURE)\n returns (uint256 configuration)\n {\n // If there is a previous configuration, reconfigureFundingCyclesOf should be called instead\n if (fundingCycleStore.latestConfigurationOf(_projectId) > 0)\n revert FUNDING_CYCLE_ALREADY_LAUNCHED();\n\n // Set this contract as the project's controller in the directory.\n directory.setControllerOf(_projectId, address(this));\n\n // Configure the first funding cycle.\n configuration = _configure(\n _projectId,\n _data,\n _metadata,\n _mustStartAtOrAfter,\n _groupedSplits,\n _fundAccessConstraints\n );\n\n // Add the provided terminals to the list of terminals.\n if (_terminals.length > 0) directory.setTerminalsOf(_projectId, _terminals);\n\n emit LaunchFundingCycles(configuration, _projectId, _memo, msg.sender);\n }\n\n /// @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.\n /// @dev Only a project's owner or a designated operator can configure its funding cycles.\n /// @param _projectId The ID of the project whose funding cycles are being reconfigured.\n /// @param _data Data that defines the funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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`.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return configuration The configuration of the funding cycle that was successfully reconfigured.\n function reconfigureFundingCyclesOf(\n uint256 _projectId,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] calldata _groupedSplits,\n JBFundAccessConstraints[] calldata _fundAccessConstraints,\n string calldata _memo\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.RECONFIGURE)\n returns (uint256 configuration)\n {\n // Configure the next funding cycle.\n configuration = _configure(\n _projectId,\n _data,\n _metadata,\n _mustStartAtOrAfter,\n _groupedSplits,\n _fundAccessConstraints\n );\n\n emit ReconfigureFundingCycles(configuration, _projectId, _memo, msg.sender);\n }\n\n /// @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.\n /// @dev Only a project's owner, a designated operator, one of its terminals, or the current data source can mint its tokens.\n /// @param _projectId The ID of the project to which the tokens being minted belong.\n /// @param _tokenCount The amount of tokens to mint in total, counting however many should be reserved.\n /// @param _beneficiary The account that the tokens are being minted for.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _preferClaimedTokens A flag indicating whether a project's attached token contract should be minted if they have been issued.\n /// @param _useReservedRate Whether to use the current funding cycle's reserved rate in the mint calculation.\n /// @return beneficiaryTokenCount The amount of tokens minted for the beneficiary.\n function mintTokensOf(\n uint256 _projectId,\n uint256 _tokenCount,\n address _beneficiary,\n string calldata _memo,\n bool _preferClaimedTokens,\n bool _useReservedRate\n ) external virtual override returns (uint256 beneficiaryTokenCount) {\n // There should be tokens to mint.\n if (_tokenCount == 0) revert ZERO_TOKENS_TO_MINT();\n\n // Define variables that will be needed outside scoped section below.\n // Keep a reference to the reserved rate to use\n uint256 _reservedRate;\n\n // Scoped section prevents stack too deep. `_fundingCycle` only used within scope.\n {\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Minting limited to: project owner, authorized callers, project terminal and current funding cycle data source\n _requirePermissionAllowingOverride(\n projects.ownerOf(_projectId),\n _projectId,\n JBOperations.MINT,\n directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender)) ||\n msg.sender == address(_fundingCycle.dataSource())\n );\n\n // If the message sender is not a terminal or a datasource, the current funding cycle must allow minting.\n if (\n !_fundingCycle.mintingAllowed() &&\n !directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender)) &&\n msg.sender != address(_fundingCycle.dataSource())\n ) revert MINT_NOT_ALLOWED_AND_NOT_TERMINAL_DELEGATE();\n\n // Determine the reserved rate to use.\n _reservedRate = _useReservedRate ? _fundingCycle.reservedRate() : 0;\n\n // Override the claimed token preference with the funding cycle value.\n _preferClaimedTokens = _preferClaimedTokens == true\n ? _preferClaimedTokens\n : _fundingCycle.preferClaimedTokenOverride();\n }\n\n if (_reservedRate == JBConstants.MAX_RESERVED_RATE)\n // Subtract the total weighted amount from the tracker so the full reserved token amount can be printed later.\n _processedTokenTrackerOf[_projectId] =\n _processedTokenTrackerOf[_projectId] -\n SafeCast.toInt256(_tokenCount);\n else {\n // The unreserved token count that will be minted for the beneficiary.\n beneficiaryTokenCount = PRBMath.mulDiv(\n _tokenCount,\n JBConstants.MAX_RESERVED_RATE - _reservedRate,\n JBConstants.MAX_RESERVED_RATE\n );\n\n if (_reservedRate == 0)\n // If there's no reserved rate, increment the tracker with the newly minted tokens.\n _processedTokenTrackerOf[_projectId] =\n _processedTokenTrackerOf[_projectId] +\n SafeCast.toInt256(beneficiaryTokenCount);\n\n // Mint the tokens.\n tokenStore.mintFor(_beneficiary, _projectId, beneficiaryTokenCount, _preferClaimedTokens);\n }\n\n emit MintTokens(\n _beneficiary,\n _projectId,\n _tokenCount,\n beneficiaryTokenCount,\n _memo,\n _reservedRate,\n msg.sender\n );\n }\n\n /// @notice Burns a token holder's supply.\n /// @dev Only a token's holder, a designated operator, or a project's terminal can burn it.\n /// @param _holder The account that is having its tokens burned.\n /// @param _projectId The ID of the project to which the tokens being burned belong.\n /// @param _tokenCount The number of tokens to burn.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _preferClaimedTokens A flag indicating whether a project's attached token contract should be burned first if they have been issued.\n function burnTokensOf(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n string calldata _memo,\n bool _preferClaimedTokens\n )\n external\n virtual\n override\n requirePermissionAllowingOverride(\n _holder,\n _projectId,\n JBOperations.BURN,\n directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender))\n )\n {\n // There should be tokens to burn\n if (_tokenCount == 0) revert NO_BURNABLE_TOKENS();\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // If the message sender is a terminal, the current funding cycle must not be paused.\n if (\n _fundingCycle.burnPaused() &&\n !directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender))\n ) revert BURN_PAUSED_AND_SENDER_NOT_VALID_TERMINAL_DELEGATE();\n\n // Update the token tracker so that reserved tokens will still be correctly mintable.\n _processedTokenTrackerOf[_projectId] =\n _processedTokenTrackerOf[_projectId] -\n SafeCast.toInt256(_tokenCount);\n\n // Burn the tokens.\n tokenStore.burnFrom(_holder, _projectId, _tokenCount, _preferClaimedTokens);\n\n emit BurnTokens(_holder, _projectId, _tokenCount, _memo, msg.sender);\n }\n\n /// @notice Distributes all outstanding reserved tokens for a project.\n /// @param _projectId The ID of the project to which the reserved tokens belong.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return The amount of minted reserved tokens.\n function distributeReservedTokensOf(\n uint256 _projectId,\n string calldata _memo\n ) external virtual override returns (uint256) {\n return _distributeReservedTokensOf(_projectId, _memo);\n }\n\n /// @notice Allows other controllers to signal to this one that a migration is expected for the specified project.\n /// @dev This controller should not yet be the project's controller.\n /// @param _projectId The ID of the project that will be migrated to this controller.\n /// @param _from The controller being migrated from.\n function prepForMigrationOf(uint256 _projectId, address _from) external virtual override {\n // This controller must not be the project's current controller.\n if (directory.controllerOf(_projectId) == address(this))\n revert CANT_MIGRATE_TO_CURRENT_CONTROLLER();\n\n // Set the tracker as the total supply.\n _processedTokenTrackerOf[_projectId] = SafeCast.toInt256(tokenStore.totalSupplyOf(_projectId));\n\n emit PrepMigration(_projectId, _from, msg.sender);\n }\n\n /// @notice Allows a project to migrate from this controller to another.\n /// @dev Only a project's owner or a designated operator can migrate it.\n /// @param _projectId The ID of the project that will be migrated from this controller.\n /// @param _to The controller to which the project is migrating.\n function migrate(\n uint256 _projectId,\n IJBMigratable _to\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.MIGRATE_CONTROLLER)\n {\n // Keep a reference to the directory.\n IJBDirectory _directory = directory;\n\n // This controller must be the project's current controller.\n if (_directory.controllerOf(_projectId) != address(this)) revert NOT_CURRENT_CONTROLLER();\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Migration must be allowed.\n if (!_fundingCycle.controllerMigrationAllowed()) revert MIGRATION_NOT_ALLOWED();\n\n // All reserved tokens must be minted before migrating.\n if (\n _processedTokenTrackerOf[_projectId] < 0 ||\n uint256(_processedTokenTrackerOf[_projectId]) != tokenStore.totalSupplyOf(_projectId)\n ) _distributeReservedTokensOf(_projectId, '');\n\n // Make sure the new controller is prepped for the migration.\n _to.prepForMigrationOf(_projectId, address(this));\n\n // Set the new controller.\n _directory.setControllerOf(_projectId, address(_to));\n\n emit Migrate(_projectId, _to, msg.sender);\n }\n\n //*********************************************************************//\n // ------------------------ internal functions ----------------------- //\n //*********************************************************************//\n\n /// @notice Distributes all outstanding reserved tokens for a project.\n /// @param _projectId The ID of the project to which the reserved tokens belong.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return tokenCount The amount of minted reserved tokens.\n function _distributeReservedTokensOf(\n uint256 _projectId,\n string memory _memo\n ) internal returns (uint256 tokenCount) {\n // Keep a reference to the token store.\n IJBTokenStore _tokenStore = tokenStore;\n\n // Get the current funding cycle to read the reserved rate from.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Get a reference to new total supply of tokens before minting reserved tokens.\n uint256 _totalTokens = _tokenStore.totalSupplyOf(_projectId);\n\n // Get a reference to the number of tokens that need to be minted.\n tokenCount = _reservedTokenAmountFrom(\n _processedTokenTrackerOf[_projectId],\n _fundingCycle.reservedRate(),\n _totalTokens\n );\n\n // Set the tracker to be the new total supply.\n _processedTokenTrackerOf[_projectId] = SafeCast.toInt256(_totalTokens + tokenCount);\n\n // Get a reference to the project owner.\n address _owner = projects.ownerOf(_projectId);\n\n // Distribute tokens to splits and get a reference to the leftover amount to mint after all splits have gotten their share.\n uint256 _leftoverTokenCount = tokenCount == 0\n ? 0\n : _distributeToReservedTokenSplitsOf(\n _projectId,\n _fundingCycle.configuration,\n JBSplitsGroups.RESERVED_TOKENS,\n tokenCount\n );\n\n // Mint any leftover tokens to the project owner.\n if (_leftoverTokenCount > 0)\n _tokenStore.mintFor(_owner, _projectId, _leftoverTokenCount, false);\n\n emit DistributeReservedTokens(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _owner,\n tokenCount,\n _leftoverTokenCount,\n _memo,\n msg.sender\n );\n }\n\n /// @notice Distribute tokens to the splits according to the specified funding cycle configuration.\n /// @param _projectId The ID of the project for which reserved token splits are being distributed.\n /// @param _domain The domain of the splits to distribute the reserved tokens between.\n /// @param _group The group of the splits to distribute the reserved tokens between.\n /// @param _amount The total amount of tokens to mint.\n /// @return leftoverAmount If the splits percents dont add up to 100%, the leftover amount is returned.\n function _distributeToReservedTokenSplitsOf(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group,\n uint256 _amount\n ) internal returns (uint256 leftoverAmount) {\n // Keep a reference to the token store.\n IJBTokenStore _tokenStore = tokenStore;\n\n // Set the leftover amount to the initial amount.\n leftoverAmount = _amount;\n\n // Get a reference to the project's reserved token splits.\n JBSplit[] memory _splits = splitsStore.splitsOf(_projectId, _domain, _group);\n\n //Transfer between all splits.\n for (uint256 _i; _i < _splits.length; ) {\n // Get a reference to the split being iterated on.\n JBSplit memory _split = _splits[_i];\n\n // The amount to send towards the split.\n uint256 _tokenCount = PRBMath.mulDiv(\n _amount,\n _split.percent,\n JBConstants.SPLITS_TOTAL_PERCENT\n );\n\n // Mints tokens for the split if needed.\n if (_tokenCount > 0) {\n _tokenStore.mintFor(\n // If an allocator is set in the splits, set it as the beneficiary.\n // Otherwise if a projectId is set in the split, set the project's owner as the beneficiary.\n // If the split has a beneficiary send to the split's beneficiary. Otherwise send to the msg.sender.\n _split.allocator != IJBSplitAllocator(address(0))\n ? address(_split.allocator)\n : _split.projectId != 0\n ? projects.ownerOf(_split.projectId)\n : _split.beneficiary != address(0)\n ? _split.beneficiary\n : msg.sender,\n _projectId,\n _tokenCount,\n _split.preferClaimed\n );\n\n // If there's an allocator set, trigger its `allocate` function.\n if (_split.allocator != IJBSplitAllocator(address(0)))\n _split.allocator.allocate(\n JBSplitAllocationData(\n address(_tokenStore.tokenOf(_projectId)),\n _tokenCount,\n 18,\n _projectId,\n _group,\n _split\n )\n );\n\n // Subtract from the amount to be sent to the beneficiary.\n leftoverAmount = leftoverAmount - _tokenCount;\n }\n\n emit DistributeToReservedTokenSplit(\n _projectId,\n _domain,\n _group,\n _split,\n _tokenCount,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n\n /// @notice Configures a funding cycle and stores information pertinent to the configuration.\n /// @param _projectId The ID of the project whose funding cycles are being reconfigured.\n /// @param _data Data that defines the funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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.\n /// @return configuration The configuration of the funding cycle that was successfully reconfigured.\n function _configure(\n uint256 _projectId,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] memory _groupedSplits,\n JBFundAccessConstraints[] memory _fundAccessConstraints\n ) internal returns (uint256) {\n // Make sure the provided reserved rate is valid.\n if (_metadata.reservedRate > JBConstants.MAX_RESERVED_RATE) revert INVALID_RESERVED_RATE();\n\n // Make sure the provided redemption rate is valid.\n if (_metadata.redemptionRate > JBConstants.MAX_REDEMPTION_RATE)\n revert INVALID_REDEMPTION_RATE();\n\n // Make sure the provided ballot redemption rate is valid.\n if (_metadata.ballotRedemptionRate > JBConstants.MAX_REDEMPTION_RATE)\n revert INVALID_BALLOT_REDEMPTION_RATE();\n\n // Configure the funding cycle's properties.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.configureFor(\n _projectId,\n _data,\n JBFundingCycleMetadataResolver.packFundingCycleMetadata(_metadata),\n _mustStartAtOrAfter\n );\n\n // Set splits for the group.\n splitsStore.set(_projectId, _fundingCycle.configuration, _groupedSplits);\n\n // Set distribution limits if there are any.\n for (uint256 _i; _i < _fundAccessConstraints.length; ) {\n JBFundAccessConstraints memory _constraints = _fundAccessConstraints[_i];\n\n // If distribution limit value is larger than 232 bits, revert.\n if (_constraints.distributionLimit > type(uint232).max) revert INVALID_DISTRIBUTION_LIMIT();\n\n // If distribution limit currency value is larger than 24 bits, revert.\n if (_constraints.distributionLimitCurrency > type(uint24).max)\n revert INVALID_DISTRIBUTION_LIMIT_CURRENCY();\n\n // If overflow allowance value is larger than 232 bits, revert.\n if (_constraints.overflowAllowance > type(uint232).max) revert INVALID_OVERFLOW_ALLOWANCE();\n\n // If overflow allowance currency value is larger than 24 bits, revert.\n if (_constraints.overflowAllowanceCurrency > type(uint24).max)\n revert INVALID_OVERFLOW_ALLOWANCE_CURRENCY();\n\n // Set the distribution limit if there is one.\n if (_constraints.distributionLimit > 0)\n _packedDistributionLimitDataOf[_projectId][_fundingCycle.configuration][\n _constraints.terminal\n ][_constraints.token] =\n _constraints.distributionLimit |\n (_constraints.distributionLimitCurrency << 232);\n\n // Set the overflow allowance if there is one.\n if (_constraints.overflowAllowance > 0)\n _packedOverflowAllowanceDataOf[_projectId][_fundingCycle.configuration][\n _constraints.terminal\n ][_constraints.token] =\n _constraints.overflowAllowance |\n (_constraints.overflowAllowanceCurrency << 232);\n\n emit SetFundAccessConstraints(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _constraints,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n\n return _fundingCycle.configuration;\n }\n\n /// @notice Gets the amount of reserved tokens currently tracked for a project given a reserved rate.\n /// @param _processedTokenTracker The tracker to make the calculation with.\n /// @param _reservedRate The reserved rate to use to make the calculation.\n /// @param _totalEligibleTokens The total amount to make the calculation with.\n /// @return amount reserved token amount.\n function _reservedTokenAmountFrom(\n int256 _processedTokenTracker,\n uint256 _reservedRate,\n uint256 _totalEligibleTokens\n ) internal pure returns (uint256) {\n // Get a reference to the amount of tokens that are unprocessed.\n uint256 _unprocessedTokenBalanceOf = _processedTokenTracker >= 0\n ? _totalEligibleTokens - uint256(_processedTokenTracker)\n : _totalEligibleTokens + uint256(-_processedTokenTracker);\n\n // If there are no unprocessed tokens, return.\n if (_unprocessedTokenBalanceOf == 0) return 0;\n\n // If all tokens are reserved, return the full unprocessed amount.\n if (_reservedRate == JBConstants.MAX_RESERVED_RATE) return _unprocessedTokenBalanceOf;\n\n return\n PRBMath.mulDiv(\n _unprocessedTokenBalanceOf,\n JBConstants.MAX_RESERVED_RATE,\n JBConstants.MAX_RESERVED_RATE - _reservedRate\n ) - _unprocessedTokenBalanceOf;\n }\n}\n" + }, + "contracts/JBReconfigurationBufferBallot.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {ERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBBallotState} from './enums/JBBallotState.sol';\nimport {IJBFundingCycleBallot} from './interfaces/IJBFundingCycleBallot.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\n\n/// @notice Manages approving funding cycle reconfigurations automatically after a buffer period.\ncontract JBReconfigurationBufferBallot is ERC165, IJBFundingCycleBallot {\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice The number of seconds that must pass for a funding cycle reconfiguration to become either `Approved` or `Failed`.\n uint256 public immutable override duration;\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice The approval state of a particular funding cycle.\n /// @param _projectId The ID of the project to which the funding cycle being checked belongs.\n /// @param _configured The configuration of the funding cycle to check the state of.\n /// @param _start The start timestamp of the funding cycle to check the state of.\n /// @return The state of the provided ballot.\n function stateOf(\n uint256 _projectId,\n uint256 _configured,\n uint256 _start\n ) public view override returns (JBBallotState) {\n _projectId; // Prevents unused var compiler and natspec complaints.\n\n // If the provided configured timestamp is after the start timestamp, the ballot is Failed.\n if (_configured > _start) return JBBallotState.Failed;\n\n unchecked {\n // If there was sufficient time between configuration and the start of the cycle, it is approved. Otherwise, it is failed.\n return (_start - _configured < duration) ? JBBallotState.Failed : JBBallotState.Approved;\n }\n }\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if this contract adheres to the specified interface.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(ERC165, IERC165) returns (bool) {\n return\n _interfaceId == type(IJBFundingCycleBallot).interfaceId ||\n super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _duration The number of seconds to wait until a reconfiguration can be either `Approved` or `Failed`.\n constructor(uint256 _duration) {\n duration = _duration;\n }\n}\n" + }, + "contracts/JBETHERC20ProjectPayerDeployer.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Clones} from '@openzeppelin/contracts/proxy/Clones.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBProjectPayer} from './interfaces/IJBProjectPayer.sol';\nimport {IJBETHERC20ProjectPayerDeployer} from './interfaces/IJBETHERC20ProjectPayerDeployer.sol';\nimport {JBETHERC20ProjectPayer} from './JBETHERC20ProjectPayer.sol';\n\n/// @notice Deploys project payer contracts.\ncontract JBETHERC20ProjectPayerDeployer is IJBETHERC20ProjectPayerDeployer {\n //*********************************************************************//\n // --------------- public immutable stored properties ---------------- //\n //*********************************************************************//\n\n /// @notice The implementation contract on which Clones will be based.\n address immutable implementation;\n\n /// @notice directory instance which keeps a track of which controller is linked to which project.\n IJBDirectory immutable directory;\n\n //*********************************************************************//\n // ---------------------------- constructor -------------------------- //\n //*********************************************************************//\n\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n constructor(IJBDirectory _directory) {\n implementation = address(new JBETHERC20ProjectPayer(_directory));\n directory = _directory;\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Allows anyone to deploy a new project payer contract.\n /// @param _defaultProjectId The ID of the project whose treasury should be forwarded the project payer contract's received payments.\n /// @param _defaultBeneficiary The address that'll receive the project's tokens when the project payer receives payments.\n /// @param _defaultPreferClaimedTokens A flag indicating whether issued tokens from the project payer's received payments should be automatically claimed into the beneficiary's wallet.\n /// @param _defaultMemo The memo that'll be forwarded with the project payer's received payments.\n /// @param _defaultMetadata The metadata that'll be forwarded with the project payer's received payments.\n /// @param _defaultPreferAddToBalance A flag indicating if received payments should call the `pay` function or the `addToBalance` function of a project.\n /// @param _owner The address that will own the project payer.\n /// @return projectPayer The project payer contract.\n function deployProjectPayer(\n uint256 _defaultProjectId,\n address payable _defaultBeneficiary,\n bool _defaultPreferClaimedTokens,\n string memory _defaultMemo,\n bytes memory _defaultMetadata,\n bool _defaultPreferAddToBalance,\n address _owner\n ) external override returns (IJBProjectPayer projectPayer) {\n // Deploy the project payer.\n projectPayer = IJBProjectPayer(payable(Clones.clone(implementation)));\n\n // Initialize the project payer.\n projectPayer.initialize(\n _defaultProjectId,\n _defaultBeneficiary,\n _defaultPreferClaimedTokens,\n _defaultMemo,\n _defaultMetadata,\n _defaultPreferAddToBalance,\n _owner\n );\n\n emit DeployProjectPayer(\n projectPayer,\n _defaultProjectId,\n _defaultBeneficiary,\n _defaultPreferClaimedTokens,\n _defaultMemo,\n _defaultMetadata,\n _defaultPreferAddToBalance,\n directory,\n _owner,\n msg.sender\n );\n }\n}\n" + }, + "contracts/interfaces/IJBETHERC20ProjectPayerDeployer.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBDirectory} from './IJBDirectory.sol';\nimport {IJBProjectPayer} from './IJBProjectPayer.sol';\n\ninterface IJBETHERC20ProjectPayerDeployer {\n event DeployProjectPayer(\n IJBProjectPayer indexed projectPayer,\n uint256 defaultProjectId,\n address defaultBeneficiary,\n bool defaultPreferClaimedTokens,\n string defaultMemo,\n bytes defaultMetadata,\n bool preferAddToBalance,\n IJBDirectory directory,\n address owner,\n address caller\n );\n\n function deployProjectPayer(\n uint256 defaultProjectId,\n address payable defaultBeneficiary,\n bool defaultPreferClaimedTokens,\n string memory defaultMemo,\n bytes memory defaultMetadata,\n bool preferAddToBalance,\n address owner\n ) external returns (IJBProjectPayer projectPayer);\n}\n" + }, + "contracts/JBOperatorStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {JBOperatorData} from './structs/JBOperatorData.sol';\n\n/// @notice Stores operator permissions for all addresses. Addresses can give permissions to any other address to take specific indexed actions on their behalf.\ncontract JBOperatorStore is IJBOperatorStore {\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error PERMISSION_INDEX_OUT_OF_BOUNDS();\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The permissions that an operator has been given to operate on a specific domain.\n /// @dev An account can give an operator permissions that only pertain to a specific domain namespace.\n /// @dev There is no domain with a value of 0 – accounts can use the 0 domain to give an operator permissions to all domains on their behalf.\n /// @dev Permissions are stored in a packed `uint256`. Each 256 bits represents the on/off state of a permission. Applications can specify the significance of each index.\n /// @custom:param _operator The address of the operator.\n /// @custom:param _account The address of the account being operated.\n /// @custom:param _domain The domain within which the permissions apply. Applications can use the domain namespace as they wish.\n mapping(address => mapping(address => mapping(uint256 => uint256))) public override permissionsOf;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Whether or not an operator has the permission to take a certain action pertaining to the specified domain.\n /// @param _operator The operator to check.\n /// @param _account The account that has given out permissions to the operator.\n /// @param _domain The domain that the operator has been given permissions to operate.\n /// @param _permissionIndex The permission index to check for.\n /// @return A flag indicating whether the operator has the specified permission.\n function hasPermission(\n address _operator,\n address _account,\n uint256 _domain,\n uint256 _permissionIndex\n ) external view override returns (bool) {\n if (_permissionIndex > 255) revert PERMISSION_INDEX_OUT_OF_BOUNDS();\n\n return (((permissionsOf[_operator][_account][_domain] >> _permissionIndex) & 1) == 1);\n }\n\n /// @notice Whether or not an operator has the permission to take certain actions pertaining to the specified domain.\n /// @param _operator The operator to check.\n /// @param _account The account that has given out permissions to the operator.\n /// @param _domain The domain that the operator has been given permissions to operate.\n /// @param _permissionIndexes An array of permission indexes to check for.\n /// @return A flag indicating whether the operator has all specified permissions.\n function hasPermissions(\n address _operator,\n address _account,\n uint256 _domain,\n uint256[] calldata _permissionIndexes\n ) external view override returns (bool) {\n for (uint256 _i; _i < _permissionIndexes.length; ) {\n uint256 _permissionIndex = _permissionIndexes[_i];\n\n if (_permissionIndex > 255) revert PERMISSION_INDEX_OUT_OF_BOUNDS();\n\n if (((permissionsOf[_operator][_account][_domain] >> _permissionIndex) & 1) == 0)\n return false;\n\n unchecked {\n ++_i;\n }\n }\n return true;\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Sets permissions for an operators.\n /// @dev Only an address can set its own operators.\n /// @param _operatorData The data that specifies the params for the operator being set.\n function setOperator(JBOperatorData calldata _operatorData) external override {\n // Pack the indexes into a uint256.\n uint256 _packed = _packedPermissions(_operatorData.permissionIndexes);\n\n // Store the new value.\n permissionsOf[_operatorData.operator][msg.sender][_operatorData.domain] = _packed;\n\n emit SetOperator(\n _operatorData.operator,\n msg.sender,\n _operatorData.domain,\n _operatorData.permissionIndexes,\n _packed\n );\n }\n\n /// @notice Sets permissions for many operators.\n /// @dev Only an address can set its own operators.\n /// @param _operatorData The data that specify the params for each operator being set.\n function setOperators(JBOperatorData[] calldata _operatorData) external override {\n for (uint256 _i; _i < _operatorData.length; ) {\n // Pack the indexes into a uint256.\n uint256 _packed = _packedPermissions(_operatorData[_i].permissionIndexes);\n\n // Store the new value.\n permissionsOf[_operatorData[_i].operator][msg.sender][_operatorData[_i].domain] = _packed;\n\n emit SetOperator(\n _operatorData[_i].operator,\n msg.sender,\n _operatorData[_i].domain,\n _operatorData[_i].permissionIndexes,\n _packed\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n\n //*********************************************************************//\n // --------------------- private helper functions -------------------- //\n //*********************************************************************//\n\n /// @notice Converts an array of permission indexes to a packed `uint256`.\n /// @param _indexes The indexes of the permissions to pack.\n /// @return packed The packed value.\n function _packedPermissions(uint256[] calldata _indexes) private pure returns (uint256 packed) {\n for (uint256 _i; _i < _indexes.length; ) {\n uint256 _index = _indexes[_i];\n\n if (_index > 255) revert PERMISSION_INDEX_OUT_OF_BOUNDS();\n\n // Turn the bit at the index on.\n packed |= 1 << _index;\n\n unchecked {\n ++_i;\n }\n }\n }\n}\n" + }, + "contracts/JBFundAccessConstraintsStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {ERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol';\nimport {JBControllerUtility} from './abstract/JBControllerUtility.sol';\nimport {IJBFundAccessConstraintsStore} from './interfaces/IJBFundAccessConstraintsStore.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\nimport {JBFundAccessConstraints} from './structs/JBFundAccessConstraints.sol';\n\n/// @notice Information pertaining to how much funds can be accessed by a project from each payment terminal.\ncontract JBFundAccessConstraintsStore is\n JBControllerUtility,\n ERC165,\n IJBFundAccessConstraintsStore\n{\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n\n error INVALID_DISTRIBUTION_LIMIT();\n error INVALID_DISTRIBUTION_LIMIT_CURRENCY();\n error INVALID_OVERFLOW_ALLOWANCE();\n error INVALID_OVERFLOW_ALLOWANCE_CURRENCY();\n\n //*********************************************************************//\n // --------------------- internal stored properties ------------------ //\n //*********************************************************************//\n\n /// @notice Data regarding the distribution limit of a project during a configuration.\n /// @dev bits 0-231: The amount of token that a project can distribute per funding cycle.\n /// @dev bits 232-255: The currency of amount that a project can distribute.\n /// @custom:param _projectId The ID of the project to get the packed distribution limit data of.\n /// @custom:param _configuration The configuration during which the packed distribution limit data applies.\n /// @custom:param _terminal The terminal from which distributions are being limited.\n /// @custom:param _token The token for which distributions are being limited.\n mapping(uint256 => mapping(uint256 => mapping(IJBPaymentTerminal => mapping(address => uint256))))\n internal _packedDistributionLimitDataOf;\n\n /// @notice Data regarding the overflow allowance of a project during a configuration.\n /// @dev bits 0-231: The amount of overflow that a project is allowed to tap into on-demand throughout the configuration.\n /// @dev bits 232-255: The currency of the amount of overflow that a project is allowed to tap.\n /// @custom:param _projectId The ID of the project to get the packed overflow allowance data of.\n /// @custom:param _configuration The configuration during which the packed overflow allowance data applies.\n /// @custom:param _terminal The terminal managing the overflow.\n /// @custom:param _token The token for which overflow is being allowed.\n mapping(uint256 => mapping(uint256 => mapping(IJBPaymentTerminal => mapping(address => uint256))))\n internal _packedOverflowAllowanceDataOf;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice The amount of token that a project can distribute per funding cycle, and the currency it's in terms of.\n /// @dev The number of decimals in the returned fixed point amount is the same as that of the specified terminal.\n /// @param _projectId The ID of the project to get the distribution limit of.\n /// @param _configuration The configuration during which the distribution limit applies.\n /// @param _terminal The terminal from which distributions are being limited.\n /// @param _token The token for which the distribution limit applies.\n /// @return The distribution limit, as a fixed point number with the same number of decimals as the provided terminal.\n /// @return The currency of the distribution limit.\n function distributionLimitOf(\n uint256 _projectId,\n uint256 _configuration,\n IJBPaymentTerminal _terminal,\n address _token\n ) external view override returns (uint256, uint256) {\n // Get a reference to the packed data.\n uint256 _data = _packedDistributionLimitDataOf[_projectId][_configuration][_terminal][_token];\n\n // The limit is in bits 0-231. The currency is in bits 232-255.\n return (uint256(uint232(_data)), _data >> 232);\n }\n\n /// @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.\n /// @dev The number of decimals in the returned fixed point amount is the same as that of the specified terminal.\n /// @param _projectId The ID of the project to get the overflow allowance of.\n /// @param _configuration The configuration of the during which the allowance applies.\n /// @param _terminal The terminal managing the overflow.\n /// @param _token The token for which the overflow allowance applies.\n /// @return The overflow allowance, as a fixed point number with the same number of decimals as the provided terminal.\n /// @return The currency of the overflow allowance.\n function overflowAllowanceOf(\n uint256 _projectId,\n uint256 _configuration,\n IJBPaymentTerminal _terminal,\n address _token\n ) external view override returns (uint256, uint256) {\n // Get a reference to the packed data.\n uint256 _data = _packedOverflowAllowanceDataOf[_projectId][_configuration][_terminal][_token];\n\n // The allowance is in bits 0-231. The currency is in bits 232-255.\n return (uint256(uint232(_data)), _data >> 232);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n // solhint-disable-next-line no-empty-blocks\n constructor(IJBDirectory _directory) JBControllerUtility(_directory) {}\n\n //*********************************************************************//\n // --------------------- external transactions ----------------------- //\n //*********************************************************************//\n\n /// @notice Sets a project's constraints for accessing treasury funds.\n /// @dev Only a project's current controller can set its fund access constraints.\n /// @param _projectId The ID of the project whose fund access constraints are being set.\n /// @param _configuration The funding cycle configuration the constraints apply within.\n /// @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`.\n function setFor(\n uint256 _projectId,\n uint256 _configuration,\n JBFundAccessConstraints[] calldata _fundAccessConstraints\n ) external override onlyController(_projectId) {\n // Save the number of constraints.\n uint256 _numberOfFundAccessConstraints = _fundAccessConstraints.length;\n\n // Set distribution limits if there are any.\n for (uint256 _i; _i < _numberOfFundAccessConstraints; ) {\n // If distribution limit value is larger than 232 bits, revert.\n if (_fundAccessConstraints[_i].distributionLimit > type(uint232).max)\n revert INVALID_DISTRIBUTION_LIMIT();\n\n // If distribution limit currency value is larger than 24 bits, revert.\n if (_fundAccessConstraints[_i].distributionLimitCurrency > type(uint24).max)\n revert INVALID_DISTRIBUTION_LIMIT_CURRENCY();\n\n // If overflow allowance value is larger than 232 bits, revert.\n if (_fundAccessConstraints[_i].overflowAllowance > type(uint232).max)\n revert INVALID_OVERFLOW_ALLOWANCE();\n\n // If overflow allowance currency value is larger than 24 bits, revert.\n if (_fundAccessConstraints[_i].overflowAllowanceCurrency > type(uint24).max)\n revert INVALID_OVERFLOW_ALLOWANCE_CURRENCY();\n\n // Set the distribution limit if there is one.\n if (_fundAccessConstraints[_i].distributionLimit > 0)\n _packedDistributionLimitDataOf[_projectId][_configuration][\n _fundAccessConstraints[_i].terminal\n ][_fundAccessConstraints[_i].token] =\n _fundAccessConstraints[_i].distributionLimit |\n (_fundAccessConstraints[_i].distributionLimitCurrency << 232);\n\n // Set the overflow allowance if there is one.\n if (_fundAccessConstraints[_i].overflowAllowance > 0)\n _packedOverflowAllowanceDataOf[_projectId][_configuration][\n _fundAccessConstraints[_i].terminal\n ][_fundAccessConstraints[_i].token] =\n _fundAccessConstraints[_i].overflowAllowance |\n (_fundAccessConstraints[_i].overflowAllowanceCurrency << 232);\n\n emit SetFundAccessConstraints(\n _configuration,\n _projectId,\n _fundAccessConstraints[_i],\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n}\n" + }, + "contracts/interfaces/IJBTerminalUtility.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBDirectory} from './IJBDirectory.sol';\n\ninterface IJBPaymentTerminalUtility {\n function directory() external view returns (IJBDirectory);\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": [ + "ast" + ] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} \ No newline at end of file diff --git a/deployments/mainnet/JBETHPaymentTerminal3_1_1.json b/deployments/mainnet/JBETHPaymentTerminal3_1_1.json new file mode 100644 index 000000000..9fc6ee02c --- /dev/null +++ b/deployments/mainnet/JBETHPaymentTerminal3_1_1.json @@ -0,0 +1,2574 @@ +{ + "address": "0x457cD63bee88ac01f3cD4a67D5DCc921D8C0D573", + "abi": [ + { + "inputs": [ + { + "internalType": "uint256", + "name": "_baseWeightCurrency", + "type": "uint256" + }, + { + "internalType": "contract IJBOperatorStore", + "name": "_operatorStore", + "type": "address" + }, + { + "internalType": "contract IJBProjects", + "name": "_projects", + "type": "address" + }, + { + "internalType": "contract IJBDirectory", + "name": "_directory", + "type": "address" + }, + { + "internalType": "contract IJBSplitsStore", + "name": "_splitsStore", + "type": "address" + }, + { + "internalType": "contract IJBPrices", + "name": "_prices", + "type": "address" + }, + { + "internalType": "address", + "name": "_store", + "type": "address" + }, + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "FEE_TOO_HIGH", + "type": "error" + }, + { + "inputs": [], + "name": "INADEQUATE_DISTRIBUTION_AMOUNT", + "type": "error" + }, + { + "inputs": [], + "name": "INADEQUATE_RECLAIM_AMOUNT", + "type": "error" + }, + { + "inputs": [], + "name": "INADEQUATE_TOKEN_COUNT", + "type": "error" + }, + { + "inputs": [], + "name": "NO_MSG_VALUE_ALLOWED", + "type": "error" + }, + { + "inputs": [], + "name": "PAY_TO_ZERO_ADDRESS", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "prod1", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "denominator", + "type": "uint256" + } + ], + "name": "PRBMath__MulDivOverflow", + "type": "error" + }, + { + "inputs": [], + "name": "PROJECT_TERMINAL_MISMATCH", + "type": "error" + }, + { + "inputs": [], + "name": "REDEEM_TO_ZERO_ADDRESS", + "type": "error" + }, + { + "inputs": [], + "name": "TERMINAL_TOKENS_INCOMPATIBLE", + "type": "error" + }, + { + "inputs": [], + "name": "UNAUTHORIZED", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "refundedFees", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "string", + "name": "memo", + "type": "string" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "metadata", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "AddToBalance", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract IJBPayDelegate3_1_1", + "name": "delegate", + "type": "address" + }, + { + "components": [ + { + "internalType": "address", + "name": "payer", + "type": "address" + }, + { + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "currentFundingCycleConfiguration", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "decimals", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "currency", + "type": "uint256" + } + ], + "internalType": "struct JBTokenAmount", + "name": "amount", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "decimals", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "currency", + "type": "uint256" + } + ], + "internalType": "struct JBTokenAmount", + "name": "forwardedAmount", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "projectTokenCount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "beneficiary", + "type": "address" + }, + { + "internalType": "bool", + "name": "preferClaimedTokens", + "type": "bool" + }, + { + "internalType": "string", + "name": "memo", + "type": "string" + }, + { + "internalType": "bytes", + "name": "dataSourceMetadata", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "payerMetadata", + "type": "bytes" + } + ], + "indexed": false, + "internalType": "struct JBDidPayData3_1_1", + "name": "data", + "type": "tuple" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "delegatedAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "DelegateDidPay", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract IJBPayDelegate", + "name": "delegate", + "type": "address" + }, + { + "components": [ + { + "internalType": "address", + "name": "payer", + "type": "address" + }, + { + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "currentFundingCycleConfiguration", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "decimals", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "currency", + "type": "uint256" + } + ], + "internalType": "struct JBTokenAmount", + "name": "amount", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "decimals", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "currency", + "type": "uint256" + } + ], + "internalType": "struct JBTokenAmount", + "name": "forwardedAmount", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "projectTokenCount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "beneficiary", + "type": "address" + }, + { + "internalType": "bool", + "name": "preferClaimedTokens", + "type": "bool" + }, + { + "internalType": "string", + "name": "memo", + "type": "string" + }, + { + "internalType": "bytes", + "name": "metadata", + "type": "bytes" + } + ], + "indexed": false, + "internalType": "struct JBDidPayData", + "name": "data", + "type": "tuple" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "delegatedAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "DelegateDidPay", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract IJBRedemptionDelegate3_1_1", + "name": "delegate", + "type": "address" + }, + { + "components": [ + { + "internalType": "address", + "name": "holder", + "type": "address" + }, + { + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "currentFundingCycleConfiguration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "projectTokenCount", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "decimals", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "currency", + "type": "uint256" + } + ], + "internalType": "struct JBTokenAmount", + "name": "reclaimedAmount", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "decimals", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "currency", + "type": "uint256" + } + ], + "internalType": "struct JBTokenAmount", + "name": "forwardedAmount", + "type": "tuple" + }, + { + "internalType": "address payable", + "name": "beneficiary", + "type": "address" + }, + { + "internalType": "string", + "name": "memo", + "type": "string" + }, + { + "internalType": "bytes", + "name": "dataSourceMetadata", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "redeemerMetadata", + "type": "bytes" + } + ], + "indexed": false, + "internalType": "struct JBDidRedeemData3_1_1", + "name": "data", + "type": "tuple" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "delegatedAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "fee", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "DelegateDidRedeem", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract IJBRedemptionDelegate", + "name": "delegate", + "type": "address" + }, + { + "components": [ + { + "internalType": "address", + "name": "holder", + "type": "address" + }, + { + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "currentFundingCycleConfiguration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "projectTokenCount", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "decimals", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "currency", + "type": "uint256" + } + ], + "internalType": "struct JBTokenAmount", + "name": "reclaimedAmount", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "decimals", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "currency", + "type": "uint256" + } + ], + "internalType": "struct JBTokenAmount", + "name": "forwardedAmount", + "type": "tuple" + }, + { + "internalType": "address payable", + "name": "beneficiary", + "type": "address" + }, + { + "internalType": "string", + "name": "memo", + "type": "string" + }, + { + "internalType": "bytes", + "name": "metadata", + "type": "bytes" + } + ], + "indexed": false, + "internalType": "struct JBDidRedeemData", + "name": "data", + "type": "tuple" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "delegatedAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "DelegateDidRedeem", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "fundingCycleConfiguration", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "fundingCycleNumber", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "beneficiary", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "distributedAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "fee", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "beneficiaryDistributionAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "metadata", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "DistributePayouts", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "domain", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "group", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "bool", + "name": "preferClaimed", + "type": "bool" + }, + { + "internalType": "bool", + "name": "preferAddToBalance", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "percent", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "internalType": "address payable", + "name": "beneficiary", + "type": "address" + }, + { + "internalType": "uint256", + "name": "lockedUntil", + "type": "uint256" + }, + { + "internalType": "contract IJBSplitAllocator", + "name": "allocator", + "type": "address" + } + ], + "indexed": false, + "internalType": "struct JBSplit", + "name": "split", + "type": "tuple" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "netAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "DistributeToPayoutSplit", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "feeProjectId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "reason", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "FeeReverted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "fee", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "feeDiscount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "beneficiary", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "HoldFee", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "contract IJBPaymentTerminal", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "Migrate", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "fundingCycleConfiguration", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "fundingCycleNumber", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "payer", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "beneficiary", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "beneficiaryTokenCount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "string", + "name": "memo", + "type": "string" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "metadata", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "Pay", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "bool", + "name": "preferClaimed", + "type": "bool" + }, + { + "internalType": "bool", + "name": "preferAddToBalance", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "percent", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "internalType": "address payable", + "name": "beneficiary", + "type": "address" + }, + { + "internalType": "uint256", + "name": "lockedUntil", + "type": "uint256" + }, + { + "internalType": "contract IJBSplitAllocator", + "name": "allocator", + "type": "address" + } + ], + "indexed": false, + "internalType": "struct JBSplit", + "name": "split", + "type": "tuple" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "reason", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "PayoutReverted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "bool", + "name": "wasHeld", + "type": "bool" + }, + { + "indexed": false, + "internalType": "address", + "name": "beneficiary", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "ProcessFee", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "fundingCycleConfiguration", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "fundingCycleNumber", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "holder", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "beneficiary", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "tokenCount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "reclaimedAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "string", + "name": "memo", + "type": "string" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "metadata", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "RedeemTokens", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "refundedFees", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "leftoverAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "RefundHeldFees", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "fee", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "SetFee", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "feeGauge", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "SetFeeGauge", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "addrs", + "type": "address" + }, + { + "indexed": true, + "internalType": "bool", + "name": "flag", + "type": "bool" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "SetFeelessAddress", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "fundingCycleConfiguration", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "fundingCycleNumber", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "beneficiary", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "distributedAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "netDistributedamount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "string", + "name": "memo", + "type": "string" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "metadata", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "UseAllowance", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + } + ], + "name": "acceptsToken", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_token", + "type": "address" + }, + { + "internalType": "string", + "name": "_memo", + "type": "string" + }, + { + "internalType": "bytes", + "name": "_metadata", + "type": "bytes" + } + ], + "name": "addToBalanceOf", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_token", + "type": "address" + }, + { + "internalType": "bool", + "name": "_shouldRefundHeldFees", + "type": "bool" + }, + { + "internalType": "string", + "name": "_memo", + "type": "string" + }, + { + "internalType": "bytes", + "name": "_metadata", + "type": "bytes" + } + ], + "name": "addToBalanceOf", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "baseWeightCurrency", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "currency", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_token", + "type": "address" + } + ], + "name": "currencyForToken", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + } + ], + "name": "currentEthOverflowOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_token", + "type": "address" + } + ], + "name": "decimalsForToken", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "directory", + "outputs": [ + { + "internalType": "contract IJBDirectory", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_currency", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_minReturnedTokens", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "_metadata", + "type": "bytes" + } + ], + "name": "distributePayoutsOf", + "outputs": [ + { + "internalType": "uint256", + "name": "netLeftoverDistributionAmount", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "fee", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "feeGauge", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + } + ], + "name": "heldFeesOf", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint32", + "name": "fee", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "feeDiscount", + "type": "uint32" + }, + { + "internalType": "address", + "name": "beneficiary", + "type": "address" + } + ], + "internalType": "struct JBFee[]", + "name": "", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "isFeelessAddress", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + }, + { + "internalType": "contract IJBPaymentTerminal", + "name": "_to", + "type": "address" + } + ], + "name": "migrate", + "outputs": [ + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "operatorStore", + "outputs": [ + { + "internalType": "contract IJBOperatorStore", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_token", + "type": "address" + }, + { + "internalType": "address", + "name": "_beneficiary", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_minReturnedTokens", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "_preferClaimedTokens", + "type": "bool" + }, + { + "internalType": "string", + "name": "_memo", + "type": "string" + }, + { + "internalType": "bytes", + "name": "_metadata", + "type": "bytes" + } + ], + "name": "pay", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "payoutSplitsGroup", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "prices", + "outputs": [ + { + "internalType": "contract IJBPrices", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + } + ], + "name": "processFees", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "projects", + "outputs": [ + { + "internalType": "contract IJBProjects", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_holder", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_tokenCount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_minReturnedTokens", + "type": "uint256" + }, + { + "internalType": "address payable", + "name": "_beneficiary", + "type": "address" + }, + { + "internalType": "string", + "name": "_memo", + "type": "string" + }, + { + "internalType": "bytes", + "name": "_metadata", + "type": "bytes" + } + ], + "name": "redeemTokensOf", + "outputs": [ + { + "internalType": "uint256", + "name": "reclaimAmount", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_fee", + "type": "uint256" + } + ], + "name": "setFee", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_feeGauge", + "type": "address" + } + ], + "name": "setFeeGauge", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_address", + "type": "address" + }, + { + "internalType": "bool", + "name": "_flag", + "type": "bool" + } + ], + "name": "setFeelessAddress", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "splitsStore", + "outputs": [ + { + "internalType": "contract IJBSplitsStore", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "store", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "token", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_currency", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_minReturnedTokens", + "type": "uint256" + }, + { + "internalType": "address payable", + "name": "_beneficiary", + "type": "address" + }, + { + "internalType": "string", + "name": "_memo", + "type": "string" + }, + { + "internalType": "bytes", + "name": "_metadata", + "type": "bytes" + } + ], + "name": "useAllowanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "netDistributedAmount", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "transactionHash": "0x08276d08bf49fbec31684c3714bffe3e31f0379cae61dcf4e070de21e7712050", + "receipt": { + "to": null, + "from": "0xc64533F8d8dEbC301cb4791e6ED941Cb38473DE6", + "contractAddress": "0x457cD63bee88ac01f3cD4a67D5DCc921D8C0D573", + "transactionIndex": 234, + "gasUsed": "5083250", + "logsBloom": "0x00000000000000000000000000000000000000000000000000801000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000001000000000000000000000000000000020000000000000000000800000000000000000000000000000000400000000000000000000100000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000004000000000000010000000000000000000200020000000000000000000000000000000000000000000000000000040000000000000", + "blockHash": "0x27e24c1cc03a073eb6947558ddffe81f8f8256e39a25000968cdad4613ed80e9", + "transactionHash": "0x08276d08bf49fbec31684c3714bffe3e31f0379cae61dcf4e070de21e7712050", + "logs": [ + { + "transactionIndex": 234, + "blockNumber": 17594325, + "transactionHash": "0x08276d08bf49fbec31684c3714bffe3e31f0379cae61dcf4e070de21e7712050", + "address": "0x457cD63bee88ac01f3cD4a67D5DCc921D8C0D573", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000c64533f8d8debc301cb4791e6ed941cb38473de6" + ], + "data": "0x", + "logIndex": 354, + "blockHash": "0x27e24c1cc03a073eb6947558ddffe81f8f8256e39a25000968cdad4613ed80e9" + }, + { + "transactionIndex": 234, + "blockNumber": 17594325, + "transactionHash": "0x08276d08bf49fbec31684c3714bffe3e31f0379cae61dcf4e070de21e7712050", + "address": "0x457cD63bee88ac01f3cD4a67D5DCc921D8C0D573", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x000000000000000000000000c64533f8d8debc301cb4791e6ed941cb38473de6", + "0x000000000000000000000000af28bcb48c40dbc86f52d459a6562f658fc94b1e" + ], + "data": "0x", + "logIndex": 355, + "blockHash": "0x27e24c1cc03a073eb6947558ddffe81f8f8256e39a25000968cdad4613ed80e9" + } + ], + "blockNumber": 17594325, + "cumulativeGasUsed": "29891539", + "status": 1, + "byzantium": true + }, + "args": [ + "1", + "0x6F3C5afCa0c9eDf3926eF2dDF17c8ae6391afEfb", + "0xD8B4359143eda5B2d763E127Ed27c77addBc47d3", + "0x65572FB928b46f9aDB7cfe5A4c41226F636161ea", + "0x0D25194ABE95185Db8e4B0294F5669E21C534785", + "0x63CF55ab55ABcaD4E84335B80bbE3D2DefA09410", + "0x82129d4109625F94582bDdF6101a8Cd1a27919f5", + "0xAF28bcB48C40dBC86f52D459A6562F658fc94B1e" + ], + "numDeployments": 1, + "solcInputHash": "11cb1f66a0f8213d7bf83deb0ae9d2f7", + "metadata": "{\"compiler\":{\"version\":\"0.8.16+commit.07a7930e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_baseWeightCurrency\",\"type\":\"uint256\"},{\"internalType\":\"contract IJBOperatorStore\",\"name\":\"_operatorStore\",\"type\":\"address\"},{\"internalType\":\"contract IJBProjects\",\"name\":\"_projects\",\"type\":\"address\"},{\"internalType\":\"contract IJBDirectory\",\"name\":\"_directory\",\"type\":\"address\"},{\"internalType\":\"contract IJBSplitsStore\",\"name\":\"_splitsStore\",\"type\":\"address\"},{\"internalType\":\"contract IJBPrices\",\"name\":\"_prices\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_store\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"FEE_TOO_HIGH\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"INADEQUATE_DISTRIBUTION_AMOUNT\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"INADEQUATE_RECLAIM_AMOUNT\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"INADEQUATE_TOKEN_COUNT\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NO_MSG_VALUE_ALLOWED\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PAY_TO_ZERO_ADDRESS\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"prod1\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"denominator\",\"type\":\"uint256\"}],\"name\":\"PRBMath__MulDivOverflow\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PROJECT_TERMINAL_MISMATCH\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"REDEEM_TO_ZERO_ADDRESS\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TERMINAL_TOKENS_INCOMPATIBLE\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UNAUTHORIZED\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"refundedFees\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"memo\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"metadata\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"AddToBalance\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"contract IJBPayDelegate3_1_1\",\"name\":\"delegate\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"payer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"currentFundingCycleConfiguration\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"decimals\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"currency\",\"type\":\"uint256\"}],\"internalType\":\"struct JBTokenAmount\",\"name\":\"amount\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"decimals\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"currency\",\"type\":\"uint256\"}],\"internalType\":\"struct JBTokenAmount\",\"name\":\"forwardedAmount\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"projectTokenCount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"beneficiary\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"preferClaimedTokens\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"memo\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"dataSourceMetadata\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"payerMetadata\",\"type\":\"bytes\"}],\"indexed\":false,\"internalType\":\"struct JBDidPayData3_1_1\",\"name\":\"data\",\"type\":\"tuple\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"delegatedAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"DelegateDidPay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"contract IJBPayDelegate\",\"name\":\"delegate\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"payer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"currentFundingCycleConfiguration\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"decimals\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"currency\",\"type\":\"uint256\"}],\"internalType\":\"struct JBTokenAmount\",\"name\":\"amount\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"decimals\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"currency\",\"type\":\"uint256\"}],\"internalType\":\"struct JBTokenAmount\",\"name\":\"forwardedAmount\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"projectTokenCount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"beneficiary\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"preferClaimedTokens\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"memo\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"metadata\",\"type\":\"bytes\"}],\"indexed\":false,\"internalType\":\"struct JBDidPayData\",\"name\":\"data\",\"type\":\"tuple\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"delegatedAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"DelegateDidPay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"contract IJBRedemptionDelegate3_1_1\",\"name\":\"delegate\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"holder\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"currentFundingCycleConfiguration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"projectTokenCount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"decimals\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"currency\",\"type\":\"uint256\"}],\"internalType\":\"struct JBTokenAmount\",\"name\":\"reclaimedAmount\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"decimals\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"currency\",\"type\":\"uint256\"}],\"internalType\":\"struct JBTokenAmount\",\"name\":\"forwardedAmount\",\"type\":\"tuple\"},{\"internalType\":\"address payable\",\"name\":\"beneficiary\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"memo\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"dataSourceMetadata\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"redeemerMetadata\",\"type\":\"bytes\"}],\"indexed\":false,\"internalType\":\"struct JBDidRedeemData3_1_1\",\"name\":\"data\",\"type\":\"tuple\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"delegatedAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fee\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"DelegateDidRedeem\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"contract IJBRedemptionDelegate\",\"name\":\"delegate\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"holder\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"currentFundingCycleConfiguration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"projectTokenCount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"decimals\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"currency\",\"type\":\"uint256\"}],\"internalType\":\"struct JBTokenAmount\",\"name\":\"reclaimedAmount\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"decimals\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"currency\",\"type\":\"uint256\"}],\"internalType\":\"struct JBTokenAmount\",\"name\":\"forwardedAmount\",\"type\":\"tuple\"},{\"internalType\":\"address payable\",\"name\":\"beneficiary\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"memo\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"metadata\",\"type\":\"bytes\"}],\"indexed\":false,\"internalType\":\"struct JBDidRedeemData\",\"name\":\"data\",\"type\":\"tuple\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"delegatedAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"DelegateDidRedeem\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"fundingCycleConfiguration\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"fundingCycleNumber\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"beneficiary\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"distributedAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fee\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"beneficiaryDistributionAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"metadata\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"DistributePayouts\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"domain\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"group\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"preferClaimed\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"preferAddToBalance\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"percent\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"internalType\":\"address payable\",\"name\":\"beneficiary\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"lockedUntil\",\"type\":\"uint256\"},{\"internalType\":\"contract IJBSplitAllocator\",\"name\":\"allocator\",\"type\":\"address\"}],\"indexed\":false,\"internalType\":\"struct JBSplit\",\"name\":\"split\",\"type\":\"tuple\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"netAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"DistributeToPayoutSplit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"feeProjectId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"reason\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"FeeReverted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"fee\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"feeDiscount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"beneficiary\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"HoldFee\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"contract IJBPaymentTerminal\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"Migrate\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"fundingCycleConfiguration\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"fundingCycleNumber\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"payer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"beneficiary\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"beneficiaryTokenCount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"memo\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"metadata\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"Pay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"preferClaimed\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"preferAddToBalance\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"percent\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"internalType\":\"address payable\",\"name\":\"beneficiary\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"lockedUntil\",\"type\":\"uint256\"},{\"internalType\":\"contract IJBSplitAllocator\",\"name\":\"allocator\",\"type\":\"address\"}],\"indexed\":false,\"internalType\":\"struct JBSplit\",\"name\":\"split\",\"type\":\"tuple\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"reason\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"PayoutReverted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bool\",\"name\":\"wasHeld\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"beneficiary\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"ProcessFee\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"fundingCycleConfiguration\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"fundingCycleNumber\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"holder\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"beneficiary\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokenCount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"reclaimedAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"memo\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"metadata\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"RedeemTokens\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"refundedFees\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"leftoverAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"RefundHeldFees\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fee\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"SetFee\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"feeGauge\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"SetFeeGauge\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"addrs\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bool\",\"name\":\"flag\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"SetFeelessAddress\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"fundingCycleConfiguration\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"fundingCycleNumber\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"beneficiary\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"distributedAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"netDistributedamount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"memo\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"metadata\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"UseAllowance\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"}],\"name\":\"acceptsToken\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"_memo\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"_metadata\",\"type\":\"bytes\"}],\"name\":\"addToBalanceOf\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"_shouldRefundHeldFees\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"_memo\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"_metadata\",\"type\":\"bytes\"}],\"name\":\"addToBalanceOf\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"baseWeightCurrency\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"currency\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"}],\"name\":\"currencyForToken\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"}],\"name\":\"currentEthOverflowOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"}],\"name\":\"decimalsForToken\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"directory\",\"outputs\":[{\"internalType\":\"contract IJBDirectory\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_currency\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_minReturnedTokens\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_metadata\",\"type\":\"bytes\"}],\"name\":\"distributePayoutsOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"netLeftoverDistributionAmount\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"feeGauge\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"}],\"name\":\"heldFeesOf\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"fee\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feeDiscount\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"beneficiary\",\"type\":\"address\"}],\"internalType\":\"struct JBFee[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"isFeelessAddress\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"},{\"internalType\":\"contract IJBPaymentTerminal\",\"name\":\"_to\",\"type\":\"address\"}],\"name\":\"migrate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"operatorStore\",\"outputs\":[{\"internalType\":\"contract IJBOperatorStore\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_beneficiary\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_minReturnedTokens\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"_preferClaimedTokens\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"_memo\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"_metadata\",\"type\":\"bytes\"}],\"name\":\"pay\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"payoutSplitsGroup\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"prices\",\"outputs\":[{\"internalType\":\"contract IJBPrices\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"}],\"name\":\"processFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"projects\",\"outputs\":[{\"internalType\":\"contract IJBProjects\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_holder\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_tokenCount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_minReturnedTokens\",\"type\":\"uint256\"},{\"internalType\":\"address payable\",\"name\":\"_beneficiary\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"_memo\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"_metadata\",\"type\":\"bytes\"}],\"name\":\"redeemTokensOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"reclaimAmount\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_fee\",\"type\":\"uint256\"}],\"name\":\"setFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_feeGauge\",\"type\":\"address\"}],\"name\":\"setFeeGauge\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"_flag\",\"type\":\"bool\"}],\"name\":\"setFeelessAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"splitsStore\",\"outputs\":[{\"internalType\":\"contract IJBSplitsStore\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"store\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"_interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"token\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_currency\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_minReturnedTokens\",\"type\":\"uint256\"},{\"internalType\":\"address payable\",\"name\":\"_beneficiary\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"_memo\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"_metadata\",\"type\":\"bytes\"}],\"name\":\"useAllowanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"netDistributedAmount\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"acceptsToken(address,uint256)\":{\"params\":{\"_projectId\":\"The project ID to check for token acceptance.\",\"_token\":\"The token to check if this terminal accepts or not.\"},\"returns\":{\"_0\":\"The flag.\"}},\"addToBalanceOf(uint256,uint256,address,bool,string,bytes)\":{\"params\":{\"_amount\":\"The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\",\"_memo\":\"A memo to pass along to the emitted event.\",\"_metadata\":\"Extra data to pass along to the emitted event.\",\"_projectId\":\"The ID of the project to which the funds received belong.\",\"_shouldRefundHeldFees\":\"A flag indicating if held fees should be refunded based on the amount being added.\",\"_token\":\"The token being paid. This terminal ignores this property since it only manages one currency.\"}},\"addToBalanceOf(uint256,uint256,address,string,bytes)\":{\"params\":{\"_amount\":\"The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\",\"_memo\":\"A memo to pass along to the emitted event.\",\"_metadata\":\"Extra data to pass along to the emitted event.\",\"_projectId\":\"The ID of the project to which the funds received belong.\",\"_token\":\"The token being paid. This terminal ignores this property since it only manages one currency.\"}},\"constructor\":{\"params\":{\"_baseWeightCurrency\":\"The currency to base token issuance on.\",\"_directory\":\"A contract storing directories of terminals and controllers for each project.\",\"_operatorStore\":\"A contract storing operator assignments.\",\"_owner\":\"The address that will own this contract.\",\"_prices\":\"A contract that exposes price feeds.\",\"_projects\":\"A contract which mints ERC-721's that represent project ownership and transfers.\",\"_splitsStore\":\"A contract that stores splits for each project.\",\"_store\":\"A contract that stores the terminal's data.\"}},\"currencyForToken(address)\":{\"params\":{\"_token\":\"The token to check for the currency of.\"},\"returns\":{\"_0\":\"The currency index.\"}},\"currentEthOverflowOf(uint256)\":{\"details\":\"The current overflow is represented as a fixed point number with 18 decimals.\",\"params\":{\"_projectId\":\"The ID of the project to get overflow for.\"},\"returns\":{\"_0\":\"The current amount of ETH overflow that project has in this terminal, as a fixed point number with 18 decimals.\"}},\"decimalsForToken(address)\":{\"params\":{\"_token\":\"The token to check for the decimals of.\"},\"returns\":{\"_0\":\"The number of decimals for the token.\"}},\"distributePayoutsOf(uint256,uint256,uint256,address,uint256,bytes)\":{\"details\":\"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.\",\"params\":{\"_amount\":\"The amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal.\",\"_currency\":\"The expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency.\",\"_metadata\":\"Bytes to send along to the emitted event, if provided.\",\"_minReturnedTokens\":\"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.\",\"_projectId\":\"The ID of the project having its payouts distributed.\",\"_token\":\"The token being distributed. This terminal ignores this property since it only manages one token.\"},\"returns\":{\"netLeftoverDistributionAmount\":\"The amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal.\"}},\"heldFeesOf(uint256)\":{\"params\":{\"_projectId\":\"The ID of the project for which fees are being held.\"},\"returns\":{\"_0\":\"An array of fees that are being held.\"}},\"migrate(uint256,address)\":{\"details\":\"Only a project's owner or a designated operator can migrate it.\",\"params\":{\"_projectId\":\"The ID of the project being migrated.\",\"_to\":\"The terminal contract that will gain the project's funds.\"},\"returns\":{\"balance\":\"The amount of funds that were migrated, as a fixed point number with the same amount of decimals as this terminal.\"}},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"pay(uint256,uint256,address,address,uint256,bool,string,bytes)\":{\"params\":{\"_amount\":\"The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place.\",\"_beneficiary\":\"The address to mint tokens for and pass along to the funding cycle's data source and delegate.\",\"_memo\":\"A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\",\"_metadata\":\"Bytes to send along to the data source, delegate, and emitted event, if provided.\",\"_minReturnedTokens\":\"The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal.\",\"_preferClaimedTokens\":\"A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\",\"_projectId\":\"The ID of the project being paid.\",\"_token\":\"The token being paid. This terminal ignores this property since it only manages one token.\"},\"returns\":{\"_0\":\"The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals.\"}},\"processFees(uint256)\":{\"details\":\"Only a project owner, an operator, or the contract's owner can process held fees.\",\"params\":{\"_projectId\":\"The ID of the project whos held fees should be processed.\"}},\"redeemTokensOf(address,uint256,uint256,address,uint256,address,string,bytes)\":{\"details\":\"Only a token holder or a designated operator can redeem its tokens.\",\"params\":{\"_beneficiary\":\"The address to send the terminal tokens to.\",\"_holder\":\"The account to redeem tokens for.\",\"_memo\":\"A memo to pass along to the emitted event.\",\"_metadata\":\"Bytes to send along to the data source, delegate, and emitted event, if provided.\",\"_minReturnedTokens\":\"The minimum amount of terminal tokens expected in return, as a fixed point number with the same amount of decimals as the terminal.\",\"_projectId\":\"The ID of the project to which the tokens being redeemed belong.\",\"_token\":\"The token being reclaimed. This terminal ignores this property since it only manages one token.\",\"_tokenCount\":\"The number of project tokens to redeem, as a fixed point number with 18 decimals.\"},\"returns\":{\"reclaimAmount\":\"The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals.\"}},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"setFee(uint256)\":{\"details\":\"Only the owner of this contract can change the fee.\",\"params\":{\"_fee\":\"The new fee, out of MAX_FEE.\"}},\"setFeeGauge(address)\":{\"details\":\"Only the owner of this contract can change the fee gauge.\",\"params\":{\"_feeGauge\":\"The new fee gauge.\"}},\"setFeelessAddress(address,bool)\":{\"details\":\"Only the owner of this contract can set addresses as feeless.\",\"params\":{\"_address\":\"The address that can be paid towards while still bypassing fees.\",\"_flag\":\"A flag indicating whether the terminal should be feeless or not.\"}},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\",\"params\":{\"_interfaceId\":\"The ID of the interface to check for adherance to.\"},\"returns\":{\"_0\":\"A flag indicating if the provided interface ID is supported.\"}},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"},\"useAllowanceOf(uint256,uint256,uint256,address,uint256,address,string,bytes)\":{\"details\":\"Only a project's owner or a designated operator can use its allowance.Incurs the protocol fee.\",\"params\":{\"_amount\":\"The amount of terminal tokens to use from this project's current allowance, as a fixed point number with the same amount of decimals as this terminal.\",\"_beneficiary\":\"The address to send the funds to.\",\"_currency\":\"The expected currency of the amount being distributed. Must match the project's current funding cycle's overflow allowance currency.\",\"_memo\":\"A memo to pass along to the emitted event.\",\"_metadata\":\"Bytes to send along to the emitted event, if provided.\",\"_minReturnedTokens\":\"The minimum number of tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with 18 decimals.\",\"_projectId\":\"The ID of the project to use the allowance of.\",\"_token\":\"The token being distributed. This terminal ignores this property since it only manages one token.\"},\"returns\":{\"netDistributedAmount\":\"The amount of tokens that was distributed to the beneficiary, as a fixed point number with the same amount of decimals as the terminal.\"}}},\"version\":1},\"userdoc\":{\"errors\":{\"PRBMath__MulDivOverflow(uint256,uint256)\":[{\"notice\":\"Emitted when the result overflows uint256.\"}]},\"kind\":\"user\",\"methods\":{\"acceptsToken(address,uint256)\":{\"notice\":\"A flag indicating if this terminal accepts the specified token.\"},\"addToBalanceOf(uint256,uint256,address,bool,string,bytes)\":{\"notice\":\"Receives funds belonging to the specified project.\"},\"addToBalanceOf(uint256,uint256,address,string,bytes)\":{\"notice\":\"Receives funds belonging to the specified project.\"},\"baseWeightCurrency()\":{\"notice\":\"The currency to base token issuance on.\"},\"currency()\":{\"notice\":\"The currency to use when resolving price feeds for this terminal.\"},\"currencyForToken(address)\":{\"notice\":\"The currency that should be used for the specified token.\"},\"currentEthOverflowOf(uint256)\":{\"notice\":\"Gets the current overflowed amount in this terminal for a specified project, in terms of ETH.\"},\"decimals()\":{\"notice\":\"The number of decimals the token fixed point amounts are expected to have.\"},\"decimalsForToken(address)\":{\"notice\":\"The decimals that should be used in fixed number accounting for the specified token.\"},\"directory()\":{\"notice\":\"The directory of terminals and controllers for projects.\"},\"distributePayoutsOf(uint256,uint256,uint256,address,uint256,bytes)\":{\"notice\":\"Distributes payouts for a project with the distribution limit of its current funding cycle.\"},\"fee()\":{\"notice\":\"The platform fee percent.\"},\"feeGauge()\":{\"notice\":\"The data source that returns a discount to apply to a project's fee.\"},\"heldFeesOf(uint256)\":{\"notice\":\"The fees that are currently being held to be processed later for each project.\"},\"isFeelessAddress(address)\":{\"notice\":\"Addresses that can be paid towards from this terminal without incurring a fee.\"},\"migrate(uint256,address)\":{\"notice\":\"Allows a project owner to migrate its funds and operations to a new terminal that accepts the same token type.\"},\"operatorStore()\":{\"notice\":\"A contract storing operator assignments.\"},\"pay(uint256,uint256,address,address,uint256,bool,string,bytes)\":{\"notice\":\"Contribute tokens to a project.\"},\"payoutSplitsGroup()\":{\"notice\":\"The group that payout splits coming from this terminal are identified by.\"},\"prices()\":{\"notice\":\"The contract that exposes price feeds.\"},\"processFees(uint256)\":{\"notice\":\"Process any fees that are being held for the project.\"},\"projects()\":{\"notice\":\"Mints ERC-721's that represent project ownership and transfers.\"},\"redeemTokensOf(address,uint256,uint256,address,uint256,address,string,bytes)\":{\"notice\":\"Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source.\"},\"setFee(uint256)\":{\"notice\":\"Allows the fee to be updated.\"},\"setFeeGauge(address)\":{\"notice\":\"Allows the fee gauge to be updated.\"},\"setFeelessAddress(address,bool)\":{\"notice\":\"Sets whether projects operating on this terminal can pay towards the specified address without incurring a fee.\"},\"splitsStore()\":{\"notice\":\"The contract that stores splits for each project.\"},\"store()\":{\"notice\":\"The contract that stores and manages the terminal's data.\"},\"supportsInterface(bytes4)\":{\"notice\":\"Indicates if this contract adheres to the specified interface.\"},\"token()\":{\"notice\":\"The token that this terminal accepts.\"},\"useAllowanceOf(uint256,uint256,uint256,address,uint256,address,string,bytes)\":{\"notice\":\"Allows a project to send funds from its overflow up to the preconfigured allowance.\"}},\"notice\":\"Manages all inflows and outflows of ETH funds into the protocol ecosystem.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/JBETHPaymentTerminal3_1_1.sol\":\"JBETHPaymentTerminal3_1_1\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n _;\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0x24e0364e503a9bbde94c715d26573a76f14cd2a202d45f96f52134ab806b67b9\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC721/IERC721.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../../utils/introspection/IERC165.sol\\\";\\n\\n/**\\n * @dev Required interface of an ERC721 compliant contract.\\n */\\ninterface IERC721 is IERC165 {\\n /**\\n * @dev Emitted when `tokenId` token is transferred from `from` to `to`.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);\\n\\n /**\\n * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.\\n */\\n event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);\\n\\n /**\\n * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.\\n */\\n event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\\n\\n /**\\n * @dev Returns the number of tokens in ``owner``'s account.\\n */\\n function balanceOf(address owner) external view returns (uint256 balance);\\n\\n /**\\n * @dev Returns the owner of the `tokenId` token.\\n *\\n * Requirements:\\n *\\n * - `tokenId` must exist.\\n */\\n function ownerOf(uint256 tokenId) external view returns (address owner);\\n\\n /**\\n * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\\n * are aware of the ERC721 protocol to prevent tokens from being forever locked.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `tokenId` token must exist and be owned by `from`.\\n * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.\\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\\n *\\n * Emits a {Transfer} event.\\n */\\n function safeTransferFrom(\\n address from,\\n address to,\\n uint256 tokenId\\n ) external;\\n\\n /**\\n * @dev Transfers `tokenId` token from `from` to `to`.\\n *\\n * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `tokenId` token must be owned by `from`.\\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 tokenId\\n ) external;\\n\\n /**\\n * @dev Gives permission to `to` to transfer `tokenId` token to another account.\\n * The approval is cleared when the token is transferred.\\n *\\n * Only a single account can be approved at a time, so approving the zero address clears previous approvals.\\n *\\n * Requirements:\\n *\\n * - The caller must own the token or be an approved operator.\\n * - `tokenId` must exist.\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address to, uint256 tokenId) external;\\n\\n /**\\n * @dev Returns the account approved for `tokenId` token.\\n *\\n * Requirements:\\n *\\n * - `tokenId` must exist.\\n */\\n function getApproved(uint256 tokenId) external view returns (address operator);\\n\\n /**\\n * @dev Approve or remove `operator` as an operator for the caller.\\n * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.\\n *\\n * Requirements:\\n *\\n * - The `operator` cannot be the caller.\\n *\\n * Emits an {ApprovalForAll} event.\\n */\\n function setApprovalForAll(address operator, bool _approved) external;\\n\\n /**\\n * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.\\n *\\n * See {setApprovalForAll}\\n */\\n function isApprovedForAll(address owner, address operator) external view returns (bool);\\n\\n /**\\n * @dev Safely transfers `tokenId` token from `from` to `to`.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `tokenId` token must exist and be owned by `from`.\\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\\n *\\n * Emits a {Transfer} event.\\n */\\n function safeTransferFrom(\\n address from,\\n address to,\\n uint256 tokenId,\\n bytes calldata data\\n ) external;\\n}\\n\",\"keccak256\":\"0x516a22876c1fab47f49b1bc22b4614491cd05338af8bd2e7b382da090a079990\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x3777e696b62134e6177440dbe6e6601c0c156a443f57167194b67e75527439de\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/ERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC165.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC165} interface.\\n *\\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\\n * for the additional interface id that will be supported. For example:\\n *\\n * ```solidity\\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\\n * }\\n * ```\\n *\\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\\n */\\nabstract contract ERC165 is IERC165 {\\n /**\\n * @dev See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n return interfaceId == type(IERC165).interfaceId;\\n }\\n}\\n\",\"keccak256\":\"0xd10975de010d89fd1c78dc5e8a9a7e7f496198085c151648f20cba166b32582b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/ERC165Checker.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165Checker.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC165.sol\\\";\\n\\n/**\\n * @dev Library used to query support of an interface declared via {IERC165}.\\n *\\n * Note that these functions return the actual result of the query: they do not\\n * `revert` if an interface is not supported. It is up to the caller to decide\\n * what to do in these cases.\\n */\\nlibrary ERC165Checker {\\n // As per the EIP-165 spec, no interface should ever match 0xffffffff\\n bytes4 private constant _INTERFACE_ID_INVALID = 0xffffffff;\\n\\n /**\\n * @dev Returns true if `account` supports the {IERC165} interface,\\n */\\n function supportsERC165(address account) internal view returns (bool) {\\n // Any contract that implements ERC165 must explicitly indicate support of\\n // InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid\\n return\\n _supportsERC165Interface(account, type(IERC165).interfaceId) &&\\n !_supportsERC165Interface(account, _INTERFACE_ID_INVALID);\\n }\\n\\n /**\\n * @dev Returns true if `account` supports the interface defined by\\n * `interfaceId`. Support for {IERC165} itself is queried automatically.\\n *\\n * See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) {\\n // query support of both ERC165 as per the spec and support of _interfaceId\\n return supportsERC165(account) && _supportsERC165Interface(account, interfaceId);\\n }\\n\\n /**\\n * @dev Returns a boolean array where each value corresponds to the\\n * interfaces passed in and whether they're supported or not. This allows\\n * you to batch check interfaces for a contract where your expectation\\n * is that some interfaces may not be supported.\\n *\\n * See {IERC165-supportsInterface}.\\n *\\n * _Available since v3.4._\\n */\\n function getSupportedInterfaces(address account, bytes4[] memory interfaceIds)\\n internal\\n view\\n returns (bool[] memory)\\n {\\n // an array of booleans corresponding to interfaceIds and whether they're supported or not\\n bool[] memory interfaceIdsSupported = new bool[](interfaceIds.length);\\n\\n // query support of ERC165 itself\\n if (supportsERC165(account)) {\\n // query support of each interface in interfaceIds\\n for (uint256 i = 0; i < interfaceIds.length; i++) {\\n interfaceIdsSupported[i] = _supportsERC165Interface(account, interfaceIds[i]);\\n }\\n }\\n\\n return interfaceIdsSupported;\\n }\\n\\n /**\\n * @dev Returns true if `account` supports all the interfaces defined in\\n * `interfaceIds`. Support for {IERC165} itself is queried automatically.\\n *\\n * Batch-querying can lead to gas savings by skipping repeated checks for\\n * {IERC165} support.\\n *\\n * See {IERC165-supportsInterface}.\\n */\\n function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) {\\n // query support of ERC165 itself\\n if (!supportsERC165(account)) {\\n return false;\\n }\\n\\n // query support of each interface in _interfaceIds\\n for (uint256 i = 0; i < interfaceIds.length; i++) {\\n if (!_supportsERC165Interface(account, interfaceIds[i])) {\\n return false;\\n }\\n }\\n\\n // all interfaces supported\\n return true;\\n }\\n\\n /**\\n * @notice Query if a contract implements an interface, does not check ERC165 support\\n * @param account The address of the contract to query for support of an interface\\n * @param interfaceId The interface identifier, as specified in ERC-165\\n * @return true if the contract at account indicates support of the interface with\\n * identifier interfaceId, false otherwise\\n * @dev Assumes that account contains a contract that supports ERC165, otherwise\\n * the behavior of this method is undefined. This precondition can be checked\\n * with {supportsERC165}.\\n * Interface identification is specified in ERC-165.\\n */\\n function _supportsERC165Interface(address account, bytes4 interfaceId) private view returns (bool) {\\n bytes memory encodedParams = abi.encodeWithSelector(IERC165.supportsInterface.selector, interfaceId);\\n (bool success, bytes memory result) = account.staticcall{gas: 30000}(encodedParams);\\n if (result.length < 32) return false;\\n return success && abi.decode(result, (bool));\\n }\\n}\\n\",\"keccak256\":\"0xf7291d7213336b00ee7edbf7cd5034778dd7b0bda2a7489e664f1e5cacc6c24e\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/IERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC165 standard, as defined in the\\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\\n *\\n * Implementers can declare support of contract interfaces, which can then be\\n * queried by others ({ERC165Checker}).\\n *\\n * For an implementation, see {ERC165}.\\n */\\ninterface IERC165 {\\n /**\\n * @dev Returns true if this contract implements the interface defined by\\n * `interfaceId`. See the corresponding\\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\\n * to learn more about how these ids are created.\\n *\\n * This function call must use less than 30 000 gas.\\n */\\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\\n}\\n\",\"keccak256\":\"0x447a5f3ddc18419d41ff92b3773fb86471b1db25773e07f877f548918a185bf1\",\"license\":\"MIT\"},\"@paulrberg/contracts/math/PRBMath.sol\":{\"content\":\"// SPDX-License-Identifier: Unlicense\\npragma solidity >=0.8.4;\\n\\nimport \\\"prb-math/contracts/PRBMath.sol\\\";\\n\",\"keccak256\":\"0x42821345981bc0434a90ba2268a2f5278dfe9e38166981d72fc7f3b776a29495\",\"license\":\"Unlicense\"},\"contracts/JBETHPaymentTerminal3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.16;\\n\\nimport {Address} from '@openzeppelin/contracts/utils/Address.sol';\\nimport {JBPayoutRedemptionPaymentTerminal3_1_1} from './abstract/JBPayoutRedemptionPaymentTerminal3_1_1.sol';\\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\\nimport {JBCurrencies} from './libraries/JBCurrencies.sol';\\nimport {JBSplitsGroups} from './libraries/JBSplitsGroups.sol';\\nimport {JBTokens} from './libraries/JBTokens.sol';\\n\\n/// @notice Manages all inflows and outflows of ETH funds into the protocol ecosystem.\\ncontract JBETHPaymentTerminal3_1_1 is JBPayoutRedemptionPaymentTerminal3_1_1 {\\n //*********************************************************************//\\n // -------------------------- internal views ------------------------- //\\n //*********************************************************************//\\n\\n /// @notice Checks the balance of tokens in this contract.\\n /// @return The contract's balance, as a fixed point number with the same amount of decimals as this terminal.\\n function _balance() internal view override returns (uint256) {\\n return address(this).balance;\\n }\\n\\n //*********************************************************************//\\n // -------------------------- constructor ---------------------------- //\\n //*********************************************************************//\\n\\n /// @param _baseWeightCurrency The currency to base token issuance on.\\n /// @param _operatorStore A contract storing operator assignments.\\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\\n /// @param _directory A contract storing directories of terminals and controllers for each project.\\n /// @param _splitsStore A contract that stores splits for each project.\\n /// @param _prices A contract that exposes price feeds.\\n /// @param _store A contract that stores the terminal's data.\\n /// @param _owner The address that will own this contract.\\n constructor(\\n uint256 _baseWeightCurrency,\\n IJBOperatorStore _operatorStore,\\n IJBProjects _projects,\\n IJBDirectory _directory,\\n IJBSplitsStore _splitsStore,\\n IJBPrices _prices,\\n address _store,\\n address _owner\\n )\\n JBPayoutRedemptionPaymentTerminal3_1_1(\\n JBTokens.ETH,\\n 18, // 18 decimals.\\n JBCurrencies.ETH,\\n _baseWeightCurrency,\\n JBSplitsGroups.ETH_PAYOUT,\\n _operatorStore,\\n _projects,\\n _directory,\\n _splitsStore,\\n _prices,\\n _store,\\n _owner\\n )\\n // solhint-disable-next-line no-empty-blocks\\n {\\n\\n }\\n\\n //*********************************************************************//\\n // ---------------------- internal transactions ---------------------- //\\n //*********************************************************************//\\n\\n /// @notice Transfers tokens.\\n /// @param _from The address from which the transfer should originate.\\n /// @param _to The address to which the transfer should go.\\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\\n function _transferFrom(address _from, address payable _to, uint256 _amount) internal override {\\n _from; // Prevents unused var compiler and natspec complaints.\\n\\n Address.sendValue(_to, _amount);\\n }\\n}\\n\",\"keccak256\":\"0x2df0a5c2a17371ce249dae553a919521d9f3037ae397efb68aac726702097060\",\"license\":\"MIT\"},\"contracts/abstract/JBOperatable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.16;\\n\\nimport {IJBOperatable} from './../interfaces/IJBOperatable.sol';\\nimport {IJBOperatorStore} from './../interfaces/IJBOperatorStore.sol';\\n\\n/// @notice Modifiers to allow access to functions based on the message sender's operator status.\\nabstract contract JBOperatable is IJBOperatable {\\n //*********************************************************************//\\n // --------------------------- custom errors -------------------------- //\\n //*********************************************************************//\\n error UNAUTHORIZED();\\n\\n //*********************************************************************//\\n // ---------------------------- modifiers ---------------------------- //\\n //*********************************************************************//\\n\\n /// @notice Only allows the speficied account or an operator of the account to proceed.\\n /// @param _account The account to check for.\\n /// @param _domain The domain namespace to look for an operator within.\\n /// @param _permissionIndex The index of the permission to check for.\\n modifier requirePermission(\\n address _account,\\n uint256 _domain,\\n uint256 _permissionIndex\\n ) {\\n _requirePermission(_account, _domain, _permissionIndex);\\n _;\\n }\\n\\n /// @notice Only allows the speficied account, an operator of the account to proceed, or a truthy override flag.\\n /// @param _account The account to check for.\\n /// @param _domain The domain namespace to look for an operator within.\\n /// @param _permissionIndex The index of the permission to check for.\\n /// @param _override A condition to force allowance for.\\n modifier requirePermissionAllowingOverride(\\n address _account,\\n uint256 _domain,\\n uint256 _permissionIndex,\\n bool _override\\n ) {\\n _requirePermissionAllowingOverride(_account, _domain, _permissionIndex, _override);\\n _;\\n }\\n\\n //*********************************************************************//\\n // ---------------- public immutable stored properties --------------- //\\n //*********************************************************************//\\n\\n /// @notice A contract storing operator assignments.\\n IJBOperatorStore public immutable override operatorStore;\\n\\n //*********************************************************************//\\n // -------------------------- constructor ---------------------------- //\\n //*********************************************************************//\\n\\n /// @param _operatorStore A contract storing operator assignments.\\n constructor(IJBOperatorStore _operatorStore) {\\n operatorStore = _operatorStore;\\n }\\n\\n //*********************************************************************//\\n // -------------------------- internal views ------------------------- //\\n //*********************************************************************//\\n\\n /// @notice Require the message sender is either the account or has the specified permission.\\n /// @param _account The account to allow.\\n /// @param _domain The domain namespace within which the permission index will be checked.\\n /// @param _permissionIndex The permission index that an operator must have within the specified domain to be allowed.\\n function _requirePermission(\\n address _account,\\n uint256 _domain,\\n uint256 _permissionIndex\\n ) internal view {\\n if (\\n msg.sender != _account &&\\n !operatorStore.hasPermission(msg.sender, _account, _domain, _permissionIndex) &&\\n !operatorStore.hasPermission(msg.sender, _account, 0, _permissionIndex)\\n ) revert UNAUTHORIZED();\\n }\\n\\n /// @notice Require the message sender is either the account, has the specified permission, or the override condition is true.\\n /// @param _account The account to allow.\\n /// @param _domain The domain namespace within which the permission index will be checked.\\n /// @param _domain The permission index that an operator must have within the specified domain to be allowed.\\n /// @param _override The override condition to allow.\\n function _requirePermissionAllowingOverride(\\n address _account,\\n uint256 _domain,\\n uint256 _permissionIndex,\\n bool _override\\n ) internal view {\\n if (\\n !_override &&\\n msg.sender != _account &&\\n !operatorStore.hasPermission(msg.sender, _account, _domain, _permissionIndex) &&\\n !operatorStore.hasPermission(msg.sender, _account, 0, _permissionIndex)\\n ) revert UNAUTHORIZED();\\n }\\n}\\n\",\"keccak256\":\"0xed3071b63f3ac427ffcd357a53be2675d405e94e40a7b1bc0475054005807e91\",\"license\":\"MIT\"},\"contracts/abstract/JBPayoutRedemptionPaymentTerminal3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.16;\\n\\nimport {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\\nimport {ERC165Checker} from '@openzeppelin/contracts/utils/introspection/ERC165Checker.sol';\\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\\nimport {JBFeeType} from './../enums/JBFeeType.sol';\\nimport {IJBAllowanceTerminal3_1} from './../interfaces/IJBAllowanceTerminal3_1.sol';\\nimport {IJBController} from './../interfaces/IJBController.sol';\\nimport {IJBDirectory} from './../interfaces/IJBDirectory.sol';\\nimport {IJBPayoutRedemptionPaymentTerminal3_1} from './../interfaces/IJBPayoutRedemptionPaymentTerminal3_1.sol';\\nimport {IJBPayoutRedemptionPaymentTerminal3_1_1} from './../interfaces/IJBPayoutRedemptionPaymentTerminal3_1_1.sol';\\nimport {IJBSplitsStore} from './../interfaces/IJBSplitsStore.sol';\\nimport {IJBFeeGauge3_1} from './../interfaces/IJBFeeGauge3_1.sol';\\nimport {IJBOperatable} from './../interfaces/IJBOperatable.sol';\\nimport {IJBOperatorStore} from './../interfaces/IJBOperatorStore.sol';\\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\\nimport {IJBPayoutTerminal3_1} from './../interfaces/IJBPayoutTerminal3_1.sol';\\nimport {IJBPrices} from './../interfaces/IJBPrices.sol';\\nimport {IJBProjects} from './../interfaces/IJBProjects.sol';\\nimport {IJBRedemptionTerminal} from './../interfaces/IJBRedemptionTerminal.sol';\\nimport {IJBSingleTokenPaymentTerminalStore3_1_1} from './../interfaces/IJBSingleTokenPaymentTerminalStore3_1_1.sol';\\nimport {IJBSplitAllocator} from './../interfaces/IJBSplitAllocator.sol';\\nimport {JBConstants} from './../libraries/JBConstants.sol';\\nimport {JBCurrencies} from './../libraries/JBCurrencies.sol';\\nimport {JBFixedPointNumber} from './../libraries/JBFixedPointNumber.sol';\\nimport {JBFundingCycleMetadataResolver} from './../libraries/JBFundingCycleMetadataResolver.sol';\\nimport {JBOperations} from './../libraries/JBOperations.sol';\\nimport {JBTokens} from './../libraries/JBTokens.sol';\\nimport {JBDidRedeemData3_1_1} from './../structs/JBDidRedeemData3_1_1.sol';\\nimport {JBDidPayData3_1_1} from './../structs/JBDidPayData3_1_1.sol';\\nimport {JBFee} from './../structs/JBFee.sol';\\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\\nimport {JBPayDelegateAllocation3_1_1} from './../structs/JBPayDelegateAllocation3_1_1.sol';\\nimport {JBRedemptionDelegateAllocation3_1_1} from './../structs/JBRedemptionDelegateAllocation3_1_1.sol';\\nimport {JBSplit} from './../structs/JBSplit.sol';\\nimport {JBSplitAllocationData} from './../structs/JBSplitAllocationData.sol';\\nimport {JBTokenAmount} from './../structs/JBTokenAmount.sol';\\nimport {JBOperatable} from './JBOperatable.sol';\\nimport {JBSingleTokenPaymentTerminal} from './JBSingleTokenPaymentTerminal.sol';\\n\\n/// @notice Generic terminal managing all inflows and outflows of funds into the protocol ecosystem.\\nabstract contract JBPayoutRedemptionPaymentTerminal3_1_1 is\\n JBSingleTokenPaymentTerminal,\\n JBOperatable,\\n Ownable,\\n IJBPayoutRedemptionPaymentTerminal3_1,\\n IJBPayoutRedemptionPaymentTerminal3_1_1\\n{\\n // A library that parses the packed funding cycle metadata into a friendlier format.\\n using JBFundingCycleMetadataResolver for JBFundingCycle;\\n\\n //*********************************************************************//\\n // --------------------------- custom errors ------------------------- //\\n //*********************************************************************//\\n error FEE_TOO_HIGH();\\n error INADEQUATE_DISTRIBUTION_AMOUNT();\\n error INADEQUATE_RECLAIM_AMOUNT();\\n error INADEQUATE_TOKEN_COUNT();\\n error NO_MSG_VALUE_ALLOWED();\\n error PAY_TO_ZERO_ADDRESS();\\n error PROJECT_TERMINAL_MISMATCH();\\n error REDEEM_TO_ZERO_ADDRESS();\\n error TERMINAL_TOKENS_INCOMPATIBLE();\\n\\n //*********************************************************************//\\n // --------------------- internal stored constants ------------------- //\\n //*********************************************************************//\\n\\n /// @notice Maximum fee that can be set for a funding cycle configuration.\\n /// @dev Out of MAX_FEE (50_000_000 / 1_000_000_000).\\n uint256 internal constant _FEE_CAP = 50_000_000;\\n\\n /// @notice The fee beneficiary project ID is 1, as it should be the first project launched during the deployment process.\\n uint256 internal constant _FEE_BENEFICIARY_PROJECT_ID = 1;\\n\\n //*********************************************************************//\\n // --------------------- internal stored properties ------------------ //\\n //*********************************************************************//\\n\\n /// @notice Fees that are being held to be processed later.\\n /// @custom:param _projectId The ID of the project for which fees are being held.\\n mapping(uint256 => JBFee[]) internal _heldFeesOf;\\n\\n //*********************************************************************//\\n // ---------------- public immutable stored properties --------------- //\\n //*********************************************************************//\\n\\n /// @notice Mints ERC-721's that represent project ownership and transfers.\\n IJBProjects public immutable override projects;\\n\\n /// @notice The directory of terminals and controllers for projects.\\n IJBDirectory public immutable override directory;\\n\\n /// @notice The contract that stores splits for each project.\\n IJBSplitsStore public immutable override splitsStore;\\n\\n /// @notice The contract that exposes price feeds.\\n IJBPrices public immutable override prices;\\n\\n /// @notice The contract that stores and manages the terminal's data.\\n address public immutable override store;\\n\\n /// @notice The currency to base token issuance on.\\n /// @dev If this differs from `currency`, there must be a price feed available to convert `currency` to `baseWeightCurrency`.\\n uint256 public immutable override baseWeightCurrency;\\n\\n /// @notice The group that payout splits coming from this terminal are identified by.\\n uint256 public immutable override payoutSplitsGroup;\\n\\n //*********************************************************************//\\n // --------------------- public stored properties -------------------- //\\n //*********************************************************************//\\n\\n /// @notice The platform fee percent.\\n /// @dev Out of MAX_FEE (25_000_000 / 1_000_000_000)\\n uint256 public override fee = 25_000_000; // 2.5%\\n\\n /// @notice The data source that returns a discount to apply to a project's fee.\\n address public override feeGauge;\\n\\n /// @notice Addresses that can be paid towards from this terminal without incurring a fee.\\n /// @dev Only addresses that are considered to be contained within the ecosystem can be feeless. Funds sent outside the ecosystem may incur fees despite being stored as feeless.\\n /// @custom:param _address The address that can be paid toward.\\n mapping(address => bool) public override isFeelessAddress;\\n\\n //*********************************************************************//\\n // ------------------------- external views -------------------------- //\\n //*********************************************************************//\\n\\n /// @notice Gets the current overflowed amount in this terminal for a specified project, in terms of ETH.\\n /// @dev The current overflow is represented as a fixed point number with 18 decimals.\\n /// @param _projectId The ID of the project to get overflow for.\\n /// @return The current amount of ETH overflow that project has in this terminal, as a fixed point number with 18 decimals.\\n function currentEthOverflowOf(\\n uint256 _projectId\\n ) external view virtual override returns (uint256) {\\n // Get this terminal's current overflow.\\n uint256 _overflow = IJBSingleTokenPaymentTerminalStore3_1_1(store).currentOverflowOf(\\n this,\\n _projectId\\n );\\n\\n // Adjust the decimals of the fixed point number if needed to have 18 decimals.\\n uint256 _adjustedOverflow = (decimals == 18)\\n ? _overflow\\n : JBFixedPointNumber.adjustDecimals(_overflow, decimals, 18);\\n\\n // Return the amount converted to ETH.\\n return\\n (currency == JBCurrencies.ETH)\\n ? _adjustedOverflow\\n : PRBMath.mulDiv(\\n _adjustedOverflow,\\n 10 ** decimals,\\n prices.priceFor(currency, JBCurrencies.ETH, decimals)\\n );\\n }\\n\\n /// @notice The fees that are currently being held to be processed later for each project.\\n /// @param _projectId The ID of the project for which fees are being held.\\n /// @return An array of fees that are being held.\\n function heldFeesOf(uint256 _projectId) external view override returns (JBFee[] memory) {\\n return _heldFeesOf[_projectId];\\n }\\n\\n //*********************************************************************//\\n // -------------------------- public views --------------------------- //\\n //*********************************************************************//\\n\\n /// @notice Indicates if this contract adheres to the specified interface.\\n /// @dev See {IERC165-supportsInterface}.\\n /// @param _interfaceId The ID of the interface to check for adherance to.\\n /// @return A flag indicating if the provided interface ID is supported.\\n function supportsInterface(\\n bytes4 _interfaceId\\n ) public view virtual override(JBSingleTokenPaymentTerminal, IERC165) returns (bool) {\\n return\\n _interfaceId == type(IJBPayoutRedemptionPaymentTerminal3_1_1).interfaceId ||\\n _interfaceId == type(IJBPayoutRedemptionPaymentTerminal3_1).interfaceId ||\\n _interfaceId == type(IJBPayoutTerminal3_1).interfaceId ||\\n _interfaceId == type(IJBAllowanceTerminal3_1).interfaceId ||\\n _interfaceId == type(IJBRedemptionTerminal).interfaceId ||\\n _interfaceId == type(IJBOperatable).interfaceId ||\\n super.supportsInterface(_interfaceId);\\n }\\n\\n //*********************************************************************//\\n // -------------------------- internal views ------------------------- //\\n //*********************************************************************//\\n\\n /// @notice Checks the balance of tokens in this contract.\\n /// @return The contract's balance.\\n function _balance() internal view virtual returns (uint256);\\n\\n //*********************************************************************//\\n // -------------------------- constructor ---------------------------- //\\n //*********************************************************************//\\n\\n /// @param _token The token that this terminal manages.\\n /// @param _decimals The number of decimals the token fixed point amounts are expected to have.\\n /// @param _currency The currency that this terminal's token adheres to for price feeds.\\n /// @param _baseWeightCurrency The currency to base token issuance on.\\n /// @param _payoutSplitsGroup The group that denotes payout splits from this terminal in the splits store.\\n /// @param _operatorStore A contract storing operator assignments.\\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\\n /// @param _directory A contract storing directories of terminals and controllers for each project.\\n /// @param _splitsStore A contract that stores splits for each project.\\n /// @param _prices A contract that exposes price feeds.\\n /// @param _store A contract that stores the terminal's data.\\n /// @param _owner The address that will own this contract.\\n constructor(\\n // payable constructor save the gas used to check msg.value==0\\n address _token,\\n uint256 _decimals,\\n uint256 _currency,\\n uint256 _baseWeightCurrency,\\n uint256 _payoutSplitsGroup,\\n IJBOperatorStore _operatorStore,\\n IJBProjects _projects,\\n IJBDirectory _directory,\\n IJBSplitsStore _splitsStore,\\n IJBPrices _prices,\\n address _store,\\n address _owner\\n )\\n payable\\n JBSingleTokenPaymentTerminal(_token, _decimals, _currency)\\n JBOperatable(_operatorStore)\\n {\\n baseWeightCurrency = _baseWeightCurrency;\\n payoutSplitsGroup = _payoutSplitsGroup;\\n projects = _projects;\\n directory = _directory;\\n splitsStore = _splitsStore;\\n prices = _prices;\\n store = _store;\\n\\n transferOwnership(_owner);\\n }\\n\\n //*********************************************************************//\\n // ---------------------- external transactions ---------------------- //\\n //*********************************************************************//\\n\\n /// @notice Contribute tokens to a project.\\n /// @param _projectId The ID of the project being paid.\\n /// @param _amount The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place.\\n /// @param _token The token being paid. This terminal ignores this property since it only manages one token.\\n /// @param _beneficiary The address to mint tokens for and pass along to the funding cycle's data source and delegate.\\n /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal.\\n /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\\n /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\\n /// @return The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals.\\n function pay(\\n uint256 _projectId,\\n uint256 _amount,\\n address _token,\\n address _beneficiary,\\n uint256 _minReturnedTokens,\\n bool _preferClaimedTokens,\\n string calldata _memo,\\n bytes calldata _metadata\\n ) external payable virtual override returns (uint256) {\\n _token; // Prevents unused var compiler and natspec complaints.\\n\\n // valid terminal check\\n _isTerminalOf(_projectId);\\n\\n // ETH shouldn't be sent if this terminal's token isn't ETH.\\n if (token != JBTokens.ETH) {\\n if (msg.value != 0) revert NO_MSG_VALUE_ALLOWED();\\n\\n // Get a reference to the balance before receiving tokens.\\n uint256 _balanceBefore = _balance();\\n\\n // Transfer tokens to this terminal from the msg sender.\\n _transferFrom(msg.sender, payable(address(this)), _amount);\\n\\n // The amount should reflect the change in balance.\\n _amount = _balance() - _balanceBefore;\\n }\\n // If this terminal's token is ETH, override _amount with msg.value.\\n else _amount = msg.value;\\n\\n return\\n _pay(\\n _amount,\\n msg.sender,\\n _projectId,\\n _beneficiary,\\n _minReturnedTokens,\\n _preferClaimedTokens,\\n _memo,\\n _metadata\\n );\\n }\\n\\n /// @notice Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source.\\n /// @dev Only a token holder or a designated operator can redeem its tokens.\\n /// @param _holder The account to redeem tokens for.\\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\\n /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals.\\n /// @param _token The token being reclaimed. This terminal ignores this property since it only manages one token.\\n /// @param _minReturnedTokens The minimum amount of terminal tokens expected in return, as a fixed point number with the same amount of decimals as the terminal.\\n /// @param _beneficiary The address to send the terminal tokens to.\\n /// @param _memo A memo to pass along to the emitted event.\\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\\n /// @return reclaimAmount The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals.\\n function redeemTokensOf(\\n address _holder,\\n uint256 _projectId,\\n uint256 _tokenCount,\\n address _token,\\n uint256 _minReturnedTokens,\\n address payable _beneficiary,\\n string memory _memo,\\n bytes memory _metadata\\n )\\n external\\n virtual\\n override\\n requirePermission(_holder, _projectId, JBOperations.REDEEM)\\n returns (uint256 reclaimAmount)\\n {\\n _token; // Prevents unused var compiler and natspec complaints.\\n\\n return\\n _redeemTokensOf(\\n _holder,\\n _projectId,\\n _tokenCount,\\n _minReturnedTokens,\\n _beneficiary,\\n _memo,\\n _metadata\\n );\\n }\\n\\n /// @notice Distributes payouts for a project with the distribution limit of its current funding cycle.\\n /// @dev Payouts are sent to the preprogrammed splits. Any leftover is sent to the project's owner.\\n /// @dev 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.\\n /// @dev All funds distributed outside of this contract or any feeless terminals incure the protocol fee.\\n /// @param _projectId The ID of the project having its payouts distributed.\\n /// @param _amount The amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal.\\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency.\\n /// @param _token The token being distributed. This terminal ignores this property since it only manages one token.\\n /// @param _minReturnedTokens 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.\\n /// @param _metadata Bytes to send along to the emitted event, if provided.\\n /// @return netLeftoverDistributionAmount The amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal.\\n function distributePayoutsOf(\\n uint256 _projectId,\\n uint256 _amount,\\n uint256 _currency,\\n address _token,\\n uint256 _minReturnedTokens,\\n bytes calldata _metadata\\n ) external virtual override returns (uint256 netLeftoverDistributionAmount) {\\n _token; // Prevents unused var compiler and natspec complaints.\\n\\n return _distributePayoutsOf(_projectId, _amount, _currency, _minReturnedTokens, _metadata);\\n }\\n\\n /// @notice Allows a project to send funds from its overflow up to the preconfigured allowance.\\n /// @dev Only a project's owner or a designated operator can use its allowance.\\n /// @dev Incurs the protocol fee.\\n /// @param _projectId The ID of the project to use the allowance of.\\n /// @param _amount The amount of terminal tokens to use from this project's current allowance, as a fixed point number with the same amount of decimals as this terminal.\\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's overflow allowance currency.\\n /// @param _token The token being distributed. This terminal ignores this property since it only manages one token.\\n /// @param _minReturnedTokens The minimum number of tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with 18 decimals.\\n /// @param _beneficiary The address to send the funds to.\\n /// @param _memo A memo to pass along to the emitted event.\\n /// @param _metadata Bytes to send along to the emitted event, if provided.\\n /// @return netDistributedAmount The amount of tokens that was distributed to the beneficiary, as a fixed point number with the same amount of decimals as the terminal.\\n function useAllowanceOf(\\n uint256 _projectId,\\n uint256 _amount,\\n uint256 _currency,\\n address _token,\\n uint256 _minReturnedTokens,\\n address payable _beneficiary,\\n string memory _memo,\\n bytes calldata _metadata\\n )\\n external\\n virtual\\n override\\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.USE_ALLOWANCE)\\n returns (uint256 netDistributedAmount)\\n {\\n _token; // Prevents unused var compiler and natspec complaints.\\n\\n return\\n _useAllowanceOf(\\n _projectId,\\n _amount,\\n _currency,\\n _minReturnedTokens,\\n _beneficiary,\\n _memo,\\n _metadata\\n );\\n }\\n\\n /// @notice Allows a project owner to migrate its funds and operations to a new terminal that accepts the same token type.\\n /// @dev Only a project's owner or a designated operator can migrate it.\\n /// @param _projectId The ID of the project being migrated.\\n /// @param _to The terminal contract that will gain the project's funds.\\n /// @return balance The amount of funds that were migrated, as a fixed point number with the same amount of decimals as this terminal.\\n function migrate(\\n uint256 _projectId,\\n IJBPaymentTerminal _to\\n )\\n external\\n virtual\\n override\\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.MIGRATE_TERMINAL)\\n returns (uint256 balance)\\n {\\n // The terminal being migrated to must accept the same token as this terminal.\\n if (!_to.acceptsToken(token, _projectId)) revert TERMINAL_TOKENS_INCOMPATIBLE();\\n\\n // Record the migration in the store.\\n balance = IJBSingleTokenPaymentTerminalStore3_1_1(store).recordMigration(_projectId);\\n\\n // Transfer the balance if needed.\\n if (balance != 0) {\\n // Trigger any inherited pre-transfer logic.\\n _beforeTransferTo(address(_to), balance);\\n\\n // If this terminal's token is ETH, send it in msg.value.\\n uint256 _payableValue = token == JBTokens.ETH ? balance : 0;\\n\\n // Withdraw the balance to transfer to the new terminal;\\n _to.addToBalanceOf{value: _payableValue}(_projectId, balance, token, '', bytes(''));\\n }\\n\\n emit Migrate(_projectId, _to, balance, msg.sender);\\n }\\n\\n /// @notice Receives funds belonging to the specified project.\\n /// @param _projectId The ID of the project to which the funds received belong.\\n /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\\n /// @param _token The token being paid. This terminal ignores this property since it only manages one currency.\\n /// @param _memo A memo to pass along to the emitted event.\\n /// @param _metadata Extra data to pass along to the emitted event.\\n function addToBalanceOf(\\n uint256 _projectId,\\n uint256 _amount,\\n address _token,\\n string calldata _memo,\\n bytes calldata _metadata\\n ) external payable virtual override {\\n // valid terminal check\\n _isTerminalOf(_projectId);\\n\\n // Do not refund held fees by default.\\n addToBalanceOf(_projectId, _amount, _token, false, _memo, _metadata);\\n }\\n\\n /// @notice Process any fees that are being held for the project.\\n /// @dev Only a project owner, an operator, or the contract's owner can process held fees.\\n /// @param _projectId The ID of the project whos held fees should be processed.\\n function processFees(\\n uint256 _projectId\\n )\\n external\\n virtual\\n override\\n requirePermissionAllowingOverride(\\n projects.ownerOf(_projectId),\\n _projectId,\\n JBOperations.PROCESS_FEES,\\n msg.sender == owner()\\n )\\n {\\n // Get a reference to the project's held fees.\\n JBFee[] memory _heldFees = _heldFeesOf[_projectId];\\n\\n // Delete the held fees.\\n delete _heldFeesOf[_projectId];\\n\\n // Push array length in stack\\n uint256 _heldFeeLength = _heldFees.length;\\n\\n // Keep a reference to the amount.\\n uint256 _amount;\\n\\n // Process each fee.\\n for (uint256 _i; _i < _heldFeeLength; ) {\\n // Get the fee amount.\\n _amount = (\\n _heldFees[_i].fee == 0 || _heldFees[_i].feeDiscount == JBConstants.MAX_FEE_DISCOUNT\\n ? 0\\n : _feeAmount(_heldFees[_i].amount, _heldFees[_i].fee, _heldFees[_i].feeDiscount)\\n );\\n\\n // Process the fee.\\n _processFee(_amount, _heldFees[_i].beneficiary, _projectId);\\n\\n emit ProcessFee(_projectId, _amount, true, _heldFees[_i].beneficiary, msg.sender);\\n\\n unchecked {\\n ++_i;\\n }\\n }\\n }\\n\\n /// @notice Allows the fee to be updated.\\n /// @dev Only the owner of this contract can change the fee.\\n /// @param _fee The new fee, out of MAX_FEE.\\n function setFee(uint256 _fee) external virtual override onlyOwner {\\n // The provided fee must be within the max.\\n if (_fee > _FEE_CAP) revert FEE_TOO_HIGH();\\n\\n // Store the new fee.\\n fee = _fee;\\n\\n emit SetFee(_fee, msg.sender);\\n }\\n\\n /// @notice Allows the fee gauge to be updated.\\n /// @dev Only the owner of this contract can change the fee gauge.\\n /// @param _feeGauge The new fee gauge.\\n function setFeeGauge(address _feeGauge) external virtual override onlyOwner {\\n // Store the new fee gauge.\\n feeGauge = _feeGauge;\\n\\n emit SetFeeGauge(_feeGauge, msg.sender);\\n }\\n\\n /// @notice Sets whether projects operating on this terminal can pay towards the specified address without incurring a fee.\\n /// @dev Only the owner of this contract can set addresses as feeless.\\n /// @param _address The address that can be paid towards while still bypassing fees.\\n /// @param _flag A flag indicating whether the terminal should be feeless or not.\\n function setFeelessAddress(address _address, bool _flag) external virtual override onlyOwner {\\n // Set the flag value.\\n isFeelessAddress[_address] = _flag;\\n\\n emit SetFeelessAddress(_address, _flag, msg.sender);\\n }\\n\\n //*********************************************************************//\\n // ----------------------- public transactions ----------------------- //\\n //*********************************************************************//\\n\\n /// @notice Receives funds belonging to the specified project.\\n /// @param _projectId The ID of the project to which the funds received belong.\\n /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\\n /// @param _token The token being paid. This terminal ignores this property since it only manages one currency.\\n /// @param _shouldRefundHeldFees A flag indicating if held fees should be refunded based on the amount being added.\\n /// @param _memo A memo to pass along to the emitted event.\\n /// @param _metadata Extra data to pass along to the emitted event.\\n function addToBalanceOf(\\n uint256 _projectId,\\n uint256 _amount,\\n address _token,\\n bool _shouldRefundHeldFees,\\n string calldata _memo,\\n bytes calldata _metadata\\n ) public payable virtual override {\\n // valid terminal check\\n _isTerminalOf(_projectId);\\n\\n _token; // Prevents unused var compiler and natspec complaints.\\n\\n // If this terminal's token isn't ETH, make sure no msg.value was sent, then transfer the tokens in from msg.sender.\\n if (token != JBTokens.ETH) {\\n // Amount must be greater than 0.\\n if (msg.value != 0) revert NO_MSG_VALUE_ALLOWED();\\n\\n // Get a reference to the balance before receiving tokens.\\n uint256 _balanceBefore = _balance();\\n\\n // Transfer tokens to this terminal from the msg sender.\\n _transferFrom(msg.sender, payable(address(this)), _amount);\\n\\n // The amount should reflect the change in balance.\\n _amount = _balance() - _balanceBefore;\\n }\\n // If the terminal's token is ETH, override `_amount` with msg.value.\\n else _amount = msg.value;\\n\\n // Add to balance.\\n _addToBalanceOf(_projectId, _amount, _shouldRefundHeldFees, _memo, _metadata);\\n }\\n\\n //*********************************************************************//\\n // ---------------------- internal transactions ---------------------- //\\n //*********************************************************************//\\n\\n /// @notice Transfers tokens.\\n /// @param _from The address from which the transfer should originate.\\n /// @param _to The address to which the transfer should go.\\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\\n function _transferFrom(address _from, address payable _to, uint256 _amount) internal virtual {\\n _from; // Prevents unused var compiler and natspec complaints.\\n _to; // Prevents unused var compiler and natspec complaints.\\n _amount; // Prevents unused var compiler and natspec complaints.\\n }\\n\\n /// @notice Logic to be triggered before transferring tokens from this terminal.\\n /// @param _to The address to which the transfer is going.\\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\\n function _beforeTransferTo(address _to, uint256 _amount) internal virtual {\\n _to; // Prevents unused var compiler and natspec complaints.\\n _amount; // Prevents unused var compiler and natspec complaints.\\n }\\n\\n /// @notice Logic to be triggered if a transfer should be undone\\n /// @param _to The address to which the transfer went.\\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\\n function _cancelTransferTo(address _to, uint256 _amount) internal virtual {\\n _to; // Prevents unused var compiler and natspec complaints.\\n _amount; // Prevents unused var compiler and natspec complaints.\\n }\\n\\n /// @notice Verifies this terminal is a terminal of provided project ID.\\n /// @param _projectId The ID of the project to check if this contract is a terminal of.\\n function _isTerminalOf(uint256 _projectId) internal view {\\n if (!directory.isTerminalOf(_projectId, this)) revert PROJECT_TERMINAL_MISMATCH();\\n }\\n\\n /// @notice Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source.\\n /// @dev Only a token holder or a designated operator can redeem its tokens.\\n /// @param _holder The account to redeem tokens for.\\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\\n /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals.\\n /// @param _minReturnedTokens The minimum amount of terminal tokens expected in return, as a fixed point number with the same amount of decimals as the terminal.\\n /// @param _beneficiary The address to send the terminal tokens to.\\n /// @param _memo A memo to pass along to the emitted event.\\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\\n /// @return reclaimAmount The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals.\\n function _redeemTokensOf(\\n address _holder,\\n uint256 _projectId,\\n uint256 _tokenCount,\\n uint256 _minReturnedTokens,\\n address payable _beneficiary,\\n string memory _memo,\\n bytes memory _metadata\\n ) internal returns (uint256 reclaimAmount) {\\n // Can't send reclaimed funds to the zero address.\\n if (_beneficiary == address(0)) revert REDEEM_TO_ZERO_ADDRESS();\\n\\n // Define variables that will be needed outside the scoped section below.\\n // Keep a reference to the funding cycle during which the redemption is being made.\\n JBFundingCycle memory _fundingCycle;\\n\\n // Scoped section prevents stack too deep. `_feeEligibleDistributionAmount`, `_feeDiscount` and `_feePercent` only used within scope.\\n {\\n // Keep a reference to the amount being reclaimed that should have fees withheld from.\\n uint256 _feeEligibleDistributionAmount;\\n\\n // Keep a reference to the amount of discount to apply to the fee.\\n uint256 _feeDiscount;\\n\\n // Keep a reference to the fee.\\n uint256 _feePercent = fee;\\n\\n // Scoped section prevents stack too deep. `_delegateAllocations` only used within scope.\\n {\\n JBRedemptionDelegateAllocation3_1_1[] memory _delegateAllocations;\\n\\n // Record the redemption.\\n (\\n _fundingCycle,\\n reclaimAmount,\\n _delegateAllocations,\\n _memo\\n ) = IJBSingleTokenPaymentTerminalStore3_1_1(store).recordRedemptionFor(\\n _holder,\\n _projectId,\\n _tokenCount,\\n _memo,\\n _metadata\\n );\\n\\n // Set the reference to the fee discount to apply. No fee if the beneficiary is feeless or if the redemption rate is at its max.\\n _feeDiscount = isFeelessAddress[_beneficiary] ||\\n (_fundingCycle.redemptionRate() == JBConstants.MAX_REDEMPTION_RATE &&\\n _fundingCycle.ballotRedemptionRate() == JBConstants.MAX_REDEMPTION_RATE) ||\\n _feePercent == 0\\n ? JBConstants.MAX_FEE_DISCOUNT\\n : _currentFeeDiscount(_projectId, JBFeeType.REDEMPTION);\\n\\n // The amount being reclaimed must be at least as much as was expected.\\n if (reclaimAmount < _minReturnedTokens) revert INADEQUATE_RECLAIM_AMOUNT();\\n\\n // Burn the project tokens.\\n if (_tokenCount != 0)\\n IJBController(directory.controllerOf(_projectId)).burnTokensOf(\\n _holder,\\n _projectId,\\n _tokenCount,\\n '',\\n false\\n );\\n\\n // If delegate allocations were specified by the data source, fulfill them.\\n if (_delegateAllocations.length != 0) {\\n JBDidRedeemData3_1_1 memory _data = JBDidRedeemData3_1_1(\\n _holder,\\n _projectId,\\n _fundingCycle.configuration,\\n _tokenCount,\\n JBTokenAmount(token, reclaimAmount, decimals, currency),\\n JBTokenAmount(token, 0, decimals, currency),\\n _beneficiary,\\n _memo,\\n bytes(''),\\n _metadata\\n );\\n\\n // Keep a reference to the allocation.\\n JBRedemptionDelegateAllocation3_1_1 memory _delegateAllocation;\\n\\n // Keep a reference to the fee.\\n uint256 _delegatedAmountFee;\\n\\n // Keep a reference to the number of allocations.\\n uint256 _numDelegates = _delegateAllocations.length;\\n\\n for (uint256 _i; _i < _numDelegates; ) {\\n // Get a reference to the delegate being iterated on.\\n _delegateAllocation = _delegateAllocations[_i];\\n\\n // Get the fee for the delegated amount.\\n _delegatedAmountFee = _feePercent == 0\\n ? 0\\n : _feeAmount(_delegateAllocation.amount, _feePercent, _feeDiscount);\\n\\n // Add the delegated amount to the amount eligible for having a fee taken.\\n if (_delegatedAmountFee != 0) {\\n _feeEligibleDistributionAmount += _delegateAllocation.amount;\\n _delegateAllocation.amount -= _delegatedAmountFee;\\n }\\n\\n // Trigger any inherited pre-transfer logic.\\n _beforeTransferTo(address(_delegateAllocation.delegate), _delegateAllocation.amount);\\n\\n // Pass the correct token forwardedAmount to the delegate\\n _data.forwardedAmount.value = _delegateAllocation.amount;\\n\\n // Pass the correct metadata from the data source.\\n _data.dataSourceMetadata = _delegateAllocation.metadata;\\n\\n _delegateAllocation.delegate.didRedeem{\\n value: token == JBTokens.ETH ? _delegateAllocation.amount : 0\\n }(_data);\\n\\n emit DelegateDidRedeem(\\n _delegateAllocation.delegate,\\n _data,\\n _delegateAllocation.amount,\\n _delegatedAmountFee,\\n msg.sender\\n );\\n\\n unchecked {\\n ++_i;\\n }\\n }\\n }\\n }\\n\\n // Send the reclaimed funds to the beneficiary.\\n if (reclaimAmount != 0) {\\n // Get the fee for the reclaimed amount.\\n uint256 _reclaimAmountFee = _feeDiscount == JBConstants.MAX_FEE_DISCOUNT\\n ? 0\\n : _feeAmount(reclaimAmount, _feePercent, _feeDiscount);\\n\\n if (_reclaimAmountFee != 0) {\\n _feeEligibleDistributionAmount += reclaimAmount;\\n reclaimAmount -= _reclaimAmountFee;\\n }\\n\\n // Subtract the fee from the reclaim amount.\\n if (reclaimAmount != 0) _transferFrom(address(this), _beneficiary, reclaimAmount);\\n }\\n\\n // Take the fee from all outbound reclaimations.\\n _feeEligibleDistributionAmount != 0\\n ? _takeFeeFrom(\\n _projectId,\\n false,\\n _feeEligibleDistributionAmount,\\n _feePercent,\\n _beneficiary,\\n _feeDiscount\\n )\\n : 0;\\n }\\n\\n emit RedeemTokens(\\n _fundingCycle.configuration,\\n _fundingCycle.number,\\n _projectId,\\n _holder,\\n _beneficiary,\\n _tokenCount,\\n reclaimAmount,\\n _memo,\\n _metadata,\\n msg.sender\\n );\\n }\\n\\n /// @notice Distributes payouts for a project with the distribution limit of its current funding cycle.\\n /// @dev Payouts are sent to the preprogrammed splits. Any leftover is sent to the project's owner.\\n /// @dev 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.\\n /// @dev All funds distributed outside of this contract or any feeless terminals incure the protocol fee.\\n /// @param _projectId The ID of the project having its payouts distributed.\\n /// @param _amount The amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal.\\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency.\\n /// @param _minReturnedTokens 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.\\n /// @param _metadata Bytes to send along to the emitted event, if provided.\\n /// @return netLeftoverDistributionAmount The amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal.\\n function _distributePayoutsOf(\\n uint256 _projectId,\\n uint256 _amount,\\n uint256 _currency,\\n uint256 _minReturnedTokens,\\n bytes calldata _metadata\\n ) internal returns (uint256 netLeftoverDistributionAmount) {\\n // Record the distribution.\\n (\\n JBFundingCycle memory _fundingCycle,\\n uint256 _distributedAmount\\n ) = IJBSingleTokenPaymentTerminalStore3_1_1(store).recordDistributionFor(\\n _projectId,\\n _amount,\\n _currency\\n );\\n\\n // The amount being distributed must be at least as much as was expected.\\n if (_distributedAmount < _minReturnedTokens) revert INADEQUATE_DISTRIBUTION_AMOUNT();\\n\\n // Get a reference to the project owner, which will receive tokens from paying the platform fee\\n // and receive any extra distributable funds not allocated to payout splits.\\n address payable _projectOwner = payable(projects.ownerOf(_projectId));\\n\\n // Define variables that will be needed outside the scoped section below.\\n // Keep a reference to the fee amount that was paid.\\n uint256 _feeTaken;\\n\\n // Scoped section prevents stack too deep. `_feePercent`, `_feeDiscount`, `_feeEligibleDistributionAmount`, and `_leftoverDistributionAmount` only used within scope.\\n {\\n // Keep a reference to the fee.\\n uint256 _feePercent = fee;\\n\\n // Get the amount of discount that should be applied to any fees taken.\\n // If the fee is zero, set the discount to 100% for convenience.\\n uint256 _feeDiscount = _feePercent == 0\\n ? JBConstants.MAX_FEE_DISCOUNT\\n : _currentFeeDiscount(_projectId, JBFeeType.PAYOUT);\\n\\n // The amount distributed that is eligible for incurring fees.\\n uint256 _feeEligibleDistributionAmount;\\n\\n // The amount leftover after distributing to the splits.\\n uint256 _leftoverDistributionAmount;\\n\\n // Payout to splits and get a reference to the leftover transfer amount after all splits have been paid.\\n // Also get a reference to the amount that was distributed to splits from which fees should be taken.\\n (_leftoverDistributionAmount, _feeEligibleDistributionAmount) = _distributeToPayoutSplitsOf(\\n _projectId,\\n _fundingCycle.configuration,\\n payoutSplitsGroup,\\n _distributedAmount,\\n _feePercent,\\n _feeDiscount\\n );\\n\\n if (_feeDiscount != JBConstants.MAX_FEE_DISCOUNT) {\\n // Leftover distribution amount is also eligible for a fee since the funds are going out of the ecosystem to _beneficiary.\\n unchecked {\\n _feeEligibleDistributionAmount += _leftoverDistributionAmount;\\n }\\n }\\n\\n // Take the fee.\\n _feeTaken = _feeEligibleDistributionAmount != 0\\n ? _takeFeeFrom(\\n _projectId,\\n _fundingCycle.shouldHoldFees(),\\n _feeEligibleDistributionAmount,\\n _feePercent,\\n _projectOwner,\\n _feeDiscount\\n )\\n : 0;\\n\\n // Transfer any remaining balance to the project owner and update returned leftover accordingly.\\n if (_leftoverDistributionAmount != 0) {\\n // Subtract the fee from the net leftover amount.\\n netLeftoverDistributionAmount =\\n _leftoverDistributionAmount -\\n (\\n _feeDiscount == JBConstants.MAX_FEE_DISCOUNT\\n ? 0\\n : _feeAmount(_leftoverDistributionAmount, _feePercent, _feeDiscount)\\n );\\n\\n // Transfer the amount to the project owner.\\n _transferFrom(address(this), _projectOwner, netLeftoverDistributionAmount);\\n }\\n }\\n\\n emit DistributePayouts(\\n _fundingCycle.configuration,\\n _fundingCycle.number,\\n _projectId,\\n _projectOwner,\\n _amount,\\n _distributedAmount,\\n _feeTaken,\\n netLeftoverDistributionAmount,\\n _metadata,\\n msg.sender\\n );\\n }\\n\\n /// @notice Allows a project to send funds from its overflow up to the preconfigured allowance.\\n /// @dev Only a project's owner or a designated operator can use its allowance.\\n /// @dev Incurs the protocol fee.\\n /// @param _projectId The ID of the project to use the allowance of.\\n /// @param _amount The amount of terminal tokens to use from this project's current allowance, as a fixed point number with the same amount of decimals as this terminal.\\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's overflow allowance currency.\\n /// @param _minReturnedTokens The minimum number of tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with 18 decimals.\\n /// @param _beneficiary The address to send the funds to.\\n /// @param _memo A memo to pass along to the emitted event.\\n /// @param _metadata Bytes to send along to the emitted event, if provided.\\n /// @return netDistributedAmount The amount of tokens that was distributed to the beneficiary, as a fixed point number with the same amount of decimals as the terminal.\\n function _useAllowanceOf(\\n uint256 _projectId,\\n uint256 _amount,\\n uint256 _currency,\\n uint256 _minReturnedTokens,\\n address payable _beneficiary,\\n string memory _memo,\\n bytes calldata _metadata\\n ) internal returns (uint256 netDistributedAmount) {\\n // Record the use of the allowance.\\n (\\n JBFundingCycle memory _fundingCycle,\\n uint256 _distributedAmount\\n ) = IJBSingleTokenPaymentTerminalStore3_1_1(store).recordUsedAllowanceOf(\\n _projectId,\\n _amount,\\n _currency\\n );\\n\\n // The amount being withdrawn must be at least as much as was expected.\\n if (_distributedAmount < _minReturnedTokens) revert INADEQUATE_DISTRIBUTION_AMOUNT();\\n\\n // Scoped section prevents stack too deep. `_fee`, `_projectOwner`, `_feeDiscount`, and `_netAmount` only used within scope.\\n {\\n // Keep a reference to the fee amount that was paid.\\n uint256 _feeTaken;\\n\\n // Keep a reference to the fee.\\n uint256 _feePercent = fee;\\n\\n // Get a reference to the project owner, which will receive tokens from paying the platform fee.\\n address _projectOwner = projects.ownerOf(_projectId);\\n\\n // Get the amount of discount that should be applied to any fees taken.\\n // 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.\\n uint256 _feeDiscount = _feePercent == 0 || isFeelessAddress[msg.sender]\\n ? JBConstants.MAX_FEE_DISCOUNT\\n : _currentFeeDiscount(_projectId, JBFeeType.ALLOWANCE);\\n\\n // Take a fee from the `_distributedAmount`, if needed.\\n _feeTaken = _feeDiscount == JBConstants.MAX_FEE_DISCOUNT\\n ? 0\\n : _takeFeeFrom(\\n _projectId,\\n _fundingCycle.shouldHoldFees(),\\n _distributedAmount,\\n _feePercent,\\n _projectOwner,\\n _feeDiscount\\n );\\n\\n unchecked {\\n // The net amount is the withdrawn amount without the fee.\\n netDistributedAmount = _distributedAmount - _feeTaken;\\n }\\n\\n // Transfer any remaining balance to the beneficiary.\\n if (netDistributedAmount != 0)\\n _transferFrom(address(this), _beneficiary, netDistributedAmount);\\n }\\n\\n emit UseAllowance(\\n _fundingCycle.configuration,\\n _fundingCycle.number,\\n _projectId,\\n _beneficiary,\\n _amount,\\n _distributedAmount,\\n netDistributedAmount,\\n _memo,\\n _metadata,\\n msg.sender\\n );\\n }\\n\\n /// @notice Pays out splits for a project's funding cycle configuration.\\n /// @param _projectId The ID of the project for which payout splits are being distributed.\\n /// @param _domain The domain of the splits to distribute the payout between.\\n /// @param _group The group of the splits to distribute the payout between.\\n /// @param _amount The total amount being distributed, as a fixed point number with the same number of decimals as this terminal.\\n /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE.\\n /// @param _feePercent The percent of fees to take, out of MAX_FEE.\\n /// @return If the leftover amount if the splits don't add up to 100%.\\n /// @return feeEligibleDistributionAmount The total amount of distributions that are eligible to have fees taken from.\\n function _distributeToPayoutSplitsOf(\\n uint256 _projectId,\\n uint256 _domain,\\n uint256 _group,\\n uint256 _amount,\\n uint256 _feePercent,\\n uint256 _feeDiscount\\n ) internal returns (uint256, uint256 feeEligibleDistributionAmount) {\\n // The total percentage available to split\\n uint256 _leftoverPercentage = JBConstants.SPLITS_TOTAL_PERCENT;\\n\\n // Get a reference to the project's payout splits.\\n JBSplit[] memory _splits = splitsStore.splitsOf(_projectId, _domain, _group);\\n\\n // Keep a reference to the split being iterated on.\\n JBSplit memory _split;\\n\\n // Transfer between all splits.\\n for (uint256 _i; _i < _splits.length; ) {\\n // Get a reference to the split being iterated on.\\n _split = _splits[_i];\\n\\n // The amount to send towards the split.\\n uint256 _payoutAmount = PRBMath.mulDiv(_amount, _split.percent, _leftoverPercentage);\\n\\n // The payout amount substracting any applicable incurred fees.\\n uint256 _netPayoutAmount = _distributeToPayoutSplit(\\n _split,\\n _projectId,\\n _group,\\n _payoutAmount,\\n _feePercent,\\n _feeDiscount\\n );\\n\\n // If the split allocator is set as feeless, this distribution is not eligible for a fee.\\n if (_netPayoutAmount != 0 && _netPayoutAmount != _payoutAmount)\\n feeEligibleDistributionAmount += _payoutAmount;\\n\\n if (_payoutAmount != 0) {\\n // Subtract from the amount to be sent to the beneficiary.\\n unchecked {\\n _amount -= _payoutAmount;\\n }\\n }\\n\\n unchecked {\\n // Decrement the leftover percentage.\\n _leftoverPercentage -= _split.percent;\\n }\\n\\n emit DistributeToPayoutSplit(\\n _projectId,\\n _domain,\\n _group,\\n _split,\\n _payoutAmount,\\n _netPayoutAmount,\\n msg.sender\\n );\\n\\n unchecked {\\n ++_i;\\n }\\n }\\n\\n return (_amount, feeEligibleDistributionAmount);\\n }\\n\\n /// @notice Pays out a split for a project's funding cycle configuration.\\n /// @param _split The split to distribute payouts to.\\n /// @param _amount The total amount being distributed to the split, as a fixed point number with the same number of decimals as this terminal.\\n /// @param _feePercent The percent of fees to take, out of MAX_FEE.\\n /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE.\\n /// @return netPayoutAmount The amount sent to the split after subtracting fees.\\n function _distributeToPayoutSplit(\\n JBSplit memory _split,\\n uint256 _projectId,\\n uint256 _group,\\n uint256 _amount,\\n uint256 _feePercent,\\n uint256 _feeDiscount\\n ) internal returns (uint256 netPayoutAmount) {\\n // By default, the net payout amount is the full amount. This will be adjusted if fees are taken.\\n netPayoutAmount = _amount;\\n\\n // If there's an allocator set, transfer to its `allocate` function.\\n if (_split.allocator != IJBSplitAllocator(address(0))) {\\n // This distribution is eligible for a fee since the funds are leaving this contract and the allocator isn't listed as feeless.\\n if (\\n _feeDiscount != JBConstants.MAX_FEE_DISCOUNT && !isFeelessAddress[address(_split.allocator)]\\n ) {\\n unchecked {\\n netPayoutAmount -= _feeAmount(_amount, _feePercent, _feeDiscount);\\n }\\n }\\n\\n // Trigger any inherited pre-transfer logic.\\n _beforeTransferTo(address(_split.allocator), netPayoutAmount);\\n\\n // Create the data to send to the allocator.\\n JBSplitAllocationData memory _data = JBSplitAllocationData(\\n token,\\n netPayoutAmount,\\n decimals,\\n _projectId,\\n _group,\\n _split\\n );\\n\\n // Trigger the allocator's `allocate` function.\\n bytes memory _reason;\\n\\n if (\\n ERC165Checker.supportsInterface(\\n address(_split.allocator),\\n type(IJBSplitAllocator).interfaceId\\n )\\n )\\n // If this terminal's token is ETH, send it in msg.value.\\n try\\n _split.allocator.allocate{value: token == JBTokens.ETH ? netPayoutAmount : 0}(_data)\\n {} catch (bytes memory __reason) {\\n _reason = __reason.length == 0 ? abi.encode('Allocate fail') : __reason;\\n }\\n else {\\n _reason = abi.encode('IERC165 fail');\\n }\\n\\n if (_reason.length != 0) {\\n // Revert the payout.\\n _revertTransferFrom(_projectId, address(_split.allocator), netPayoutAmount, _amount);\\n\\n // Set the net payout amount to 0 to signal the reversion.\\n netPayoutAmount = 0;\\n\\n emit PayoutReverted(_projectId, _split, _amount, _reason, msg.sender);\\n }\\n\\n // Otherwise, if a project is specified, make a payment to it.\\n } else if (_split.projectId != 0) {\\n // Get a reference to the Juicebox terminal being used.\\n IJBPaymentTerminal _terminal = directory.primaryTerminalOf(_split.projectId, token);\\n\\n // The project must have a terminal to send funds to.\\n if (_terminal == IJBPaymentTerminal(address(0))) {\\n // Set the net payout amount to 0 to signal the reversion.\\n netPayoutAmount = 0;\\n\\n // Revert the payout.\\n _revertTransferFrom(_projectId, address(0), 0, _amount);\\n\\n emit PayoutReverted(_projectId, _split, _amount, 'Terminal not found', msg.sender);\\n } else {\\n // This distribution is eligible for a fee since the funds are leaving this contract and the terminal isn't listed as feeless.\\n if (\\n _terminal != this &&\\n _feeDiscount != JBConstants.MAX_FEE_DISCOUNT &&\\n !isFeelessAddress[address(_terminal)]\\n ) {\\n unchecked {\\n netPayoutAmount -= _feeAmount(_amount, _feePercent, _feeDiscount);\\n }\\n }\\n\\n // Trigger any inherited pre-transfer logic.\\n _beforeTransferTo(address(_terminal), netPayoutAmount);\\n\\n // Add to balance if prefered.\\n if (_split.preferAddToBalance)\\n try\\n _terminal.addToBalanceOf{value: token == JBTokens.ETH ? netPayoutAmount : 0}(\\n _split.projectId,\\n netPayoutAmount,\\n token,\\n '',\\n // Send the projectId in the metadata as a referral.\\n bytes(abi.encodePacked(_projectId))\\n )\\n {} catch (bytes memory _reason) {\\n // Revert the payout.\\n _revertTransferFrom(_projectId, address(_terminal), netPayoutAmount, _amount);\\n\\n // Set the net payout amount to 0 to signal the reversion.\\n netPayoutAmount = 0;\\n\\n emit PayoutReverted(_projectId, _split, _amount, _reason, msg.sender);\\n }\\n else\\n try\\n _terminal.pay{value: token == JBTokens.ETH ? netPayoutAmount : 0}(\\n _split.projectId,\\n netPayoutAmount,\\n token,\\n _split.beneficiary != address(0) ? _split.beneficiary : msg.sender,\\n 0,\\n _split.preferClaimed,\\n '',\\n // Send the projectId in the metadata as a referral.\\n bytes(abi.encodePacked(_projectId))\\n )\\n {} catch (bytes memory _reason) {\\n // Revert the payout.\\n _revertTransferFrom(_projectId, address(_terminal), netPayoutAmount, _amount);\\n\\n // Set the net payout amount to 0 to signal the reversion.\\n netPayoutAmount = 0;\\n\\n emit PayoutReverted(_projectId, _split, _amount, _reason, msg.sender);\\n }\\n }\\n } else {\\n // This distribution is eligible for a fee since the funds are leaving this contract and the beneficiary isn't listed as feeless.\\n // Don't enforce feeless address for the beneficiary since the funds are leaving the ecosystem.\\n if (_feeDiscount != JBConstants.MAX_FEE_DISCOUNT) {\\n unchecked {\\n netPayoutAmount -= _feeAmount(_amount, _feePercent, _feeDiscount);\\n }\\n }\\n\\n // If there's a beneficiary, send the funds directly to the beneficiary. Otherwise send to the msg.sender.\\n _transferFrom(\\n address(this),\\n _split.beneficiary != address(0) ? _split.beneficiary : payable(msg.sender),\\n netPayoutAmount\\n );\\n }\\n }\\n\\n /// @notice Takes a fee into the platform's project, which has an id of _FEE_BENEFICIARY_PROJECT_ID.\\n /// @param _projectId The ID of the project having fees taken from.\\n /// @param _shouldHoldFees If fees should be tracked and held back.\\n /// @param _feePercent The percent of fees to take, out of MAX_FEE.\\n /// @param _amount The amount of the fee to take, as a floating point number with 18 decimals.\\n /// @param _beneficiary The address to mint the platforms tokens for.\\n /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE.\\n /// @return feeAmount The amount of the fee taken.\\n function _takeFeeFrom(\\n uint256 _projectId,\\n bool _shouldHoldFees,\\n uint256 _amount,\\n uint256 _feePercent,\\n address _beneficiary,\\n uint256 _feeDiscount\\n ) internal returns (uint256 feeAmount) {\\n feeAmount = _feeAmount(_amount, _feePercent, _feeDiscount);\\n\\n if (_shouldHoldFees) {\\n // Store the held fee.\\n _heldFeesOf[_projectId].push(\\n JBFee(_amount, uint32(_feePercent), uint32(_feeDiscount), _beneficiary)\\n );\\n\\n emit HoldFee(_projectId, _amount, _feePercent, _feeDiscount, _beneficiary, msg.sender);\\n } else {\\n // Process the fee.\\n _processFee(feeAmount, _beneficiary, _projectId); // Take the fee.\\n\\n emit ProcessFee(_projectId, feeAmount, false, _beneficiary, msg.sender);\\n }\\n }\\n\\n /// @notice Process a fee of the specified amount.\\n /// @param _amount The fee amount, as a floating point number with 18 decimals.\\n /// @param _beneficiary The address to mint the platform's tokens for.\\n /// @param _from The project ID the fee is being paid from.\\n function _processFee(uint256 _amount, address _beneficiary, uint256 _from) internal {\\n // Get the terminal for the protocol project.\\n IJBPaymentTerminal _terminal = directory.primaryTerminalOf(_FEE_BENEFICIARY_PROJECT_ID, token);\\n\\n // Trigger any inherited pre-transfer logic if funds will be transferred.\\n if (address(_terminal) != address(this)) _beforeTransferTo(address(_terminal), _amount);\\n\\n try\\n // Send the fee.\\n // If this terminal's token is ETH, send it in msg.value.\\n _terminal.pay{value: token == JBTokens.ETH ? _amount : 0}(\\n _FEE_BENEFICIARY_PROJECT_ID,\\n _amount,\\n token,\\n _beneficiary,\\n 0,\\n false,\\n '',\\n // Send the projectId in the metadata.\\n bytes(abi.encodePacked(_from))\\n )\\n {} catch (bytes memory _reason) {\\n _revertTransferFrom(\\n _from,\\n address(_terminal) != address(this) ? address(_terminal) : address(0),\\n address(_terminal) != address(this) ? _amount : 0,\\n _amount\\n );\\n emit FeeReverted(_from, _FEE_BENEFICIARY_PROJECT_ID, _amount, _reason, msg.sender);\\n }\\n }\\n\\n /// @notice Reverts an expected payout.\\n /// @param _projectId The ID of the project having paying out.\\n /// @param _expectedDestination The address the payout was expected to go to.\\n /// @param _allowanceAmount The amount that the destination has been allowed to use.\\n /// @param _depositAmount The amount of the payout as debited from the project's balance.\\n function _revertTransferFrom(\\n uint256 _projectId,\\n address _expectedDestination,\\n uint256 _allowanceAmount,\\n uint256 _depositAmount\\n ) internal {\\n // Cancel allowance if needed.\\n if (_allowanceAmount != 0) _cancelTransferTo(_expectedDestination, _allowanceAmount);\\n\\n // Add undistributed amount back to project's balance.\\n IJBSingleTokenPaymentTerminalStore3_1_1(store).recordAddedBalanceFor(\\n _projectId,\\n _depositAmount\\n );\\n }\\n\\n /// @notice Contribute tokens to a project.\\n /// @param _amount The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place.\\n /// @param _payer The address making the payment.\\n /// @param _projectId The ID of the project being paid.\\n /// @param _beneficiary The address to mint tokens for and pass along to the funding cycle's data source and delegate.\\n /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal.\\n /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\\n /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\\n /// @return beneficiaryTokenCount The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals.\\n function _pay(\\n uint256 _amount,\\n address _payer,\\n uint256 _projectId,\\n address _beneficiary,\\n uint256 _minReturnedTokens,\\n bool _preferClaimedTokens,\\n string memory _memo,\\n bytes memory _metadata\\n ) internal returns (uint256 beneficiaryTokenCount) {\\n // Cant send tokens to the zero address.\\n if (_beneficiary == address(0)) revert PAY_TO_ZERO_ADDRESS();\\n\\n // Define variables that will be needed outside the scoped section below.\\n // Keep a reference to the funding cycle during which the payment is being made.\\n JBFundingCycle memory _fundingCycle;\\n\\n // Scoped section prevents stack too deep. `_delegateAllocations` and `_tokenCount` only used within scope.\\n {\\n JBPayDelegateAllocation3_1_1[] memory _delegateAllocations;\\n uint256 _tokenCount;\\n\\n // Bundle the amount info into a JBTokenAmount struct.\\n JBTokenAmount memory _bundledAmount = JBTokenAmount(token, _amount, decimals, currency);\\n\\n // Record the payment.\\n (\\n _fundingCycle,\\n _tokenCount,\\n _delegateAllocations,\\n _memo\\n ) = IJBSingleTokenPaymentTerminalStore3_1_1(store).recordPaymentFrom(\\n _payer,\\n _bundledAmount,\\n _projectId,\\n baseWeightCurrency,\\n _beneficiary,\\n _memo,\\n _metadata\\n );\\n\\n // Mint the tokens if needed.\\n if (_tokenCount != 0)\\n // Set token count to be the number of tokens minted for the beneficiary instead of the total amount.\\n beneficiaryTokenCount = IJBController(directory.controllerOf(_projectId)).mintTokensOf(\\n _projectId,\\n _tokenCount,\\n _beneficiary,\\n '',\\n _preferClaimedTokens,\\n true\\n );\\n\\n // The token count for the beneficiary must be greater than or equal to the minimum expected.\\n if (beneficiaryTokenCount < _minReturnedTokens) revert INADEQUATE_TOKEN_COUNT();\\n\\n // If delegate allocations were specified by the data source, fulfill them.\\n if (_delegateAllocations.length != 0) {\\n JBDidPayData3_1_1 memory _data = JBDidPayData3_1_1(\\n _payer,\\n _projectId,\\n _fundingCycle.configuration,\\n _bundledAmount,\\n JBTokenAmount(token, 0, decimals, currency),\\n beneficiaryTokenCount,\\n _beneficiary,\\n _preferClaimedTokens,\\n _memo,\\n bytes(''),\\n _metadata\\n );\\n\\n // Get a reference to the number of delegates to allocate to.\\n uint256 _numDelegates = _delegateAllocations.length;\\n\\n // Keep a reference to the allocation.\\n JBPayDelegateAllocation3_1_1 memory _delegateAllocation;\\n\\n for (uint256 _i; _i < _numDelegates; ) {\\n // Get a reference to the delegate being iterated on.\\n _delegateAllocation = _delegateAllocations[_i];\\n\\n // Trigger any inherited pre-transfer logic.\\n _beforeTransferTo(address(_delegateAllocation.delegate), _delegateAllocation.amount);\\n\\n // Pass the correct token forwardedAmount to the delegate\\n _data.forwardedAmount.value = _delegateAllocation.amount;\\n\\n // Pass the correct metadata from the data source.\\n _data.dataSourceMetadata = _delegateAllocation.metadata;\\n\\n _delegateAllocation.delegate.didPay{\\n value: token == JBTokens.ETH ? _delegateAllocation.amount : 0\\n }(_data);\\n\\n emit DelegateDidPay(\\n _delegateAllocation.delegate,\\n _data,\\n _delegateAllocation.amount,\\n msg.sender\\n );\\n\\n unchecked {\\n ++_i;\\n }\\n }\\n }\\n }\\n\\n emit Pay(\\n _fundingCycle.configuration,\\n _fundingCycle.number,\\n _projectId,\\n _payer,\\n _beneficiary,\\n _amount,\\n beneficiaryTokenCount,\\n _memo,\\n _metadata,\\n msg.sender\\n );\\n }\\n\\n /// @notice Receives funds belonging to the specified project.\\n /// @param _projectId The ID of the project to which the funds received belong.\\n /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\\n /// @param _shouldRefundHeldFees A flag indicating if held fees should be refunded based on the amount being added.\\n /// @param _memo A memo to pass along to the emitted event.\\n /// @param _metadata Extra data to pass along to the emitted event.\\n function _addToBalanceOf(\\n uint256 _projectId,\\n uint256 _amount,\\n bool _shouldRefundHeldFees,\\n string memory _memo,\\n bytes memory _metadata\\n ) internal {\\n // Refund any held fees to make sure the project doesn't pay double for funds going in and out of the protocol.\\n uint256 _refundedFees = _shouldRefundHeldFees ? _refundHeldFees(_projectId, _amount) : 0;\\n\\n // Record the added funds with any refunded fees.\\n IJBSingleTokenPaymentTerminalStore3_1_1(store).recordAddedBalanceFor(\\n _projectId,\\n _amount + _refundedFees\\n );\\n\\n emit AddToBalance(_projectId, _amount, _refundedFees, _memo, _metadata, msg.sender);\\n }\\n\\n /// @notice Refund fees based on the specified amount.\\n /// @param _projectId The project for which fees are being refunded.\\n /// @param _amount The amount to base the refund on, as a fixed point number with the same amount of decimals as this terminal.\\n /// @return refundedFees How much fees were refunded, as a fixed point number with the same number of decimals as this terminal\\n function _refundHeldFees(\\n uint256 _projectId,\\n uint256 _amount\\n ) internal returns (uint256 refundedFees) {\\n // Get a reference to the project's held fees.\\n JBFee[] memory _heldFees = _heldFeesOf[_projectId];\\n\\n // Delete the current held fees.\\n delete _heldFeesOf[_projectId];\\n\\n // Get a reference to the leftover amount once all fees have been settled.\\n uint256 leftoverAmount = _amount;\\n\\n // Push length in stack\\n uint256 _heldFeesLength = _heldFees.length;\\n\\n // Process each fee.\\n for (uint256 _i; _i < _heldFeesLength; ) {\\n if (leftoverAmount == 0) _heldFeesOf[_projectId].push(_heldFees[_i]);\\n else if (leftoverAmount >= _heldFees[_i].amount) {\\n unchecked {\\n leftoverAmount = leftoverAmount - _heldFees[_i].amount;\\n refundedFees += (\\n _heldFees[_i].fee == 0 || _heldFees[_i].feeDiscount == JBConstants.MAX_FEE_DISCOUNT\\n ? 0\\n : _feeAmount(_heldFees[_i].amount, _heldFees[_i].fee, _heldFees[_i].feeDiscount)\\n );\\n }\\n } else {\\n unchecked {\\n _heldFeesOf[_projectId].push(\\n JBFee(\\n _heldFees[_i].amount - leftoverAmount,\\n _heldFees[_i].fee,\\n _heldFees[_i].feeDiscount,\\n _heldFees[_i].beneficiary\\n )\\n );\\n refundedFees += (\\n _heldFees[_i].fee == 0 || _heldFees[_i].feeDiscount == JBConstants.MAX_FEE_DISCOUNT\\n ? 0\\n : _feeAmount(leftoverAmount, _heldFees[_i].fee, _heldFees[_i].feeDiscount)\\n );\\n }\\n leftoverAmount = 0;\\n }\\n\\n unchecked {\\n ++_i;\\n }\\n }\\n\\n emit RefundHeldFees(_projectId, _amount, refundedFees, leftoverAmount, msg.sender);\\n }\\n\\n /// @notice Returns the fee amount based on the provided amount for the specified project.\\n /// @param _amount The amount that the fee is based on, as a fixed point number with the same amount of decimals as this terminal.\\n /// @param _fee The percentage of the fee, out of MAX_FEE.\\n /// @param _feeDiscount The percentage discount that should be applied out of the max amount, out of MAX_FEE_DISCOUNT.\\n /// @return The amount of the fee, as a fixed point number with the same amount of decimals as this terminal.\\n function _feeAmount(\\n uint256 _amount,\\n uint256 _fee,\\n uint256 _feeDiscount\\n ) internal pure returns (uint256) {\\n // Calculate the discounted fee.\\n uint256 _discountedFee = _fee -\\n PRBMath.mulDiv(_fee, _feeDiscount, JBConstants.MAX_FEE_DISCOUNT);\\n\\n // The amount of tokens from the `_amount` to pay as a fee.\\n return\\n _amount - PRBMath.mulDiv(_amount, JBConstants.MAX_FEE, _discountedFee + JBConstants.MAX_FEE);\\n }\\n\\n /// @notice Get the fee discount from the fee gauge for the specified project.\\n /// @param _projectId The ID of the project to get a fee discount for.\\n /// @param _feeType The type of fee the discount is being applied to.\\n /// @return feeDiscount The fee discount, which should be interpreted as a percentage out MAX_FEE_DISCOUNT.\\n function _currentFeeDiscount(\\n uint256 _projectId,\\n JBFeeType _feeType\\n ) internal view returns (uint256) {\\n // Can't take a fee if the protocol project doesn't have a terminal that accepts the token.\\n if (\\n directory.primaryTerminalOf(_FEE_BENEFICIARY_PROJECT_ID, token) ==\\n IJBPaymentTerminal(address(0))\\n ) return JBConstants.MAX_FEE_DISCOUNT;\\n\\n // Get the fee discount.\\n if (feeGauge != address(0))\\n // If the guage reverts, keep the discount at 0.\\n try IJBFeeGauge3_1(feeGauge).currentDiscountFor(_projectId, _feeType) returns (\\n uint256 discount\\n ) {\\n // If the fee discount is greater than the max, we ignore the return value\\n if (discount <= JBConstants.MAX_FEE_DISCOUNT) return discount;\\n } catch {\\n return 0;\\n }\\n\\n return 0;\\n }\\n}\\n\",\"keccak256\":\"0xac6578a64c8c0544d26442921ae6b577f86e3f18e6338c7eda9ee2f5eb2c927d\",\"license\":\"MIT\"},\"contracts/abstract/JBSingleTokenPaymentTerminal.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.16;\\n\\nimport {ERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol';\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol';\\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\\nimport {IJBSingleTokenPaymentTerminal} from './../interfaces/IJBSingleTokenPaymentTerminal.sol';\\n\\n/// @notice Generic terminal managing all inflows of funds into the protocol ecosystem for one token.\\nabstract contract JBSingleTokenPaymentTerminal is ERC165, IJBSingleTokenPaymentTerminal {\\n //*********************************************************************//\\n // ---------------- public immutable stored properties --------------- //\\n //*********************************************************************//\\n\\n /// @notice The token that this terminal accepts.\\n address public immutable override token;\\n\\n /// @notice The number of decimals the token fixed point amounts are expected to have.\\n uint256 public immutable override decimals;\\n\\n /// @notice The currency to use when resolving price feeds for this terminal.\\n uint256 public immutable override currency;\\n\\n //*********************************************************************//\\n // ------------------------- external views -------------------------- //\\n //*********************************************************************//\\n\\n /// @notice A flag indicating if this terminal accepts the specified token.\\n /// @param _token The token to check if this terminal accepts or not.\\n /// @param _projectId The project ID to check for token acceptance.\\n /// @return The flag.\\n function acceptsToken(address _token, uint256 _projectId) external view override returns (bool) {\\n _projectId; // Prevents unused var compiler and natspec complaints.\\n\\n return _token == token;\\n }\\n\\n /// @notice The decimals that should be used in fixed number accounting for the specified token.\\n /// @param _token The token to check for the decimals of.\\n /// @return The number of decimals for the token.\\n function decimalsForToken(address _token) external view override returns (uint256) {\\n _token; // Prevents unused var compiler and natspec complaints.\\n\\n return decimals;\\n }\\n\\n /// @notice The currency that should be used for the specified token.\\n /// @param _token The token to check for the currency of.\\n /// @return The currency index.\\n function currencyForToken(address _token) external view override returns (uint256) {\\n _token; // Prevents unused var compiler and natspec complaints.\\n\\n return currency;\\n }\\n\\n //*********************************************************************//\\n // -------------------------- public views --------------------------- //\\n //*********************************************************************//\\n\\n /// @notice Indicates if this contract adheres to the specified interface.\\n /// @dev See {IERC165-supportsInterface}.\\n /// @param _interfaceId The ID of the interface to check for adherance to.\\n /// @return A flag indicating if the provided interface ID is supported.\\n function supportsInterface(\\n bytes4 _interfaceId\\n ) public view virtual override(ERC165, IERC165) returns (bool) {\\n return\\n _interfaceId == type(IJBPaymentTerminal).interfaceId ||\\n _interfaceId == type(IJBSingleTokenPaymentTerminal).interfaceId ||\\n super.supportsInterface(_interfaceId);\\n }\\n\\n //*********************************************************************//\\n // -------------------------- constructor ---------------------------- //\\n //*********************************************************************//\\n\\n /// @param _token The token that this terminal manages.\\n /// @param _decimals The number of decimals the token fixed point amounts are expected to have.\\n /// @param _currency The currency that this terminal's token adheres to for price feeds.\\n constructor(address _token, uint256 _decimals, uint256 _currency) {\\n token = _token;\\n decimals = _decimals;\\n currency = _currency;\\n }\\n}\\n\",\"keccak256\":\"0x27bd0b9e8170f16bc1318d6dee16aa3273e7d8f6cb8b80d7d905d0dce93e307c\",\"license\":\"MIT\"},\"contracts/enums/JBBallotState.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nenum JBBallotState {\\n Active,\\n Approved,\\n Failed\\n}\\n\",\"keccak256\":\"0x891fcac63470398b3a11239da7feba6b07d640809fcefd2404303b823d7378f8\",\"license\":\"MIT\"},\"contracts/enums/JBFeeType.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nenum JBFeeType {\\n PAYOUT,\\n ALLOWANCE,\\n REDEMPTION\\n}\\n\",\"keccak256\":\"0x02418e9bd3cce5ccf5a76822909558c61672719767bffe16490256268b05cb22\",\"license\":\"MIT\"},\"contracts/interfaces/IJBAllowanceTerminal3_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IJBAllowanceTerminal3_1 {\\n function useAllowanceOf(\\n uint256 projectId,\\n uint256 amount,\\n uint256 currency,\\n address token,\\n uint256 minReturnedTokens,\\n address payable beneficiary,\\n string calldata memo,\\n bytes calldata metadata\\n ) external returns (uint256 netDistributedAmount);\\n}\\n\",\"keccak256\":\"0x3d9f7edf01473dd1bf444c2c9c2cae93e5980e17134e77efd50ad1723fa66559\",\"license\":\"MIT\"},\"contracts/interfaces/IJBController.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\\nimport {JBBallotState} from './../enums/JBBallotState.sol';\\nimport {JBFundAccessConstraints} from './../structs/JBFundAccessConstraints.sol';\\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\\nimport {JBFundingCycleData} from './../structs/JBFundingCycleData.sol';\\nimport {JBFundingCycleMetadata} from './../structs/JBFundingCycleMetadata.sol';\\nimport {JBGroupedSplits} from './../structs/JBGroupedSplits.sol';\\nimport {JBProjectMetadata} from './../structs/JBProjectMetadata.sol';\\nimport {JBSplit} from './../structs/JBSplit.sol';\\nimport {IJBDirectory} from './IJBDirectory.sol';\\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\\nimport {IJBMigratable} from './IJBMigratable.sol';\\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\\nimport {IJBProjects} from './IJBProjects.sol';\\nimport {IJBSplitsStore} from './IJBSplitsStore.sol';\\nimport {IJBTokenStore} from './IJBTokenStore.sol';\\n\\ninterface IJBController is IERC165 {\\n event LaunchProject(uint256 configuration, uint256 projectId, string memo, address caller);\\n\\n event LaunchFundingCycles(uint256 configuration, uint256 projectId, string memo, address caller);\\n\\n event ReconfigureFundingCycles(\\n uint256 configuration,\\n uint256 projectId,\\n string memo,\\n address caller\\n );\\n\\n event SetFundAccessConstraints(\\n uint256 indexed fundingCycleConfiguration,\\n uint256 indexed fundingCycleNumber,\\n uint256 indexed projectId,\\n JBFundAccessConstraints constraints,\\n address caller\\n );\\n\\n event DistributeReservedTokens(\\n uint256 indexed fundingCycleConfiguration,\\n uint256 indexed fundingCycleNumber,\\n uint256 indexed projectId,\\n address beneficiary,\\n uint256 tokenCount,\\n uint256 beneficiaryTokenCount,\\n string memo,\\n address caller\\n );\\n\\n event DistributeToReservedTokenSplit(\\n uint256 indexed projectId,\\n uint256 indexed domain,\\n uint256 indexed group,\\n JBSplit split,\\n uint256 tokenCount,\\n address caller\\n );\\n\\n event MintTokens(\\n address indexed beneficiary,\\n uint256 indexed projectId,\\n uint256 tokenCount,\\n uint256 beneficiaryTokenCount,\\n string memo,\\n uint256 reservedRate,\\n address caller\\n );\\n\\n event BurnTokens(\\n address indexed holder,\\n uint256 indexed projectId,\\n uint256 tokenCount,\\n string memo,\\n address caller\\n );\\n\\n event Migrate(uint256 indexed projectId, IJBMigratable to, address caller);\\n\\n event PrepMigration(uint256 indexed projectId, address from, address caller);\\n\\n function projects() external view returns (IJBProjects);\\n\\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\\n\\n function tokenStore() external view returns (IJBTokenStore);\\n\\n function splitsStore() external view returns (IJBSplitsStore);\\n\\n function directory() external view returns (IJBDirectory);\\n\\n function reservedTokenBalanceOf(\\n uint256 projectId,\\n uint256 reservedRate\\n ) external view returns (uint256);\\n\\n function distributionLimitOf(\\n uint256 projectId,\\n uint256 configuration,\\n IJBPaymentTerminal terminal,\\n address token\\n ) external view returns (uint256 distributionLimit, uint256 distributionLimitCurrency);\\n\\n function overflowAllowanceOf(\\n uint256 projectId,\\n uint256 configuration,\\n IJBPaymentTerminal terminal,\\n address token\\n ) external view returns (uint256 overflowAllowance, uint256 overflowAllowanceCurrency);\\n\\n function totalOutstandingTokensOf(\\n uint256 projectId,\\n uint256 reservedRate\\n ) external view returns (uint256);\\n\\n function getFundingCycleOf(\\n uint256 projectId,\\n uint256 configuration\\n )\\n external\\n view\\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata);\\n\\n function latestConfiguredFundingCycleOf(\\n uint256 projectId\\n )\\n external\\n view\\n returns (JBFundingCycle memory, JBFundingCycleMetadata memory metadata, JBBallotState);\\n\\n function currentFundingCycleOf(\\n uint256 projectId\\n )\\n external\\n view\\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata);\\n\\n function queuedFundingCycleOf(\\n uint256 projectId\\n )\\n external\\n view\\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata);\\n\\n function launchProjectFor(\\n address owner,\\n JBProjectMetadata calldata projectMetadata,\\n JBFundingCycleData calldata data,\\n JBFundingCycleMetadata calldata metadata,\\n uint256 mustStartAtOrAfter,\\n JBGroupedSplits[] memory groupedSplits,\\n JBFundAccessConstraints[] memory fundAccessConstraints,\\n IJBPaymentTerminal[] memory terminals,\\n string calldata memo\\n ) external returns (uint256 projectId);\\n\\n function launchFundingCyclesFor(\\n uint256 projectId,\\n JBFundingCycleData calldata data,\\n JBFundingCycleMetadata calldata metadata,\\n uint256 mustStartAtOrAfter,\\n JBGroupedSplits[] memory groupedSplits,\\n JBFundAccessConstraints[] memory fundAccessConstraints,\\n IJBPaymentTerminal[] memory terminals,\\n string calldata memo\\n ) external returns (uint256 configuration);\\n\\n function reconfigureFundingCyclesOf(\\n uint256 projectId,\\n JBFundingCycleData calldata data,\\n JBFundingCycleMetadata calldata metadata,\\n uint256 mustStartAtOrAfter,\\n JBGroupedSplits[] memory groupedSplits,\\n JBFundAccessConstraints[] memory fundAccessConstraints,\\n string calldata memo\\n ) external returns (uint256);\\n\\n function mintTokensOf(\\n uint256 projectId,\\n uint256 tokenCount,\\n address beneficiary,\\n string calldata memo,\\n bool preferClaimedTokens,\\n bool useReservedRate\\n ) external returns (uint256 beneficiaryTokenCount);\\n\\n function burnTokensOf(\\n address holder,\\n uint256 projectId,\\n uint256 tokenCount,\\n string calldata memo,\\n bool preferClaimedTokens\\n ) external;\\n\\n function distributeReservedTokensOf(\\n uint256 projectId,\\n string memory memo\\n ) external returns (uint256);\\n\\n function migrate(uint256 projectId, IJBMigratable to) external;\\n}\\n\",\"keccak256\":\"0x6ebcb31173eff32f16f2f1fa6979a9dad0d7fac51e34441fafffa5e097ad507f\",\"license\":\"MIT\"},\"contracts/interfaces/IJBDirectory.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\\nimport {IJBProjects} from './IJBProjects.sol';\\n\\ninterface IJBDirectory {\\n event SetController(uint256 indexed projectId, address indexed controller, address caller);\\n\\n event AddTerminal(uint256 indexed projectId, IJBPaymentTerminal indexed terminal, address caller);\\n\\n event SetTerminals(uint256 indexed projectId, IJBPaymentTerminal[] terminals, address caller);\\n\\n event SetPrimaryTerminal(\\n uint256 indexed projectId,\\n address indexed token,\\n IJBPaymentTerminal indexed terminal,\\n address caller\\n );\\n\\n event SetIsAllowedToSetFirstController(address indexed addr, bool indexed flag, address caller);\\n\\n function projects() external view returns (IJBProjects);\\n\\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\\n\\n function controllerOf(uint256 projectId) external view returns (address);\\n\\n function isAllowedToSetFirstController(address account) external view returns (bool);\\n\\n function terminalsOf(uint256 projectId) external view returns (IJBPaymentTerminal[] memory);\\n\\n function isTerminalOf(\\n uint256 projectId,\\n IJBPaymentTerminal terminal\\n ) external view returns (bool);\\n\\n function primaryTerminalOf(\\n uint256 projectId,\\n address token\\n ) external view returns (IJBPaymentTerminal);\\n\\n function setControllerOf(uint256 projectId, address controller) external;\\n\\n function setTerminalsOf(uint256 projectId, IJBPaymentTerminal[] calldata terminals) external;\\n\\n function setPrimaryTerminalOf(\\n uint256 projectId,\\n address token,\\n IJBPaymentTerminal terminal\\n ) external;\\n\\n function setIsAllowedToSetFirstController(address account, bool flag) external;\\n}\\n\",\"keccak256\":\"0x490d5fe691ee7d9c9179fa19964de279882176513d92f3efc0aa98dc34799d1c\",\"license\":\"MIT\"},\"contracts/interfaces/IJBFeeGauge3_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBFeeType} from './../enums/JBFeeType.sol';\\n\\ninterface IJBFeeGauge3_1 {\\n function currentDiscountFor(uint256 projectId, JBFeeType feeType) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0xcf64e4b203422b50c968e890e3cf8621b63014e59dc8be25f13884c316f95266\",\"license\":\"MIT\"},\"contracts/interfaces/IJBFeeHoldingTerminal.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IJBFeeHoldingTerminal {\\n function addToBalanceOf(\\n uint256 projectId,\\n uint256 amount,\\n address token,\\n bool shouldRefundHeldFees,\\n string calldata memo,\\n bytes calldata metadata\\n ) external payable;\\n}\\n\",\"keccak256\":\"0xdda2332beec8a4f7f5ecd45a660b11796516933998b397c5d05ae639b5755454\",\"license\":\"MIT\"},\"contracts/interfaces/IJBFundingCycleBallot.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\\nimport {JBBallotState} from './../enums/JBBallotState.sol';\\n\\ninterface IJBFundingCycleBallot is IERC165 {\\n function duration() external view returns (uint256);\\n\\n function stateOf(\\n uint256 projectId,\\n uint256 configuration,\\n uint256 start\\n ) external view returns (JBBallotState);\\n}\\n\",\"keccak256\":\"0x729b4a700618f890e434d31ef9252e1cce9d0473fe7f8f070872df5b348bed23\",\"license\":\"MIT\"},\"contracts/interfaces/IJBFundingCycleStore.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBBallotState} from './../enums/JBBallotState.sol';\\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\\nimport {JBFundingCycleData} from './../structs/JBFundingCycleData.sol';\\n\\ninterface IJBFundingCycleStore {\\n event Configure(\\n uint256 indexed configuration,\\n uint256 indexed projectId,\\n JBFundingCycleData data,\\n uint256 metadata,\\n uint256 mustStartAtOrAfter,\\n address caller\\n );\\n\\n event Init(uint256 indexed configuration, uint256 indexed projectId, uint256 indexed basedOn);\\n\\n function latestConfigurationOf(uint256 projectId) external view returns (uint256);\\n\\n function get(\\n uint256 projectId,\\n uint256 configuration\\n ) external view returns (JBFundingCycle memory);\\n\\n function latestConfiguredOf(\\n uint256 projectId\\n ) external view returns (JBFundingCycle memory fundingCycle, JBBallotState ballotState);\\n\\n function queuedOf(uint256 projectId) external view returns (JBFundingCycle memory fundingCycle);\\n\\n function currentOf(uint256 projectId) external view returns (JBFundingCycle memory fundingCycle);\\n\\n function currentBallotStateOf(uint256 projectId) external view returns (JBBallotState);\\n\\n function configureFor(\\n uint256 projectId,\\n JBFundingCycleData calldata data,\\n uint256 metadata,\\n uint256 mustStartAtOrAfter\\n ) external returns (JBFundingCycle memory fundingCycle);\\n}\\n\",\"keccak256\":\"0x524350f6c6fcb45eaf927f4e6d13cd2f5029c2b858233bb9a338fe411ce34dab\",\"license\":\"MIT\"},\"contracts/interfaces/IJBMigratable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IJBMigratable {\\n function prepForMigrationOf(uint256 projectId, address from) external;\\n}\\n\",\"keccak256\":\"0xdee578477bbb7a66e9a1735e45a7795e95cfd374d85f55b61b3302476844c418\",\"license\":\"MIT\"},\"contracts/interfaces/IJBOperatable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBOperatorStore} from './IJBOperatorStore.sol';\\n\\ninterface IJBOperatable {\\n function operatorStore() external view returns (IJBOperatorStore);\\n}\\n\",\"keccak256\":\"0xe083d0c1b181e5c38cf3f03f97dd782f913710bf8cc54411eb4b6e7ec4c5a0c8\",\"license\":\"MIT\"},\"contracts/interfaces/IJBOperatorStore.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBOperatorData} from './../structs/JBOperatorData.sol';\\n\\ninterface IJBOperatorStore {\\n event SetOperator(\\n address indexed operator,\\n address indexed account,\\n uint256 indexed domain,\\n uint256[] permissionIndexes,\\n uint256 packed\\n );\\n\\n function permissionsOf(\\n address operator,\\n address account,\\n uint256 domain\\n ) external view returns (uint256);\\n\\n function hasPermission(\\n address operator,\\n address account,\\n uint256 domain,\\n uint256 permissionIndex\\n ) external view returns (bool);\\n\\n function hasPermissions(\\n address operator,\\n address account,\\n uint256 domain,\\n uint256[] calldata permissionIndexes\\n ) external view returns (bool);\\n\\n function setOperator(JBOperatorData calldata operatorData) external;\\n\\n function setOperators(JBOperatorData[] calldata operatorData) external;\\n}\\n\",\"keccak256\":\"0xb6ce539d040601d7e4b1cec567c64d93e5b14d5fa249e04dd67cf222c4431678\",\"license\":\"MIT\"},\"contracts/interfaces/IJBPayDelegate.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\\nimport {JBDidPayData} from './../structs/JBDidPayData.sol';\\n\\n/// @title Pay delegate\\n/// @notice Delegate called after JBTerminal.pay(..) logic completion (if passed by the funding cycle datasource)\\ninterface IJBPayDelegate is IERC165 {\\n /// @notice This function is called by JBPaymentTerminal.pay(..), after the execution of its logic\\n /// @dev Critical business logic should be protected by an appropriate access control\\n /// @param data the data passed by the terminal, as a JBDidPayData struct:\\n function didPay(JBDidPayData calldata data) external payable;\\n}\\n\",\"keccak256\":\"0x2321bc8e990c5e2cb4236e0ca68e7e556306b6aa3ba10fa19ff018039d6d1a02\",\"license\":\"MIT\"},\"contracts/interfaces/IJBPayDelegate3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\\nimport {JBDidPayData3_1_1} from './../structs/JBDidPayData3_1_1.sol';\\n\\n/// @title Pay delegate\\n/// @notice Delegate called after JBTerminal.pay(..) logic completion (if passed by the funding cycle datasource)\\ninterface IJBPayDelegate3_1_1 is IERC165 {\\n /// @notice This function is called by JBPaymentTerminal.pay(..), after the execution of its logic\\n /// @dev Critical business logic should be protected by an appropriate access control\\n /// @param data the data passed by the terminal, as a JBDidPayData3_1_1 struct:\\n function didPay(JBDidPayData3_1_1 calldata data) external payable;\\n}\\n\",\"keccak256\":\"0x9448d24cd9c559b44c468c6a76d850f6eaadf31446db903092a2f32503a67294\",\"license\":\"MIT\"},\"contracts/interfaces/IJBPaymentTerminal.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\\n\\ninterface IJBPaymentTerminal is IERC165 {\\n function acceptsToken(address token, uint256 projectId) external view returns (bool);\\n\\n function currencyForToken(address token) external view returns (uint256);\\n\\n function decimalsForToken(address token) external view returns (uint256);\\n\\n // Return value must be a fixed point number with 18 decimals.\\n function currentEthOverflowOf(uint256 projectId) external view returns (uint256);\\n\\n function pay(\\n uint256 projectId,\\n uint256 amount,\\n address token,\\n address beneficiary,\\n uint256 minReturnedTokens,\\n bool preferClaimedTokens,\\n string calldata memo,\\n bytes calldata metadata\\n ) external payable returns (uint256 beneficiaryTokenCount);\\n\\n function addToBalanceOf(\\n uint256 projectId,\\n uint256 amount,\\n address token,\\n string calldata memo,\\n bytes calldata metadata\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x273bc1fa373fac08e5635fce7d38fd92e9fabba353568b3f7a5be54c01fe4d27\",\"license\":\"MIT\"},\"contracts/interfaces/IJBPayoutRedemptionPaymentTerminal3_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBFee} from './../structs/JBFee.sol';\\nimport {IJBAllowanceTerminal3_1} from './IJBAllowanceTerminal3_1.sol';\\nimport {IJBDirectory} from './IJBDirectory.sol';\\nimport {IJBFeeHoldingTerminal} from './IJBFeeHoldingTerminal.sol';\\nimport {IJBPayDelegate} from './IJBPayDelegate.sol';\\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\\nimport {IJBPayoutTerminal3_1} from './IJBPayoutTerminal3_1.sol';\\nimport {IJBPrices} from './IJBPrices.sol';\\nimport {IJBProjects} from './IJBProjects.sol';\\nimport {IJBRedemptionDelegate} from './IJBRedemptionDelegate.sol';\\nimport {IJBRedemptionTerminal} from './IJBRedemptionTerminal.sol';\\nimport {IJBSplitsStore} from './IJBSplitsStore.sol';\\nimport {JBDidPayData} from './../structs/JBDidPayData.sol';\\nimport {JBDidRedeemData} from './../structs/JBDidRedeemData.sol';\\nimport {JBSplit} from './../structs/JBSplit.sol';\\n\\ninterface IJBPayoutRedemptionPaymentTerminal3_1 is\\n IJBPaymentTerminal,\\n IJBPayoutTerminal3_1,\\n IJBAllowanceTerminal3_1,\\n IJBRedemptionTerminal,\\n IJBFeeHoldingTerminal\\n{\\n event AddToBalance(\\n uint256 indexed projectId,\\n uint256 amount,\\n uint256 refundedFees,\\n string memo,\\n bytes metadata,\\n address caller\\n );\\n\\n event Migrate(\\n uint256 indexed projectId,\\n IJBPaymentTerminal indexed to,\\n uint256 amount,\\n address caller\\n );\\n\\n event DistributePayouts(\\n uint256 indexed fundingCycleConfiguration,\\n uint256 indexed fundingCycleNumber,\\n uint256 indexed projectId,\\n address beneficiary,\\n uint256 amount,\\n uint256 distributedAmount,\\n uint256 fee,\\n uint256 beneficiaryDistributionAmount,\\n bytes metadata,\\n address caller\\n );\\n\\n event UseAllowance(\\n uint256 indexed fundingCycleConfiguration,\\n uint256 indexed fundingCycleNumber,\\n uint256 indexed projectId,\\n address beneficiary,\\n uint256 amount,\\n uint256 distributedAmount,\\n uint256 netDistributedamount,\\n string memo,\\n bytes metadata,\\n address caller\\n );\\n\\n event HoldFee(\\n uint256 indexed projectId,\\n uint256 indexed amount,\\n uint256 indexed fee,\\n uint256 feeDiscount,\\n address beneficiary,\\n address caller\\n );\\n\\n event ProcessFee(\\n uint256 indexed projectId,\\n uint256 indexed amount,\\n bool indexed wasHeld,\\n address beneficiary,\\n address caller\\n );\\n\\n event RefundHeldFees(\\n uint256 indexed projectId,\\n uint256 indexed amount,\\n uint256 indexed refundedFees,\\n uint256 leftoverAmount,\\n address caller\\n );\\n\\n event Pay(\\n uint256 indexed fundingCycleConfiguration,\\n uint256 indexed fundingCycleNumber,\\n uint256 indexed projectId,\\n address payer,\\n address beneficiary,\\n uint256 amount,\\n uint256 beneficiaryTokenCount,\\n string memo,\\n bytes metadata,\\n address caller\\n );\\n\\n event DelegateDidPay(\\n IJBPayDelegate indexed delegate,\\n JBDidPayData data,\\n uint256 delegatedAmount,\\n address caller\\n );\\n\\n event RedeemTokens(\\n uint256 indexed fundingCycleConfiguration,\\n uint256 indexed fundingCycleNumber,\\n uint256 indexed projectId,\\n address holder,\\n address beneficiary,\\n uint256 tokenCount,\\n uint256 reclaimedAmount,\\n string memo,\\n bytes metadata,\\n address caller\\n );\\n\\n event DelegateDidRedeem(\\n IJBRedemptionDelegate indexed delegate,\\n JBDidRedeemData data,\\n uint256 delegatedAmount,\\n address caller\\n );\\n\\n event DistributeToPayoutSplit(\\n uint256 indexed projectId,\\n uint256 indexed domain,\\n uint256 indexed group,\\n JBSplit split,\\n uint256 amount,\\n uint256 netAmount,\\n address caller\\n );\\n\\n event SetFee(uint256 fee, address caller);\\n\\n event SetFeeGauge(address indexed feeGauge, address caller);\\n\\n event SetFeelessAddress(address indexed addrs, bool indexed flag, address caller);\\n\\n event PayoutReverted(\\n uint256 indexed projectId,\\n JBSplit split,\\n uint256 amount,\\n bytes reason,\\n address caller\\n );\\n\\n event FeeReverted(\\n uint256 indexed projectId,\\n uint256 indexed feeProjectId,\\n uint256 amount,\\n bytes reason,\\n address caller\\n );\\n\\n function projects() external view returns (IJBProjects);\\n\\n function splitsStore() external view returns (IJBSplitsStore);\\n\\n function directory() external view returns (IJBDirectory);\\n\\n function prices() external view returns (IJBPrices);\\n\\n function store() external view returns (address);\\n\\n function baseWeightCurrency() external view returns (uint256);\\n\\n function payoutSplitsGroup() external view returns (uint256);\\n\\n function heldFeesOf(uint256 projectId) external view returns (JBFee[] memory);\\n\\n function fee() external view returns (uint256);\\n\\n function feeGauge() external view returns (address);\\n\\n function isFeelessAddress(address account) external view returns (bool);\\n\\n function migrate(uint256 projectId, IJBPaymentTerminal to) external returns (uint256 balance);\\n\\n function processFees(uint256 projectId) external;\\n\\n function setFee(uint256 fee) external;\\n\\n function setFeeGauge(address feeGauge) external;\\n\\n function setFeelessAddress(address account, bool flag) external;\\n}\\n\",\"keccak256\":\"0xa96558c3623b7a9e71df7a6034af14b9e3bbd34cdc02c9b36136eb1b4b88da00\",\"license\":\"MIT\"},\"contracts/interfaces/IJBPayoutRedemptionPaymentTerminal3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBFee} from './../structs/JBFee.sol';\\nimport {JBDidRedeemData3_1_1} from './../structs/JBDidRedeemData3_1_1.sol';\\nimport {JBDidPayData3_1_1} from './../structs/JBDidPayData3_1_1.sol';\\nimport {IJBPayDelegate3_1_1} from './IJBPayDelegate3_1_1.sol';\\nimport {IJBRedemptionDelegate3_1_1} from './IJBRedemptionDelegate3_1_1.sol';\\n\\ninterface IJBPayoutRedemptionPaymentTerminal3_1_1 {\\n event DelegateDidRedeem(\\n IJBRedemptionDelegate3_1_1 indexed delegate,\\n JBDidRedeemData3_1_1 data,\\n uint256 delegatedAmount,\\n uint256 fee,\\n address caller\\n );\\n\\n event DelegateDidPay(\\n IJBPayDelegate3_1_1 indexed delegate,\\n JBDidPayData3_1_1 data,\\n uint256 delegatedAmount,\\n address caller\\n );\\n}\\n\",\"keccak256\":\"0x66908701a06aa3b692a75873567cb14f4c9999ed6c42519ae5564a643fd65f15\",\"license\":\"MIT\"},\"contracts/interfaces/IJBPayoutTerminal3_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IJBPayoutTerminal3_1 {\\n function distributePayoutsOf(\\n uint256 projectId,\\n uint256 amount,\\n uint256 currency,\\n address token,\\n uint256 minReturnedTokens,\\n bytes calldata metadata\\n ) external returns (uint256 netLeftoverDistributionAmount);\\n}\\n\",\"keccak256\":\"0x2e0b8c37a451f1723296af656bd4982d4e5339ce76061eb63bb5f57b235bdc44\",\"license\":\"MIT\"},\"contracts/interfaces/IJBPriceFeed.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IJBPriceFeed {\\n function currentPrice(uint256 targetDecimals) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0x9328b2b52bc112641f3a6167c8cf242831a52c85016ce1310626bdc3489bded7\",\"license\":\"MIT\"},\"contracts/interfaces/IJBPrices.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBPriceFeed} from './IJBPriceFeed.sol';\\n\\ninterface IJBPrices {\\n event AddFeed(uint256 indexed currency, uint256 indexed base, IJBPriceFeed feed);\\n\\n function feedFor(uint256 currency, uint256 base) external view returns (IJBPriceFeed);\\n\\n function priceFor(\\n uint256 currency,\\n uint256 base,\\n uint256 decimals\\n ) external view returns (uint256);\\n\\n function addFeedFor(uint256 currency, uint256 base, IJBPriceFeed priceFeed) external;\\n}\\n\",\"keccak256\":\"0xc1623499fa541b15891e27a59288e03360ce78c7933d28bf575b48b68ce4981c\",\"license\":\"MIT\"},\"contracts/interfaces/IJBProjects.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC721} from '@openzeppelin/contracts/token/ERC721/IERC721.sol';\\nimport {JBProjectMetadata} from './../structs/JBProjectMetadata.sol';\\nimport {IJBTokenUriResolver} from './IJBTokenUriResolver.sol';\\n\\ninterface IJBProjects is IERC721 {\\n event Create(\\n uint256 indexed projectId,\\n address indexed owner,\\n JBProjectMetadata metadata,\\n address caller\\n );\\n\\n event SetMetadata(uint256 indexed projectId, JBProjectMetadata metadata, address caller);\\n\\n event SetTokenUriResolver(IJBTokenUriResolver indexed resolver, address caller);\\n\\n function count() external view returns (uint256);\\n\\n function metadataContentOf(\\n uint256 projectId,\\n uint256 domain\\n ) external view returns (string memory);\\n\\n function tokenUriResolver() external view returns (IJBTokenUriResolver);\\n\\n function createFor(\\n address owner,\\n JBProjectMetadata calldata metadata\\n ) external returns (uint256 projectId);\\n\\n function setMetadataOf(uint256 projectId, JBProjectMetadata calldata metadata) external;\\n\\n function setTokenUriResolver(IJBTokenUriResolver newResolver) external;\\n}\\n\",\"keccak256\":\"0x00235f20975e6a9465ac921076c85125a3834e29893f93f93e287a89f9e6b915\",\"license\":\"MIT\"},\"contracts/interfaces/IJBRedemptionDelegate.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\\nimport {JBDidRedeemData} from './../structs/JBDidRedeemData.sol';\\n\\n/// @title Redemption delegate\\n/// @notice Delegate called after JBTerminal.redeemTokensOf(..) logic completion (if passed by the funding cycle datasource)\\ninterface IJBRedemptionDelegate is IERC165 {\\n /// @notice This function is called by JBPaymentTerminal.redeemTokensOf(..), after the execution of its logic\\n /// @dev Critical business logic should be protected by an appropriate access control\\n /// @param data the data passed by the terminal, as a JBDidRedeemData struct:\\n function didRedeem(JBDidRedeemData calldata data) external payable;\\n}\\n\",\"keccak256\":\"0xd70f498197187982962b9e6a5b7572bb6b2c524228a267b01758f7e50a827387\",\"license\":\"MIT\"},\"contracts/interfaces/IJBRedemptionDelegate3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\\nimport {JBDidRedeemData3_1_1} from './../structs/JBDidRedeemData3_1_1.sol';\\n\\n/// @title Redemption delegate\\n/// @notice Delegate called after JBTerminal.redeemTokensOf(..) logic completion (if passed by the funding cycle datasource)\\ninterface IJBRedemptionDelegate3_1_1 is IERC165 {\\n /// @notice This function is called by JBPaymentTerminal.redeemTokensOf(..), after the execution of its logic\\n /// @dev Critical business logic should be protected by an appropriate access control\\n /// @param data the data passed by the terminal, as a JBDidRedeemData struct:\\n function didRedeem(JBDidRedeemData3_1_1 calldata data) external payable;\\n}\\n\",\"keccak256\":\"0x6034773b78e98902625563bd176a97267e729cb5205d25b06e8a2262b131c0d8\",\"license\":\"MIT\"},\"contracts/interfaces/IJBRedemptionTerminal.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IJBRedemptionTerminal {\\n function redeemTokensOf(\\n address holder,\\n uint256 projectId,\\n uint256 tokenCount,\\n address token,\\n uint256 minReturnedTokens,\\n address payable beneficiary,\\n string calldata memo,\\n bytes calldata metadata\\n ) external returns (uint256 reclaimAmount);\\n}\\n\",\"keccak256\":\"0x5e6bbbfe81a6cc151ca7e7ce603e4adb861ba8eb0bd4a35a9f12e29795b161f5\",\"license\":\"MIT\"},\"contracts/interfaces/IJBSingleTokenPaymentTerminal.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\\n\\ninterface IJBSingleTokenPaymentTerminal is IJBPaymentTerminal {\\n function token() external view returns (address);\\n\\n function currency() external view returns (uint256);\\n\\n function decimals() external view returns (uint256);\\n}\\n\",\"keccak256\":\"0x8e00670c66dea368dc523615425c2a79fcee10ec3c3355bf94feb82638172b3f\",\"license\":\"MIT\"},\"contracts/interfaces/IJBSingleTokenPaymentTerminalStore3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\\nimport {JBPayDelegateAllocation3_1_1} from './../structs/JBPayDelegateAllocation3_1_1.sol';\\nimport {JBRedemptionDelegateAllocation3_1_1} from './../structs/JBRedemptionDelegateAllocation3_1_1.sol';\\nimport {JBTokenAmount} from './../structs/JBTokenAmount.sol';\\nimport {IJBDirectory} from './IJBDirectory.sol';\\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\\nimport {IJBPrices} from './IJBPrices.sol';\\nimport {IJBSingleTokenPaymentTerminal} from './IJBSingleTokenPaymentTerminal.sol';\\n\\ninterface IJBSingleTokenPaymentTerminalStore3_1_1 {\\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\\n\\n function directory() external view returns (IJBDirectory);\\n\\n function prices() external view returns (IJBPrices);\\n\\n function balanceOf(\\n IJBSingleTokenPaymentTerminal terminal,\\n uint256 projectId\\n ) external view returns (uint256);\\n\\n function usedDistributionLimitOf(\\n IJBSingleTokenPaymentTerminal terminal,\\n uint256 projectId,\\n uint256 fundingCycleNumber\\n ) external view returns (uint256);\\n\\n function usedOverflowAllowanceOf(\\n IJBSingleTokenPaymentTerminal terminal,\\n uint256 projectId,\\n uint256 fundingCycleConfiguration\\n ) external view returns (uint256);\\n\\n function currentOverflowOf(\\n IJBSingleTokenPaymentTerminal terminal,\\n uint256 projectId\\n ) external view returns (uint256);\\n\\n function currentTotalOverflowOf(\\n uint256 projectId,\\n uint256 decimals,\\n uint256 currency\\n ) external view returns (uint256);\\n\\n function currentReclaimableOverflowOf(\\n IJBSingleTokenPaymentTerminal terminal,\\n uint256 projectId,\\n uint256 tokenCount,\\n bool useTotalOverflow\\n ) external view returns (uint256);\\n\\n function currentReclaimableOverflowOf(\\n uint256 projectId,\\n uint256 tokenCount,\\n uint256 totalSupply,\\n uint256 overflow\\n ) external view returns (uint256);\\n\\n function recordPaymentFrom(\\n address payer,\\n JBTokenAmount memory amount,\\n uint256 projectId,\\n uint256 baseWeightCurrency,\\n address beneficiary,\\n string calldata inputMemo,\\n bytes calldata metadata\\n )\\n external\\n returns (\\n JBFundingCycle memory fundingCycle,\\n uint256 tokenCount,\\n JBPayDelegateAllocation3_1_1[] memory delegateAllocations,\\n string memory outputMemo\\n );\\n\\n function recordRedemptionFor(\\n address holder,\\n uint256 projectId,\\n uint256 tokenCount,\\n string calldata inputMemo,\\n bytes calldata metadata\\n )\\n external\\n returns (\\n JBFundingCycle memory fundingCycle,\\n uint256 reclaimAmount,\\n JBRedemptionDelegateAllocation3_1_1[] memory delegateAllocations,\\n string memory outputMemo\\n );\\n\\n function recordDistributionFor(\\n uint256 projectId,\\n uint256 amount,\\n uint256 currency\\n ) external returns (JBFundingCycle memory fundingCycle, uint256 distributedAmount);\\n\\n function recordUsedAllowanceOf(\\n uint256 projectId,\\n uint256 amount,\\n uint256 currency\\n ) external returns (JBFundingCycle memory fundingCycle, uint256 withdrawnAmount);\\n\\n function recordAddedBalanceFor(uint256 projectId, uint256 amount) external;\\n\\n function recordMigration(uint256 projectId) external returns (uint256 balance);\\n}\\n\",\"keccak256\":\"0xf009c9fb787cda2a18805b9a9e2105c7f1309ade1eac3af229816cfd27ba1d64\",\"license\":\"MIT\"},\"contracts/interfaces/IJBSplitAllocator.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\\nimport {JBSplitAllocationData} from '../structs/JBSplitAllocationData.sol';\\n\\n/// @title Split allocator\\n/// @notice Provide a way to process a single split with extra logic\\n/// @dev The contract address should be set as an allocator in the adequate split\\ninterface IJBSplitAllocator is IERC165 {\\n /// @notice This function is called by JBPaymentTerminal.distributePayoutOf(..), during the processing of the split including it\\n /// @dev Critical business logic should be protected by an appropriate access control. The token and/or eth are optimistically transfered to the allocator for its logic.\\n /// @param data the data passed by the terminal, as a JBSplitAllocationData struct:\\n function allocate(JBSplitAllocationData calldata data) external payable;\\n}\\n\",\"keccak256\":\"0x1643b444409d91858eb86f67abf3d757d2deb3ccd7265eb8e68d6ffdac083de6\",\"license\":\"MIT\"},\"contracts/interfaces/IJBSplitsStore.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBGroupedSplits} from './../structs/JBGroupedSplits.sol';\\nimport {JBSplit} from './../structs/JBSplit.sol';\\nimport {IJBDirectory} from './IJBDirectory.sol';\\nimport {IJBProjects} from './IJBProjects.sol';\\n\\ninterface IJBSplitsStore {\\n event SetSplit(\\n uint256 indexed projectId,\\n uint256 indexed domain,\\n uint256 indexed group,\\n JBSplit split,\\n address caller\\n );\\n\\n function projects() external view returns (IJBProjects);\\n\\n function directory() external view returns (IJBDirectory);\\n\\n function splitsOf(\\n uint256 projectId,\\n uint256 domain,\\n uint256 group\\n ) external view returns (JBSplit[] memory);\\n\\n function set(uint256 projectId, uint256 domain, JBGroupedSplits[] memory groupedSplits) external;\\n}\\n\",\"keccak256\":\"0x3ce0eb12f10282481a3bf86e62b368bcff254081088cfabb20353d60cfadbc7a\",\"license\":\"MIT\"},\"contracts/interfaces/IJBToken.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IJBToken {\\n function projectId() external view returns (uint256);\\n\\n function decimals() external view returns (uint8);\\n\\n function totalSupply(uint256 projectId) external view returns (uint256);\\n\\n function balanceOf(address account, uint256 projectId) external view returns (uint256);\\n\\n function mint(uint256 projectId, address account, uint256 amount) external;\\n\\n function burn(uint256 projectId, address account, uint256 amount) external;\\n\\n function approve(uint256, address spender, uint256 amount) external;\\n\\n function transfer(uint256 projectId, address to, uint256 amount) external;\\n\\n function transferFrom(uint256 projectId, address from, address to, uint256 amount) external;\\n}\\n\",\"keccak256\":\"0xeefe58d140e4e13f255d5c7c5cdf5ba66dd00835f04015c446ff224f8ad14c34\",\"license\":\"MIT\"},\"contracts/interfaces/IJBTokenStore.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\\nimport {IJBProjects} from './IJBProjects.sol';\\nimport {IJBToken} from './IJBToken.sol';\\n\\ninterface IJBTokenStore {\\n event Issue(\\n uint256 indexed projectId,\\n IJBToken indexed token,\\n string name,\\n string symbol,\\n address caller\\n );\\n\\n event Mint(\\n address indexed holder,\\n uint256 indexed projectId,\\n uint256 amount,\\n bool tokensWereClaimed,\\n bool preferClaimedTokens,\\n address caller\\n );\\n\\n event Burn(\\n address indexed holder,\\n uint256 indexed projectId,\\n uint256 amount,\\n uint256 initialUnclaimedBalance,\\n uint256 initialClaimedBalance,\\n bool preferClaimedTokens,\\n address caller\\n );\\n\\n event Claim(\\n address indexed holder,\\n uint256 indexed projectId,\\n uint256 initialUnclaimedBalance,\\n uint256 amount,\\n address caller\\n );\\n\\n event Set(uint256 indexed projectId, IJBToken indexed newToken, address caller);\\n\\n event Transfer(\\n address indexed holder,\\n uint256 indexed projectId,\\n address indexed recipient,\\n uint256 amount,\\n address caller\\n );\\n\\n function tokenOf(uint256 projectId) external view returns (IJBToken);\\n\\n function projects() external view returns (IJBProjects);\\n\\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\\n\\n function unclaimedBalanceOf(address holder, uint256 projectId) external view returns (uint256);\\n\\n function unclaimedTotalSupplyOf(uint256 projectId) external view returns (uint256);\\n\\n function totalSupplyOf(uint256 projectId) external view returns (uint256);\\n\\n function balanceOf(address holder, uint256 projectId) external view returns (uint256 result);\\n\\n function issueFor(\\n uint256 projectId,\\n string calldata name,\\n string calldata symbol\\n ) external returns (IJBToken token);\\n\\n function setFor(uint256 projectId, IJBToken token) external;\\n\\n function burnFrom(\\n address holder,\\n uint256 projectId,\\n uint256 amount,\\n bool preferClaimedTokens\\n ) external;\\n\\n function mintFor(\\n address holder,\\n uint256 projectId,\\n uint256 amount,\\n bool preferClaimedTokens\\n ) external;\\n\\n function claimFor(address holder, uint256 projectId, uint256 amount) external;\\n\\n function transferFrom(\\n address holder,\\n uint256 projectId,\\n address recipient,\\n uint256 amount\\n ) external;\\n}\\n\",\"keccak256\":\"0x4db7bb4fe824dc9bfbc997ea3e07f42be8900bcad4e0b991e726c23c2de84ba4\",\"license\":\"MIT\"},\"contracts/interfaces/IJBTokenUriResolver.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IJBTokenUriResolver {\\n function getUri(uint256 projectId) external view returns (string memory tokenUri);\\n}\\n\",\"keccak256\":\"0xc7c9537184a1a36bc30874e5ac29b0fbccf45a99d40806837cfe30d6d9a1c84a\",\"license\":\"MIT\"},\"contracts/libraries/JBConstants.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/// @notice Global constants used across Juicebox contracts.\\nlibrary JBConstants {\\n uint256 public constant MAX_RESERVED_RATE = 10_000;\\n uint256 public constant MAX_REDEMPTION_RATE = 10_000;\\n uint256 public constant MAX_DISCOUNT_RATE = 1_000_000_000;\\n uint256 public constant SPLITS_TOTAL_PERCENT = 1_000_000_000;\\n uint256 public constant MAX_FEE = 1_000_000_000;\\n uint256 public constant MAX_FEE_DISCOUNT = 1_000_000_000;\\n}\\n\",\"keccak256\":\"0x7f2741e86062c5019f51d7e1a7b192ec1880d7e15a9a1589362ae7424de3003b\",\"license\":\"MIT\"},\"contracts/libraries/JBCurrencies.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nlibrary JBCurrencies {\\n uint256 public constant ETH = 1;\\n uint256 public constant USD = 2;\\n}\\n\",\"keccak256\":\"0x7e417ff25c173608ee4fe6d9fc3dcd5e1458c78c889af12bac47b1189a436076\",\"license\":\"MIT\"},\"contracts/libraries/JBFixedPointNumber.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.16;\\n\\nlibrary JBFixedPointNumber {\\n function adjustDecimals(\\n uint256 _value,\\n uint256 _decimals,\\n uint256 _targetDecimals\\n ) internal pure returns (uint256) {\\n // If decimals need adjusting, multiply or divide the price by the decimal adjuster to get the normalized result.\\n if (_targetDecimals == _decimals) return _value;\\n else if (_targetDecimals > _decimals) return _value * 10**(_targetDecimals - _decimals);\\n else return _value / 10**(_decimals - _targetDecimals);\\n }\\n}\\n\",\"keccak256\":\"0x18efac48269f3a3bd7e9a1c770776f950e0afa86769e6f8b128002c3b8c6742c\",\"license\":\"MIT\"},\"contracts/libraries/JBFundingCycleMetadataResolver.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.16;\\n\\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\\nimport {JBFundingCycleMetadata} from './../structs/JBFundingCycleMetadata.sol';\\nimport {JBGlobalFundingCycleMetadata} from './../structs/JBGlobalFundingCycleMetadata.sol';\\nimport {JBConstants} from './JBConstants.sol';\\nimport {JBGlobalFundingCycleMetadataResolver} from './JBGlobalFundingCycleMetadataResolver.sol';\\n\\nlibrary JBFundingCycleMetadataResolver {\\n function global(JBFundingCycle memory _fundingCycle)\\n internal\\n pure\\n returns (JBGlobalFundingCycleMetadata memory)\\n {\\n return JBGlobalFundingCycleMetadataResolver.expandMetadata(uint8(_fundingCycle.metadata >> 8));\\n }\\n\\n function reservedRate(JBFundingCycle memory _fundingCycle) internal pure returns (uint256) {\\n return uint256(uint16(_fundingCycle.metadata >> 24));\\n }\\n\\n function redemptionRate(JBFundingCycle memory _fundingCycle) internal pure returns (uint256) {\\n // Redemption rate is a number 0-10000. It's inverse was stored so the most common case of 100% results in no storage needs.\\n return JBConstants.MAX_REDEMPTION_RATE - uint256(uint16(_fundingCycle.metadata >> 40));\\n }\\n\\n function ballotRedemptionRate(JBFundingCycle memory _fundingCycle)\\n internal\\n pure\\n returns (uint256)\\n {\\n // Redemption rate is a number 0-10000. It's inverse was stored so the most common case of 100% results in no storage needs.\\n return JBConstants.MAX_REDEMPTION_RATE - uint256(uint16(_fundingCycle.metadata >> 56));\\n }\\n\\n function payPaused(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\\n return ((_fundingCycle.metadata >> 72) & 1) == 1;\\n }\\n\\n function distributionsPaused(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\\n return ((_fundingCycle.metadata >> 73) & 1) == 1;\\n }\\n\\n function redeemPaused(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\\n return ((_fundingCycle.metadata >> 74) & 1) == 1;\\n }\\n\\n function burnPaused(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\\n return ((_fundingCycle.metadata >> 75) & 1) == 1;\\n }\\n\\n function mintingAllowed(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\\n return ((_fundingCycle.metadata >> 76) & 1) == 1;\\n }\\n\\n function terminalMigrationAllowed(JBFundingCycle memory _fundingCycle)\\n internal\\n pure\\n returns (bool)\\n {\\n return ((_fundingCycle.metadata >> 77) & 1) == 1;\\n }\\n\\n function controllerMigrationAllowed(JBFundingCycle memory _fundingCycle)\\n internal\\n pure\\n returns (bool)\\n {\\n return ((_fundingCycle.metadata >> 78) & 1) == 1;\\n }\\n\\n function shouldHoldFees(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\\n return ((_fundingCycle.metadata >> 79) & 1) == 1;\\n }\\n\\n function preferClaimedTokenOverride(JBFundingCycle memory _fundingCycle)\\n internal\\n pure\\n returns (bool)\\n {\\n return ((_fundingCycle.metadata >> 80) & 1) == 1;\\n }\\n\\n function useTotalOverflowForRedemptions(JBFundingCycle memory _fundingCycle)\\n internal\\n pure\\n returns (bool)\\n {\\n return ((_fundingCycle.metadata >> 81) & 1) == 1;\\n }\\n\\n function useDataSourceForPay(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\\n return (_fundingCycle.metadata >> 82) & 1 == 1;\\n }\\n\\n function useDataSourceForRedeem(JBFundingCycle memory _fundingCycle)\\n internal\\n pure\\n returns (bool)\\n {\\n return (_fundingCycle.metadata >> 83) & 1 == 1;\\n }\\n\\n function dataSource(JBFundingCycle memory _fundingCycle) internal pure returns (address) {\\n return address(uint160(_fundingCycle.metadata >> 84));\\n }\\n\\n function metadata(JBFundingCycle memory _fundingCycle) internal pure returns (uint256) {\\n return uint256(uint8(_fundingCycle.metadata >> 244));\\n }\\n\\n /// @notice Pack the funding cycle metadata.\\n /// @param _metadata The metadata to validate and pack.\\n /// @return packed The packed uint256 of all metadata params. The first 8 bits specify the version. \\n function packFundingCycleMetadata(JBFundingCycleMetadata memory _metadata)\\n internal\\n pure\\n returns (uint256 packed)\\n {\\n // version 1 in the bits 0-7 (8 bits).\\n packed = 1;\\n // global metadta in bits 8-23 (16 bits).\\n packed |=\\n JBGlobalFundingCycleMetadataResolver.packFundingCycleGlobalMetadata(_metadata.global) <<\\n 8;\\n // reserved rate in bits 24-39 (16 bits).\\n packed |= _metadata.reservedRate << 24;\\n // redemption rate in bits 40-55 (16 bits).\\n // redemption rate is a number 0-10000. Store the reverse so the most common case of 100% results in no storage needs.\\n packed |= (JBConstants.MAX_REDEMPTION_RATE - _metadata.redemptionRate) << 40;\\n // ballot redemption rate rate in bits 56-71 (16 bits).\\n // ballot redemption rate is a number 0-10000. Store the reverse so the most common case of 100% results in no storage needs.\\n packed |= (JBConstants.MAX_REDEMPTION_RATE - _metadata.ballotRedemptionRate) << 56;\\n // pause pay in bit 72.\\n if (_metadata.pausePay) packed |= 1 << 72;\\n // pause tap in bit 73.\\n if (_metadata.pauseDistributions) packed |= 1 << 73;\\n // pause redeem in bit 74.\\n if (_metadata.pauseRedeem) packed |= 1 << 74;\\n // pause burn in bit 75.\\n if (_metadata.pauseBurn) packed |= 1 << 75;\\n // allow minting in bit 76.\\n if (_metadata.allowMinting) packed |= 1 << 76;\\n // allow terminal migration in bit 77.\\n if (_metadata.allowTerminalMigration) packed |= 1 << 77;\\n // allow controller migration in bit 78.\\n if (_metadata.allowControllerMigration) packed |= 1 << 78;\\n // hold fees in bit 79.\\n if (_metadata.holdFees) packed |= 1 << 79;\\n // prefer claimed token override in bit 80.\\n if (_metadata.preferClaimedTokenOverride) packed |= 1 << 80;\\n // useTotalOverflowForRedemptions in bit 81.\\n if (_metadata.useTotalOverflowForRedemptions) packed |= 1 << 81;\\n // use pay data source in bit 82.\\n if (_metadata.useDataSourceForPay) packed |= 1 << 82;\\n // use redeem data source in bit 83.\\n if (_metadata.useDataSourceForRedeem) packed |= 1 << 83;\\n // data source address in bits 84-243.\\n packed |= uint256(uint160(address(_metadata.dataSource))) << 84;\\n // metadata in bits 244-252 (8 bits).\\n packed |= _metadata.metadata << 244;\\n }\\n\\n /// @notice Expand the funding cycle metadata.\\n /// @param _fundingCycle The funding cycle having its metadata expanded.\\n /// @return metadata The metadata object. \\n function expandMetadata(JBFundingCycle memory _fundingCycle)\\n internal\\n pure\\n returns (JBFundingCycleMetadata memory)\\n {\\n return\\n JBFundingCycleMetadata(\\n global(_fundingCycle),\\n reservedRate(_fundingCycle),\\n redemptionRate(_fundingCycle),\\n ballotRedemptionRate(_fundingCycle),\\n payPaused(_fundingCycle),\\n distributionsPaused(_fundingCycle),\\n redeemPaused(_fundingCycle),\\n burnPaused(_fundingCycle),\\n mintingAllowed(_fundingCycle),\\n terminalMigrationAllowed(_fundingCycle),\\n controllerMigrationAllowed(_fundingCycle),\\n shouldHoldFees(_fundingCycle),\\n preferClaimedTokenOverride(_fundingCycle),\\n useTotalOverflowForRedemptions(_fundingCycle),\\n useDataSourceForPay(_fundingCycle),\\n useDataSourceForRedeem(_fundingCycle),\\n dataSource(_fundingCycle),\\n metadata(_fundingCycle)\\n );\\n }\\n}\\n\",\"keccak256\":\"0xedb0b93d5578ca5a21ab55f65274e441513bce982b04ffc76f26e627abfbbe0c\",\"license\":\"MIT\"},\"contracts/libraries/JBGlobalFundingCycleMetadataResolver.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.16;\\n\\nimport {JBFundingCycleMetadata} from './../structs/JBFundingCycleMetadata.sol';\\nimport {JBGlobalFundingCycleMetadata} from './../structs/JBGlobalFundingCycleMetadata.sol';\\n\\nlibrary JBGlobalFundingCycleMetadataResolver {\\n function setTerminalsAllowed(uint8 _data) internal pure returns (bool) {\\n return (_data & 1) == 1;\\n }\\n\\n function setControllerAllowed(uint8 _data) internal pure returns (bool) {\\n return ((_data >> 1) & 1) == 1;\\n }\\n\\n function transfersPaused(uint8 _data) internal pure returns (bool) {\\n return ((_data >> 2) & 1) == 1;\\n }\\n\\n /// @notice Pack the global funding cycle metadata.\\n /// @param _metadata The metadata to validate and pack.\\n /// @return packed The packed uint256 of all global metadata params. The first 8 bits specify the version.\\n function packFundingCycleGlobalMetadata(\\n JBGlobalFundingCycleMetadata memory _metadata\\n ) internal pure returns (uint256 packed) {\\n // allow set terminals in bit 0.\\n if (_metadata.allowSetTerminals) packed |= 1;\\n // allow set controller in bit 1.\\n if (_metadata.allowSetController) packed |= 1 << 1;\\n // pause transfers in bit 2.\\n if (_metadata.pauseTransfers) packed |= 1 << 2;\\n }\\n\\n /// @notice Expand the global funding cycle metadata.\\n /// @param _packedMetadata The packed metadata to expand.\\n /// @return metadata The global metadata object.\\n function expandMetadata(\\n uint8 _packedMetadata\\n ) internal pure returns (JBGlobalFundingCycleMetadata memory metadata) {\\n return\\n JBGlobalFundingCycleMetadata(\\n setTerminalsAllowed(_packedMetadata),\\n setControllerAllowed(_packedMetadata),\\n transfersPaused(_packedMetadata)\\n );\\n }\\n}\\n\",\"keccak256\":\"0x8a016001787db05e3bbd442db7eaa3f49f1d3a3210d2b5c6e52254a241f3b161\",\"license\":\"MIT\"},\"contracts/libraries/JBOperations.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nlibrary JBOperations {\\n uint256 public constant RECONFIGURE = 1;\\n uint256 public constant REDEEM = 2;\\n uint256 public constant MIGRATE_CONTROLLER = 3;\\n uint256 public constant MIGRATE_TERMINAL = 4;\\n uint256 public constant PROCESS_FEES = 5;\\n uint256 public constant SET_METADATA = 6;\\n uint256 public constant ISSUE = 7;\\n uint256 public constant SET_TOKEN = 8;\\n uint256 public constant MINT = 9;\\n uint256 public constant BURN = 10;\\n uint256 public constant CLAIM = 11;\\n uint256 public constant TRANSFER = 12;\\n uint256 public constant REQUIRE_CLAIM = 13; // unused in v3\\n uint256 public constant SET_CONTROLLER = 14;\\n uint256 public constant SET_TERMINALS = 15;\\n uint256 public constant SET_PRIMARY_TERMINAL = 16;\\n uint256 public constant USE_ALLOWANCE = 17;\\n uint256 public constant SET_SPLITS = 18;\\n}\\n\",\"keccak256\":\"0x7f8e501e6890297f4015b1c27cebdb44fadbf21204bea1f3162f5388c060f690\",\"license\":\"MIT\"},\"contracts/libraries/JBSplitsGroups.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nlibrary JBSplitsGroups {\\n uint256 public constant ETH_PAYOUT = 1;\\n uint256 public constant RESERVED_TOKENS = 2;\\n}\\n\",\"keccak256\":\"0x4183db6087bd8db645fc3a0d3d8afb0d6356e003650793f63c301ebbbae47269\",\"license\":\"MIT\"},\"contracts/libraries/JBTokens.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nlibrary JBTokens {\\n /// @notice The ETH token address in Juicebox is represented by 0x000000000000000000000000000000000000EEEe.\\n address public constant ETH = address(0x000000000000000000000000000000000000EEEe);\\n}\\n\",\"keccak256\":\"0x9e724a7e65c6d6e01e7f0c1419d750307ed6ce8bc29bbd959e029bcdd4b4e479\",\"license\":\"MIT\"},\"contracts/structs/JBDidPayData.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBTokenAmount} from './JBTokenAmount.sol';\\n\\n/// @custom:member payer The address from which the payment originated.\\n/// @custom:member projectId The ID of the project for which the payment was made.\\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the payment is being made.\\n/// @custom:member amount The amount of the payment. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\\n/// @custom:member forwardedAmount The amount of the payment that is being sent to the delegate. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\\n/// @custom:member projectTokenCount The number of project tokens minted for the beneficiary.\\n/// @custom:member beneficiary The address to which the tokens were minted.\\n/// @custom:member preferClaimedTokens A flag indicating whether the request prefered to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract.\\n/// @custom:member memo The memo that is being emitted alongside the payment.\\n/// @custom:member metadata Extra data to send to the delegate.\\nstruct JBDidPayData {\\n address payer;\\n uint256 projectId;\\n uint256 currentFundingCycleConfiguration;\\n JBTokenAmount amount;\\n JBTokenAmount forwardedAmount;\\n uint256 projectTokenCount;\\n address beneficiary;\\n bool preferClaimedTokens;\\n string memo;\\n bytes metadata;\\n}\\n\",\"keccak256\":\"0x235e117009bfb825d14c5433fa46f777fa512400df74e76290e869d4c3d8b26e\",\"license\":\"MIT\"},\"contracts/structs/JBDidPayData3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBTokenAmount} from './JBTokenAmount.sol';\\n\\n/// @custom:member payer The address from which the payment originated.\\n/// @custom:member projectId The ID of the project for which the payment was made.\\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the payment is being made.\\n/// @custom:member amount The amount of the payment. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\\n/// @custom:member forwardedAmount The amount of the payment that is being sent to the delegate. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\\n/// @custom:member projectTokenCount The number of project tokens minted for the beneficiary.\\n/// @custom:member beneficiary The address to which the tokens were minted.\\n/// @custom:member preferClaimedTokens A flag indicating whether the request prefered to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract.\\n/// @custom:member memo The memo that is being emitted alongside the payment.\\n/// @custom:member dataSourceMetadata Extra data to send to the delegate sent by the data source.\\n/// @custom:member payerMetadata Extra data to send to the delegate sent by the payer.\\nstruct JBDidPayData3_1_1 {\\n address payer;\\n uint256 projectId;\\n uint256 currentFundingCycleConfiguration;\\n JBTokenAmount amount;\\n JBTokenAmount forwardedAmount;\\n uint256 projectTokenCount;\\n address beneficiary;\\n bool preferClaimedTokens;\\n string memo;\\n bytes dataSourceMetadata;\\n bytes payerMetadata;\\n}\\n\",\"keccak256\":\"0x2e659555149ff14c045b749b1d1a3156b8296ab08375ac2abec92afc43bf3acf\",\"license\":\"MIT\"},\"contracts/structs/JBDidRedeemData.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBTokenAmount} from './JBTokenAmount.sol';\\n\\n/// @custom:member holder The holder of the tokens being redeemed.\\n/// @custom:member projectId The ID of the project with which the redeemed tokens are associated.\\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the redemption is being made.\\n/// @custom:member projectTokenCount The number of project tokens being redeemed.\\n/// @custom:member reclaimedAmount The amount reclaimed from the treasury. Includes the token being reclaimed, the value, the number of decimals included, and the currency of the amount.\\n/// @custom:member forwardedAmount The amount of the payment that is being sent to the delegate. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\\n/// @custom:member beneficiary The address to which the reclaimed amount will be sent.\\n/// @custom:member memo The memo that is being emitted alongside the redemption.\\n/// @custom:member metadata Extra data to send to the delegate.\\nstruct JBDidRedeemData {\\n address holder;\\n uint256 projectId;\\n uint256 currentFundingCycleConfiguration;\\n uint256 projectTokenCount;\\n JBTokenAmount reclaimedAmount;\\n JBTokenAmount forwardedAmount;\\n address payable beneficiary;\\n string memo;\\n bytes metadata;\\n}\\n\",\"keccak256\":\"0xee0c3728a39069f5a2a9b25c120739da5cae4c4e6fd0cae371a961a9d1367549\",\"license\":\"MIT\"},\"contracts/structs/JBDidRedeemData3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBTokenAmount} from './JBTokenAmount.sol';\\n\\n/// @custom:member holder The holder of the tokens being redeemed.\\n/// @custom:member projectId The ID of the project with which the redeemed tokens are associated.\\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the redemption is being made.\\n/// @custom:member projectTokenCount The number of project tokens being redeemed.\\n/// @custom:member reclaimedAmount The amount reclaimed from the treasury. Includes the token being reclaimed, the value, the number of decimals included, and the currency of the amount.\\n/// @custom:member forwardedAmount The amount of the payment that is being sent to the delegate. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\\n/// @custom:member beneficiary The address to which the reclaimed amount will be sent.\\n/// @custom:member memo The memo that is being emitted alongside the redemption.\\n/// @custom:member dataSourceMetadata Extra data to send to the delegate sent by the data source.\\n/// @custom:member redeemerMetadata Extra data to send to the delegate sent by the redeemer.\\nstruct JBDidRedeemData3_1_1 {\\n address holder;\\n uint256 projectId;\\n uint256 currentFundingCycleConfiguration;\\n uint256 projectTokenCount;\\n JBTokenAmount reclaimedAmount;\\n JBTokenAmount forwardedAmount;\\n address payable beneficiary;\\n string memo;\\n bytes dataSourceMetadata;\\n bytes redeemerMetadata;\\n}\\n\",\"keccak256\":\"0x23848d41aa179d16e9b7033befd3a855d43f6a009e24030c2ba1bb5b06cb3924\",\"license\":\"MIT\"},\"contracts/structs/JBFee.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/// @custom:member amount The total amount the fee was taken from, as a fixed point number with the same number of decimals as the terminal in which this struct was created.\\n/// @custom:member fee The percent of the fee, out of MAX_FEE.\\n/// @custom:member feeDiscount The discount of the fee.\\n/// @custom:member beneficiary The address that will receive the tokens that are minted as a result of the fee payment.\\nstruct JBFee {\\n uint256 amount;\\n uint32 fee;\\n uint32 feeDiscount;\\n address beneficiary;\\n}\\n\",\"keccak256\":\"0xd105627d21718704db798df0b958e6223fb2d79854e72cda2bfa9eca0630c1f6\",\"license\":\"MIT\"},\"contracts/structs/JBFundAccessConstraints.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\\n\\n/// @custom:member terminal The terminal within which the distribution limit and the overflow allowance applies.\\n/// @custom:member token The token for which the fund access constraints apply.\\n/// @custom:member distributionLimit The amount of the distribution limit, as a fixed point number with the same number of decimals as the terminal within which the limit applies.\\n/// @custom:member distributionLimitCurrency The currency of the distribution limit.\\n/// @custom:member overflowAllowance The amount of the allowance, as a fixed point number with the same number of decimals as the terminal within which the allowance applies.\\n/// @custom:member overflowAllowanceCurrency The currency of the overflow allowance.\\nstruct JBFundAccessConstraints {\\n IJBPaymentTerminal terminal;\\n address token;\\n uint256 distributionLimit;\\n uint256 distributionLimitCurrency;\\n uint256 overflowAllowance;\\n uint256 overflowAllowanceCurrency;\\n}\\n\",\"keccak256\":\"0xbef975eb73e58c00eaaa7abbd449db545056b049907bb2034aefcdde10bcf11f\",\"license\":\"MIT\"},\"contracts/structs/JBFundingCycle.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBFundingCycleBallot} from './../interfaces/IJBFundingCycleBallot.sol';\\n\\n/// @custom:member number The funding cycle number for the cycle's project. Each funding cycle has a number that is an increment of the cycle that directly preceded it. Each project's first funding cycle has a number of 1.\\n/// @custom:member configuration The timestamp when the parameters for this funding cycle were configured. This value will stay the same for subsequent funding cycles that roll over from an originally configured cycle.\\n/// @custom:member basedOn The `configuration` of the funding cycle that was active when this cycle was created.\\n/// @custom:member start The timestamp marking the moment from which the funding cycle is considered active. It is a unix timestamp measured in seconds.\\n/// @custom:member duration The number of seconds the funding cycle lasts for, after which a new funding cycle will start. A duration of 0 means that the funding cycle will stay active until the project owner explicitly issues a reconfiguration, at which point a new funding cycle will immediately start with the updated properties. If the duration is greater than 0, a project owner cannot make changes to a funding cycle's parameters while it is active \\u2013 any proposed changes will apply to the subsequent cycle. If no changes are proposed, a funding cycle rolls over to another one with the same properties but new `start` timestamp and a discounted `weight`.\\n/// @custom:member weight A fixed point number with 18 decimals that contracts can use to base arbitrary calculations on. For example, payment terminals can use this to determine how many tokens should be minted when a payment is received.\\n/// @custom:member discountRate A percent by how much the `weight` of the subsequent funding cycle should be reduced, if the project owner hasn't configured the subsequent funding cycle with an explicit `weight`. If it's 0, each funding cycle will have equal weight. If the number is 90%, the next funding cycle will have a 10% smaller weight. This weight is out of `JBConstants.MAX_DISCOUNT_RATE`.\\n/// @custom:member ballot An address of a contract that says whether a proposed reconfiguration should be accepted or rejected. It can be used to create rules around how a project owner can change funding cycle parameters over time.\\n/// @custom:member metadata Extra data that can be associated with a funding cycle.\\nstruct JBFundingCycle {\\n uint256 number;\\n uint256 configuration;\\n uint256 basedOn;\\n uint256 start;\\n uint256 duration;\\n uint256 weight;\\n uint256 discountRate;\\n IJBFundingCycleBallot ballot;\\n uint256 metadata;\\n}\\n\",\"keccak256\":\"0x01d2ee9ae017694097985a08a36421b6801d96badd16e38c6085f3a5ac796ed1\",\"license\":\"MIT\"},\"contracts/structs/JBFundingCycleData.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBFundingCycleBallot} from './../interfaces/IJBFundingCycleBallot.sol';\\n\\n/// @custom:member duration The number of seconds the funding cycle lasts for, after which a new funding cycle will start. A duration of 0 means that the funding cycle will stay active until the project owner explicitly issues a reconfiguration, at which point a new funding cycle will immediately start with the updated properties. If the duration is greater than 0, a project owner cannot make changes to a funding cycle's parameters while it is active \\u2013 any proposed changes will apply to the subsequent cycle. If no changes are proposed, a funding cycle rolls over to another one with the same properties but new `start` timestamp and a discounted `weight`.\\n/// @custom:member weight A fixed point number with 18 decimals that contracts can use to base arbitrary calculations on. For example, payment terminals can use this to determine how many tokens should be minted when a payment is received.\\n/// @custom:member discountRate A percent by how much the `weight` of the subsequent funding cycle should be reduced, if the project owner hasn't configured the subsequent funding cycle with an explicit `weight`. If it's 0, each funding cycle will have equal weight. If the number is 90%, the next funding cycle will have a 10% smaller weight. This weight is out of `JBConstants.MAX_DISCOUNT_RATE`.\\n/// @custom:member ballot An address of a contract that says whether a proposed reconfiguration should be accepted or rejected. It can be used to create rules around how a project owner can change funding cycle parameters over time.\\nstruct JBFundingCycleData {\\n uint256 duration;\\n uint256 weight;\\n uint256 discountRate;\\n IJBFundingCycleBallot ballot;\\n}\\n\",\"keccak256\":\"0x3cd9257969fdd54bee497b01be2c623e33c941306662002b3b88fa0ab8a27db5\",\"license\":\"MIT\"},\"contracts/structs/JBFundingCycleMetadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBGlobalFundingCycleMetadata} from './JBGlobalFundingCycleMetadata.sol';\\n\\n/// @custom:member global Data used globally in non-migratable ecosystem contracts.\\n/// @custom:member reservedRate The reserved rate of the funding cycle. This number is a percentage calculated out of `JBConstants.MAX_RESERVED_RATE`.\\n/// @custom:member redemptionRate The redemption rate of the funding cycle. This number is a percentage calculated out of `JBConstants.MAX_REDEMPTION_RATE`.\\n/// @custom:member ballotRedemptionRate The redemption rate to use during an active ballot of the funding cycle. This number is a percentage calculated out of `JBConstants.MAX_REDEMPTION_RATE`.\\n/// @custom:member pausePay A flag indicating if the pay functionality should be paused during the funding cycle.\\n/// @custom:member pauseDistributions A flag indicating if the distribute functionality should be paused during the funding cycle.\\n/// @custom:member pauseRedeem A flag indicating if the redeem functionality should be paused during the funding cycle.\\n/// @custom:member pauseBurn A flag indicating if the burn functionality should be paused during the funding cycle.\\n/// @custom:member allowMinting A flag indicating if minting tokens should be allowed during this funding cycle.\\n/// @custom:member allowTerminalMigration A flag indicating if migrating terminals should be allowed during this funding cycle.\\n/// @custom:member allowControllerMigration A flag indicating if migrating controllers should be allowed during this funding cycle.\\n/// @custom:member holdFees A flag indicating if fees should be held during this funding cycle.\\n/// @custom:member preferClaimedTokenOverride A flag indicating if claimed tokens should always be prefered to unclaimed tokens when minting.\\n/// @custom:member useTotalOverflowForRedemptions A flag indicating if redemptions should use the project's balance held in all terminals instead of the project's local terminal balance from which the redemption is being fulfilled.\\n/// @custom:member useDataSourceForPay A flag indicating if the data source should be used for pay transactions during this funding cycle.\\n/// @custom:member useDataSourceForRedeem A flag indicating if the data source should be used for redeem transactions during this funding cycle.\\n/// @custom:member dataSource The data source to use during this funding cycle.\\n/// @custom:member metadata Metadata of the metadata, up to uint8 in size.\\nstruct JBFundingCycleMetadata {\\n JBGlobalFundingCycleMetadata global;\\n uint256 reservedRate;\\n uint256 redemptionRate;\\n uint256 ballotRedemptionRate;\\n bool pausePay;\\n bool pauseDistributions;\\n bool pauseRedeem;\\n bool pauseBurn;\\n bool allowMinting;\\n bool allowTerminalMigration;\\n bool allowControllerMigration;\\n bool holdFees;\\n bool preferClaimedTokenOverride;\\n bool useTotalOverflowForRedemptions;\\n bool useDataSourceForPay;\\n bool useDataSourceForRedeem;\\n address dataSource;\\n uint256 metadata;\\n}\\n\",\"keccak256\":\"0x477bbd36c94da3f56fac6c8c60b2e2e3c5b8fc557a880b5359980bc556ccd300\",\"license\":\"MIT\"},\"contracts/structs/JBGlobalFundingCycleMetadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/// @custom:member allowSetTerminals A flag indicating if setting terminals should be allowed during this funding cycle.\\n/// @custom:member allowSetController A flag indicating if setting a new controller should be allowed during this funding cycle.\\n/// @custom:member pauseTransfers A flag indicating if the project token transfer functionality should be paused during the funding cycle.\\nstruct JBGlobalFundingCycleMetadata {\\n bool allowSetTerminals;\\n bool allowSetController;\\n bool pauseTransfers;\\n}\\n\",\"keccak256\":\"0x5f95bce22550c69bb7b1ee17279d51415ae8bae10c5b759c8b88f0b0aba854ed\",\"license\":\"MIT\"},\"contracts/structs/JBGroupedSplits.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBSplit} from './JBSplit.sol';\\n\\n/// @custom:member group The group indentifier.\\n/// @custom:member splits The splits to associate with the group.\\nstruct JBGroupedSplits {\\n uint256 group;\\n JBSplit[] splits;\\n}\\n\",\"keccak256\":\"0x71fcdbff5cd055cee8d06b73568c44cedda8f5a2351e7d8ce9dd71d8a1f914a8\",\"license\":\"MIT\"},\"contracts/structs/JBOperatorData.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/// @custom:member operator The address of the operator.\\n/// @custom:member domain The domain within which the operator is being given permissions. A domain of 0 is a wildcard domain, which gives an operator access to all domains.\\n/// @custom:member permissionIndexes The indexes of the permissions the operator is being given.\\nstruct JBOperatorData {\\n address operator;\\n uint256 domain;\\n uint256[] permissionIndexes;\\n}\\n\",\"keccak256\":\"0x77fba183d08748c7b75a12425f987b1b48f6bbfec0284517ffaf261429b45a7c\",\"license\":\"MIT\"},\"contracts/structs/JBPayDelegateAllocation3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBPayDelegate3_1_1} from '../interfaces/IJBPayDelegate3_1_1.sol';\\n\\n/// @custom:member delegate A delegate contract to use for subsequent calls.\\n/// @custom:member amount The amount to send to the delegate.\\n/// @custom:member metadata Metadata to pass the delegate.\\nstruct JBPayDelegateAllocation3_1_1 {\\n IJBPayDelegate3_1_1 delegate;\\n uint256 amount;\\n bytes metadata;\\n}\\n\",\"keccak256\":\"0x8d87206a7015af9ec9e5fc059e39bfcea44aa007f8812213c6fd489d0a9c2e17\",\"license\":\"MIT\"},\"contracts/structs/JBProjectMetadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/// @custom:member content The metadata content.\\n/// @custom:member domain The domain within which the metadata applies.\\nstruct JBProjectMetadata {\\n string content;\\n uint256 domain;\\n}\\n\",\"keccak256\":\"0x9545ea42927f3451c9d901a2f7ab7c1aeef3242e5ed2b75521a90225a5a0f891\",\"license\":\"MIT\"},\"contracts/structs/JBRedemptionDelegateAllocation3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBRedemptionDelegate3_1_1} from '../interfaces/IJBRedemptionDelegate3_1_1.sol';\\n\\n/// @custom:member delegate A delegate contract to use for subsequent calls.\\n/// @custom:member amount The amount to send to the delegate.\\n/// @custom:member metadata Metadata to pass the delegate.\\nstruct JBRedemptionDelegateAllocation3_1_1 {\\n IJBRedemptionDelegate3_1_1 delegate;\\n uint256 amount;\\n bytes metadata;\\n}\\n\",\"keccak256\":\"0x16d2b586f4591b0d18324f233b4d4a13c6dc687b5f2c5becadbedbbdc373cdc4\",\"license\":\"MIT\"},\"contracts/structs/JBSplit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBSplitAllocator} from './../interfaces/IJBSplitAllocator.sol';\\n\\n/// @custom:member preferClaimed A flag that only has effect if a projectId is also specified, and the project has a token contract attached. If so, this flag indicates if the tokens that result from making a payment to the project should be delivered claimed into the beneficiary's wallet, or unclaimed to save gas.\\n/// @custom:member preferAddToBalance A flag indicating if a distribution to a project should prefer triggering it's addToBalance function instead of its pay function.\\n/// @custom:member percent The percent of the whole group that this split occupies. This number is out of `JBConstants.SPLITS_TOTAL_PERCENT`.\\n/// @custom:member projectId The ID of a project. If an allocator is not set but a projectId is set, funds will be sent to the protocol treasury belonging to the project who's ID is specified. Resulting tokens will be routed to the beneficiary with the claimed token preference respected.\\n/// @custom:member beneficiary An address. The role the of the beneficary depends on whether or not projectId is specified, and whether or not an allocator is specified. If allocator is set, the beneficiary will be forwarded to the allocator for it to use. If allocator is not set but projectId is set, the beneficiary is the address to which the project's tokens will be sent that result from a payment to it. If neither allocator or projectId are set, the beneficiary is where the funds from the split will be sent.\\n/// @custom:member lockedUntil Specifies if the split should be unchangeable until the specified time, with the exception of extending the locked period.\\n/// @custom:member allocator If an allocator is specified, funds will be sent to the allocator contract along with all properties of this split.\\nstruct JBSplit {\\n bool preferClaimed;\\n bool preferAddToBalance;\\n uint256 percent;\\n uint256 projectId;\\n address payable beneficiary;\\n uint256 lockedUntil;\\n IJBSplitAllocator allocator;\\n}\\n\",\"keccak256\":\"0x7bf3f79f95cf6211dcdcf5af68ddc963f2304379ea50a5feaf27c645879fe3fe\",\"license\":\"MIT\"},\"contracts/structs/JBSplitAllocationData.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBSplit} from './JBSplit.sol';\\n\\n/// @custom:member token The token being sent to the split allocator.\\n/// @custom:member amount The amount being sent to the split allocator, as a fixed point number.\\n/// @custom:member decimals The number of decimals in the amount.\\n/// @custom:member projectId The project to which the split belongs.\\n/// @custom:member group The group to which the split belongs.\\n/// @custom:member split The split that caused the allocation.\\nstruct JBSplitAllocationData {\\n address token;\\n uint256 amount;\\n uint256 decimals;\\n uint256 projectId;\\n uint256 group;\\n JBSplit split;\\n}\\n\",\"keccak256\":\"0x85dcbcad02f315a1a3cc44140ffc77fdfbcafed7089eab55ffb66f1bebc2b40b\",\"license\":\"MIT\"},\"contracts/structs/JBTokenAmount.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/// @custom:member token The token the payment was made in.\\n/// @custom:member value The amount of tokens that was paid, as a fixed point number.\\n/// @custom:member decimals The number of decimals included in the value fixed point number.\\n/// @custom:member currency The expected currency of the value.\\nstruct JBTokenAmount {\\n address token;\\n uint256 value;\\n uint256 decimals;\\n uint256 currency;\\n}\\n\",\"keccak256\":\"0x9317f1f47aef544de592a48a4b20fa3d54586d988c8bb7420b40076920ea200d\",\"license\":\"MIT\"},\"prb-math/contracts/PRBMath.sol\":{\"content\":\"// SPDX-License-Identifier: Unlicense\\npragma solidity >=0.8.4;\\n\\n/// @notice Emitted when the result overflows uint256.\\nerror PRBMath__MulDivFixedPointOverflow(uint256 prod1);\\n\\n/// @notice Emitted when the result overflows uint256.\\nerror PRBMath__MulDivOverflow(uint256 prod1, uint256 denominator);\\n\\n/// @notice Emitted when one of the inputs is type(int256).min.\\nerror PRBMath__MulDivSignedInputTooSmall();\\n\\n/// @notice Emitted when the intermediary absolute result overflows int256.\\nerror PRBMath__MulDivSignedOverflow(uint256 rAbs);\\n\\n/// @notice Emitted when the input is MIN_SD59x18.\\nerror PRBMathSD59x18__AbsInputTooSmall();\\n\\n/// @notice Emitted when ceiling a number overflows SD59x18.\\nerror PRBMathSD59x18__CeilOverflow(int256 x);\\n\\n/// @notice Emitted when one of the inputs is MIN_SD59x18.\\nerror PRBMathSD59x18__DivInputTooSmall();\\n\\n/// @notice Emitted when one of the intermediary unsigned results overflows SD59x18.\\nerror PRBMathSD59x18__DivOverflow(uint256 rAbs);\\n\\n/// @notice Emitted when the input is greater than 133.084258667509499441.\\nerror PRBMathSD59x18__ExpInputTooBig(int256 x);\\n\\n/// @notice Emitted when the input is greater than 192.\\nerror PRBMathSD59x18__Exp2InputTooBig(int256 x);\\n\\n/// @notice Emitted when flooring a number underflows SD59x18.\\nerror PRBMathSD59x18__FloorUnderflow(int256 x);\\n\\n/// @notice Emitted when converting a basic integer to the fixed-point format overflows SD59x18.\\nerror PRBMathSD59x18__FromIntOverflow(int256 x);\\n\\n/// @notice Emitted when converting a basic integer to the fixed-point format underflows SD59x18.\\nerror PRBMathSD59x18__FromIntUnderflow(int256 x);\\n\\n/// @notice Emitted when the product of the inputs is negative.\\nerror PRBMathSD59x18__GmNegativeProduct(int256 x, int256 y);\\n\\n/// @notice Emitted when multiplying the inputs overflows SD59x18.\\nerror PRBMathSD59x18__GmOverflow(int256 x, int256 y);\\n\\n/// @notice Emitted when the input is less than or equal to zero.\\nerror PRBMathSD59x18__LogInputTooSmall(int256 x);\\n\\n/// @notice Emitted when one of the inputs is MIN_SD59x18.\\nerror PRBMathSD59x18__MulInputTooSmall();\\n\\n/// @notice Emitted when the intermediary absolute result overflows SD59x18.\\nerror PRBMathSD59x18__MulOverflow(uint256 rAbs);\\n\\n/// @notice Emitted when the intermediary absolute result overflows SD59x18.\\nerror PRBMathSD59x18__PowuOverflow(uint256 rAbs);\\n\\n/// @notice Emitted when the input is negative.\\nerror PRBMathSD59x18__SqrtNegativeInput(int256 x);\\n\\n/// @notice Emitted when the calculating the square root overflows SD59x18.\\nerror PRBMathSD59x18__SqrtOverflow(int256 x);\\n\\n/// @notice Emitted when addition overflows UD60x18.\\nerror PRBMathUD60x18__AddOverflow(uint256 x, uint256 y);\\n\\n/// @notice Emitted when ceiling a number overflows UD60x18.\\nerror PRBMathUD60x18__CeilOverflow(uint256 x);\\n\\n/// @notice Emitted when the input is greater than 133.084258667509499441.\\nerror PRBMathUD60x18__ExpInputTooBig(uint256 x);\\n\\n/// @notice Emitted when the input is greater than 192.\\nerror PRBMathUD60x18__Exp2InputTooBig(uint256 x);\\n\\n/// @notice Emitted when converting a basic integer to the fixed-point format format overflows UD60x18.\\nerror PRBMathUD60x18__FromUintOverflow(uint256 x);\\n\\n/// @notice Emitted when multiplying the inputs overflows UD60x18.\\nerror PRBMathUD60x18__GmOverflow(uint256 x, uint256 y);\\n\\n/// @notice Emitted when the input is less than 1.\\nerror PRBMathUD60x18__LogInputTooSmall(uint256 x);\\n\\n/// @notice Emitted when the calculating the square root overflows UD60x18.\\nerror PRBMathUD60x18__SqrtOverflow(uint256 x);\\n\\n/// @notice Emitted when subtraction underflows UD60x18.\\nerror PRBMathUD60x18__SubUnderflow(uint256 x, uint256 y);\\n\\n/// @dev Common mathematical functions used in both PRBMathSD59x18 and PRBMathUD60x18. Note that this shared library\\n/// does not always assume the signed 59.18-decimal fixed-point or the unsigned 60.18-decimal fixed-point\\n/// representation. When it does not, it is explicitly mentioned in the NatSpec documentation.\\nlibrary PRBMath {\\n /// STRUCTS ///\\n\\n struct SD59x18 {\\n int256 value;\\n }\\n\\n struct UD60x18 {\\n uint256 value;\\n }\\n\\n /// STORAGE ///\\n\\n /// @dev How many trailing decimals can be represented.\\n uint256 internal constant SCALE = 1e18;\\n\\n /// @dev Largest power of two divisor of SCALE.\\n uint256 internal constant SCALE_LPOTD = 262144;\\n\\n /// @dev SCALE inverted mod 2^256.\\n uint256 internal constant SCALE_INVERSE =\\n 78156646155174841979727994598816262306175212592076161876661_508869554232690281;\\n\\n /// FUNCTIONS ///\\n\\n /// @notice Calculates the binary exponent of x using the binary fraction method.\\n /// @dev Has to use 192.64-bit fixed-point numbers.\\n /// See https://ethereum.stackexchange.com/a/96594/24693.\\n /// @param x The exponent as an unsigned 192.64-bit fixed-point number.\\n /// @return result The result as an unsigned 60.18-decimal fixed-point number.\\n function exp2(uint256 x) internal pure returns (uint256 result) {\\n unchecked {\\n // Start from 0.5 in the 192.64-bit fixed-point format.\\n result = 0x800000000000000000000000000000000000000000000000;\\n\\n // Multiply the result by root(2, 2^-i) when the bit at position i is 1. None of the intermediary results overflows\\n // because the initial result is 2^191 and all magic factors are less than 2^65.\\n if (x & 0x8000000000000000 > 0) {\\n result = (result * 0x16A09E667F3BCC909) >> 64;\\n }\\n if (x & 0x4000000000000000 > 0) {\\n result = (result * 0x1306FE0A31B7152DF) >> 64;\\n }\\n if (x & 0x2000000000000000 > 0) {\\n result = (result * 0x1172B83C7D517ADCE) >> 64;\\n }\\n if (x & 0x1000000000000000 > 0) {\\n result = (result * 0x10B5586CF9890F62A) >> 64;\\n }\\n if (x & 0x800000000000000 > 0) {\\n result = (result * 0x1059B0D31585743AE) >> 64;\\n }\\n if (x & 0x400000000000000 > 0) {\\n result = (result * 0x102C9A3E778060EE7) >> 64;\\n }\\n if (x & 0x200000000000000 > 0) {\\n result = (result * 0x10163DA9FB33356D8) >> 64;\\n }\\n if (x & 0x100000000000000 > 0) {\\n result = (result * 0x100B1AFA5ABCBED61) >> 64;\\n }\\n if (x & 0x80000000000000 > 0) {\\n result = (result * 0x10058C86DA1C09EA2) >> 64;\\n }\\n if (x & 0x40000000000000 > 0) {\\n result = (result * 0x1002C605E2E8CEC50) >> 64;\\n }\\n if (x & 0x20000000000000 > 0) {\\n result = (result * 0x100162F3904051FA1) >> 64;\\n }\\n if (x & 0x10000000000000 > 0) {\\n result = (result * 0x1000B175EFFDC76BA) >> 64;\\n }\\n if (x & 0x8000000000000 > 0) {\\n result = (result * 0x100058BA01FB9F96D) >> 64;\\n }\\n if (x & 0x4000000000000 > 0) {\\n result = (result * 0x10002C5CC37DA9492) >> 64;\\n }\\n if (x & 0x2000000000000 > 0) {\\n result = (result * 0x1000162E525EE0547) >> 64;\\n }\\n if (x & 0x1000000000000 > 0) {\\n result = (result * 0x10000B17255775C04) >> 64;\\n }\\n if (x & 0x800000000000 > 0) {\\n result = (result * 0x1000058B91B5BC9AE) >> 64;\\n }\\n if (x & 0x400000000000 > 0) {\\n result = (result * 0x100002C5C89D5EC6D) >> 64;\\n }\\n if (x & 0x200000000000 > 0) {\\n result = (result * 0x10000162E43F4F831) >> 64;\\n }\\n if (x & 0x100000000000 > 0) {\\n result = (result * 0x100000B1721BCFC9A) >> 64;\\n }\\n if (x & 0x80000000000 > 0) {\\n result = (result * 0x10000058B90CF1E6E) >> 64;\\n }\\n if (x & 0x40000000000 > 0) {\\n result = (result * 0x1000002C5C863B73F) >> 64;\\n }\\n if (x & 0x20000000000 > 0) {\\n result = (result * 0x100000162E430E5A2) >> 64;\\n }\\n if (x & 0x10000000000 > 0) {\\n result = (result * 0x1000000B172183551) >> 64;\\n }\\n if (x & 0x8000000000 > 0) {\\n result = (result * 0x100000058B90C0B49) >> 64;\\n }\\n if (x & 0x4000000000 > 0) {\\n result = (result * 0x10000002C5C8601CC) >> 64;\\n }\\n if (x & 0x2000000000 > 0) {\\n result = (result * 0x1000000162E42FFF0) >> 64;\\n }\\n if (x & 0x1000000000 > 0) {\\n result = (result * 0x10000000B17217FBB) >> 64;\\n }\\n if (x & 0x800000000 > 0) {\\n result = (result * 0x1000000058B90BFCE) >> 64;\\n }\\n if (x & 0x400000000 > 0) {\\n result = (result * 0x100000002C5C85FE3) >> 64;\\n }\\n if (x & 0x200000000 > 0) {\\n result = (result * 0x10000000162E42FF1) >> 64;\\n }\\n if (x & 0x100000000 > 0) {\\n result = (result * 0x100000000B17217F8) >> 64;\\n }\\n if (x & 0x80000000 > 0) {\\n result = (result * 0x10000000058B90BFC) >> 64;\\n }\\n if (x & 0x40000000 > 0) {\\n result = (result * 0x1000000002C5C85FE) >> 64;\\n }\\n if (x & 0x20000000 > 0) {\\n result = (result * 0x100000000162E42FF) >> 64;\\n }\\n if (x & 0x10000000 > 0) {\\n result = (result * 0x1000000000B17217F) >> 64;\\n }\\n if (x & 0x8000000 > 0) {\\n result = (result * 0x100000000058B90C0) >> 64;\\n }\\n if (x & 0x4000000 > 0) {\\n result = (result * 0x10000000002C5C860) >> 64;\\n }\\n if (x & 0x2000000 > 0) {\\n result = (result * 0x1000000000162E430) >> 64;\\n }\\n if (x & 0x1000000 > 0) {\\n result = (result * 0x10000000000B17218) >> 64;\\n }\\n if (x & 0x800000 > 0) {\\n result = (result * 0x1000000000058B90C) >> 64;\\n }\\n if (x & 0x400000 > 0) {\\n result = (result * 0x100000000002C5C86) >> 64;\\n }\\n if (x & 0x200000 > 0) {\\n result = (result * 0x10000000000162E43) >> 64;\\n }\\n if (x & 0x100000 > 0) {\\n result = (result * 0x100000000000B1721) >> 64;\\n }\\n if (x & 0x80000 > 0) {\\n result = (result * 0x10000000000058B91) >> 64;\\n }\\n if (x & 0x40000 > 0) {\\n result = (result * 0x1000000000002C5C8) >> 64;\\n }\\n if (x & 0x20000 > 0) {\\n result = (result * 0x100000000000162E4) >> 64;\\n }\\n if (x & 0x10000 > 0) {\\n result = (result * 0x1000000000000B172) >> 64;\\n }\\n if (x & 0x8000 > 0) {\\n result = (result * 0x100000000000058B9) >> 64;\\n }\\n if (x & 0x4000 > 0) {\\n result = (result * 0x10000000000002C5D) >> 64;\\n }\\n if (x & 0x2000 > 0) {\\n result = (result * 0x1000000000000162E) >> 64;\\n }\\n if (x & 0x1000 > 0) {\\n result = (result * 0x10000000000000B17) >> 64;\\n }\\n if (x & 0x800 > 0) {\\n result = (result * 0x1000000000000058C) >> 64;\\n }\\n if (x & 0x400 > 0) {\\n result = (result * 0x100000000000002C6) >> 64;\\n }\\n if (x & 0x200 > 0) {\\n result = (result * 0x10000000000000163) >> 64;\\n }\\n if (x & 0x100 > 0) {\\n result = (result * 0x100000000000000B1) >> 64;\\n }\\n if (x & 0x80 > 0) {\\n result = (result * 0x10000000000000059) >> 64;\\n }\\n if (x & 0x40 > 0) {\\n result = (result * 0x1000000000000002C) >> 64;\\n }\\n if (x & 0x20 > 0) {\\n result = (result * 0x10000000000000016) >> 64;\\n }\\n if (x & 0x10 > 0) {\\n result = (result * 0x1000000000000000B) >> 64;\\n }\\n if (x & 0x8 > 0) {\\n result = (result * 0x10000000000000006) >> 64;\\n }\\n if (x & 0x4 > 0) {\\n result = (result * 0x10000000000000003) >> 64;\\n }\\n if (x & 0x2 > 0) {\\n result = (result * 0x10000000000000001) >> 64;\\n }\\n if (x & 0x1 > 0) {\\n result = (result * 0x10000000000000001) >> 64;\\n }\\n\\n // We're doing two things at the same time:\\n //\\n // 1. Multiply the result by 2^n + 1, where \\\"2^n\\\" is the integer part and the one is added to account for\\n // the fact that we initially set the result to 0.5. This is accomplished by subtracting from 191\\n // rather than 192.\\n // 2. Convert the result to the unsigned 60.18-decimal fixed-point format.\\n //\\n // This works because 2^(191-ip) = 2^ip / 2^191, where \\\"ip\\\" is the integer part \\\"2^n\\\".\\n result *= SCALE;\\n result >>= (191 - (x >> 64));\\n }\\n }\\n\\n /// @notice Finds the zero-based index of the first one in the binary representation of x.\\n /// @dev See the note on msb in the \\\"Find First Set\\\" Wikipedia article https://en.wikipedia.org/wiki/Find_first_set\\n /// @param x The uint256 number for which to find the index of the most significant bit.\\n /// @return msb The index of the most significant bit as an uint256.\\n function mostSignificantBit(uint256 x) internal pure returns (uint256 msb) {\\n if (x >= 2**128) {\\n x >>= 128;\\n msb += 128;\\n }\\n if (x >= 2**64) {\\n x >>= 64;\\n msb += 64;\\n }\\n if (x >= 2**32) {\\n x >>= 32;\\n msb += 32;\\n }\\n if (x >= 2**16) {\\n x >>= 16;\\n msb += 16;\\n }\\n if (x >= 2**8) {\\n x >>= 8;\\n msb += 8;\\n }\\n if (x >= 2**4) {\\n x >>= 4;\\n msb += 4;\\n }\\n if (x >= 2**2) {\\n x >>= 2;\\n msb += 2;\\n }\\n if (x >= 2**1) {\\n // No need to shift x any more.\\n msb += 1;\\n }\\n }\\n\\n /// @notice Calculates floor(x*y\\u00f7denominator) with full precision.\\n ///\\n /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv.\\n ///\\n /// Requirements:\\n /// - The denominator cannot be zero.\\n /// - The result must fit within uint256.\\n ///\\n /// Caveats:\\n /// - This function does not work with fixed-point numbers.\\n ///\\n /// @param x The multiplicand as an uint256.\\n /// @param y The multiplier as an uint256.\\n /// @param denominator The divisor as an uint256.\\n /// @return result The result as an uint256.\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator\\n ) internal pure returns (uint256 result) {\\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\\n // variables such that product = prod1 * 2^256 + prod0.\\n uint256 prod0; // Least significant 256 bits of the product\\n uint256 prod1; // Most significant 256 bits of the product\\n assembly {\\n let mm := mulmod(x, y, not(0))\\n prod0 := mul(x, y)\\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\\n }\\n\\n // Handle non-overflow cases, 256 by 256 division.\\n if (prod1 == 0) {\\n unchecked {\\n result = prod0 / denominator;\\n }\\n return result;\\n }\\n\\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\\n if (prod1 >= denominator) {\\n revert PRBMath__MulDivOverflow(prod1, denominator);\\n }\\n\\n ///////////////////////////////////////////////\\n // 512 by 256 division.\\n ///////////////////////////////////////////////\\n\\n // Make division exact by subtracting the remainder from [prod1 prod0].\\n uint256 remainder;\\n assembly {\\n // Compute remainder using mulmod.\\n remainder := mulmod(x, y, denominator)\\n\\n // Subtract 256 bit number from 512 bit number.\\n prod1 := sub(prod1, gt(remainder, prod0))\\n prod0 := sub(prod0, remainder)\\n }\\n\\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\\n // See https://cs.stackexchange.com/q/138556/92363.\\n unchecked {\\n // Does not overflow because the denominator cannot be zero at this stage in the function.\\n uint256 lpotdod = denominator & (~denominator + 1);\\n assembly {\\n // Divide denominator by lpotdod.\\n denominator := div(denominator, lpotdod)\\n\\n // Divide [prod1 prod0] by lpotdod.\\n prod0 := div(prod0, lpotdod)\\n\\n // Flip lpotdod such that it is 2^256 / lpotdod. If lpotdod is zero, then it becomes one.\\n lpotdod := add(div(sub(0, lpotdod), lpotdod), 1)\\n }\\n\\n // Shift in bits from prod1 into prod0.\\n prod0 |= prod1 * lpotdod;\\n\\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\\n // four bits. That is, denominator * inv = 1 mod 2^4.\\n uint256 inverse = (3 * denominator) ^ 2;\\n\\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\\n // in modular arithmetic, doubling the correct bits in each step.\\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\\n\\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\\n // is no longer required.\\n result = prod0 * inverse;\\n return result;\\n }\\n }\\n\\n /// @notice Calculates floor(x*y\\u00f71e18) with full precision.\\n ///\\n /// @dev Variant of \\\"mulDiv\\\" with constant folding, i.e. in which the denominator is always 1e18. Before returning the\\n /// final result, we add 1 if (x * y) % SCALE >= HALF_SCALE. Without this, 6.6e-19 would be truncated to 0 instead of\\n /// being rounded to 1e-18. See \\\"Listing 6\\\" and text above it at https://accu.org/index.php/journals/1717.\\n ///\\n /// Requirements:\\n /// - The result must fit within uint256.\\n ///\\n /// Caveats:\\n /// - The body is purposely left uncommented; see the NatSpec comments in \\\"PRBMath.mulDiv\\\" to understand how this works.\\n /// - It is assumed that the result can never be type(uint256).max when x and y solve the following two equations:\\n /// 1. x * y = type(uint256).max * SCALE\\n /// 2. (x * y) % SCALE >= SCALE / 2\\n ///\\n /// @param x The multiplicand as an unsigned 60.18-decimal fixed-point number.\\n /// @param y The multiplier as an unsigned 60.18-decimal fixed-point number.\\n /// @return result The result as an unsigned 60.18-decimal fixed-point number.\\n function mulDivFixedPoint(uint256 x, uint256 y) internal pure returns (uint256 result) {\\n uint256 prod0;\\n uint256 prod1;\\n assembly {\\n let mm := mulmod(x, y, not(0))\\n prod0 := mul(x, y)\\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\\n }\\n\\n if (prod1 >= SCALE) {\\n revert PRBMath__MulDivFixedPointOverflow(prod1);\\n }\\n\\n uint256 remainder;\\n uint256 roundUpUnit;\\n assembly {\\n remainder := mulmod(x, y, SCALE)\\n roundUpUnit := gt(remainder, 499999999999999999)\\n }\\n\\n if (prod1 == 0) {\\n unchecked {\\n result = (prod0 / SCALE) + roundUpUnit;\\n return result;\\n }\\n }\\n\\n assembly {\\n result := add(\\n mul(\\n or(\\n div(sub(prod0, remainder), SCALE_LPOTD),\\n mul(sub(prod1, gt(remainder, prod0)), add(div(sub(0, SCALE_LPOTD), SCALE_LPOTD), 1))\\n ),\\n SCALE_INVERSE\\n ),\\n roundUpUnit\\n )\\n }\\n }\\n\\n /// @notice Calculates floor(x*y\\u00f7denominator) with full precision.\\n ///\\n /// @dev An extension of \\\"mulDiv\\\" for signed numbers. Works by computing the signs and the absolute values separately.\\n ///\\n /// Requirements:\\n /// - None of the inputs can be type(int256).min.\\n /// - The result must fit within int256.\\n ///\\n /// @param x The multiplicand as an int256.\\n /// @param y The multiplier as an int256.\\n /// @param denominator The divisor as an int256.\\n /// @return result The result as an int256.\\n function mulDivSigned(\\n int256 x,\\n int256 y,\\n int256 denominator\\n ) internal pure returns (int256 result) {\\n if (x == type(int256).min || y == type(int256).min || denominator == type(int256).min) {\\n revert PRBMath__MulDivSignedInputTooSmall();\\n }\\n\\n // Get hold of the absolute values of x, y and the denominator.\\n uint256 ax;\\n uint256 ay;\\n uint256 ad;\\n unchecked {\\n ax = x < 0 ? uint256(-x) : uint256(x);\\n ay = y < 0 ? uint256(-y) : uint256(y);\\n ad = denominator < 0 ? uint256(-denominator) : uint256(denominator);\\n }\\n\\n // Compute the absolute value of (x*y)\\u00f7denominator. The result must fit within int256.\\n uint256 rAbs = mulDiv(ax, ay, ad);\\n if (rAbs > uint256(type(int256).max)) {\\n revert PRBMath__MulDivSignedOverflow(rAbs);\\n }\\n\\n // Get the signs of x, y and the denominator.\\n uint256 sx;\\n uint256 sy;\\n uint256 sd;\\n assembly {\\n sx := sgt(x, sub(0, 1))\\n sy := sgt(y, sub(0, 1))\\n sd := sgt(denominator, sub(0, 1))\\n }\\n\\n // XOR over sx, sy and sd. This is checking whether there are one or three negative signs in the inputs.\\n // If yes, the result should be negative.\\n result = sx ^ sy ^ sd == 0 ? -int256(rAbs) : int256(rAbs);\\n }\\n\\n /// @notice Calculates the square root of x, rounding down.\\n /// @dev Uses the Babylonian method https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method.\\n ///\\n /// Caveats:\\n /// - This function does not work with fixed-point numbers.\\n ///\\n /// @param x The uint256 number for which to calculate the square root.\\n /// @return result The result as an uint256.\\n function sqrt(uint256 x) internal pure returns (uint256 result) {\\n if (x == 0) {\\n return 0;\\n }\\n\\n // Set the initial guess to the closest power of two that is higher than x.\\n uint256 xAux = uint256(x);\\n result = 1;\\n if (xAux >= 0x100000000000000000000000000000000) {\\n xAux >>= 128;\\n result <<= 64;\\n }\\n if (xAux >= 0x10000000000000000) {\\n xAux >>= 64;\\n result <<= 32;\\n }\\n if (xAux >= 0x100000000) {\\n xAux >>= 32;\\n result <<= 16;\\n }\\n if (xAux >= 0x10000) {\\n xAux >>= 16;\\n result <<= 8;\\n }\\n if (xAux >= 0x100) {\\n xAux >>= 8;\\n result <<= 4;\\n }\\n if (xAux >= 0x10) {\\n xAux >>= 4;\\n result <<= 2;\\n }\\n if (xAux >= 0x8) {\\n result <<= 1;\\n }\\n\\n // The operations can never overflow because the result is max 2^127 when it enters this block.\\n unchecked {\\n result = (result + x / result) >> 1;\\n result = (result + x / result) >> 1;\\n result = (result + x / result) >> 1;\\n result = (result + x / result) >> 1;\\n result = (result + x / result) >> 1;\\n result = (result + x / result) >> 1;\\n result = (result + x / result) >> 1; // Seven iterations should be enough\\n uint256 roundedDownResult = x / result;\\n return result >= roundedDownResult ? roundedDownResult : result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x62cbabae4910e168e99b9c2c3e3b5c9c7ad5e7abd961dcc63b7ea3d83d8ea87e\",\"license\":\"Unlicense\"}},\"version\":1}", + "bytecode": "0x6101e060405263017d78406002553480156200001a57600080fd5b5060405162005f4a38038062005f4a8339810160408190526200003d916200020a565b61eeee6080819052601260a0819052600160c08190526001600160a01b038a1660e0528a818b8b8b8b8b8b8b6200007433620000cf565b6101a08990526101c08890526001600160a01b0380871661010052858116610120528481166101405283811661016052821661018052620000b5816200011f565b5050505050505050505050505050505050505050620002bf565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000546001600160a01b031633146200017f5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064015b60405180910390fd5b6001600160a01b038116620001e65760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840162000176565b620001f181620000cf565b50565b6001600160a01b0381168114620001f157600080fd5b600080600080600080600080610100898b0312156200022857600080fd5b8851975060208901516200023c81620001f4565b60408a01519097506200024f81620001f4565b60608a01519096506200026281620001f4565b60808a01519095506200027581620001f4565b60a08a01519094506200028881620001f4565b60c08a01519093506200029b81620001f4565b60e08a0151909250620002ae81620001f4565b809150509295985092959890939650565b60805160a05160c05160e05161010051610120516101405161016051610180516101a0516101c051615a2f6200051b600039600081816103cf015261206e01526000818161030701526118d00152600081816104f701528181610ad5015281816112fc0152818161189e01528181611f19015281816126250152818161298701528181612a9401526136d101526000818161065601526114810152600081816102bb01526133a801526000818161060f0152818161173b01528181611981015281816123ce01528181612bdf0152818161324e0152613ea80152600081816104a50152818161099001528181610e7d0152818161123101528181611fc501526126df01526000818161056b01528181611dad01528181611e4901528181612200015261229c0152600081816102660152818161070e015281816113cc0152818161142e0152818161187801528181611b5401528181612d750152612e0501526000818161033b015281816105db0152818161136d01528181611399015281816113f90152818161145b0152818161185201528181611b2e01528181612d4f01528181612ddf0152613c5c0152600081816106cc015281816107620152818161087e01528181610a2801528181610b5601528181610bc9015281816115130152818161181d01528181611af801528181611c46015281816123a30152818161245a0152818161249501528181612d1a01528181612da901528181612f320152818161322101528181613c2701528181613ccf01528181613ed5015281816140300152818161406e015281816141a301526141e70152615a2f6000f3fe6080604052600436106101f95760003560e01c80638da5cb5b1161010d578063c715967a116100a0578063df21a7dd1161006f578063df21a7dd146106ae578063e5a6b10f146106fc578063f2fde38b14610730578063fc0c546a14610750578063fe663f0f1461078457600080fd5b8063c715967a14610631578063d3419bf314610644578063d6dacc5314610678578063ddca3f431461069857600080fd5b8063ad007d63116100dc578063ad007d6314610559578063b631b5001461058d578063b7bad1b1146105bd578063c41c2f24146105fd57600080fd5b80638da5cb5b146104c7578063975057e7146104e5578063a02f801c14610519578063a32e1e961461053957600080fd5b80634a4305c011610190578063715018a61161015f578063715018a6146104115780637258002c1461042657806389701db5146104465780638af56094146104665780638b79543c1461049357600080fd5b80634a4305c01461037d578063637913ac1461039d57806366248b86146103bd57806369fe0e2d146103f157600080fd5b80632bdfe004116101cc5780632bdfe004146102a95780632d1a5903146102f5578063313ce56714610329578063405b84fa1461035d57600080fd5b806301ffc9a7146101fe5780630cf8e858146102335780631982d679146102485780631ebc263f14610296575b600080fd5b34801561020a57600080fd5b5061021e6102193660046144ec565b6107a4565b60405190151581526020015b60405180910390f35b610246610241366004614573565b61084e565b005b34801561025457600080fd5b50610288610263366004614608565b507f000000000000000000000000000000000000000000000000000000000000000090565b60405190815260200161022a565b6102886102a4366004614633565b610871565b3480156102b557600080fd5b506102dd7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200161022a565b34801561030157600080fd5b506102887f000000000000000000000000000000000000000000000000000000000000000081565b34801561033557600080fd5b506102887f000000000000000000000000000000000000000000000000000000000000000081565b34801561036957600080fd5b506102886103783660046146fa565b610977565b34801561038957600080fd5b5061028861039836600461472a565b610c73565b3480156103a957600080fd5b506102466103b8366004614608565b610c8f565b3480156103c957600080fd5b506102887f000000000000000000000000000000000000000000000000000000000000000081565b3480156103fd57600080fd5b5061024661040c366004614793565b610d16565b34801561041d57600080fd5b50610246610da5565b34801561043257600080fd5b506102466104413660046147ac565b610ddb565b34801561045257600080fd5b50610246610461366004614793565b610e67565b34801561047257600080fd5b50610486610481366004614793565b61116b565b60405161022a91906147da565b34801561049f57600080fd5b506102dd7f000000000000000000000000000000000000000000000000000000000000000081565b3480156104d357600080fd5b506000546001600160a01b03166102dd565b3480156104f157600080fd5b506102dd7f000000000000000000000000000000000000000000000000000000000000000081565b34801561052557600080fd5b50610288610534366004614980565b611218565b34801561054557600080fd5b50610288610554366004614793565b6112d3565b34801561056557600080fd5b506102dd7f000000000000000000000000000000000000000000000000000000000000000081565b34801561059957600080fd5b5061021e6105a8366004614608565b60046020526000908152604090205460ff1681565b3480156105c957600080fd5b506102886105d8366004614608565b507f000000000000000000000000000000000000000000000000000000000000000090565b34801561060957600080fd5b506102dd7f000000000000000000000000000000000000000000000000000000000000000081565b61024661063f366004614a38565b611508565b34801561065057600080fd5b506102dd7f000000000000000000000000000000000000000000000000000000000000000081565b34801561068457600080fd5b506003546102dd906001600160a01b031681565b3480156106a457600080fd5b5061028860025481565b3480156106ba57600080fd5b5061021e6106c9366004614adf565b507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b34801561070857600080fd5b506102887f000000000000000000000000000000000000000000000000000000000000000081565b34801561073c57600080fd5b5061024661074b366004614608565b611604565b34801561075c57600080fd5b506102dd7f000000000000000000000000000000000000000000000000000000000000000081565b34801561079057600080fd5b5061028861079f366004614b0b565b61169f565b60006001600160e01b0319821615806107cd57506001600160e01b0319821663edb527eb60e01b145b806107e857506001600160e01b031982166301290c1760e61b145b8061080357506001600160e01b0319821663280be00760e21b145b8061081e57506001600160e01b0319821663fe663f0f60e01b145b8061083957506001600160e01b0319821663ad007d6360e01b145b806108485750610848826116cf565b92915050565b6108578761171f565b610868878787600088888888611508565b50505050505050565b600061087c8b61171f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031661eeee146108eb5734156108cd57604051635e7e9adf60e11b815260040160405180910390fd5b476108d933308d6117cb565b6108e38147614bd9565b9a50506108ef565b3499505b6109688a338d8b8b8b8b8b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8f018190048102820181019092528d815292508d91508c90819084018382808284376000920191909152506117da92505050565b9b9a5050505050505050505050565b6040516331a9108f60e11b8152600481018390526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636352211e90602401602060405180830381865afa1580156109df573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a039190614bec565b836004610a11838383611d82565b60405163df21a7dd60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301526024820188905286169063df21a7dd90604401602060405180830381865afa158015610a7e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aa29190614c09565b610abf5760405163581010ed60e01b815260040160405180910390fd5b604051636bb6a5ad60e01b8152600481018790527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636bb6a5ad906024016020604051808303816000875af1158015610b26573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b4a9190614c26565b93508315610c255760007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031661eeee14610b8d576000610b8f565b845b6040805160208101825260008152905163019f1d0b60e31b81529192506001600160a01b03881691630cf8e858918491610bf1918c918b917f000000000000000000000000000000000000000000000000000000000000000091600401614c8f565b6000604051808303818588803b158015610c0a57600080fd5b505af1158015610c1e573d6000803e3d6000fd5b5050505050505b604080518581523360208201526001600160a01b0387169188917fa7519e5f94697b7f53e97c5eb46a0c730a296ab686ab8fd333835c5f735784eb910160405180910390a350505092915050565b6000610c83888888878787611ee6565b98975050505050505050565b6000546001600160a01b03163314610cc25760405162461bcd60e51b8152600401610cb990614cca565b60405180910390fd5b600380546001600160a01b0319166001600160a01b0383169081179091556040513381527f0a9a80fe9716605b3e52abb3d792d6a4e7816d6afc02a5a4ef023081feaf9f609060200160405180910390a250565b6000546001600160a01b03163314610d405760405162461bcd60e51b8152600401610cb990614cca565b6302faf080811115610d65576040516345fbd9c160e01b815260040160405180910390fd5b6002819055604080518281523360208201527fd7414e590e1cb532989ab2a34c8f4c2c17f7ab6f006efeeaef2e87cd5008c202910160405180910390a150565b6000546001600160a01b03163314610dcf5760405162461bcd60e51b8152600401610cb990614cca565b610dd9600061217b565b565b6000546001600160a01b03163314610e055760405162461bcd60e51b8152600401610cb990614cca565b6001600160a01b038216600081815260046020908152604091829020805460ff191685151590811790915591513381529192917fa2653e25a502c023a5830d0de847ef6f458387865b1f4f575d7594f9f2c0d71e910160405180910390a35050565b6040516331a9108f60e11b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636352211e90602401602060405180830381865afa158015610ecc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ef09190614bec565b816005610f056000546001600160a01b031690565b6001600160a01b0316336001600160a01b031614610f25848484846121cb565b600085815260016020908152604080832080548251818502810185019093528083529192909190849084015b82821015610fbe57600084815260209081902060408051608081018252600286029092018054835260019081015463ffffffff8082168587015264010000000082041692840192909252600160401b9091046001600160a01b031660608301529083529092019101610f51565b5050506000888152600160205260408120929350610fdd92915061444b565b80516000805b8281101561116057838181518110610ffd57610ffd614cff565b60200260200101516020015163ffffffff16600014806110435750633b9aca0084828151811061102f5761102f614cff565b60200260200101516040015163ffffffff16145b6110ba576110b584828151811061105c5761105c614cff565b60200260200101516000015185838151811061107a5761107a614cff565b60200260200101516020015163ffffffff1686848151811061109e5761109e614cff565b60200260200101516040015163ffffffff1661233f565b6110bd565b60005b91506110e7828583815181106110d5576110d5614cff565b6020026020010151606001518b612385565b60011515828a7fcf0c92a2c6d7c42f488326b0cb900104b99984b6b218db81cd29371364a3525187858151811061112057611120614cff565b602002602001015160600151336040516111509291906001600160a01b0392831681529116602082015260400190565b60405180910390a4600101610fe3565b505050505050505050565b606060016000838152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b8282101561120d57600084815260209081902060408051608081018252600286029092018054835260019081015463ffffffff8082168587015264010000000082041692840192909252600160401b9091046001600160a01b0316606083015290835290920191016111a0565b505050509050919050565b6040516331a9108f60e11b8152600481018a90526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636352211e90602401602060405180830381865afa158015611280573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112a49190614bec565b8a60116112b2838383611d82565b6112c28d8d8d8c8c8c8c8c6125f2565b9d9c50505050505050505050505050565b60405163035240c760e61b81523060048201526024810182905260009081906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063d49031c090604401602060405180830381865afa158015611343573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113679190614c26565b905060007f00000000000000000000000000000000000000000000000000000000000000006012146113c4576113bf827f00000000000000000000000000000000000000000000000000000000000000006012612839565b6113c6565b815b905060017f0000000000000000000000000000000000000000000000000000000000000000146114fe576114f98161141f7f0000000000000000000000000000000000000000000000000000000000000000600a614df9565b604051635268657960e11b81527f00000000000000000000000000000000000000000000000000000000000000006004820152600160248201527f000000000000000000000000000000000000000000000000000000000000000060448201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a4d0caf290606401602060405180830381865afa1580156114d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114f49190614c26565b612896565b611500565b805b949350505050565b6115118861171f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031661eeee1461158057341561156257604051635e7e9adf60e11b815260040160405180910390fd5b4761156e33308a6117cb565b6115788147614bd9565b975050611584565b3496505b6115fa88888787878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8b01819004810282018101909252898152925089915088908190840183828082843760009201919091525061296392505050565b5050505050505050565b6000546001600160a01b0316331461162e5760405162461bcd60e51b8152600401610cb990614cca565b6001600160a01b0381166116935760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610cb9565b61169c8161217b565b50565b6000888860026116b0838383611d82565b6116bf8c8c8c8b8b8b8b612a55565b9c9b505050505050505050505050565b60006001600160e01b0319821663301cdc3960e21b148061170057506001600160e01b0319821663144b000160e11b145b8061084857506301ffc9a760e01b6001600160e01b0319831614610848565b604051636e49181f60e01b8152600481018290523060248201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636e49181f90604401602060405180830381865afa15801561178a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117ae9190614c09565b61169c57604051631b1d5a5960e31b815260040160405180910390fd5b6117d582826130ea565b505050565b60006001600160a01b0386166118035760405163a762251360e01b815260040160405180910390fd5b61180b61446c565b606060008060405180608001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020018e81526020017f000000000000000000000000000000000000000000000000000000000000000081526020017f000000000000000000000000000000000000000000000000000000000000000081525090507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632fa1b3918d838e7f00000000000000000000000000000000000000000000000000000000000000008f8d8d6040518863ffffffff1660e01b81526004016119149796959493929190614e31565b6000604051808303816000875af1158015611933573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261195b9190810190614f95565b995091955090935091508115611a9057604051632eec7b5560e11b8152600481018c90527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635dd8f6aa90602401602060405180830381865afa1580156119d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119f49190614bec565b604051638ae9c07b60e01b8152600481018d9052602481018490526001600160a01b038c8116604483015260c06064830152600060c48301528a15156084830152600160a48301529190911690638ae9c07b9060e4016020604051808303816000875af1158015611a69573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a8d9190614c26565b94505b88851015611ab157604051633dca309360e11b815260040160405180910390fd5b825115611d245760006040518061016001604052808e6001600160a01b031681526020018d81526020018660200151815260200183815260200160405180608001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602001600081526020017f000000000000000000000000000000000000000000000000000000000000000081526020017f000000000000000000000000000000000000000000000000000000000000000081525081526020018781526020018c6001600160a01b031681526020018a15158152602001898152602001604051806020016040528060008152508152602001888152509050600084519050611bec604051806060016040528060006001600160a01b0316815260200160008152602001606081525090565b60005b82811015611d1f57868181518110611c0957611c09614cff565b60209081029190910101519150602080830151608086015190910152604082015161012085015281516001600160a01b0390811690636b204943907f00000000000000000000000000000000000000000000000000000000000000001661eeee14611c75576000611c7b565b83602001515b866040518363ffffffff1660e01b8152600401611c9891906151b0565b6000604051808303818588803b158015611cb157600080fd5b505af1158015611cc5573d6000803e3d6000fd5b505050505081600001516001600160a01b03167f232bbbe420e7bac6f941dc82678daec2b4c712378d91e864b69aab6e26cdd42485846020015133604051611d0f939291906151c3565b60405180910390a2600101611bef565b505050505b50505087816000015182602001517f133161f1c9161488f777ab9a26aae91d47c0d9a3fafb398960f138db02c737978c8b8f888b8b33604051611d6d97969594939291906151f6565b60405180910390a45098975050505050505050565b336001600160a01b03841614801590611e2b575060405163c161c93f60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063c161c93f90611de8903390879087908790600401615256565b602060405180830381865afa158015611e05573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e299190614c09565b155b8015611ec8575060405163c161c93f60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063c161c93f90611e8590339087906000908790600401615256565b602060405180830381865afa158015611ea2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ec69190614c09565b155b156117d55760405163075fd2b160e01b815260040160405180910390fd5b60405163c664459760e01b8152600481018790526024810186905260448101859052600090819081906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063c664459790606401610140604051808303816000875af1158015611f63573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f87919061527f565b9150915085811015611fac5760405163b01493c160e01b815260040160405180910390fd5b6040516331a9108f60e11b8152600481018a90526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636352211e90602401602060405180830381865afa158015612014573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120389190614bec565b600254909150600090818115612058576120538d6000613203565b61205e565b633b9aca005b90506000806120958f89602001517f00000000000000000000000000000000000000000000000000000000000000008a8888613377565b92509050633b9aca0083146120a957908101905b816000036120b85760006120dc565b6120dc8f6120d38a61010001516001604f9190911c81161490565b84878a88613537565b9450801561211957633b9aca0083146120ff576120fa81858561233f565b612102565b60005b61210c9082614bd9565b985061211930878b6117cb565b505050508a846000015185602001517fc41a8d26c70cfcf1b9ea10f82482ac947b8be5bea2750bc729af844bbfde1e28858e88878c8f8f336040516121659897969594939291906152d7565b60405180910390a4505050509695505050505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b801580156121e25750336001600160a01b03851614155b801561227e575060405163c161c93f60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063c161c93f9061223b903390889088908890600401615256565b602060405180830381865afa158015612258573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061227c9190614c09565b155b801561231b575060405163c161c93f60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063c161c93f906122d890339088906000908890600401615256565b602060405180830381865afa1580156122f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123199190614c09565b155b156123395760405163075fd2b160e01b815260040160405180910390fd5b50505050565b6000806123518484633b9aca00612896565b61235b9085614bd9565b905061237085633b9aca006114f4818561532a565b61237a9086614bd9565b9150505b9392505050565b604051630862026560e41b8152600160048201526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660248301526000917f000000000000000000000000000000000000000000000000000000000000000090911690638620265090604401602060405180830381865afa158015612417573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061243b9190614bec565b9050806001600160a01b0316631ebc263f61eeee6001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03161461248e576000612490565b855b6001877f0000000000000000000000000000000000000000000000000000000000000000886000808a6040516020016124cb91815260200190565b6040516020818303038152906040526040518963ffffffff1660e01b81526004016124fc979695949392919061533d565b60206040518083038185885af193505050508015612537575060408051601f3d908101601f1916820190925261253491810190614c26565b60015b6125eb573d808015612565576040519150601f19603f3d011682016040523d82523d6000602084013e61256a565b606091505b506125a783306001600160a01b03851603612586576000612588565b835b306001600160a01b0386160361259f5760006125a1565b875b886136b4565b6001837f80a889d08f0d59eb962335b57fb1d5b29e86e3d23f15087b5541fddf15422bbe8784336040516125dd93929190615395565b60405180910390a350612339565b5050505050565b604051632538671560e01b8152600481018990526024810188905260448101879052600090819081906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690632538671590606401610140604051808303816000875af115801561266f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612693919061527f565b91509150878110156126b85760405163b01493c160e01b815260040160405180910390fd5b6002546040516331a9108f60e11b8152600481018d90526000919082906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690636352211e90602401602060405180830381865afa158015612726573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061274a9190614bec565b9050600082158061276a57503360009081526004602052604090205460ff165b61277e576127798f6001613203565b612784565b633b9aca005b9050633b9aca0081146127ba576127b58f6127ac8861010001516001604f9190911c81161490565b87868686613537565b6127bd565b60005b93508385039650866000146127d7576127d7308c896117cb565b505050508a826000015183602001517f2eeee47c6d8d31c3523c3aa07b4c3e3795db36be4c04546ef3e30a5102f568e18a8e86898d8d8d336040516128239897969594939291906153c6565b60405180910390a4505098975050505050505050565b600082820361284957508261237e565b828211156128775761285b8383614bd9565b61286690600a614df9565b6128709085615426565b905061237e565b6128818284614bd9565b61288c90600a614df9565b612870908561545b565b60008080600019858709858702925082811083820303915050806000036128d0578382816128c6576128c6615445565b049250505061237e565b8381106128fa57604051631dcf306360e21b81526004810182905260248101859052604401610cb9565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60008361297157600061297b565b61297b8686613731565b90506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663e7c8e3e3876129b7848961532a565b6040516001600160e01b031960e085901b16815260048101929092526024820152604401600060405180830381600087803b1580156129f557600080fd5b505af1158015612a09573d6000803e3d6000fd5b50505050857f9ecaf7fc3dfffd6867c175d6e684b1f1e3aef019398ba8db2c1ffab4a09db2538683868633604051612a4595949392919061547d565b60405180910390a2505050505050565b60006001600160a01b038416612a7e57604051637ba50db360e11b815260040160405180910390fd5b612a8661446c565b6000806000600254905060607f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a2df1f958e8e8e8c8c6040518663ffffffff1660e01b8152600401612ae69594939291906154c9565b6000604051808303816000875af1158015612b05573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612b2d9190810190615508565b6001600160a01b038d16600090815260046020526040902054909b5091985091965090915060ff1680612b7d5750612710612b6786613b85565b148015612b7d5750612710612b7b86613ba2565b145b80612b86575081155b612b9a57612b958c6002613203565b612ba0565b633b9aca005b925089861015612bc35760405163f896960b60e01b815260040160405180910390fd5b8a15612cd357604051632eec7b5560e11b8152600481018d90527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635dd8f6aa90602401602060405180830381865afa158015612c2e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c529190614bec565b604051631665bc0f60e01b81526001600160a01b038f81166004830152602482018f9052604482018e905260a06064830152600060a4830181905260848301529190911690631665bc0f9060c401600060405180830381600087803b158015612cba57600080fd5b505af1158015612cce573d6000803e3d6000fd5b505050505b8051156130135760006040518061014001604052808f6001600160a01b031681526020018e8152602001876020015181526020018d815260200160405180608001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020018a81526020017f000000000000000000000000000000000000000000000000000000000000000081526020017f0000000000000000000000000000000000000000000000000000000000000000815250815260200160405180608001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602001600081526020017f000000000000000000000000000000000000000000000000000000000000000081526020017f000000000000000000000000000000000000000000000000000000000000000081525081526020018b6001600160a01b031681526020018a8152602001604051806020016040528060008152508152602001898152509050612e89604051806060016040528060006001600160a01b0316815260200160008152602001606081525090565b8251600090815b8181101561300d57858181518110612eaa57612eaa614cff565b6020026020010151935086600014612ed057612ecb8460200151888a61233f565b612ed3565b60005b92508215612f02576020840151612eea908a61532a565b98508284602001818151612efe9190614bd9565b9052505b60208085015160a087015190910152604084015161010086015283516001600160a01b0390811690630bf46e59907f00000000000000000000000000000000000000000000000000000000000000001661eeee14612f61576000612f67565b85602001515b876040518363ffffffff1660e01b8152600401612f8491906156da565b6000604051808303818588803b158015612f9d57600080fd5b505af1158015612fb1573d6000803e3d6000fd5b505050505083600001516001600160a01b03167f6596068545b2541b0aff5579d91f991d0fe5957df8e2082483ef361953e1f9978686602001518633604051612ffd94939291906156ed565b60405180910390a2600101612e90565b50505050505b50841561306e576000633b9aca0083146130375761303286838561233f565b61303a565b60005b9050801561305b5761304c868561532a565b93506130588187614bd9565b95505b851561306c5761306c308a886117cb565b505b8260000361307d57600061308c565b61308c8b600085848c87613537565b5050505087816000015182602001517f2be10f2a0203c77d0fcaa9fd6484a8a1d6904de31cd820587f60c1c8c338c8148c898c888b8b336040516130d697969594939291906151f6565b60405180910390a450979650505050505050565b8047101561313a5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e63650000006044820152606401610cb9565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114613187576040519150601f19603f3d011682016040523d82523d6000602084013e61318c565b606091505b50509050806117d55760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d617920686176652072657665727465640000000000006064820152608401610cb9565b604051630862026560e41b8152600160048201526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116602483015260009182917f00000000000000000000000000000000000000000000000000000000000000001690638620265090604401602060405180830381865afa158015613295573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132b99190614bec565b6001600160a01b0316036132d25750633b9aca00610848565b6003546001600160a01b03161561336e5760035460405163192dd60960e01b81526001600160a01b039091169063192dd609906133159086908690600401615725565b602060405180830381865afa92505050801561334e575060408051601f3d908101601f1916820190925261334b91810190614c26565b60015b61335a57506000610848565b633b9aca00811161336c579050610848565b505b50600092915050565b6040516369e11cc560e01b81526004810187905260248101869052604481018590526000908190633b9aca009082907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906369e11cc590606401600060405180830381865afa1580156133f7573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261341f9190810190615757565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081018290529192505b82518110156135255782818151811061347657613476614cff565b6020026020010151915060006134918a846040015187612896565b905060006134a3848f8e858e8e613bbf565b905080158015906134b45750818114155b156134c6576134c3828861532a565b96505b81156134d257818b039a505b8360400151860395508b8d8f7f0d31ab573f6daa4b1edba8d31973b4ba9f98fbfecc47010c1533eeefd2a1225a8786863360405161351394939291906158b4565b60405180910390a4505060010161345b565b50879450505050965096945050505050565b600061354485858461233f565b9050851561365657600087815260016020818152604080842081516080810183528a815263ffffffff808b168286019081528982168386019081526001600160a01b03808d16606086019081528654808b018855968b5297909920935160029095029093019384555192909501805491519451909616600160401b02600160401b600160e01b03199486166401000000000267ffffffffffffffff199092169290951691909117179190911691909117909155518490869089907f77813be0661650ddc1a5193ff2837df4162b251cb432651e2c060c3fc39756be90613649908790899033909283526001600160a01b03918216602084015216604082015260600190565b60405180910390a46136aa565b613661818489612385565b604080516001600160a01b038516815233602082015260009183918a917fcf0c92a2c6d7c42f488326b0cb900104b99984b6b218db81cd29371364a35251910160405180910390a45b9695505050505050565b60405163e7c8e3e360e01b815260048101859052602481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063e7c8e3e390604401600060405180830381600087803b15801561371d57600080fd5b505af11580156115fa573d6000803e3d6000fd5b600082815260016020908152604080832080548251818502810185019093528083528493849084015b828210156137c757600084815260209081902060408051608081018252600286029092018054835260019081015463ffffffff8082168587015264010000000082041692840192909252600160401b9091046001600160a01b03166060830152908352909201910161375a565b50505060008681526001602052604081209293506137e692915061444b565b8051839060005b81811015613b3d57826000036138ac576000878152600160205260409020845185908390811061381f5761381f614cff565b60209081029190910181015182546001818101855560009485529383902082516002909202019081559181015191909201805460408401516060909401516001600160a01b0316600160401b02600160401b600160e01b031963ffffffff9586166401000000000267ffffffffffffffff1990931695909416949094171791909116919091179055613b35565b8381815181106138be576138be614cff565b6020026020010151600001518310613974578381815181106138e2576138e2614cff565b6020026020010151600001518303925083818151811061390457613904614cff565b60200260200101516020015163ffffffff166000148061394a5750633b9aca0084828151811061393657613936614cff565b60200260200101516040015163ffffffff16145b6139685761396384828151811061105c5761105c614cff565b61396b565b60005b85019450613b35565b600160008881526020019081526020016000206040518060800160405280858785815181106139a5576139a5614cff565b6020026020010151600001510381526020018684815181106139c9576139c9614cff565b60200260200101516020015163ffffffff1681526020018684815181106139f2576139f2614cff565b60200260200101516040015163ffffffff168152602001868481518110613a1b57613a1b614cff565b6020908102919091018101516060908101516001600160a01b0390811690935284546001818101875560009687529583902085516002909202019081559184015191909401805460408501519490950151909216600160401b02600160401b600160e01b031963ffffffff9485166401000000000267ffffffffffffffff19909616949092169390931793909317929092161790558351849082908110613ac457613ac4614cff565b60200260200101516020015163ffffffff1660001480613b0a5750633b9aca00848281518110613af657613af6614cff565b60200260200101516040015163ffffffff16145b613b2957613b248385838151811061107a5761107a614cff565b613b2c565b60005b85019450600092505b6001016137ed565b50604080518381523360208201528591879189917f59860d79d97c1fce2be7f987915c631471f4b08f671200463cc40a3380194ffb910160405180910390a450505092915050565b60006028826101000151901c61ffff166127106108489190614bd9565b60006038826101000151901c61ffff166127106108489190614bd9565b60c086015183906001600160a01b031615613e7f57633b9aca008214158015613c05575060c08701516001600160a01b031660009081526004602052604090205460ff16155b15613c1857613c1584848461233f565b90035b60006040518060c001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020018381526020017f000000000000000000000000000000000000000000000000000000000000000081526020018881526020018781526020018981525090506060613ca98960c00151634eba05fd60e11b61431d565b15613ddc578860c001516001600160a01b0316639d740bfa61eeee6001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614613d03576000613d05565b845b846040518363ffffffff1660e01b8152600401613d2291906158e9565b6000604051808303818588803b158015613d3b57600080fd5b505af193505050508015613d4d575060015b613dd7573d808015613d7b576040519150601f19603f3d011682016040523d82523d6000602084013e613d80565b606091505b50805115613d8e5780613dcf565b604051602001613dbf906020808252600d908201526c105b1b1bd8d85d194819985a5b609a1b604082015260600190565b6040516020818303038152906040525b915050613e1e565b613e1e565b604051602001613e0c906020808252600c908201526b12515490cc4d8d4819985a5b60a21b604082015260600190565b60405160208183030381529060405290505b805115613e7857613e35888a60c0015185896136b4565b60009250877f290b5df59e172593762964e4f8ed2b4a9192d3197bfd2be4bae123908f8007968a888433604051613e6f949392919061593d565b60405180910390a25b50506136aa565b6060870151156142da576060870151604051630862026560e41b81526000916001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691638620265091613f0f917f0000000000000000000000000000000000000000000000000000000000000000906004019182526001600160a01b0316602082015260400190565b602060405180830381865afa158015613f2c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f509190614bec565b90506001600160a01b038116613fb25760009150613f7187600080886136b4565b867f290b5df59e172593762964e4f8ed2b4a9192d3197bfd2be4bae123908f800796898733604051613fa593929190615980565b60405180910390a26142d4565b6001600160a01b0381163014801590613fcf5750633b9aca008314155b8015613ff457506001600160a01b03811660009081526004602052604090205460ff16155b156140095761400485858561233f565b820391505b87602001511561418657806001600160a01b0316630cf8e85861eeee6001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614614064576000614066565b835b8a60600151857f00000000000000000000000000000000000000000000000000000000000000008c6040516020016140a091815260200190565b6040516020818303038152906040526040518663ffffffff1660e01b81526004016140ce9493929190614c8f565b6000604051808303818588803b1580156140e757600080fd5b505af1935050505080156140f9575060015b614181573d808015614127576040519150601f19603f3d011682016040523d82523d6000602084013e61412c565b606091505b50614139888385896136b4565b60009250877f290b5df59e172593762964e4f8ed2b4a9192d3197bfd2be4bae123908f8007968a888433604051614173949392919061593d565b60405180910390a2506142d4565b6142d4565b806001600160a01b0316631ebc263f61eeee6001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316146141d75760006141d9565b835b60608b015160808c015186907f0000000000000000000000000000000000000000000000000000000000000000906001600160a01b031661421a5733614220565b8d608001515b60008f600001518f60405160200161423a91815260200190565b6040516020818303038152906040526040518963ffffffff1660e01b815260040161426b979695949392919061533d565b60206040518083038185885af1935050505080156142a6575060408051601f3d908101601f191682019092526142a391810190614c26565b60015b613e78573d808015614127576040519150601f19603f3d011682016040523d82523d6000602084013e61412c565b506136aa565b633b9aca0082146142f3576142f084848461233f565b90035b60808701516136aa9030906001600160a01b03166143115733614317565b88608001515b836117cb565b600061432883614339565b801561237e575061237e838361436c565b600061434c826301ffc9a760e01b61436c565b80156108485750614365826001600160e01b031961436c565b1592915050565b604080516001600160e01b0319831660248083019190915282518083039091018152604490910182526020810180516001600160e01b03166301ffc9a760e01b179052905160009190829081906001600160a01b03871690617530906143d39086906159dd565b6000604051808303818686fa925050503d806000811461440f576040519150601f19603f3d011682016040523d82523d6000602084013e614414565b606091505b509150915060208151101561442f5760009350505050610848565b8180156136aa5750808060200190518101906136aa9190614c09565b508054600082556002029060005260206000209081019061169c91906144c1565b6040518061012001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b03168152602001600081525090565b5b808211156144e857600081556001810180546001600160e01b03191690556002016144c2565b5090565b6000602082840312156144fe57600080fd5b81356001600160e01b03198116811461237e57600080fd5b6001600160a01b038116811461169c57600080fd5b60008083601f84011261453d57600080fd5b5081356001600160401b0381111561455457600080fd5b60208301915083602082850101111561456c57600080fd5b9250929050565b600080600080600080600060a0888a03121561458e57600080fd5b873596506020880135955060408801356145a781614516565b945060608801356001600160401b03808211156145c357600080fd5b6145cf8b838c0161452b565b909650945060808a01359150808211156145e857600080fd5b506145f58a828b0161452b565b989b979a50959850939692959293505050565b60006020828403121561461a57600080fd5b813561237e81614516565b801515811461169c57600080fd5b6000806000806000806000806000806101008b8d03121561465357600080fd5b8a35995060208b0135985060408b013561466c81614516565b975060608b013561467c81614516565b965060808b0135955060a08b013561469381614625565b945060c08b01356001600160401b03808211156146af57600080fd5b6146bb8e838f0161452b565b909650945060e08d01359150808211156146d457600080fd5b506146e18d828e0161452b565b915080935050809150509295989b9194979a5092959850565b6000806040838503121561470d57600080fd5b82359150602083013561471f81614516565b809150509250929050565b600080600080600080600060c0888a03121561474557600080fd5b873596506020880135955060408801359450606088013561476581614516565b93506080880135925060a08801356001600160401b0381111561478757600080fd5b6145f58a828b0161452b565b6000602082840312156147a557600080fd5b5035919050565b600080604083850312156147bf57600080fd5b82356147ca81614516565b9150602083013561471f81614625565b602080825282518282018190526000919060409081850190868401855b82811015614843578151805185528681015163ffffffff908116888701528682015116868601526060908101516001600160a01b031690850152608090930192908501906001016147f7565b5091979650505050505050565b634e487b7160e01b600052604160045260246000fd5b60405161012081016001600160401b038111828210171561488957614889614850565b60405290565b604051606081016001600160401b038111828210171561488957614889614850565b60405160e081016001600160401b038111828210171561488957614889614850565b604051601f8201601f191681016001600160401b03811182821017156148fb576148fb614850565b604052919050565b60006001600160401b0382111561491c5761491c614850565b50601f01601f191660200190565b600082601f83011261493b57600080fd5b813561494e61494982614903565b6148d3565b81815284602083860101111561496357600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060008060006101008a8c03121561499f57600080fd5b8935985060208a0135975060408a0135965060608a01356149bf81614516565b955060808a0135945060a08a01356149d681614516565b935060c08a01356001600160401b03808211156149f257600080fd5b6149fe8d838e0161492a565b945060e08c0135915080821115614a1457600080fd5b50614a218c828d0161452b565b915080935050809150509295985092959850929598565b60008060008060008060008060c0898b031215614a5457600080fd5b88359750602089013596506040890135614a6d81614516565b95506060890135614a7d81614625565b945060808901356001600160401b0380821115614a9957600080fd5b614aa58c838d0161452b565b909650945060a08b0135915080821115614abe57600080fd5b50614acb8b828c0161452b565b999c989b5096995094979396929594505050565b60008060408385031215614af257600080fd5b8235614afd81614516565b946020939093013593505050565b600080600080600080600080610100898b031215614b2857600080fd5b8835614b3381614516565b975060208901359650604089013595506060890135614b5181614516565b94506080890135935060a0890135614b6881614516565b925060c08901356001600160401b0380821115614b8457600080fd5b614b908c838d0161492a565b935060e08b0135915080821115614ba657600080fd5b50614bb38b828c0161492a565b9150509295985092959890939650565b634e487b7160e01b600052601160045260246000fd5b8181038181111561084857610848614bc3565b600060208284031215614bfe57600080fd5b815161237e81614516565b600060208284031215614c1b57600080fd5b815161237e81614625565b600060208284031215614c3857600080fd5b5051919050565b60005b83811015614c5a578181015183820152602001614c42565b50506000910152565b60008151808452614c7b816020860160208601614c3f565b601f01601f19169290920160200192915050565b84815283602082015260018060a01b038316604082015260a06060820152600060a082015260c0608082015260006136aa60c0830184614c63565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b634e487b7160e01b600052603260045260246000fd5b600181815b80851115614d50578160001904821115614d3657614d36614bc3565b80851615614d4357918102915b93841c9390800290614d1a565b509250929050565b600082614d6757506001610848565b81614d7457506000610848565b8160018114614d8a5760028114614d9457614db0565b6001915050610848565b60ff841115614da557614da5614bc3565b50506001821b610848565b5060208310610133831016604e8410600b8410161715614dd3575081810a610848565b614ddd8383614d15565b8060001904821115614df157614df1614bc3565b029392505050565b600061237e8383614d58565b80516001600160a01b031682526020808201519083015260408082015190830152606090810151910152565b6001600160a01b03888116825260009061014090614e52602085018b614e05565b8860a08501528760c085015280871660e08501525080610100840152614e7a81840186614c63565b9050828103610120840152614e8f8185614c63565b9a9950505050505050505050565b8051614ea881614516565b919050565b60006101208284031215614ec057600080fd5b614ec8614866565b9050815181526020820151602082015260408201516040820152606082015160608201526080820151608082015260a082015160a082015260c082015160c0820152614f1660e08301614e9d565b60e082015261010080830151818301525092915050565b60006001600160401b03821115614f4657614f46614850565b5060051b60200190565b600082601f830112614f6157600080fd5b8151614f6f61494982614903565b818152846020838601011115614f8457600080fd5b611500826020830160208701614c3f565b6000806000806101808587031215614fac57600080fd5b614fb68686614ead565b935061012085015192506101408501516001600160401b0380821115614fdb57600080fd5b818701915087601f830112614fef57600080fd5b8151614ffd61494982614f2d565b8082825260208201915060208360051b86010192508a83111561501f57600080fd5b602085015b838110156150a95780518581111561503b57600080fd5b86016060818e03601f1901121561505157600080fd5b61505961488f565b602082015161506781614516565b81526040820151602082015260608201518781111561508557600080fd5b6150948f602083860101614f50565b60408301525084525060209283019201615024565b506101608a015190965093505050808211156150c457600080fd5b506150d187828801614f50565b91505092959194509250565b80516001600160a01b031682526000610220602083015160208501526040830151604085015260608301516151156060860182614e05565b50608083015161512860e0860182614e05565b5060a083015161016085015260c08301516001600160a01b031661018085015260e083015115156101a08501526101008301516101c0850182905261516f82860182614c63565b9150506101208301518482036101e086015261518b8282614c63565b9150506101408301518482036102008601526151a78282614c63565b95945050505050565b60208152600061237e60208301846150dd565b6060815260006151d660608301866150dd565b6020830194909452506001600160a01b0391909116604090910152919050565b600060018060a01b03808a168352808916602084015287604084015286606084015260e0608084015261522c60e0840187614c63565b83810360a085015261523e8187614c63565b92505080841660c08401525098975050505050505050565b6001600160a01b0394851681529290931660208301526040820152606081019190915260800190565b600080610140838503121561529357600080fd5b61529d8484614ead565b915061012083015190509250929050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b600060018060a01b03808b16835289602084015288604084015287606084015286608084015260e060a084015261531260e0840186886152ae565b915080841660c0840152509998505050505050505050565b8082018082111561084857610848614bc3565b878152602081018790526001600160a01b038681166040830152851660608201526080810184905282151560a082015261010060c08201819052600090820181905261012060e08301819052614e8f81840185614c63565b8381526060602082015260006153ae6060830185614c63565b905060018060a01b0383166040830152949350505050565b600060018060a01b03808b16835289602084015288604084015287606084015260e060808401526153fa60e0840188614c63565b83810360a085015261540d8187896152ae565b92505080841660c0840152509998505050505050505050565b600081600019048311821515161561544057615440614bc3565b500290565b634e487b7160e01b600052601260045260246000fd5b60008261547857634e487b7160e01b600052601260045260246000fd5b500490565b85815284602082015260a06040820152600061549c60a0830186614c63565b82810360608401526154ae8186614c63565b91505060018060a01b03831660808301529695505050505050565b60018060a01b038616815284602082015283604082015260a0606082015260006154f660a0830185614c63565b8281036080840152610c838185614c63565b600080600080610180858703121561551f57600080fd5b6155298686614ead565b935061012085015192506101408501516001600160401b038082111561554e57600080fd5b818701915087601f83011261556257600080fd5b815161557061494982614f2d565b8082825260208201915060208360051b86010192508a83111561559257600080fd5b602085015b838110156150a9578051858111156155ae57600080fd5b86016060818e03601f190112156155c457600080fd5b6155cc61488f565b60208201516155da81614516565b8152604082015160208201526060820151878111156155f857600080fd5b6156078f602083860101614f50565b60408301525084525060209283019201615597565b80516001600160a01b031682526000610200602083015160208501526040830151604085015260608301516060850152608083015161565e6080860182614e05565b5060a083015161010061567381870183614e05565b60c08501516001600160a01b031661018087015260e08501516101a0870184905291506156a283870183614c63565b9250808501519150508482036101c08601526156be8282614c63565b9150506101208301518482036101e08601526151a78282614c63565b60208152600061237e602083018461561c565b608081526000615700608083018761561c565b60208301959095525060408101929092526001600160a01b0316606090910152919050565b828152604081016003831061574a57634e487b7160e01b600052602160045260246000fd5b8260208301529392505050565b6000602080838503121561576a57600080fd5b82516001600160401b0381111561578057600080fd5b8301601f8101851361579157600080fd5b805161579f61494982614f2d565b81815260e091820283018401918482019190888411156157be57600080fd5b938501935b838510156158545780858a0312156157db5760008081fd5b6157e36148b1565b85516157ee81614625565b8152858701516157fd81614625565b81880152604086810151908201526060808701519082015260808087015161582481614516565b9082015260a0868101519082015260c08087015161584181614516565b90820152835293840193918501916157c3565b50979650505050505050565b80511515825260208082015115159083015260408082015190830152606080820151908301526080808201516001600160a01b039081169184019190915260a0808301519084015260c09182015116910152565b61014081016158c38287615860565b60e08201949094526101008101929092526001600160a01b031661012090910152919050565b81516001600160a01b031681526020808301519082015260408083015190820152606080830151908201526080808301519082015260a08281015161018083019161593690840182615860565b5092915050565b600061014061594c8388615860565b8560e08401528061010084015261596581840186614c63565b91505060018060a01b03831661012083015295945050505050565b600061014061598f8387615860565b60e08301949094525061010081018390526012928101929092527115195c9b5a5b985b081b9bdd08199bdd5b9960721b6101608301526001600160a01b031661012082015261018001919050565b600082516159ef818460208701614c3f565b919091019291505056fea2646970667358221220558248dbc04ea10c612e57468002e5730c490a4a5abc710d603914a962691a5464736f6c63430008100033", + "deployedBytecode": "0x6080604052600436106101f95760003560e01c80638da5cb5b1161010d578063c715967a116100a0578063df21a7dd1161006f578063df21a7dd146106ae578063e5a6b10f146106fc578063f2fde38b14610730578063fc0c546a14610750578063fe663f0f1461078457600080fd5b8063c715967a14610631578063d3419bf314610644578063d6dacc5314610678578063ddca3f431461069857600080fd5b8063ad007d63116100dc578063ad007d6314610559578063b631b5001461058d578063b7bad1b1146105bd578063c41c2f24146105fd57600080fd5b80638da5cb5b146104c7578063975057e7146104e5578063a02f801c14610519578063a32e1e961461053957600080fd5b80634a4305c011610190578063715018a61161015f578063715018a6146104115780637258002c1461042657806389701db5146104465780638af56094146104665780638b79543c1461049357600080fd5b80634a4305c01461037d578063637913ac1461039d57806366248b86146103bd57806369fe0e2d146103f157600080fd5b80632bdfe004116101cc5780632bdfe004146102a95780632d1a5903146102f5578063313ce56714610329578063405b84fa1461035d57600080fd5b806301ffc9a7146101fe5780630cf8e858146102335780631982d679146102485780631ebc263f14610296575b600080fd5b34801561020a57600080fd5b5061021e6102193660046144ec565b6107a4565b60405190151581526020015b60405180910390f35b610246610241366004614573565b61084e565b005b34801561025457600080fd5b50610288610263366004614608565b507f000000000000000000000000000000000000000000000000000000000000000090565b60405190815260200161022a565b6102886102a4366004614633565b610871565b3480156102b557600080fd5b506102dd7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200161022a565b34801561030157600080fd5b506102887f000000000000000000000000000000000000000000000000000000000000000081565b34801561033557600080fd5b506102887f000000000000000000000000000000000000000000000000000000000000000081565b34801561036957600080fd5b506102886103783660046146fa565b610977565b34801561038957600080fd5b5061028861039836600461472a565b610c73565b3480156103a957600080fd5b506102466103b8366004614608565b610c8f565b3480156103c957600080fd5b506102887f000000000000000000000000000000000000000000000000000000000000000081565b3480156103fd57600080fd5b5061024661040c366004614793565b610d16565b34801561041d57600080fd5b50610246610da5565b34801561043257600080fd5b506102466104413660046147ac565b610ddb565b34801561045257600080fd5b50610246610461366004614793565b610e67565b34801561047257600080fd5b50610486610481366004614793565b61116b565b60405161022a91906147da565b34801561049f57600080fd5b506102dd7f000000000000000000000000000000000000000000000000000000000000000081565b3480156104d357600080fd5b506000546001600160a01b03166102dd565b3480156104f157600080fd5b506102dd7f000000000000000000000000000000000000000000000000000000000000000081565b34801561052557600080fd5b50610288610534366004614980565b611218565b34801561054557600080fd5b50610288610554366004614793565b6112d3565b34801561056557600080fd5b506102dd7f000000000000000000000000000000000000000000000000000000000000000081565b34801561059957600080fd5b5061021e6105a8366004614608565b60046020526000908152604090205460ff1681565b3480156105c957600080fd5b506102886105d8366004614608565b507f000000000000000000000000000000000000000000000000000000000000000090565b34801561060957600080fd5b506102dd7f000000000000000000000000000000000000000000000000000000000000000081565b61024661063f366004614a38565b611508565b34801561065057600080fd5b506102dd7f000000000000000000000000000000000000000000000000000000000000000081565b34801561068457600080fd5b506003546102dd906001600160a01b031681565b3480156106a457600080fd5b5061028860025481565b3480156106ba57600080fd5b5061021e6106c9366004614adf565b507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b34801561070857600080fd5b506102887f000000000000000000000000000000000000000000000000000000000000000081565b34801561073c57600080fd5b5061024661074b366004614608565b611604565b34801561075c57600080fd5b506102dd7f000000000000000000000000000000000000000000000000000000000000000081565b34801561079057600080fd5b5061028861079f366004614b0b565b61169f565b60006001600160e01b0319821615806107cd57506001600160e01b0319821663edb527eb60e01b145b806107e857506001600160e01b031982166301290c1760e61b145b8061080357506001600160e01b0319821663280be00760e21b145b8061081e57506001600160e01b0319821663fe663f0f60e01b145b8061083957506001600160e01b0319821663ad007d6360e01b145b806108485750610848826116cf565b92915050565b6108578761171f565b610868878787600088888888611508565b50505050505050565b600061087c8b61171f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031661eeee146108eb5734156108cd57604051635e7e9adf60e11b815260040160405180910390fd5b476108d933308d6117cb565b6108e38147614bd9565b9a50506108ef565b3499505b6109688a338d8b8b8b8b8b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8f018190048102820181019092528d815292508d91508c90819084018382808284376000920191909152506117da92505050565b9b9a5050505050505050505050565b6040516331a9108f60e11b8152600481018390526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636352211e90602401602060405180830381865afa1580156109df573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a039190614bec565b836004610a11838383611d82565b60405163df21a7dd60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301526024820188905286169063df21a7dd90604401602060405180830381865afa158015610a7e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aa29190614c09565b610abf5760405163581010ed60e01b815260040160405180910390fd5b604051636bb6a5ad60e01b8152600481018790527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636bb6a5ad906024016020604051808303816000875af1158015610b26573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b4a9190614c26565b93508315610c255760007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031661eeee14610b8d576000610b8f565b845b6040805160208101825260008152905163019f1d0b60e31b81529192506001600160a01b03881691630cf8e858918491610bf1918c918b917f000000000000000000000000000000000000000000000000000000000000000091600401614c8f565b6000604051808303818588803b158015610c0a57600080fd5b505af1158015610c1e573d6000803e3d6000fd5b5050505050505b604080518581523360208201526001600160a01b0387169188917fa7519e5f94697b7f53e97c5eb46a0c730a296ab686ab8fd333835c5f735784eb910160405180910390a350505092915050565b6000610c83888888878787611ee6565b98975050505050505050565b6000546001600160a01b03163314610cc25760405162461bcd60e51b8152600401610cb990614cca565b60405180910390fd5b600380546001600160a01b0319166001600160a01b0383169081179091556040513381527f0a9a80fe9716605b3e52abb3d792d6a4e7816d6afc02a5a4ef023081feaf9f609060200160405180910390a250565b6000546001600160a01b03163314610d405760405162461bcd60e51b8152600401610cb990614cca565b6302faf080811115610d65576040516345fbd9c160e01b815260040160405180910390fd5b6002819055604080518281523360208201527fd7414e590e1cb532989ab2a34c8f4c2c17f7ab6f006efeeaef2e87cd5008c202910160405180910390a150565b6000546001600160a01b03163314610dcf5760405162461bcd60e51b8152600401610cb990614cca565b610dd9600061217b565b565b6000546001600160a01b03163314610e055760405162461bcd60e51b8152600401610cb990614cca565b6001600160a01b038216600081815260046020908152604091829020805460ff191685151590811790915591513381529192917fa2653e25a502c023a5830d0de847ef6f458387865b1f4f575d7594f9f2c0d71e910160405180910390a35050565b6040516331a9108f60e11b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636352211e90602401602060405180830381865afa158015610ecc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ef09190614bec565b816005610f056000546001600160a01b031690565b6001600160a01b0316336001600160a01b031614610f25848484846121cb565b600085815260016020908152604080832080548251818502810185019093528083529192909190849084015b82821015610fbe57600084815260209081902060408051608081018252600286029092018054835260019081015463ffffffff8082168587015264010000000082041692840192909252600160401b9091046001600160a01b031660608301529083529092019101610f51565b5050506000888152600160205260408120929350610fdd92915061444b565b80516000805b8281101561116057838181518110610ffd57610ffd614cff565b60200260200101516020015163ffffffff16600014806110435750633b9aca0084828151811061102f5761102f614cff565b60200260200101516040015163ffffffff16145b6110ba576110b584828151811061105c5761105c614cff565b60200260200101516000015185838151811061107a5761107a614cff565b60200260200101516020015163ffffffff1686848151811061109e5761109e614cff565b60200260200101516040015163ffffffff1661233f565b6110bd565b60005b91506110e7828583815181106110d5576110d5614cff565b6020026020010151606001518b612385565b60011515828a7fcf0c92a2c6d7c42f488326b0cb900104b99984b6b218db81cd29371364a3525187858151811061112057611120614cff565b602002602001015160600151336040516111509291906001600160a01b0392831681529116602082015260400190565b60405180910390a4600101610fe3565b505050505050505050565b606060016000838152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b8282101561120d57600084815260209081902060408051608081018252600286029092018054835260019081015463ffffffff8082168587015264010000000082041692840192909252600160401b9091046001600160a01b0316606083015290835290920191016111a0565b505050509050919050565b6040516331a9108f60e11b8152600481018a90526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636352211e90602401602060405180830381865afa158015611280573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112a49190614bec565b8a60116112b2838383611d82565b6112c28d8d8d8c8c8c8c8c6125f2565b9d9c50505050505050505050505050565b60405163035240c760e61b81523060048201526024810182905260009081906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063d49031c090604401602060405180830381865afa158015611343573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113679190614c26565b905060007f00000000000000000000000000000000000000000000000000000000000000006012146113c4576113bf827f00000000000000000000000000000000000000000000000000000000000000006012612839565b6113c6565b815b905060017f0000000000000000000000000000000000000000000000000000000000000000146114fe576114f98161141f7f0000000000000000000000000000000000000000000000000000000000000000600a614df9565b604051635268657960e11b81527f00000000000000000000000000000000000000000000000000000000000000006004820152600160248201527f000000000000000000000000000000000000000000000000000000000000000060448201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a4d0caf290606401602060405180830381865afa1580156114d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114f49190614c26565b612896565b611500565b805b949350505050565b6115118861171f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031661eeee1461158057341561156257604051635e7e9adf60e11b815260040160405180910390fd5b4761156e33308a6117cb565b6115788147614bd9565b975050611584565b3496505b6115fa88888787878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8b01819004810282018101909252898152925089915088908190840183828082843760009201919091525061296392505050565b5050505050505050565b6000546001600160a01b0316331461162e5760405162461bcd60e51b8152600401610cb990614cca565b6001600160a01b0381166116935760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610cb9565b61169c8161217b565b50565b6000888860026116b0838383611d82565b6116bf8c8c8c8b8b8b8b612a55565b9c9b505050505050505050505050565b60006001600160e01b0319821663301cdc3960e21b148061170057506001600160e01b0319821663144b000160e11b145b8061084857506301ffc9a760e01b6001600160e01b0319831614610848565b604051636e49181f60e01b8152600481018290523060248201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636e49181f90604401602060405180830381865afa15801561178a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117ae9190614c09565b61169c57604051631b1d5a5960e31b815260040160405180910390fd5b6117d582826130ea565b505050565b60006001600160a01b0386166118035760405163a762251360e01b815260040160405180910390fd5b61180b61446c565b606060008060405180608001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020018e81526020017f000000000000000000000000000000000000000000000000000000000000000081526020017f000000000000000000000000000000000000000000000000000000000000000081525090507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632fa1b3918d838e7f00000000000000000000000000000000000000000000000000000000000000008f8d8d6040518863ffffffff1660e01b81526004016119149796959493929190614e31565b6000604051808303816000875af1158015611933573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261195b9190810190614f95565b995091955090935091508115611a9057604051632eec7b5560e11b8152600481018c90527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635dd8f6aa90602401602060405180830381865afa1580156119d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119f49190614bec565b604051638ae9c07b60e01b8152600481018d9052602481018490526001600160a01b038c8116604483015260c06064830152600060c48301528a15156084830152600160a48301529190911690638ae9c07b9060e4016020604051808303816000875af1158015611a69573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a8d9190614c26565b94505b88851015611ab157604051633dca309360e11b815260040160405180910390fd5b825115611d245760006040518061016001604052808e6001600160a01b031681526020018d81526020018660200151815260200183815260200160405180608001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602001600081526020017f000000000000000000000000000000000000000000000000000000000000000081526020017f000000000000000000000000000000000000000000000000000000000000000081525081526020018781526020018c6001600160a01b031681526020018a15158152602001898152602001604051806020016040528060008152508152602001888152509050600084519050611bec604051806060016040528060006001600160a01b0316815260200160008152602001606081525090565b60005b82811015611d1f57868181518110611c0957611c09614cff565b60209081029190910101519150602080830151608086015190910152604082015161012085015281516001600160a01b0390811690636b204943907f00000000000000000000000000000000000000000000000000000000000000001661eeee14611c75576000611c7b565b83602001515b866040518363ffffffff1660e01b8152600401611c9891906151b0565b6000604051808303818588803b158015611cb157600080fd5b505af1158015611cc5573d6000803e3d6000fd5b505050505081600001516001600160a01b03167f232bbbe420e7bac6f941dc82678daec2b4c712378d91e864b69aab6e26cdd42485846020015133604051611d0f939291906151c3565b60405180910390a2600101611bef565b505050505b50505087816000015182602001517f133161f1c9161488f777ab9a26aae91d47c0d9a3fafb398960f138db02c737978c8b8f888b8b33604051611d6d97969594939291906151f6565b60405180910390a45098975050505050505050565b336001600160a01b03841614801590611e2b575060405163c161c93f60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063c161c93f90611de8903390879087908790600401615256565b602060405180830381865afa158015611e05573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e299190614c09565b155b8015611ec8575060405163c161c93f60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063c161c93f90611e8590339087906000908790600401615256565b602060405180830381865afa158015611ea2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ec69190614c09565b155b156117d55760405163075fd2b160e01b815260040160405180910390fd5b60405163c664459760e01b8152600481018790526024810186905260448101859052600090819081906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063c664459790606401610140604051808303816000875af1158015611f63573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f87919061527f565b9150915085811015611fac5760405163b01493c160e01b815260040160405180910390fd5b6040516331a9108f60e11b8152600481018a90526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636352211e90602401602060405180830381865afa158015612014573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120389190614bec565b600254909150600090818115612058576120538d6000613203565b61205e565b633b9aca005b90506000806120958f89602001517f00000000000000000000000000000000000000000000000000000000000000008a8888613377565b92509050633b9aca0083146120a957908101905b816000036120b85760006120dc565b6120dc8f6120d38a61010001516001604f9190911c81161490565b84878a88613537565b9450801561211957633b9aca0083146120ff576120fa81858561233f565b612102565b60005b61210c9082614bd9565b985061211930878b6117cb565b505050508a846000015185602001517fc41a8d26c70cfcf1b9ea10f82482ac947b8be5bea2750bc729af844bbfde1e28858e88878c8f8f336040516121659897969594939291906152d7565b60405180910390a4505050509695505050505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b801580156121e25750336001600160a01b03851614155b801561227e575060405163c161c93f60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063c161c93f9061223b903390889088908890600401615256565b602060405180830381865afa158015612258573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061227c9190614c09565b155b801561231b575060405163c161c93f60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063c161c93f906122d890339088906000908890600401615256565b602060405180830381865afa1580156122f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123199190614c09565b155b156123395760405163075fd2b160e01b815260040160405180910390fd5b50505050565b6000806123518484633b9aca00612896565b61235b9085614bd9565b905061237085633b9aca006114f4818561532a565b61237a9086614bd9565b9150505b9392505050565b604051630862026560e41b8152600160048201526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660248301526000917f000000000000000000000000000000000000000000000000000000000000000090911690638620265090604401602060405180830381865afa158015612417573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061243b9190614bec565b9050806001600160a01b0316631ebc263f61eeee6001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03161461248e576000612490565b855b6001877f0000000000000000000000000000000000000000000000000000000000000000886000808a6040516020016124cb91815260200190565b6040516020818303038152906040526040518963ffffffff1660e01b81526004016124fc979695949392919061533d565b60206040518083038185885af193505050508015612537575060408051601f3d908101601f1916820190925261253491810190614c26565b60015b6125eb573d808015612565576040519150601f19603f3d011682016040523d82523d6000602084013e61256a565b606091505b506125a783306001600160a01b03851603612586576000612588565b835b306001600160a01b0386160361259f5760006125a1565b875b886136b4565b6001837f80a889d08f0d59eb962335b57fb1d5b29e86e3d23f15087b5541fddf15422bbe8784336040516125dd93929190615395565b60405180910390a350612339565b5050505050565b604051632538671560e01b8152600481018990526024810188905260448101879052600090819081906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690632538671590606401610140604051808303816000875af115801561266f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612693919061527f565b91509150878110156126b85760405163b01493c160e01b815260040160405180910390fd5b6002546040516331a9108f60e11b8152600481018d90526000919082906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690636352211e90602401602060405180830381865afa158015612726573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061274a9190614bec565b9050600082158061276a57503360009081526004602052604090205460ff165b61277e576127798f6001613203565b612784565b633b9aca005b9050633b9aca0081146127ba576127b58f6127ac8861010001516001604f9190911c81161490565b87868686613537565b6127bd565b60005b93508385039650866000146127d7576127d7308c896117cb565b505050508a826000015183602001517f2eeee47c6d8d31c3523c3aa07b4c3e3795db36be4c04546ef3e30a5102f568e18a8e86898d8d8d336040516128239897969594939291906153c6565b60405180910390a4505098975050505050505050565b600082820361284957508261237e565b828211156128775761285b8383614bd9565b61286690600a614df9565b6128709085615426565b905061237e565b6128818284614bd9565b61288c90600a614df9565b612870908561545b565b60008080600019858709858702925082811083820303915050806000036128d0578382816128c6576128c6615445565b049250505061237e565b8381106128fa57604051631dcf306360e21b81526004810182905260248101859052604401610cb9565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60008361297157600061297b565b61297b8686613731565b90506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663e7c8e3e3876129b7848961532a565b6040516001600160e01b031960e085901b16815260048101929092526024820152604401600060405180830381600087803b1580156129f557600080fd5b505af1158015612a09573d6000803e3d6000fd5b50505050857f9ecaf7fc3dfffd6867c175d6e684b1f1e3aef019398ba8db2c1ffab4a09db2538683868633604051612a4595949392919061547d565b60405180910390a2505050505050565b60006001600160a01b038416612a7e57604051637ba50db360e11b815260040160405180910390fd5b612a8661446c565b6000806000600254905060607f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a2df1f958e8e8e8c8c6040518663ffffffff1660e01b8152600401612ae69594939291906154c9565b6000604051808303816000875af1158015612b05573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612b2d9190810190615508565b6001600160a01b038d16600090815260046020526040902054909b5091985091965090915060ff1680612b7d5750612710612b6786613b85565b148015612b7d5750612710612b7b86613ba2565b145b80612b86575081155b612b9a57612b958c6002613203565b612ba0565b633b9aca005b925089861015612bc35760405163f896960b60e01b815260040160405180910390fd5b8a15612cd357604051632eec7b5560e11b8152600481018d90527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635dd8f6aa90602401602060405180830381865afa158015612c2e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c529190614bec565b604051631665bc0f60e01b81526001600160a01b038f81166004830152602482018f9052604482018e905260a06064830152600060a4830181905260848301529190911690631665bc0f9060c401600060405180830381600087803b158015612cba57600080fd5b505af1158015612cce573d6000803e3d6000fd5b505050505b8051156130135760006040518061014001604052808f6001600160a01b031681526020018e8152602001876020015181526020018d815260200160405180608001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020018a81526020017f000000000000000000000000000000000000000000000000000000000000000081526020017f0000000000000000000000000000000000000000000000000000000000000000815250815260200160405180608001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602001600081526020017f000000000000000000000000000000000000000000000000000000000000000081526020017f000000000000000000000000000000000000000000000000000000000000000081525081526020018b6001600160a01b031681526020018a8152602001604051806020016040528060008152508152602001898152509050612e89604051806060016040528060006001600160a01b0316815260200160008152602001606081525090565b8251600090815b8181101561300d57858181518110612eaa57612eaa614cff565b6020026020010151935086600014612ed057612ecb8460200151888a61233f565b612ed3565b60005b92508215612f02576020840151612eea908a61532a565b98508284602001818151612efe9190614bd9565b9052505b60208085015160a087015190910152604084015161010086015283516001600160a01b0390811690630bf46e59907f00000000000000000000000000000000000000000000000000000000000000001661eeee14612f61576000612f67565b85602001515b876040518363ffffffff1660e01b8152600401612f8491906156da565b6000604051808303818588803b158015612f9d57600080fd5b505af1158015612fb1573d6000803e3d6000fd5b505050505083600001516001600160a01b03167f6596068545b2541b0aff5579d91f991d0fe5957df8e2082483ef361953e1f9978686602001518633604051612ffd94939291906156ed565b60405180910390a2600101612e90565b50505050505b50841561306e576000633b9aca0083146130375761303286838561233f565b61303a565b60005b9050801561305b5761304c868561532a565b93506130588187614bd9565b95505b851561306c5761306c308a886117cb565b505b8260000361307d57600061308c565b61308c8b600085848c87613537565b5050505087816000015182602001517f2be10f2a0203c77d0fcaa9fd6484a8a1d6904de31cd820587f60c1c8c338c8148c898c888b8b336040516130d697969594939291906151f6565b60405180910390a450979650505050505050565b8047101561313a5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e63650000006044820152606401610cb9565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114613187576040519150601f19603f3d011682016040523d82523d6000602084013e61318c565b606091505b50509050806117d55760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d617920686176652072657665727465640000000000006064820152608401610cb9565b604051630862026560e41b8152600160048201526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116602483015260009182917f00000000000000000000000000000000000000000000000000000000000000001690638620265090604401602060405180830381865afa158015613295573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132b99190614bec565b6001600160a01b0316036132d25750633b9aca00610848565b6003546001600160a01b03161561336e5760035460405163192dd60960e01b81526001600160a01b039091169063192dd609906133159086908690600401615725565b602060405180830381865afa92505050801561334e575060408051601f3d908101601f1916820190925261334b91810190614c26565b60015b61335a57506000610848565b633b9aca00811161336c579050610848565b505b50600092915050565b6040516369e11cc560e01b81526004810187905260248101869052604481018590526000908190633b9aca009082907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906369e11cc590606401600060405180830381865afa1580156133f7573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261341f9190810190615757565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081018290529192505b82518110156135255782818151811061347657613476614cff565b6020026020010151915060006134918a846040015187612896565b905060006134a3848f8e858e8e613bbf565b905080158015906134b45750818114155b156134c6576134c3828861532a565b96505b81156134d257818b039a505b8360400151860395508b8d8f7f0d31ab573f6daa4b1edba8d31973b4ba9f98fbfecc47010c1533eeefd2a1225a8786863360405161351394939291906158b4565b60405180910390a4505060010161345b565b50879450505050965096945050505050565b600061354485858461233f565b9050851561365657600087815260016020818152604080842081516080810183528a815263ffffffff808b168286019081528982168386019081526001600160a01b03808d16606086019081528654808b018855968b5297909920935160029095029093019384555192909501805491519451909616600160401b02600160401b600160e01b03199486166401000000000267ffffffffffffffff199092169290951691909117179190911691909117909155518490869089907f77813be0661650ddc1a5193ff2837df4162b251cb432651e2c060c3fc39756be90613649908790899033909283526001600160a01b03918216602084015216604082015260600190565b60405180910390a46136aa565b613661818489612385565b604080516001600160a01b038516815233602082015260009183918a917fcf0c92a2c6d7c42f488326b0cb900104b99984b6b218db81cd29371364a35251910160405180910390a45b9695505050505050565b60405163e7c8e3e360e01b815260048101859052602481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063e7c8e3e390604401600060405180830381600087803b15801561371d57600080fd5b505af11580156115fa573d6000803e3d6000fd5b600082815260016020908152604080832080548251818502810185019093528083528493849084015b828210156137c757600084815260209081902060408051608081018252600286029092018054835260019081015463ffffffff8082168587015264010000000082041692840192909252600160401b9091046001600160a01b03166060830152908352909201910161375a565b50505060008681526001602052604081209293506137e692915061444b565b8051839060005b81811015613b3d57826000036138ac576000878152600160205260409020845185908390811061381f5761381f614cff565b60209081029190910181015182546001818101855560009485529383902082516002909202019081559181015191909201805460408401516060909401516001600160a01b0316600160401b02600160401b600160e01b031963ffffffff9586166401000000000267ffffffffffffffff1990931695909416949094171791909116919091179055613b35565b8381815181106138be576138be614cff565b6020026020010151600001518310613974578381815181106138e2576138e2614cff565b6020026020010151600001518303925083818151811061390457613904614cff565b60200260200101516020015163ffffffff166000148061394a5750633b9aca0084828151811061393657613936614cff565b60200260200101516040015163ffffffff16145b6139685761396384828151811061105c5761105c614cff565b61396b565b60005b85019450613b35565b600160008881526020019081526020016000206040518060800160405280858785815181106139a5576139a5614cff565b6020026020010151600001510381526020018684815181106139c9576139c9614cff565b60200260200101516020015163ffffffff1681526020018684815181106139f2576139f2614cff565b60200260200101516040015163ffffffff168152602001868481518110613a1b57613a1b614cff565b6020908102919091018101516060908101516001600160a01b0390811690935284546001818101875560009687529583902085516002909202019081559184015191909401805460408501519490950151909216600160401b02600160401b600160e01b031963ffffffff9485166401000000000267ffffffffffffffff19909616949092169390931793909317929092161790558351849082908110613ac457613ac4614cff565b60200260200101516020015163ffffffff1660001480613b0a5750633b9aca00848281518110613af657613af6614cff565b60200260200101516040015163ffffffff16145b613b2957613b248385838151811061107a5761107a614cff565b613b2c565b60005b85019450600092505b6001016137ed565b50604080518381523360208201528591879189917f59860d79d97c1fce2be7f987915c631471f4b08f671200463cc40a3380194ffb910160405180910390a450505092915050565b60006028826101000151901c61ffff166127106108489190614bd9565b60006038826101000151901c61ffff166127106108489190614bd9565b60c086015183906001600160a01b031615613e7f57633b9aca008214158015613c05575060c08701516001600160a01b031660009081526004602052604090205460ff16155b15613c1857613c1584848461233f565b90035b60006040518060c001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020018381526020017f000000000000000000000000000000000000000000000000000000000000000081526020018881526020018781526020018981525090506060613ca98960c00151634eba05fd60e11b61431d565b15613ddc578860c001516001600160a01b0316639d740bfa61eeee6001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614613d03576000613d05565b845b846040518363ffffffff1660e01b8152600401613d2291906158e9565b6000604051808303818588803b158015613d3b57600080fd5b505af193505050508015613d4d575060015b613dd7573d808015613d7b576040519150601f19603f3d011682016040523d82523d6000602084013e613d80565b606091505b50805115613d8e5780613dcf565b604051602001613dbf906020808252600d908201526c105b1b1bd8d85d194819985a5b609a1b604082015260600190565b6040516020818303038152906040525b915050613e1e565b613e1e565b604051602001613e0c906020808252600c908201526b12515490cc4d8d4819985a5b60a21b604082015260600190565b60405160208183030381529060405290505b805115613e7857613e35888a60c0015185896136b4565b60009250877f290b5df59e172593762964e4f8ed2b4a9192d3197bfd2be4bae123908f8007968a888433604051613e6f949392919061593d565b60405180910390a25b50506136aa565b6060870151156142da576060870151604051630862026560e41b81526000916001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691638620265091613f0f917f0000000000000000000000000000000000000000000000000000000000000000906004019182526001600160a01b0316602082015260400190565b602060405180830381865afa158015613f2c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f509190614bec565b90506001600160a01b038116613fb25760009150613f7187600080886136b4565b867f290b5df59e172593762964e4f8ed2b4a9192d3197bfd2be4bae123908f800796898733604051613fa593929190615980565b60405180910390a26142d4565b6001600160a01b0381163014801590613fcf5750633b9aca008314155b8015613ff457506001600160a01b03811660009081526004602052604090205460ff16155b156140095761400485858561233f565b820391505b87602001511561418657806001600160a01b0316630cf8e85861eeee6001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614614064576000614066565b835b8a60600151857f00000000000000000000000000000000000000000000000000000000000000008c6040516020016140a091815260200190565b6040516020818303038152906040526040518663ffffffff1660e01b81526004016140ce9493929190614c8f565b6000604051808303818588803b1580156140e757600080fd5b505af1935050505080156140f9575060015b614181573d808015614127576040519150601f19603f3d011682016040523d82523d6000602084013e61412c565b606091505b50614139888385896136b4565b60009250877f290b5df59e172593762964e4f8ed2b4a9192d3197bfd2be4bae123908f8007968a888433604051614173949392919061593d565b60405180910390a2506142d4565b6142d4565b806001600160a01b0316631ebc263f61eeee6001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316146141d75760006141d9565b835b60608b015160808c015186907f0000000000000000000000000000000000000000000000000000000000000000906001600160a01b031661421a5733614220565b8d608001515b60008f600001518f60405160200161423a91815260200190565b6040516020818303038152906040526040518963ffffffff1660e01b815260040161426b979695949392919061533d565b60206040518083038185885af1935050505080156142a6575060408051601f3d908101601f191682019092526142a391810190614c26565b60015b613e78573d808015614127576040519150601f19603f3d011682016040523d82523d6000602084013e61412c565b506136aa565b633b9aca0082146142f3576142f084848461233f565b90035b60808701516136aa9030906001600160a01b03166143115733614317565b88608001515b836117cb565b600061432883614339565b801561237e575061237e838361436c565b600061434c826301ffc9a760e01b61436c565b80156108485750614365826001600160e01b031961436c565b1592915050565b604080516001600160e01b0319831660248083019190915282518083039091018152604490910182526020810180516001600160e01b03166301ffc9a760e01b179052905160009190829081906001600160a01b03871690617530906143d39086906159dd565b6000604051808303818686fa925050503d806000811461440f576040519150601f19603f3d011682016040523d82523d6000602084013e614414565b606091505b509150915060208151101561442f5760009350505050610848565b8180156136aa5750808060200190518101906136aa9190614c09565b508054600082556002029060005260206000209081019061169c91906144c1565b6040518061012001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b03168152602001600081525090565b5b808211156144e857600081556001810180546001600160e01b03191690556002016144c2565b5090565b6000602082840312156144fe57600080fd5b81356001600160e01b03198116811461237e57600080fd5b6001600160a01b038116811461169c57600080fd5b60008083601f84011261453d57600080fd5b5081356001600160401b0381111561455457600080fd5b60208301915083602082850101111561456c57600080fd5b9250929050565b600080600080600080600060a0888a03121561458e57600080fd5b873596506020880135955060408801356145a781614516565b945060608801356001600160401b03808211156145c357600080fd5b6145cf8b838c0161452b565b909650945060808a01359150808211156145e857600080fd5b506145f58a828b0161452b565b989b979a50959850939692959293505050565b60006020828403121561461a57600080fd5b813561237e81614516565b801515811461169c57600080fd5b6000806000806000806000806000806101008b8d03121561465357600080fd5b8a35995060208b0135985060408b013561466c81614516565b975060608b013561467c81614516565b965060808b0135955060a08b013561469381614625565b945060c08b01356001600160401b03808211156146af57600080fd5b6146bb8e838f0161452b565b909650945060e08d01359150808211156146d457600080fd5b506146e18d828e0161452b565b915080935050809150509295989b9194979a5092959850565b6000806040838503121561470d57600080fd5b82359150602083013561471f81614516565b809150509250929050565b600080600080600080600060c0888a03121561474557600080fd5b873596506020880135955060408801359450606088013561476581614516565b93506080880135925060a08801356001600160401b0381111561478757600080fd5b6145f58a828b0161452b565b6000602082840312156147a557600080fd5b5035919050565b600080604083850312156147bf57600080fd5b82356147ca81614516565b9150602083013561471f81614625565b602080825282518282018190526000919060409081850190868401855b82811015614843578151805185528681015163ffffffff908116888701528682015116868601526060908101516001600160a01b031690850152608090930192908501906001016147f7565b5091979650505050505050565b634e487b7160e01b600052604160045260246000fd5b60405161012081016001600160401b038111828210171561488957614889614850565b60405290565b604051606081016001600160401b038111828210171561488957614889614850565b60405160e081016001600160401b038111828210171561488957614889614850565b604051601f8201601f191681016001600160401b03811182821017156148fb576148fb614850565b604052919050565b60006001600160401b0382111561491c5761491c614850565b50601f01601f191660200190565b600082601f83011261493b57600080fd5b813561494e61494982614903565b6148d3565b81815284602083860101111561496357600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060008060006101008a8c03121561499f57600080fd5b8935985060208a0135975060408a0135965060608a01356149bf81614516565b955060808a0135945060a08a01356149d681614516565b935060c08a01356001600160401b03808211156149f257600080fd5b6149fe8d838e0161492a565b945060e08c0135915080821115614a1457600080fd5b50614a218c828d0161452b565b915080935050809150509295985092959850929598565b60008060008060008060008060c0898b031215614a5457600080fd5b88359750602089013596506040890135614a6d81614516565b95506060890135614a7d81614625565b945060808901356001600160401b0380821115614a9957600080fd5b614aa58c838d0161452b565b909650945060a08b0135915080821115614abe57600080fd5b50614acb8b828c0161452b565b999c989b5096995094979396929594505050565b60008060408385031215614af257600080fd5b8235614afd81614516565b946020939093013593505050565b600080600080600080600080610100898b031215614b2857600080fd5b8835614b3381614516565b975060208901359650604089013595506060890135614b5181614516565b94506080890135935060a0890135614b6881614516565b925060c08901356001600160401b0380821115614b8457600080fd5b614b908c838d0161492a565b935060e08b0135915080821115614ba657600080fd5b50614bb38b828c0161492a565b9150509295985092959890939650565b634e487b7160e01b600052601160045260246000fd5b8181038181111561084857610848614bc3565b600060208284031215614bfe57600080fd5b815161237e81614516565b600060208284031215614c1b57600080fd5b815161237e81614625565b600060208284031215614c3857600080fd5b5051919050565b60005b83811015614c5a578181015183820152602001614c42565b50506000910152565b60008151808452614c7b816020860160208601614c3f565b601f01601f19169290920160200192915050565b84815283602082015260018060a01b038316604082015260a06060820152600060a082015260c0608082015260006136aa60c0830184614c63565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b634e487b7160e01b600052603260045260246000fd5b600181815b80851115614d50578160001904821115614d3657614d36614bc3565b80851615614d4357918102915b93841c9390800290614d1a565b509250929050565b600082614d6757506001610848565b81614d7457506000610848565b8160018114614d8a5760028114614d9457614db0565b6001915050610848565b60ff841115614da557614da5614bc3565b50506001821b610848565b5060208310610133831016604e8410600b8410161715614dd3575081810a610848565b614ddd8383614d15565b8060001904821115614df157614df1614bc3565b029392505050565b600061237e8383614d58565b80516001600160a01b031682526020808201519083015260408082015190830152606090810151910152565b6001600160a01b03888116825260009061014090614e52602085018b614e05565b8860a08501528760c085015280871660e08501525080610100840152614e7a81840186614c63565b9050828103610120840152614e8f8185614c63565b9a9950505050505050505050565b8051614ea881614516565b919050565b60006101208284031215614ec057600080fd5b614ec8614866565b9050815181526020820151602082015260408201516040820152606082015160608201526080820151608082015260a082015160a082015260c082015160c0820152614f1660e08301614e9d565b60e082015261010080830151818301525092915050565b60006001600160401b03821115614f4657614f46614850565b5060051b60200190565b600082601f830112614f6157600080fd5b8151614f6f61494982614903565b818152846020838601011115614f8457600080fd5b611500826020830160208701614c3f565b6000806000806101808587031215614fac57600080fd5b614fb68686614ead565b935061012085015192506101408501516001600160401b0380821115614fdb57600080fd5b818701915087601f830112614fef57600080fd5b8151614ffd61494982614f2d565b8082825260208201915060208360051b86010192508a83111561501f57600080fd5b602085015b838110156150a95780518581111561503b57600080fd5b86016060818e03601f1901121561505157600080fd5b61505961488f565b602082015161506781614516565b81526040820151602082015260608201518781111561508557600080fd5b6150948f602083860101614f50565b60408301525084525060209283019201615024565b506101608a015190965093505050808211156150c457600080fd5b506150d187828801614f50565b91505092959194509250565b80516001600160a01b031682526000610220602083015160208501526040830151604085015260608301516151156060860182614e05565b50608083015161512860e0860182614e05565b5060a083015161016085015260c08301516001600160a01b031661018085015260e083015115156101a08501526101008301516101c0850182905261516f82860182614c63565b9150506101208301518482036101e086015261518b8282614c63565b9150506101408301518482036102008601526151a78282614c63565b95945050505050565b60208152600061237e60208301846150dd565b6060815260006151d660608301866150dd565b6020830194909452506001600160a01b0391909116604090910152919050565b600060018060a01b03808a168352808916602084015287604084015286606084015260e0608084015261522c60e0840187614c63565b83810360a085015261523e8187614c63565b92505080841660c08401525098975050505050505050565b6001600160a01b0394851681529290931660208301526040820152606081019190915260800190565b600080610140838503121561529357600080fd5b61529d8484614ead565b915061012083015190509250929050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b600060018060a01b03808b16835289602084015288604084015287606084015286608084015260e060a084015261531260e0840186886152ae565b915080841660c0840152509998505050505050505050565b8082018082111561084857610848614bc3565b878152602081018790526001600160a01b038681166040830152851660608201526080810184905282151560a082015261010060c08201819052600090820181905261012060e08301819052614e8f81840185614c63565b8381526060602082015260006153ae6060830185614c63565b905060018060a01b0383166040830152949350505050565b600060018060a01b03808b16835289602084015288604084015287606084015260e060808401526153fa60e0840188614c63565b83810360a085015261540d8187896152ae565b92505080841660c0840152509998505050505050505050565b600081600019048311821515161561544057615440614bc3565b500290565b634e487b7160e01b600052601260045260246000fd5b60008261547857634e487b7160e01b600052601260045260246000fd5b500490565b85815284602082015260a06040820152600061549c60a0830186614c63565b82810360608401526154ae8186614c63565b91505060018060a01b03831660808301529695505050505050565b60018060a01b038616815284602082015283604082015260a0606082015260006154f660a0830185614c63565b8281036080840152610c838185614c63565b600080600080610180858703121561551f57600080fd5b6155298686614ead565b935061012085015192506101408501516001600160401b038082111561554e57600080fd5b818701915087601f83011261556257600080fd5b815161557061494982614f2d565b8082825260208201915060208360051b86010192508a83111561559257600080fd5b602085015b838110156150a9578051858111156155ae57600080fd5b86016060818e03601f190112156155c457600080fd5b6155cc61488f565b60208201516155da81614516565b8152604082015160208201526060820151878111156155f857600080fd5b6156078f602083860101614f50565b60408301525084525060209283019201615597565b80516001600160a01b031682526000610200602083015160208501526040830151604085015260608301516060850152608083015161565e6080860182614e05565b5060a083015161010061567381870183614e05565b60c08501516001600160a01b031661018087015260e08501516101a0870184905291506156a283870183614c63565b9250808501519150508482036101c08601526156be8282614c63565b9150506101208301518482036101e08601526151a78282614c63565b60208152600061237e602083018461561c565b608081526000615700608083018761561c565b60208301959095525060408101929092526001600160a01b0316606090910152919050565b828152604081016003831061574a57634e487b7160e01b600052602160045260246000fd5b8260208301529392505050565b6000602080838503121561576a57600080fd5b82516001600160401b0381111561578057600080fd5b8301601f8101851361579157600080fd5b805161579f61494982614f2d565b81815260e091820283018401918482019190888411156157be57600080fd5b938501935b838510156158545780858a0312156157db5760008081fd5b6157e36148b1565b85516157ee81614625565b8152858701516157fd81614625565b81880152604086810151908201526060808701519082015260808087015161582481614516565b9082015260a0868101519082015260c08087015161584181614516565b90820152835293840193918501916157c3565b50979650505050505050565b80511515825260208082015115159083015260408082015190830152606080820151908301526080808201516001600160a01b039081169184019190915260a0808301519084015260c09182015116910152565b61014081016158c38287615860565b60e08201949094526101008101929092526001600160a01b031661012090910152919050565b81516001600160a01b031681526020808301519082015260408083015190820152606080830151908201526080808301519082015260a08281015161018083019161593690840182615860565b5092915050565b600061014061594c8388615860565b8560e08401528061010084015261596581840186614c63565b91505060018060a01b03831661012083015295945050505050565b600061014061598f8387615860565b60e08301949094525061010081018390526012928101929092527115195c9b5a5b985b081b9bdd08199bdd5b9960721b6101608301526001600160a01b031661012082015261018001919050565b600082516159ef818460208701614c3f565b919091019291505056fea2646970667358221220558248dbc04ea10c612e57468002e5730c490a4a5abc710d603914a962691a5464736f6c63430008100033", + "devdoc": { + "kind": "dev", + "methods": { + "acceptsToken(address,uint256)": { + "params": { + "_projectId": "The project ID to check for token acceptance.", + "_token": "The token to check if this terminal accepts or not." + }, + "returns": { + "_0": "The flag." + } + }, + "addToBalanceOf(uint256,uint256,address,bool,string,bytes)": { + "params": { + "_amount": "The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.", + "_memo": "A memo to pass along to the emitted event.", + "_metadata": "Extra data to pass along to the emitted event.", + "_projectId": "The ID of the project to which the funds received belong.", + "_shouldRefundHeldFees": "A flag indicating if held fees should be refunded based on the amount being added.", + "_token": "The token being paid. This terminal ignores this property since it only manages one currency." + } + }, + "addToBalanceOf(uint256,uint256,address,string,bytes)": { + "params": { + "_amount": "The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.", + "_memo": "A memo to pass along to the emitted event.", + "_metadata": "Extra data to pass along to the emitted event.", + "_projectId": "The ID of the project to which the funds received belong.", + "_token": "The token being paid. This terminal ignores this property since it only manages one currency." + } + }, + "constructor": { + "params": { + "_baseWeightCurrency": "The currency to base token issuance on.", + "_directory": "A contract storing directories of terminals and controllers for each project.", + "_operatorStore": "A contract storing operator assignments.", + "_owner": "The address that will own this contract.", + "_prices": "A contract that exposes price feeds.", + "_projects": "A contract which mints ERC-721's that represent project ownership and transfers.", + "_splitsStore": "A contract that stores splits for each project.", + "_store": "A contract that stores the terminal's data." + } + }, + "currencyForToken(address)": { + "params": { + "_token": "The token to check for the currency of." + }, + "returns": { + "_0": "The currency index." + } + }, + "currentEthOverflowOf(uint256)": { + "details": "The current overflow is represented as a fixed point number with 18 decimals.", + "params": { + "_projectId": "The ID of the project to get overflow for." + }, + "returns": { + "_0": "The current amount of ETH overflow that project has in this terminal, as a fixed point number with 18 decimals." + } + }, + "decimalsForToken(address)": { + "params": { + "_token": "The token to check for the decimals of." + }, + "returns": { + "_0": "The number of decimals for the token." + } + }, + "distributePayoutsOf(uint256,uint256,uint256,address,uint256,bytes)": { + "details": "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.", + "params": { + "_amount": "The amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal.", + "_currency": "The expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency.", + "_metadata": "Bytes to send along to the emitted event, if provided.", + "_minReturnedTokens": "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.", + "_projectId": "The ID of the project having its payouts distributed.", + "_token": "The token being distributed. This terminal ignores this property since it only manages one token." + }, + "returns": { + "netLeftoverDistributionAmount": "The amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal." + } + }, + "heldFeesOf(uint256)": { + "params": { + "_projectId": "The ID of the project for which fees are being held." + }, + "returns": { + "_0": "An array of fees that are being held." + } + }, + "migrate(uint256,address)": { + "details": "Only a project's owner or a designated operator can migrate it.", + "params": { + "_projectId": "The ID of the project being migrated.", + "_to": "The terminal contract that will gain the project's funds." + }, + "returns": { + "balance": "The amount of funds that were migrated, as a fixed point number with the same amount of decimals as this terminal." + } + }, + "owner()": { + "details": "Returns the address of the current owner." + }, + "pay(uint256,uint256,address,address,uint256,bool,string,bytes)": { + "params": { + "_amount": "The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place.", + "_beneficiary": "The address to mint tokens for and pass along to the funding cycle's data source and delegate.", + "_memo": "A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.", + "_metadata": "Bytes to send along to the data source, delegate, and emitted event, if provided.", + "_minReturnedTokens": "The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal.", + "_preferClaimedTokens": "A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.", + "_projectId": "The ID of the project being paid.", + "_token": "The token being paid. This terminal ignores this property since it only manages one token." + }, + "returns": { + "_0": "The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals." + } + }, + "processFees(uint256)": { + "details": "Only a project owner, an operator, or the contract's owner can process held fees.", + "params": { + "_projectId": "The ID of the project whos held fees should be processed." + } + }, + "redeemTokensOf(address,uint256,uint256,address,uint256,address,string,bytes)": { + "details": "Only a token holder or a designated operator can redeem its tokens.", + "params": { + "_beneficiary": "The address to send the terminal tokens to.", + "_holder": "The account to redeem tokens for.", + "_memo": "A memo to pass along to the emitted event.", + "_metadata": "Bytes to send along to the data source, delegate, and emitted event, if provided.", + "_minReturnedTokens": "The minimum amount of terminal tokens expected in return, as a fixed point number with the same amount of decimals as the terminal.", + "_projectId": "The ID of the project to which the tokens being redeemed belong.", + "_token": "The token being reclaimed. This terminal ignores this property since it only manages one token.", + "_tokenCount": "The number of project tokens to redeem, as a fixed point number with 18 decimals." + }, + "returns": { + "reclaimAmount": "The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals." + } + }, + "renounceOwnership()": { + "details": "Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner." + }, + "setFee(uint256)": { + "details": "Only the owner of this contract can change the fee.", + "params": { + "_fee": "The new fee, out of MAX_FEE." + } + }, + "setFeeGauge(address)": { + "details": "Only the owner of this contract can change the fee gauge.", + "params": { + "_feeGauge": "The new fee gauge." + } + }, + "setFeelessAddress(address,bool)": { + "details": "Only the owner of this contract can set addresses as feeless.", + "params": { + "_address": "The address that can be paid towards while still bypassing fees.", + "_flag": "A flag indicating whether the terminal should be feeless or not." + } + }, + "supportsInterface(bytes4)": { + "details": "See {IERC165-supportsInterface}.", + "params": { + "_interfaceId": "The ID of the interface to check for adherance to." + }, + "returns": { + "_0": "A flag indicating if the provided interface ID is supported." + } + }, + "transferOwnership(address)": { + "details": "Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner." + }, + "useAllowanceOf(uint256,uint256,uint256,address,uint256,address,string,bytes)": { + "details": "Only a project's owner or a designated operator can use its allowance.Incurs the protocol fee.", + "params": { + "_amount": "The amount of terminal tokens to use from this project's current allowance, as a fixed point number with the same amount of decimals as this terminal.", + "_beneficiary": "The address to send the funds to.", + "_currency": "The expected currency of the amount being distributed. Must match the project's current funding cycle's overflow allowance currency.", + "_memo": "A memo to pass along to the emitted event.", + "_metadata": "Bytes to send along to the emitted event, if provided.", + "_minReturnedTokens": "The minimum number of tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with 18 decimals.", + "_projectId": "The ID of the project to use the allowance of.", + "_token": "The token being distributed. This terminal ignores this property since it only manages one token." + }, + "returns": { + "netDistributedAmount": "The amount of tokens that was distributed to the beneficiary, as a fixed point number with the same amount of decimals as the terminal." + } + } + }, + "version": 1 + }, + "userdoc": { + "errors": { + "PRBMath__MulDivOverflow(uint256,uint256)": [ + { + "notice": "Emitted when the result overflows uint256." + } + ] + }, + "kind": "user", + "methods": { + "acceptsToken(address,uint256)": { + "notice": "A flag indicating if this terminal accepts the specified token." + }, + "addToBalanceOf(uint256,uint256,address,bool,string,bytes)": { + "notice": "Receives funds belonging to the specified project." + }, + "addToBalanceOf(uint256,uint256,address,string,bytes)": { + "notice": "Receives funds belonging to the specified project." + }, + "baseWeightCurrency()": { + "notice": "The currency to base token issuance on." + }, + "currency()": { + "notice": "The currency to use when resolving price feeds for this terminal." + }, + "currencyForToken(address)": { + "notice": "The currency that should be used for the specified token." + }, + "currentEthOverflowOf(uint256)": { + "notice": "Gets the current overflowed amount in this terminal for a specified project, in terms of ETH." + }, + "decimals()": { + "notice": "The number of decimals the token fixed point amounts are expected to have." + }, + "decimalsForToken(address)": { + "notice": "The decimals that should be used in fixed number accounting for the specified token." + }, + "directory()": { + "notice": "The directory of terminals and controllers for projects." + }, + "distributePayoutsOf(uint256,uint256,uint256,address,uint256,bytes)": { + "notice": "Distributes payouts for a project with the distribution limit of its current funding cycle." + }, + "fee()": { + "notice": "The platform fee percent." + }, + "feeGauge()": { + "notice": "The data source that returns a discount to apply to a project's fee." + }, + "heldFeesOf(uint256)": { + "notice": "The fees that are currently being held to be processed later for each project." + }, + "isFeelessAddress(address)": { + "notice": "Addresses that can be paid towards from this terminal without incurring a fee." + }, + "migrate(uint256,address)": { + "notice": "Allows a project owner to migrate its funds and operations to a new terminal that accepts the same token type." + }, + "operatorStore()": { + "notice": "A contract storing operator assignments." + }, + "pay(uint256,uint256,address,address,uint256,bool,string,bytes)": { + "notice": "Contribute tokens to a project." + }, + "payoutSplitsGroup()": { + "notice": "The group that payout splits coming from this terminal are identified by." + }, + "prices()": { + "notice": "The contract that exposes price feeds." + }, + "processFees(uint256)": { + "notice": "Process any fees that are being held for the project." + }, + "projects()": { + "notice": "Mints ERC-721's that represent project ownership and transfers." + }, + "redeemTokensOf(address,uint256,uint256,address,uint256,address,string,bytes)": { + "notice": "Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source." + }, + "setFee(uint256)": { + "notice": "Allows the fee to be updated." + }, + "setFeeGauge(address)": { + "notice": "Allows the fee gauge to be updated." + }, + "setFeelessAddress(address,bool)": { + "notice": "Sets whether projects operating on this terminal can pay towards the specified address without incurring a fee." + }, + "splitsStore()": { + "notice": "The contract that stores splits for each project." + }, + "store()": { + "notice": "The contract that stores and manages the terminal's data." + }, + "supportsInterface(bytes4)": { + "notice": "Indicates if this contract adheres to the specified interface." + }, + "token()": { + "notice": "The token that this terminal accepts." + }, + "useAllowanceOf(uint256,uint256,uint256,address,uint256,address,string,bytes)": { + "notice": "Allows a project to send funds from its overflow up to the preconfigured allowance." + } + }, + "notice": "Manages all inflows and outflows of ETH funds into the protocol ecosystem.", + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 53, + "contract": "contracts/JBETHPaymentTerminal3_1_1.sol:JBETHPaymentTerminal3_1_1", + "label": "_owner", + "offset": 0, + "slot": "0", + "type": "t_address" + }, + { + "astId": 28823, + "contract": "contracts/JBETHPaymentTerminal3_1_1.sol:JBETHPaymentTerminal3_1_1", + "label": "_heldFeesOf", + "offset": 0, + "slot": "1", + "type": "t_mapping(t_uint256,t_array(t_struct(JBFee)36640_storage)dyn_storage)" + }, + { + "astId": 28860, + "contract": "contracts/JBETHPaymentTerminal3_1_1.sol:JBETHPaymentTerminal3_1_1", + "label": "fee", + "offset": 0, + "slot": "2", + "type": "t_uint256" + }, + { + "astId": 28864, + "contract": "contracts/JBETHPaymentTerminal3_1_1.sol:JBETHPaymentTerminal3_1_1", + "label": "feeGauge", + "offset": 0, + "slot": "3", + "type": "t_address" + }, + { + "astId": 28870, + "contract": "contracts/JBETHPaymentTerminal3_1_1.sol:JBETHPaymentTerminal3_1_1", + "label": "isFeelessAddress", + "offset": 0, + "slot": "4", + "type": "t_mapping(t_address,t_bool)" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_struct(JBFee)36640_storage)dyn_storage": { + "base": "t_struct(JBFee)36640_storage", + "encoding": "dynamic_array", + "label": "struct JBFee[]", + "numberOfBytes": "32" + }, + "t_bool": { + "encoding": "inplace", + "label": "bool", + "numberOfBytes": "1" + }, + "t_mapping(t_address,t_bool)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => bool)", + "numberOfBytes": "32", + "value": "t_bool" + }, + "t_mapping(t_uint256,t_array(t_struct(JBFee)36640_storage)dyn_storage)": { + "encoding": "mapping", + "key": "t_uint256", + "label": "mapping(uint256 => struct JBFee[])", + "numberOfBytes": "32", + "value": "t_array(t_struct(JBFee)36640_storage)dyn_storage" + }, + "t_struct(JBFee)36640_storage": { + "encoding": "inplace", + "label": "struct JBFee", + "members": [ + { + "astId": 36633, + "contract": "contracts/JBETHPaymentTerminal3_1_1.sol:JBETHPaymentTerminal3_1_1", + "label": "amount", + "offset": 0, + "slot": "0", + "type": "t_uint256" + }, + { + "astId": 36635, + "contract": "contracts/JBETHPaymentTerminal3_1_1.sol:JBETHPaymentTerminal3_1_1", + "label": "fee", + "offset": 0, + "slot": "1", + "type": "t_uint32" + }, + { + "astId": 36637, + "contract": "contracts/JBETHPaymentTerminal3_1_1.sol:JBETHPaymentTerminal3_1_1", + "label": "feeDiscount", + "offset": 4, + "slot": "1", + "type": "t_uint32" + }, + { + "astId": 36639, + "contract": "contracts/JBETHPaymentTerminal3_1_1.sol:JBETHPaymentTerminal3_1_1", + "label": "beneficiary", + "offset": 8, + "slot": "1", + "type": "t_address" + } + ], + "numberOfBytes": "64" + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint32": { + "encoding": "inplace", + "label": "uint32", + "numberOfBytes": "4" + } + } + } +} \ No newline at end of file diff --git a/deployments/mainnet/JBSingleTokenPaymentTerminalStore3_1_1.json b/deployments/mainnet/JBSingleTokenPaymentTerminalStore3_1_1.json new file mode 100644 index 000000000..8babb527f --- /dev/null +++ b/deployments/mainnet/JBSingleTokenPaymentTerminalStore3_1_1.json @@ -0,0 +1,1116 @@ +{ + "address": "0x82129d4109625F94582bDdF6101a8Cd1a27919f5", + "abi": [ + { + "inputs": [ + { + "internalType": "contract IJBDirectory", + "name": "_directory", + "type": "address" + }, + { + "internalType": "contract IJBFundingCycleStore", + "name": "_fundingCycleStore", + "type": "address" + }, + { + "internalType": "contract IJBPrices", + "name": "_prices", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "CURRENCY_MISMATCH", + "type": "error" + }, + { + "inputs": [], + "name": "DISTRIBUTION_AMOUNT_LIMIT_REACHED", + "type": "error" + }, + { + "inputs": [], + "name": "FUNDING_CYCLE_DISTRIBUTION_PAUSED", + "type": "error" + }, + { + "inputs": [], + "name": "FUNDING_CYCLE_PAYMENT_PAUSED", + "type": "error" + }, + { + "inputs": [], + "name": "FUNDING_CYCLE_REDEEM_PAUSED", + "type": "error" + }, + { + "inputs": [], + "name": "INADEQUATE_CONTROLLER_ALLOWANCE", + "type": "error" + }, + { + "inputs": [], + "name": "INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE", + "type": "error" + }, + { + "inputs": [], + "name": "INSUFFICIENT_TOKENS", + "type": "error" + }, + { + "inputs": [], + "name": "INVALID_AMOUNT_TO_SEND_DELEGATE", + "type": "error" + }, + { + "inputs": [], + "name": "INVALID_FUNDING_CYCLE", + "type": "error" + }, + { + "inputs": [], + "name": "PAYMENT_TERMINAL_MIGRATION_NOT_ALLOWED", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "prod1", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "denominator", + "type": "uint256" + } + ], + "name": "PRBMath__MulDivOverflow", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "contract IJBSingleTokenPaymentTerminal", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IJBSingleTokenPaymentTerminal", + "name": "_terminal", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + } + ], + "name": "currentOverflowOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_tokenCount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_totalSupply", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_overflow", + "type": "uint256" + } + ], + "name": "currentReclaimableOverflowOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IJBSingleTokenPaymentTerminal", + "name": "_terminal", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_tokenCount", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "_useTotalOverflow", + "type": "bool" + } + ], + "name": "currentReclaimableOverflowOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_decimals", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_currency", + "type": "uint256" + } + ], + "name": "currentTotalOverflowOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "directory", + "outputs": [ + { + "internalType": "contract IJBDirectory", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "fundingCycleStore", + "outputs": [ + { + "internalType": "contract IJBFundingCycleStore", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "prices", + "outputs": [ + { + "internalType": "contract IJBPrices", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "recordAddedBalanceFor", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_currency", + "type": "uint256" + } + ], + "name": "recordDistributionFor", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "number", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "configuration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "basedOn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "start", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "duration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "weight", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "discountRate", + "type": "uint256" + }, + { + "internalType": "contract IJBFundingCycleBallot", + "name": "ballot", + "type": "address" + }, + { + "internalType": "uint256", + "name": "metadata", + "type": "uint256" + } + ], + "internalType": "struct JBFundingCycle", + "name": "fundingCycle", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "distributedAmount", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + } + ], + "name": "recordMigration", + "outputs": [ + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_payer", + "type": "address" + }, + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "decimals", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "currency", + "type": "uint256" + } + ], + "internalType": "struct JBTokenAmount", + "name": "_amount", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_baseWeightCurrency", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_beneficiary", + "type": "address" + }, + { + "internalType": "string", + "name": "_memo", + "type": "string" + }, + { + "internalType": "bytes", + "name": "_metadata", + "type": "bytes" + } + ], + "name": "recordPaymentFrom", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "number", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "configuration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "basedOn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "start", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "duration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "weight", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "discountRate", + "type": "uint256" + }, + { + "internalType": "contract IJBFundingCycleBallot", + "name": "ballot", + "type": "address" + }, + { + "internalType": "uint256", + "name": "metadata", + "type": "uint256" + } + ], + "internalType": "struct JBFundingCycle", + "name": "fundingCycle", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "tokenCount", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "contract IJBPayDelegate3_1_1", + "name": "delegate", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "metadata", + "type": "bytes" + } + ], + "internalType": "struct JBPayDelegateAllocation3_1_1[]", + "name": "delegateAllocations", + "type": "tuple[]" + }, + { + "internalType": "string", + "name": "memo", + "type": "string" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_holder", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_tokenCount", + "type": "uint256" + }, + { + "internalType": "string", + "name": "_memo", + "type": "string" + }, + { + "internalType": "bytes", + "name": "_metadata", + "type": "bytes" + } + ], + "name": "recordRedemptionFor", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "number", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "configuration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "basedOn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "start", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "duration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "weight", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "discountRate", + "type": "uint256" + }, + { + "internalType": "contract IJBFundingCycleBallot", + "name": "ballot", + "type": "address" + }, + { + "internalType": "uint256", + "name": "metadata", + "type": "uint256" + } + ], + "internalType": "struct JBFundingCycle", + "name": "fundingCycle", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "reclaimAmount", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "contract IJBRedemptionDelegate3_1_1", + "name": "delegate", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "metadata", + "type": "bytes" + } + ], + "internalType": "struct JBRedemptionDelegateAllocation3_1_1[]", + "name": "delegateAllocations", + "type": "tuple[]" + }, + { + "internalType": "string", + "name": "memo", + "type": "string" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_currency", + "type": "uint256" + } + ], + "name": "recordUsedAllowanceOf", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "number", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "configuration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "basedOn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "start", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "duration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "weight", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "discountRate", + "type": "uint256" + }, + { + "internalType": "contract IJBFundingCycleBallot", + "name": "ballot", + "type": "address" + }, + { + "internalType": "uint256", + "name": "metadata", + "type": "uint256" + } + ], + "internalType": "struct JBFundingCycle", + "name": "fundingCycle", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "usedAmount", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IJBSingleTokenPaymentTerminal", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "usedDistributionLimitOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IJBSingleTokenPaymentTerminal", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "usedOverflowAllowanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "transactionHash": "0x705eb5b7ac1f28f06a10d2b2913d1a75fc9008d3ba37f0631556b8ffffc8a225", + "receipt": { + "to": null, + "from": "0xc64533F8d8dEbC301cb4791e6ED941Cb38473DE6", + "contractAddress": "0x82129d4109625F94582bDdF6101a8Cd1a27919f5", + "transactionIndex": 65, + "gasUsed": "2999374", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x285336fb6a145bbf3cf13b578356d43d9534c4970a1e4b00b46cc80cb356fcac", + "transactionHash": "0x705eb5b7ac1f28f06a10d2b2913d1a75fc9008d3ba37f0631556b8ffffc8a225", + "logs": [], + "blockNumber": 17594318, + "cumulativeGasUsed": "9902252", + "status": 1, + "byzantium": true + }, + "args": [ + "0x65572FB928b46f9aDB7cfe5A4c41226F636161ea", + "0x6f18cF9173136c0B5A6eBF45f19D58d3ff2E17e6", + "0x63CF55ab55ABcaD4E84335B80bbE3D2DefA09410" + ], + "numDeployments": 1, + "solcInputHash": "11cb1f66a0f8213d7bf83deb0ae9d2f7", + "metadata": "{\"compiler\":{\"version\":\"0.8.16+commit.07a7930e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract IJBDirectory\",\"name\":\"_directory\",\"type\":\"address\"},{\"internalType\":\"contract IJBFundingCycleStore\",\"name\":\"_fundingCycleStore\",\"type\":\"address\"},{\"internalType\":\"contract IJBPrices\",\"name\":\"_prices\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"CURRENCY_MISMATCH\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DISTRIBUTION_AMOUNT_LIMIT_REACHED\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FUNDING_CYCLE_DISTRIBUTION_PAUSED\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FUNDING_CYCLE_PAYMENT_PAUSED\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FUNDING_CYCLE_REDEEM_PAUSED\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"INADEQUATE_CONTROLLER_ALLOWANCE\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"INSUFFICIENT_TOKENS\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"INVALID_AMOUNT_TO_SEND_DELEGATE\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"INVALID_FUNDING_CYCLE\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PAYMENT_TERMINAL_MIGRATION_NOT_ALLOWED\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"prod1\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"denominator\",\"type\":\"uint256\"}],\"name\":\"PRBMath__MulDivOverflow\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"contract IJBSingleTokenPaymentTerminal\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IJBSingleTokenPaymentTerminal\",\"name\":\"_terminal\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"}],\"name\":\"currentOverflowOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_tokenCount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_totalSupply\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_overflow\",\"type\":\"uint256\"}],\"name\":\"currentReclaimableOverflowOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IJBSingleTokenPaymentTerminal\",\"name\":\"_terminal\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_tokenCount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"_useTotalOverflow\",\"type\":\"bool\"}],\"name\":\"currentReclaimableOverflowOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_decimals\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_currency\",\"type\":\"uint256\"}],\"name\":\"currentTotalOverflowOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"directory\",\"outputs\":[{\"internalType\":\"contract IJBDirectory\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fundingCycleStore\",\"outputs\":[{\"internalType\":\"contract IJBFundingCycleStore\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"prices\",\"outputs\":[{\"internalType\":\"contract IJBPrices\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"recordAddedBalanceFor\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_currency\",\"type\":\"uint256\"}],\"name\":\"recordDistributionFor\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"number\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"configuration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"basedOn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"start\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"duration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"weight\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"discountRate\",\"type\":\"uint256\"},{\"internalType\":\"contract IJBFundingCycleBallot\",\"name\":\"ballot\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"metadata\",\"type\":\"uint256\"}],\"internalType\":\"struct JBFundingCycle\",\"name\":\"fundingCycle\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"distributedAmount\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"}],\"name\":\"recordMigration\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_payer\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"decimals\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"currency\",\"type\":\"uint256\"}],\"internalType\":\"struct JBTokenAmount\",\"name\":\"_amount\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_baseWeightCurrency\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_beneficiary\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"_memo\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"_metadata\",\"type\":\"bytes\"}],\"name\":\"recordPaymentFrom\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"number\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"configuration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"basedOn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"start\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"duration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"weight\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"discountRate\",\"type\":\"uint256\"},{\"internalType\":\"contract IJBFundingCycleBallot\",\"name\":\"ballot\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"metadata\",\"type\":\"uint256\"}],\"internalType\":\"struct JBFundingCycle\",\"name\":\"fundingCycle\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"tokenCount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"contract IJBPayDelegate3_1_1\",\"name\":\"delegate\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"metadata\",\"type\":\"bytes\"}],\"internalType\":\"struct JBPayDelegateAllocation3_1_1[]\",\"name\":\"delegateAllocations\",\"type\":\"tuple[]\"},{\"internalType\":\"string\",\"name\":\"memo\",\"type\":\"string\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_holder\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_tokenCount\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"_memo\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"_metadata\",\"type\":\"bytes\"}],\"name\":\"recordRedemptionFor\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"number\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"configuration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"basedOn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"start\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"duration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"weight\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"discountRate\",\"type\":\"uint256\"},{\"internalType\":\"contract IJBFundingCycleBallot\",\"name\":\"ballot\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"metadata\",\"type\":\"uint256\"}],\"internalType\":\"struct JBFundingCycle\",\"name\":\"fundingCycle\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"reclaimAmount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"contract IJBRedemptionDelegate3_1_1\",\"name\":\"delegate\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"metadata\",\"type\":\"bytes\"}],\"internalType\":\"struct JBRedemptionDelegateAllocation3_1_1[]\",\"name\":\"delegateAllocations\",\"type\":\"tuple[]\"},{\"internalType\":\"string\",\"name\":\"memo\",\"type\":\"string\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_currency\",\"type\":\"uint256\"}],\"name\":\"recordUsedAllowanceOf\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"number\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"configuration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"basedOn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"start\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"duration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"weight\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"discountRate\",\"type\":\"uint256\"},{\"internalType\":\"contract IJBFundingCycleBallot\",\"name\":\"ballot\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"metadata\",\"type\":\"uint256\"}],\"internalType\":\"struct JBFundingCycle\",\"name\":\"fundingCycle\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"usedAmount\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IJBSingleTokenPaymentTerminal\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"usedDistributionLimitOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IJBSingleTokenPaymentTerminal\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"usedOverflowAllowanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"This Store expects a project's controller to be an IJBController3_1.\",\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_directory\":\"A contract storing directories of terminals and controllers for each project.\",\"_fundingCycleStore\":\"A contract storing all funding cycle configurations.\",\"_prices\":\"A contract that exposes price feeds.\"}},\"currentOverflowOf(address,uint256)\":{\"details\":\"The current overflow is represented as a fixed point number with the same amount of decimals as the specified terminal.\",\"params\":{\"_projectId\":\"The ID of the project to get overflow for.\",\"_terminal\":\"The terminal for which the overflow is being calculated.\"},\"returns\":{\"_0\":\"The current amount of overflow that project has in the specified terminal.\"}},\"currentReclaimableOverflowOf(address,uint256,uint256,bool)\":{\"details\":\"If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.The current reclaimable overflow is returned in terms of the specified terminal's currency.The reclaimable overflow is represented as a fixed point number with the same amount of decimals as the specified terminal.\",\"params\":{\"_projectId\":\"The ID of the project to get the reclaimable overflow amount for.\",\"_terminal\":\"The terminal from which the reclaimable amount would come.\",\"_tokenCount\":\"The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\",\"_useTotalOverflow\":\"A flag indicating whether the overflow used in the calculation should be summed from all of the project's terminals. If false, overflow should be limited to the amount in the specified `_terminal`.\"},\"returns\":{\"_0\":\"The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_terminal`.\"}},\"currentReclaimableOverflowOf(uint256,uint256,uint256,uint256)\":{\"details\":\"If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\",\"params\":{\"_overflow\":\"The amount of overflow to make the calculation with, as a fixed point number.\",\"_projectId\":\"The ID of the project to get the reclaimable overflow amount for.\",\"_tokenCount\":\"The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\",\"_totalSupply\":\"The total number of tokens to make the calculation with, as a fixed point number with 18 decimals.\"},\"returns\":{\"_0\":\"The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_overflow`.\"}},\"currentTotalOverflowOf(uint256,uint256,uint256)\":{\"params\":{\"_currency\":\"The currency that the total overflow should be in terms of.\",\"_decimals\":\"The number of decimals that the fixed point overflow should include.\",\"_projectId\":\"The ID of the project to get total overflow for.\"},\"returns\":{\"_0\":\"The current total amount of overflow that project has across all terminals.\"}},\"recordAddedBalanceFor(uint256,uint256)\":{\"details\":\"The msg.sender must be an IJBSingleTokenPaymentTerminal.\",\"params\":{\"_amount\":\"The amount of terminal tokens added, as a fixed point number with the same amount of decimals as its relative terminal.\",\"_projectId\":\"The ID of the project to which the funds being added belong.\"}},\"recordDistributionFor(uint256,uint256,uint256)\":{\"details\":\"The msg.sender must be an IJBSingleTokenPaymentTerminal.\",\"params\":{\"_amount\":\"The amount to use from the distribution limit, as a fixed point number.\",\"_currency\":\"The currency of the `_amount`. This must match the project's current funding cycle's currency.\",\"_projectId\":\"The ID of the project that is having funds distributed.\"},\"returns\":{\"distributedAmount\":\"The amount of terminal tokens distributed, as a fixed point number with the same amount of decimals as its relative terminal.\",\"fundingCycle\":\"The funding cycle during which the distribution was made.\"}},\"recordMigration(uint256)\":{\"details\":\"The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount returned is in terms of the msg.senders tokens.\",\"params\":{\"_projectId\":\"The ID of the project being migrated.\"},\"returns\":{\"balance\":\"The project's migrated balance, as a fixed point number with the same amount of decimals as its relative terminal.\"}},\"recordPaymentFrom(address,(address,uint256,uint256,uint256),uint256,uint256,address,string,bytes)\":{\"details\":\"Mints the project's tokens according to values provided by a configured data source. If no data source is configured, mints tokens proportional to the amount of the contribution.The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.sender's tokens.\",\"params\":{\"_amount\":\"The amount of tokens being paid. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\",\"_baseWeightCurrency\":\"The currency to base token issuance on.\",\"_beneficiary\":\"The specified address that should be the beneficiary of anything that results from the payment.\",\"_memo\":\"A memo to pass along to the emitted event, and passed along to the funding cycle's data source.\",\"_metadata\":\"Bytes to send along to the data source, if one is provided.\",\"_payer\":\"The original address that sent the payment to the terminal.\",\"_projectId\":\"The ID of the project being paid.\"},\"returns\":{\"delegateAllocations\":\"The amount to send to delegates instead of adding to the local balance.\",\"fundingCycle\":\"The project's funding cycle during which payment was made.\",\"memo\":\"A memo that should be passed along to the emitted event.\",\"tokenCount\":\"The number of project tokens that were minted, as a fixed point number with 18 decimals.\"}},\"recordRedemptionFor(address,uint256,uint256,string,bytes)\":{\"details\":\"Redeems the project's tokens according to values provided by a configured data source. If no data source is configured, redeems tokens along a redemption bonding curve that is a function of the number of tokens being burned.The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.senders tokens.\",\"params\":{\"_holder\":\"The account that is having its tokens redeemed.\",\"_memo\":\"A memo to pass along to the emitted event.\",\"_metadata\":\"Bytes to send along to the data source, if one is provided.\",\"_projectId\":\"The ID of the project to which the tokens being redeemed belong.\",\"_tokenCount\":\"The number of project tokens to redeem, as a fixed point number with 18 decimals.\"},\"returns\":{\"delegateAllocations\":\"The amount to send to delegates instead of sending to the beneficiary.\",\"fundingCycle\":\"The funding cycle during which the redemption was made.\",\"memo\":\"A memo that should be passed along to the emitted event.\",\"reclaimAmount\":\"The amount of terminal tokens reclaimed, as a fixed point number with 18 decimals.\"}},\"recordUsedAllowanceOf(uint256,uint256,uint256)\":{\"details\":\"The msg.sender must be an IJBSingleTokenPaymentTerminal.\",\"params\":{\"_amount\":\"The amount to use from the allowance, as a fixed point number.\",\"_currency\":\"The currency of the `_amount`. Must match the currency of the overflow allowance.\",\"_projectId\":\"The ID of the project to use the allowance of.\"},\"returns\":{\"fundingCycle\":\"The funding cycle during which the overflow allowance is being used.\",\"usedAmount\":\"The amount of terminal tokens used, as a fixed point number with the same amount of decimals as its relative terminal.\"}}},\"stateVariables\":{\"balanceOf\":{\"custom:param\":\"_terminal The terminal to which the balance applies._projectId The ID of the project to get the balance of.\",\"details\":\"The balance is represented as a fixed point number with the same amount of decimals as its relative terminal.\"},\"usedDistributionLimitOf\":{\"custom:param\":\"_terminal The terminal to which the used distribution limit applies._projectId The ID of the project to get the used distribution limit of._fundingCycleNumber The number of the funding cycle during which the distribution limit was used.\",\"details\":\"Increases as projects use their preconfigured distribution limits.The used distribution limit is represented as a fixed point number with the same amount of decimals as its relative terminal.\"},\"usedOverflowAllowanceOf\":{\"custom:param\":\"_terminal The terminal to which the overflow allowance applies._projectId The ID of the project to get the used overflow allowance of._configuration The configuration of the during which the allowance was used.\",\"details\":\"Increases as projects use their allowance.The used allowance is represented as a fixed point number with the same amount of decimals as its relative terminal.\"}},\"version\":1},\"userdoc\":{\"errors\":{\"PRBMath__MulDivOverflow(uint256,uint256)\":[{\"notice\":\"Emitted when the result overflows uint256.\"}]},\"kind\":\"user\",\"methods\":{\"balanceOf(address,uint256)\":{\"notice\":\"The amount of tokens that each project has for each terminal, in terms of the terminal's token.\"},\"currentOverflowOf(address,uint256)\":{\"notice\":\"Gets the current overflowed amount in a terminal for a specified project.\"},\"currentReclaimableOverflowOf(address,uint256,uint256,bool)\":{\"notice\":\"The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the total token supply and overflow in the ecosystem.\"},\"currentReclaimableOverflowOf(uint256,uint256,uint256,uint256)\":{\"notice\":\"The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the specified total token supply and overflow amounts.\"},\"currentTotalOverflowOf(uint256,uint256,uint256)\":{\"notice\":\"Gets the current overflowed amount for a specified project across all terminals.\"},\"directory()\":{\"notice\":\"The directory of terminals and controllers for projects.\"},\"fundingCycleStore()\":{\"notice\":\"The contract storing all funding cycle configurations.\"},\"prices()\":{\"notice\":\"The contract that exposes price feeds.\"},\"recordAddedBalanceFor(uint256,uint256)\":{\"notice\":\"Records newly added funds for the project.\"},\"recordDistributionFor(uint256,uint256,uint256)\":{\"notice\":\"Records newly distributed funds for a project.\"},\"recordMigration(uint256)\":{\"notice\":\"Records the migration of funds from this store.\"},\"recordPaymentFrom(address,(address,uint256,uint256,uint256),uint256,uint256,address,string,bytes)\":{\"notice\":\"Records newly contributed tokens to a project.\"},\"recordRedemptionFor(address,uint256,uint256,string,bytes)\":{\"notice\":\"Records newly redeemed tokens of a project.\"},\"recordUsedAllowanceOf(uint256,uint256,uint256)\":{\"notice\":\"Records newly used allowance funds of a project.\"},\"usedDistributionLimitOf(address,uint256,uint256)\":{\"notice\":\"The amount of funds that a project has distributed from its limit during the current funding cycle for each terminal, in terms of the distribution limit's currency.\"},\"usedOverflowAllowanceOf(address,uint256,uint256)\":{\"notice\":\"The amount of funds that a project has used from its allowance during the current funding cycle configuration for each terminal, in terms of the overflow allowance's currency.\"}},\"notice\":\"Manages all bookkeeping for inflows and outflows of funds from any ISingleTokenPaymentTerminal.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/JBSingleTokenPaymentTerminalStore3_1_1.sol\":\"JBSingleTokenPaymentTerminalStore3_1_1\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/security/ReentrancyGuard.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Contract module that helps prevent reentrant calls to a function.\\n *\\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\\n * available, which can be applied to functions to make sure there are no nested\\n * (reentrant) calls to them.\\n *\\n * Note that because there is a single `nonReentrant` guard, functions marked as\\n * `nonReentrant` may not call one another. This can be worked around by making\\n * those functions `private`, and then adding `external` `nonReentrant` entry\\n * points to them.\\n *\\n * TIP: If you would like to learn more about reentrancy and alternative ways\\n * to protect against it, check out our blog post\\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\\n */\\nabstract contract ReentrancyGuard {\\n // Booleans are more expensive than uint256 or any type that takes up a full\\n // word because each write operation emits an extra SLOAD to first read the\\n // slot's contents, replace the bits taken up by the boolean, and then write\\n // back. This is the compiler's defense against contract upgrades and\\n // pointer aliasing, and it cannot be disabled.\\n\\n // The values being non-zero value makes deployment a bit more expensive,\\n // but in exchange the refund on every call to nonReentrant will be lower in\\n // amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to\\n // increase the likelihood of the full refund coming into effect.\\n uint256 private constant _NOT_ENTERED = 1;\\n uint256 private constant _ENTERED = 2;\\n\\n uint256 private _status;\\n\\n constructor() {\\n _status = _NOT_ENTERED;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a `nonReentrant` function from another `nonReentrant`\\n * function is not supported. It is possible to prevent this from happening\\n * by making the `nonReentrant` function external, and making it call a\\n * `private` function that does the actual work.\\n */\\n modifier nonReentrant() {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_status != _ENTERED, \\\"ReentrancyGuard: reentrant call\\\");\\n\\n // Any calls to nonReentrant after this point will fail\\n _status = _ENTERED;\\n\\n _;\\n\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _status = _NOT_ENTERED;\\n }\\n}\\n\",\"keccak256\":\"0x0e9621f60b2faabe65549f7ed0f24e8853a45c1b7990d47e8160e523683f3935\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC721/IERC721.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../../utils/introspection/IERC165.sol\\\";\\n\\n/**\\n * @dev Required interface of an ERC721 compliant contract.\\n */\\ninterface IERC721 is IERC165 {\\n /**\\n * @dev Emitted when `tokenId` token is transferred from `from` to `to`.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);\\n\\n /**\\n * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.\\n */\\n event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);\\n\\n /**\\n * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.\\n */\\n event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\\n\\n /**\\n * @dev Returns the number of tokens in ``owner``'s account.\\n */\\n function balanceOf(address owner) external view returns (uint256 balance);\\n\\n /**\\n * @dev Returns the owner of the `tokenId` token.\\n *\\n * Requirements:\\n *\\n * - `tokenId` must exist.\\n */\\n function ownerOf(uint256 tokenId) external view returns (address owner);\\n\\n /**\\n * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\\n * are aware of the ERC721 protocol to prevent tokens from being forever locked.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `tokenId` token must exist and be owned by `from`.\\n * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.\\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\\n *\\n * Emits a {Transfer} event.\\n */\\n function safeTransferFrom(\\n address from,\\n address to,\\n uint256 tokenId\\n ) external;\\n\\n /**\\n * @dev Transfers `tokenId` token from `from` to `to`.\\n *\\n * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `tokenId` token must be owned by `from`.\\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 tokenId\\n ) external;\\n\\n /**\\n * @dev Gives permission to `to` to transfer `tokenId` token to another account.\\n * The approval is cleared when the token is transferred.\\n *\\n * Only a single account can be approved at a time, so approving the zero address clears previous approvals.\\n *\\n * Requirements:\\n *\\n * - The caller must own the token or be an approved operator.\\n * - `tokenId` must exist.\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address to, uint256 tokenId) external;\\n\\n /**\\n * @dev Returns the account approved for `tokenId` token.\\n *\\n * Requirements:\\n *\\n * - `tokenId` must exist.\\n */\\n function getApproved(uint256 tokenId) external view returns (address operator);\\n\\n /**\\n * @dev Approve or remove `operator` as an operator for the caller.\\n * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.\\n *\\n * Requirements:\\n *\\n * - The `operator` cannot be the caller.\\n *\\n * Emits an {ApprovalForAll} event.\\n */\\n function setApprovalForAll(address operator, bool _approved) external;\\n\\n /**\\n * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.\\n *\\n * See {setApprovalForAll}\\n */\\n function isApprovedForAll(address owner, address operator) external view returns (bool);\\n\\n /**\\n * @dev Safely transfers `tokenId` token from `from` to `to`.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `tokenId` token must exist and be owned by `from`.\\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\\n *\\n * Emits a {Transfer} event.\\n */\\n function safeTransferFrom(\\n address from,\\n address to,\\n uint256 tokenId,\\n bytes calldata data\\n ) external;\\n}\\n\",\"keccak256\":\"0x516a22876c1fab47f49b1bc22b4614491cd05338af8bd2e7b382da090a079990\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/IERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC165 standard, as defined in the\\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\\n *\\n * Implementers can declare support of contract interfaces, which can then be\\n * queried by others ({ERC165Checker}).\\n *\\n * For an implementation, see {ERC165}.\\n */\\ninterface IERC165 {\\n /**\\n * @dev Returns true if this contract implements the interface defined by\\n * `interfaceId`. See the corresponding\\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\\n * to learn more about how these ids are created.\\n *\\n * This function call must use less than 30 000 gas.\\n */\\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\\n}\\n\",\"keccak256\":\"0x447a5f3ddc18419d41ff92b3773fb86471b1db25773e07f877f548918a185bf1\",\"license\":\"MIT\"},\"@paulrberg/contracts/math/PRBMath.sol\":{\"content\":\"// SPDX-License-Identifier: Unlicense\\npragma solidity >=0.8.4;\\n\\nimport \\\"prb-math/contracts/PRBMath.sol\\\";\\n\",\"keccak256\":\"0x42821345981bc0434a90ba2268a2f5278dfe9e38166981d72fc7f3b776a29495\",\"license\":\"Unlicense\"},\"contracts/JBSingleTokenPaymentTerminalStore3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.16;\\n\\nimport {ReentrancyGuard} from '@openzeppelin/contracts/security/ReentrancyGuard.sol';\\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\\nimport {JBBallotState} from './enums/JBBallotState.sol';\\nimport {IJBController3_1} from './interfaces/IJBController3_1.sol';\\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\\nimport {IJBFundingCycleDataSource3_1_1} from './interfaces/IJBFundingCycleDataSource3_1_1.sol';\\nimport {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol';\\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\\nimport {IJBSingleTokenPaymentTerminal} from './interfaces/IJBSingleTokenPaymentTerminal.sol';\\nimport {IJBSingleTokenPaymentTerminalStore3_1_1} from './interfaces/IJBSingleTokenPaymentTerminalStore3_1_1.sol';\\nimport {JBConstants} from './libraries/JBConstants.sol';\\nimport {JBCurrencies} from './libraries/JBCurrencies.sol';\\nimport {JBFixedPointNumber} from './libraries/JBFixedPointNumber.sol';\\nimport {JBFundingCycleMetadataResolver} from './libraries/JBFundingCycleMetadataResolver.sol';\\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\\nimport {JBPayDelegateAllocation3_1_1} from './structs/JBPayDelegateAllocation3_1_1.sol';\\nimport {JBPayParamsData} from './structs/JBPayParamsData.sol';\\nimport {JBRedeemParamsData} from './structs/JBRedeemParamsData.sol';\\nimport {JBRedemptionDelegateAllocation3_1_1} from './structs/JBRedemptionDelegateAllocation3_1_1.sol';\\nimport {JBTokenAmount} from './structs/JBTokenAmount.sol';\\n\\n/// @notice Manages all bookkeeping for inflows and outflows of funds from any ISingleTokenPaymentTerminal.\\n/// @dev This Store expects a project's controller to be an IJBController3_1.\\ncontract JBSingleTokenPaymentTerminalStore3_1_1 is\\n ReentrancyGuard,\\n IJBSingleTokenPaymentTerminalStore3_1_1\\n{\\n // A library that parses the packed funding cycle metadata into a friendlier format.\\n using JBFundingCycleMetadataResolver for JBFundingCycle;\\n\\n //*********************************************************************//\\n // --------------------------- custom errors ------------------------- //\\n //*********************************************************************//\\n error INVALID_AMOUNT_TO_SEND_DELEGATE();\\n error CURRENCY_MISMATCH();\\n error DISTRIBUTION_AMOUNT_LIMIT_REACHED();\\n error FUNDING_CYCLE_PAYMENT_PAUSED();\\n error FUNDING_CYCLE_DISTRIBUTION_PAUSED();\\n error FUNDING_CYCLE_REDEEM_PAUSED();\\n error INADEQUATE_CONTROLLER_ALLOWANCE();\\n error INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\\n error INSUFFICIENT_TOKENS();\\n error INVALID_FUNDING_CYCLE();\\n error PAYMENT_TERMINAL_MIGRATION_NOT_ALLOWED();\\n\\n //*********************************************************************//\\n // -------------------------- private constants ---------------------- //\\n //*********************************************************************//\\n\\n /// @notice Ensures a maximum number of decimal points of persisted fidelity on mulDiv operations of fixed point numbers.\\n uint256 private constant _MAX_FIXED_POINT_FIDELITY = 18;\\n\\n //*********************************************************************//\\n // ---------------- public immutable stored properties --------------- //\\n //*********************************************************************//\\n\\n /// @notice The directory of terminals and controllers for projects.\\n IJBDirectory public immutable override directory;\\n\\n /// @notice The contract storing all funding cycle configurations.\\n IJBFundingCycleStore public immutable override fundingCycleStore;\\n\\n /// @notice The contract that exposes price feeds.\\n IJBPrices public immutable override prices;\\n\\n //*********************************************************************//\\n // --------------------- public stored properties -------------------- //\\n //*********************************************************************//\\n\\n /// @notice The amount of tokens that each project has for each terminal, in terms of the terminal's token.\\n /// @dev The balance is represented as a fixed point number with the same amount of decimals as its relative terminal.\\n /// @custom:param _terminal The terminal to which the balance applies.\\n /// @custom:param _projectId The ID of the project to get the balance of.\\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => uint256)) public override balanceOf;\\n\\n /// @notice The amount of funds that a project has distributed from its limit during the current funding cycle for each terminal, in terms of the distribution limit's currency.\\n /// @dev Increases as projects use their preconfigured distribution limits.\\n /// @dev The used distribution limit is represented as a fixed point number with the same amount of decimals as its relative terminal.\\n /// @custom:param _terminal The terminal to which the used distribution limit applies.\\n /// @custom:param _projectId The ID of the project to get the used distribution limit of.\\n /// @custom:param _fundingCycleNumber The number of the funding cycle during which the distribution limit was used.\\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => mapping(uint256 => uint256)))\\n public\\n override usedDistributionLimitOf;\\n\\n /// @notice The amount of funds that a project has used from its allowance during the current funding cycle configuration for each terminal, in terms of the overflow allowance's currency.\\n /// @dev Increases as projects use their allowance.\\n /// @dev The used allowance is represented as a fixed point number with the same amount of decimals as its relative terminal.\\n /// @custom:param _terminal The terminal to which the overflow allowance applies.\\n /// @custom:param _projectId The ID of the project to get the used overflow allowance of.\\n /// @custom:param _configuration The configuration of the during which the allowance was used.\\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => mapping(uint256 => uint256)))\\n public\\n override usedOverflowAllowanceOf;\\n\\n //*********************************************************************//\\n // ------------------------- external views -------------------------- //\\n //*********************************************************************//\\n\\n /// @notice Gets the current overflowed amount in a terminal for a specified project.\\n /// @dev The current overflow is represented as a fixed point number with the same amount of decimals as the specified terminal.\\n /// @param _terminal The terminal for which the overflow is being calculated.\\n /// @param _projectId The ID of the project to get overflow for.\\n /// @return The current amount of overflow that project has in the specified terminal.\\n function currentOverflowOf(\\n IJBSingleTokenPaymentTerminal _terminal,\\n uint256 _projectId\\n ) external view override returns (uint256) {\\n // Return the overflow during the project's current funding cycle.\\n return\\n _overflowDuring(\\n _terminal,\\n _projectId,\\n fundingCycleStore.currentOf(_projectId),\\n _terminal.currency()\\n );\\n }\\n\\n /// @notice Gets the current overflowed amount for a specified project across all terminals.\\n /// @param _projectId The ID of the project to get total overflow for.\\n /// @param _decimals The number of decimals that the fixed point overflow should include.\\n /// @param _currency The currency that the total overflow should be in terms of.\\n /// @return The current total amount of overflow that project has across all terminals.\\n function currentTotalOverflowOf(\\n uint256 _projectId,\\n uint256 _decimals,\\n uint256 _currency\\n ) external view override returns (uint256) {\\n return _currentTotalOverflowOf(_projectId, _decimals, _currency);\\n }\\n\\n /// @notice The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the total token supply and overflow in the ecosystem.\\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\\n /// @dev The current reclaimable overflow is returned in terms of the specified terminal's currency.\\n /// @dev The reclaimable overflow is represented as a fixed point number with the same amount of decimals as the specified terminal.\\n /// @param _terminal The terminal from which the reclaimable amount would come.\\n /// @param _projectId The ID of the project to get the reclaimable overflow amount for.\\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\\n /// @param _useTotalOverflow A flag indicating whether the overflow used in the calculation should be summed from all of the project's terminals. If false, overflow should be limited to the amount in the specified `_terminal`.\\n /// @return The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_terminal`.\\n function currentReclaimableOverflowOf(\\n IJBSingleTokenPaymentTerminal _terminal,\\n uint256 _projectId,\\n uint256 _tokenCount,\\n bool _useTotalOverflow\\n ) external view override returns (uint256) {\\n // Get a reference to the project's current funding cycle.\\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\\n\\n // Get the amount of current overflow.\\n // Use the project's total overflow across all of its terminals if the flag species specifies so. Otherwise, use the overflow local to the specified terminal.\\n uint256 _currentOverflow = _useTotalOverflow\\n ? _currentTotalOverflowOf(_projectId, _terminal.decimals(), _terminal.currency())\\n : _overflowDuring(_terminal, _projectId, _fundingCycle, _terminal.currency());\\n\\n // If there's no overflow, there's no reclaimable overflow.\\n if (_currentOverflow == 0) return 0;\\n\\n // Get the number of outstanding tokens the project has.\\n uint256 _totalSupply = IJBController3_1(directory.controllerOf(_projectId))\\n .totalOutstandingTokensOf(_projectId);\\n\\n // Can't redeem more tokens that is in the supply.\\n if (_tokenCount > _totalSupply) return 0;\\n\\n // Return the reclaimable overflow amount.\\n return\\n _reclaimableOverflowDuring(\\n _projectId,\\n _fundingCycle,\\n _tokenCount,\\n _totalSupply,\\n _currentOverflow\\n );\\n }\\n\\n /// @notice The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the specified total token supply and overflow amounts.\\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\\n /// @param _projectId The ID of the project to get the reclaimable overflow amount for.\\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\\n /// @param _totalSupply The total number of tokens to make the calculation with, as a fixed point number with 18 decimals.\\n /// @param _overflow The amount of overflow to make the calculation with, as a fixed point number.\\n /// @return The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_overflow`.\\n function currentReclaimableOverflowOf(\\n uint256 _projectId,\\n uint256 _tokenCount,\\n uint256 _totalSupply,\\n uint256 _overflow\\n ) external view override returns (uint256) {\\n // If there's no overflow, there's no reclaimable overflow.\\n if (_overflow == 0) return 0;\\n\\n // Can't redeem more tokens that is in the supply.\\n if (_tokenCount > _totalSupply) return 0;\\n\\n // Get a reference to the project's current funding cycle.\\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\\n\\n // Return the reclaimable overflow amount.\\n return\\n _reclaimableOverflowDuring(_projectId, _fundingCycle, _tokenCount, _totalSupply, _overflow);\\n }\\n\\n //*********************************************************************//\\n // -------------------------- constructor ---------------------------- //\\n //*********************************************************************//\\n\\n /// @param _directory A contract storing directories of terminals and controllers for each project.\\n /// @param _fundingCycleStore A contract storing all funding cycle configurations.\\n /// @param _prices A contract that exposes price feeds.\\n constructor(IJBDirectory _directory, IJBFundingCycleStore _fundingCycleStore, IJBPrices _prices) {\\n directory = _directory;\\n fundingCycleStore = _fundingCycleStore;\\n prices = _prices;\\n }\\n\\n //*********************************************************************//\\n // ---------------------- external transactions ---------------------- //\\n //*********************************************************************//\\n\\n /// @notice Records newly contributed tokens to a project.\\n /// @dev Mints the project's tokens according to values provided by a configured data source. If no data source is configured, mints tokens proportional to the amount of the contribution.\\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.sender's tokens.\\n /// @param _payer The original address that sent the payment to the terminal.\\n /// @param _amount The amount of tokens being paid. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\\n /// @param _projectId The ID of the project being paid.\\n /// @param _baseWeightCurrency The currency to base token issuance on.\\n /// @param _beneficiary The specified address that should be the beneficiary of anything that results from the payment.\\n /// @param _memo A memo to pass along to the emitted event, and passed along to the funding cycle's data source.\\n /// @param _metadata Bytes to send along to the data source, if one is provided.\\n /// @return fundingCycle The project's funding cycle during which payment was made.\\n /// @return tokenCount The number of project tokens that were minted, as a fixed point number with 18 decimals.\\n /// @return delegateAllocations The amount to send to delegates instead of adding to the local balance.\\n /// @return memo A memo that should be passed along to the emitted event.\\n function recordPaymentFrom(\\n address _payer,\\n JBTokenAmount calldata _amount,\\n uint256 _projectId,\\n uint256 _baseWeightCurrency,\\n address _beneficiary,\\n string calldata _memo,\\n bytes memory _metadata\\n )\\n external\\n override\\n nonReentrant\\n returns (\\n JBFundingCycle memory fundingCycle,\\n uint256 tokenCount,\\n JBPayDelegateAllocation3_1_1[] memory delegateAllocations,\\n string memory memo\\n )\\n {\\n // Get a reference to the current funding cycle for the project.\\n fundingCycle = fundingCycleStore.currentOf(_projectId);\\n\\n // The project must have a funding cycle configured.\\n if (fundingCycle.number == 0) revert INVALID_FUNDING_CYCLE();\\n\\n // Must not be paused.\\n if (fundingCycle.payPaused()) revert FUNDING_CYCLE_PAYMENT_PAUSED();\\n\\n // The weight according to which new token supply is to be minted, as a fixed point number with 18 decimals.\\n uint256 _weight;\\n\\n // If the funding cycle has configured a data source, use it to derive a weight and memo.\\n if (fundingCycle.useDataSourceForPay() && fundingCycle.dataSource() != address(0)) {\\n // Create the params that'll be sent to the data source.\\n JBPayParamsData memory _data = JBPayParamsData(\\n IJBSingleTokenPaymentTerminal(msg.sender),\\n _payer,\\n _amount,\\n _projectId,\\n fundingCycle.configuration,\\n _beneficiary,\\n fundingCycle.weight,\\n fundingCycle.reservedRate(),\\n _memo,\\n _metadata\\n );\\n (_weight, memo, delegateAllocations) = IJBFundingCycleDataSource3_1_1(\\n fundingCycle.dataSource()\\n ).payParams(_data);\\n }\\n // Otherwise use the funding cycle's weight\\n else {\\n _weight = fundingCycle.weight;\\n memo = _memo;\\n }\\n\\n // Scoped section prevents stack too deep. `_balanceDiff` only used within scope.\\n {\\n // Keep a reference to the amount that should be added to the project's balance.\\n uint256 _balanceDiff = _amount.value;\\n\\n // Validate all delegated amounts. This needs to be done before returning the delegate allocations to ensure valid delegated amounts.\\n if (delegateAllocations.length != 0) {\\n for (uint256 _i; _i < delegateAllocations.length; ) {\\n // Get a reference to the amount to be delegated.\\n uint256 _delegatedAmount = delegateAllocations[_i].amount;\\n\\n // Validate if non-zero.\\n if (_delegatedAmount != 0) {\\n // Can't delegate more than was paid.\\n if (_delegatedAmount > _balanceDiff) revert INVALID_AMOUNT_TO_SEND_DELEGATE();\\n\\n // Decrement the total amount being added to the balance.\\n _balanceDiff = _balanceDiff - _delegatedAmount;\\n }\\n\\n unchecked {\\n ++_i;\\n }\\n }\\n }\\n\\n // If there's no amount being recorded, there's nothing left to do.\\n if (_amount.value == 0) return (fundingCycle, 0, delegateAllocations, memo);\\n\\n // Add the correct balance difference to the token balance of the project.\\n if (_balanceDiff != 0)\\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] +\\n _balanceDiff;\\n }\\n\\n // If there's no weight, token count must be 0 so there's nothing left to do.\\n if (_weight == 0) return (fundingCycle, 0, delegateAllocations, memo);\\n\\n // Get a reference to the number of decimals in the amount. (prevents stack too deep).\\n uint256 _decimals = _amount.decimals;\\n\\n // If the terminal should base its weight on a different currency from the terminal's currency, determine the factor.\\n // The weight is always a fixed point mumber with 18 decimals. To ensure this, the ratio should use the same number of decimals as the `_amount`.\\n uint256 _weightRatio = _amount.currency == _baseWeightCurrency\\n ? 10 ** _decimals\\n : prices.priceFor(_amount.currency, _baseWeightCurrency, _decimals);\\n\\n // Find the number of tokens to mint, as a fixed point number with as many decimals as `weight` has.\\n tokenCount = PRBMath.mulDiv(_amount.value, _weight, _weightRatio);\\n }\\n\\n /// @notice Records newly redeemed tokens of a project.\\n /// @dev Redeems the project's tokens according to values provided by a configured data source. If no data source is configured, redeems tokens along a redemption bonding curve that is a function of the number of tokens being burned.\\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.senders tokens.\\n /// @param _holder The account that is having its tokens redeemed.\\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\\n /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals.\\n /// @param _memo A memo to pass along to the emitted event.\\n /// @param _metadata Bytes to send along to the data source, if one is provided.\\n /// @return fundingCycle The funding cycle during which the redemption was made.\\n /// @return reclaimAmount The amount of terminal tokens reclaimed, as a fixed point number with 18 decimals.\\n /// @return delegateAllocations The amount to send to delegates instead of sending to the beneficiary.\\n /// @return memo A memo that should be passed along to the emitted event.\\n function recordRedemptionFor(\\n address _holder,\\n uint256 _projectId,\\n uint256 _tokenCount,\\n string memory _memo,\\n bytes memory _metadata\\n )\\n external\\n override\\n nonReentrant\\n returns (\\n JBFundingCycle memory fundingCycle,\\n uint256 reclaimAmount,\\n JBRedemptionDelegateAllocation3_1_1[] memory delegateAllocations,\\n string memory memo\\n )\\n {\\n // Get a reference to the project's current funding cycle.\\n fundingCycle = fundingCycleStore.currentOf(_projectId);\\n\\n // The current funding cycle must not be paused.\\n if (fundingCycle.redeemPaused()) revert FUNDING_CYCLE_REDEEM_PAUSED();\\n\\n // Scoped section prevents stack too deep. `_reclaimedTokenAmount`, `_currentOverflow`, and `_totalSupply` only used within scope.\\n {\\n // Get a reference to the reclaimed token amount struct, the current overflow, and the total token supply.\\n JBTokenAmount memory _reclaimedTokenAmount;\\n uint256 _currentOverflow;\\n uint256 _totalSupply;\\n\\n // Another scoped section prevents stack too deep. `_token`, `_decimals`, and `_currency` only used within scope.\\n {\\n // Get a reference to the terminal's tokens.\\n address _token = IJBSingleTokenPaymentTerminal(msg.sender).token();\\n\\n // Get a reference to the terminal's decimals.\\n uint256 _decimals = IJBSingleTokenPaymentTerminal(msg.sender).decimals();\\n\\n // Get areference to the terminal's currency.\\n uint256 _currency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\\n\\n // Get the amount of current overflow.\\n // Use the local overflow if the funding cycle specifies that it should be used. Otherwise, use the project's total overflow across all of its terminals.\\n _currentOverflow = fundingCycle.useTotalOverflowForRedemptions()\\n ? _currentTotalOverflowOf(_projectId, _decimals, _currency)\\n : _overflowDuring(\\n IJBSingleTokenPaymentTerminal(msg.sender),\\n _projectId,\\n fundingCycle,\\n _currency\\n );\\n\\n // Get the number of outstanding tokens the project has.\\n _totalSupply = IJBController3_1(directory.controllerOf(_projectId))\\n .totalOutstandingTokensOf(_projectId);\\n\\n // Can't redeem more tokens that is in the supply.\\n if (_tokenCount > _totalSupply) revert INSUFFICIENT_TOKENS();\\n\\n if (_currentOverflow != 0)\\n // Calculate reclaim amount using the current overflow amount.\\n reclaimAmount = _reclaimableOverflowDuring(\\n _projectId,\\n fundingCycle,\\n _tokenCount,\\n _totalSupply,\\n _currentOverflow\\n );\\n\\n _reclaimedTokenAmount = JBTokenAmount(_token, reclaimAmount, _decimals, _currency);\\n }\\n\\n // If the funding cycle has configured a data source, use it to derive a claim amount and memo.\\n if (fundingCycle.useDataSourceForRedeem() && fundingCycle.dataSource() != address(0)) {\\n // Yet another scoped section prevents stack too deep. `_state` only used within scope.\\n {\\n // Get a reference to the ballot state.\\n JBBallotState _state = fundingCycleStore.currentBallotStateOf(_projectId);\\n\\n // Create the params that'll be sent to the data source.\\n JBRedeemParamsData memory _data = JBRedeemParamsData(\\n IJBSingleTokenPaymentTerminal(msg.sender),\\n _holder,\\n _projectId,\\n fundingCycle.configuration,\\n _tokenCount,\\n _totalSupply,\\n _currentOverflow,\\n _reclaimedTokenAmount,\\n fundingCycle.useTotalOverflowForRedemptions(),\\n _state == JBBallotState.Active\\n ? fundingCycle.ballotRedemptionRate()\\n : fundingCycle.redemptionRate(),\\n _memo,\\n _metadata\\n );\\n (reclaimAmount, memo, delegateAllocations) = IJBFundingCycleDataSource3_1_1(\\n fundingCycle.dataSource()\\n ).redeemParams(_data);\\n }\\n } else {\\n memo = _memo;\\n }\\n }\\n\\n // Keep a reference to the amount that should be subtracted from the project's balance.\\n uint256 _balanceDiff = reclaimAmount;\\n\\n if (delegateAllocations.length != 0) {\\n // Validate all delegated amounts.\\n for (uint256 _i; _i < delegateAllocations.length; ) {\\n // Get a reference to the amount to be delegated.\\n uint256 _delegatedAmount = delegateAllocations[_i].amount;\\n\\n // Validate if non-zero.\\n if (_delegatedAmount != 0)\\n // Increment the total amount being subtracted from the balance.\\n _balanceDiff = _balanceDiff + _delegatedAmount;\\n\\n unchecked {\\n ++_i;\\n }\\n }\\n }\\n\\n // The amount being reclaimed must be within the project's balance.\\n if (_balanceDiff > balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId])\\n revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\\n\\n // Remove the reclaimed funds from the project's balance.\\n if (_balanceDiff != 0) {\\n unchecked {\\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\\n _balanceDiff;\\n }\\n }\\n }\\n\\n /// @notice Records newly distributed funds for a project.\\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\\n /// @param _projectId The ID of the project that is having funds distributed.\\n /// @param _amount The amount to use from the distribution limit, as a fixed point number.\\n /// @param _currency The currency of the `_amount`. This must match the project's current funding cycle's currency.\\n /// @return fundingCycle The funding cycle during which the distribution was made.\\n /// @return distributedAmount The amount of terminal tokens distributed, as a fixed point number with the same amount of decimals as its relative terminal.\\n function recordDistributionFor(\\n uint256 _projectId,\\n uint256 _amount,\\n uint256 _currency\\n )\\n external\\n override\\n nonReentrant\\n returns (JBFundingCycle memory fundingCycle, uint256 distributedAmount)\\n {\\n // Get a reference to the project's current funding cycle.\\n fundingCycle = fundingCycleStore.currentOf(_projectId);\\n\\n // The funding cycle must not be configured to have distributions paused.\\n if (fundingCycle.distributionsPaused()) revert FUNDING_CYCLE_DISTRIBUTION_PAUSED();\\n\\n // The new total amount that has been distributed during this funding cycle.\\n uint256 _newUsedDistributionLimitOf = usedDistributionLimitOf[\\n IJBSingleTokenPaymentTerminal(msg.sender)\\n ][_projectId][fundingCycle.number] + _amount;\\n\\n // Amount must be within what is still distributable.\\n (uint256 _distributionLimitOf, uint256 _distributionLimitCurrencyOf) = IJBController3_1(\\n directory.controllerOf(_projectId)\\n ).fundAccessConstraintsStore().distributionLimitOf(\\n _projectId,\\n fundingCycle.configuration,\\n IJBSingleTokenPaymentTerminal(msg.sender),\\n IJBSingleTokenPaymentTerminal(msg.sender).token()\\n );\\n\\n // Make sure the new used amount is within the distribution limit.\\n if (_newUsedDistributionLimitOf > _distributionLimitOf || _distributionLimitOf == 0)\\n revert DISTRIBUTION_AMOUNT_LIMIT_REACHED();\\n\\n // Make sure the currencies match.\\n if (_currency != _distributionLimitCurrencyOf) revert CURRENCY_MISMATCH();\\n\\n // Get a reference to the terminal's currency.\\n uint256 _balanceCurrency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\\n\\n // Convert the amount to the balance's currency.\\n distributedAmount = (_currency == _balanceCurrency)\\n ? _amount\\n : PRBMath.mulDiv(\\n _amount,\\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\\n prices.priceFor(_currency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\\n );\\n\\n // The amount being distributed must be available.\\n if (distributedAmount > balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId])\\n revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\\n\\n // Store the new amount.\\n usedDistributionLimitOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId][\\n fundingCycle.number\\n ] = _newUsedDistributionLimitOf;\\n\\n // Removed the distributed funds from the project's token balance.\\n unchecked {\\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\\n distributedAmount;\\n }\\n }\\n\\n /// @notice Records newly used allowance funds of a project.\\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\\n /// @param _projectId The ID of the project to use the allowance of.\\n /// @param _amount The amount to use from the allowance, as a fixed point number.\\n /// @param _currency The currency of the `_amount`. Must match the currency of the overflow allowance.\\n /// @return fundingCycle The funding cycle during which the overflow allowance is being used.\\n /// @return usedAmount The amount of terminal tokens used, as a fixed point number with the same amount of decimals as its relative terminal.\\n function recordUsedAllowanceOf(\\n uint256 _projectId,\\n uint256 _amount,\\n uint256 _currency\\n )\\n external\\n override\\n nonReentrant\\n returns (JBFundingCycle memory fundingCycle, uint256 usedAmount)\\n {\\n // Get a reference to the project's current funding cycle.\\n fundingCycle = fundingCycleStore.currentOf(_projectId);\\n\\n // Get a reference to the new used overflow allowance for this funding cycle configuration.\\n uint256 _newUsedOverflowAllowanceOf = usedOverflowAllowanceOf[\\n IJBSingleTokenPaymentTerminal(msg.sender)\\n ][_projectId][fundingCycle.configuration] + _amount;\\n\\n // There must be sufficient allowance available.\\n (uint256 _overflowAllowanceOf, uint256 _overflowAllowanceCurrency) = IJBController3_1(\\n directory.controllerOf(_projectId)\\n ).fundAccessConstraintsStore().overflowAllowanceOf(\\n _projectId,\\n fundingCycle.configuration,\\n IJBSingleTokenPaymentTerminal(msg.sender),\\n IJBSingleTokenPaymentTerminal(msg.sender).token()\\n );\\n\\n // Make sure the new used amount is within the allowance.\\n if (_newUsedOverflowAllowanceOf > _overflowAllowanceOf || _overflowAllowanceOf == 0)\\n revert INADEQUATE_CONTROLLER_ALLOWANCE();\\n\\n // Make sure the currencies match.\\n if (_currency != _overflowAllowanceCurrency) revert CURRENCY_MISMATCH();\\n\\n // Get a reference to the terminal's currency.\\n uint256 _balanceCurrency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\\n\\n // Convert the amount to this store's terminal's token.\\n usedAmount = (_currency == _balanceCurrency)\\n ? _amount\\n : PRBMath.mulDiv(\\n _amount,\\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\\n prices.priceFor(_currency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\\n );\\n\\n // The amount being distributed must be available in the overflow.\\n if (\\n usedAmount >\\n _overflowDuring(\\n IJBSingleTokenPaymentTerminal(msg.sender),\\n _projectId,\\n fundingCycle,\\n _balanceCurrency\\n )\\n ) revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\\n\\n // Store the incremented value.\\n usedOverflowAllowanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId][\\n fundingCycle.configuration\\n ] = _newUsedOverflowAllowanceOf;\\n\\n // Update the project's balance.\\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\\n usedAmount;\\n }\\n\\n /// @notice Records newly added funds for the project.\\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\\n /// @param _projectId The ID of the project to which the funds being added belong.\\n /// @param _amount The amount of terminal tokens added, as a fixed point number with the same amount of decimals as its relative terminal.\\n function recordAddedBalanceFor(uint256 _projectId, uint256 _amount) external override {\\n // Increment the balance.\\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] +\\n _amount;\\n }\\n\\n /// @notice Records the migration of funds from this store.\\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount returned is in terms of the msg.senders tokens.\\n /// @param _projectId The ID of the project being migrated.\\n /// @return balance The project's migrated balance, as a fixed point number with the same amount of decimals as its relative terminal.\\n function recordMigration(\\n uint256 _projectId\\n ) external override nonReentrant returns (uint256 balance) {\\n // Get a reference to the project's current funding cycle.\\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\\n\\n // Migration must be allowed.\\n if (!_fundingCycle.terminalMigrationAllowed()) revert PAYMENT_TERMINAL_MIGRATION_NOT_ALLOWED();\\n\\n // Return the current balance.\\n balance = balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId];\\n\\n // Set the balance to 0.\\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] = 0;\\n }\\n\\n //*********************************************************************//\\n // --------------------- private helper functions -------------------- //\\n //*********************************************************************//\\n\\n /// @notice The amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens when measured from the specified.\\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\\n /// @param _projectId The ID of the project to get the reclaimable overflow amount for.\\n /// @param _fundingCycle The funding cycle during which reclaimable overflow is being calculated.\\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\\n /// @param _totalSupply The total supply of tokens to make the calculation with, as a fixed point number with 18 decimals.\\n /// @param _overflow The amount of overflow to make the calculation with.\\n /// @return The amount of overflowed tokens that can be reclaimed.\\n function _reclaimableOverflowDuring(\\n uint256 _projectId,\\n JBFundingCycle memory _fundingCycle,\\n uint256 _tokenCount,\\n uint256 _totalSupply,\\n uint256 _overflow\\n ) private view returns (uint256) {\\n // If the amount being redeemed is the total supply, return the rest of the overflow.\\n if (_tokenCount == _totalSupply) return _overflow;\\n\\n // Use the ballot redemption rate if the queued cycle is pending approval according to the previous funding cycle's ballot.\\n uint256 _redemptionRate = fundingCycleStore.currentBallotStateOf(_projectId) ==\\n JBBallotState.Active\\n ? _fundingCycle.ballotRedemptionRate()\\n : _fundingCycle.redemptionRate();\\n\\n // If the redemption rate is 0, nothing is claimable.\\n if (_redemptionRate == 0) return 0;\\n\\n // Get a reference to the linear proportion.\\n uint256 _base = PRBMath.mulDiv(_overflow, _tokenCount, _totalSupply);\\n\\n // These conditions are all part of the same curve. Edge conditions are separated because fewer operation are necessary.\\n if (_redemptionRate == JBConstants.MAX_REDEMPTION_RATE) return _base;\\n\\n return\\n PRBMath.mulDiv(\\n _base,\\n _redemptionRate +\\n PRBMath.mulDiv(\\n _tokenCount,\\n JBConstants.MAX_REDEMPTION_RATE - _redemptionRate,\\n _totalSupply\\n ),\\n JBConstants.MAX_REDEMPTION_RATE\\n );\\n }\\n\\n /// @notice Gets the amount that is overflowing when measured from the specified funding cycle.\\n /// @dev This amount changes as the value of the balance changes in relation to the currency being used to measure the distribution limit.\\n /// @param _terminal The terminal for which the overflow is being calculated.\\n /// @param _projectId The ID of the project to get overflow for.\\n /// @param _fundingCycle The ID of the funding cycle to base the overflow on.\\n /// @param _balanceCurrency The currency that the stored balance is expected to be in terms of.\\n /// @return overflow The overflow of funds, as a fixed point number with 18 decimals.\\n function _overflowDuring(\\n IJBSingleTokenPaymentTerminal _terminal,\\n uint256 _projectId,\\n JBFundingCycle memory _fundingCycle,\\n uint256 _balanceCurrency\\n ) private view returns (uint256) {\\n // Get the current balance of the project.\\n uint256 _balanceOf = balanceOf[_terminal][_projectId];\\n\\n // If there's no balance, there's no overflow.\\n if (_balanceOf == 0) return 0;\\n\\n // Get a reference to the distribution limit during the funding cycle.\\n (uint256 _distributionLimit, uint256 _distributionLimitCurrency) = IJBController3_1(\\n directory.controllerOf(_projectId)\\n ).fundAccessConstraintsStore().distributionLimitOf(\\n _projectId,\\n _fundingCycle.configuration,\\n _terminal,\\n _terminal.token()\\n );\\n\\n // Get a reference to the amount still distributable during the funding cycle.\\n uint256 _distributionLimitRemaining = _distributionLimit -\\n usedDistributionLimitOf[_terminal][_projectId][_fundingCycle.number];\\n\\n // Convert the _distributionRemaining to be in terms of the provided currency.\\n if (_distributionLimitRemaining != 0 && _distributionLimitCurrency != _balanceCurrency)\\n _distributionLimitRemaining = PRBMath.mulDiv(\\n _distributionLimitRemaining,\\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\\n prices.priceFor(_distributionLimitCurrency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\\n );\\n\\n // Overflow is the balance of this project minus the amount that can still be distributed.\\n unchecked {\\n return\\n _balanceOf > _distributionLimitRemaining ? _balanceOf - _distributionLimitRemaining : 0;\\n }\\n }\\n\\n /// @notice Gets the amount that is currently overflowing across all of a project's terminals.\\n /// @dev This amount changes as the value of the balances changes in relation to the currency being used to measure the project's distribution limits.\\n /// @param _projectId The ID of the project to get the total overflow for.\\n /// @param _decimals The number of decimals that the fixed point overflow should include.\\n /// @param _currency The currency that the overflow should be in terms of.\\n /// @return overflow The total overflow of a project's funds.\\n function _currentTotalOverflowOf(\\n uint256 _projectId,\\n uint256 _decimals,\\n uint256 _currency\\n ) private view returns (uint256) {\\n // Get a reference to the project's terminals.\\n IJBPaymentTerminal[] memory _terminals = directory.terminalsOf(_projectId);\\n\\n // Keep a reference to the ETH overflow across all terminals, as a fixed point number with 18 decimals.\\n uint256 _ethOverflow;\\n\\n // Add the current ETH overflow for each terminal.\\n for (uint256 _i; _i < _terminals.length; ) {\\n _ethOverflow = _ethOverflow + _terminals[_i].currentEthOverflowOf(_projectId);\\n unchecked {\\n ++_i;\\n }\\n }\\n\\n // Convert the ETH overflow to the specified currency if needed, maintaining a fixed point number with 18 decimals.\\n uint256 _totalOverflow18Decimal = _currency == JBCurrencies.ETH\\n ? _ethOverflow\\n : PRBMath.mulDiv(_ethOverflow, 10 ** 18, prices.priceFor(JBCurrencies.ETH, _currency, 18));\\n\\n // Adjust the decimals of the fixed point number if needed to match the target decimals.\\n return\\n (_decimals == 18)\\n ? _totalOverflow18Decimal\\n : JBFixedPointNumber.adjustDecimals(_totalOverflow18Decimal, 18, _decimals);\\n }\\n}\\n\",\"keccak256\":\"0xb0cde3ddcf06733537717094bb426d8817812ade5f5f594da1b3cc54cbfe9263\",\"license\":\"MIT\"},\"contracts/enums/JBBallotState.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nenum JBBallotState {\\n Active,\\n Approved,\\n Failed\\n}\\n\",\"keccak256\":\"0x891fcac63470398b3a11239da7feba6b07d640809fcefd2404303b823d7378f8\",\"license\":\"MIT\"},\"contracts/interfaces/IJBController3_0_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IJBController3_0_1 {\\n function reservedTokenBalanceOf(uint256 projectId) external view returns (uint256);\\n\\n function totalOutstandingTokensOf(uint256 projectId) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0xf64926bf7ab5850ea9b7ec27d92a021f02344a3fadb0396af80966ad08b3dd2b\",\"license\":\"MIT\"},\"contracts/interfaces/IJBController3_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\\nimport {JBBallotState} from './../enums/JBBallotState.sol';\\nimport {JBFundAccessConstraints} from './../structs/JBFundAccessConstraints.sol';\\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\\nimport {JBFundingCycleData} from './../structs/JBFundingCycleData.sol';\\nimport {JBFundingCycleMetadata} from './../structs/JBFundingCycleMetadata.sol';\\nimport {JBGroupedSplits} from './../structs/JBGroupedSplits.sol';\\nimport {JBProjectMetadata} from './../structs/JBProjectMetadata.sol';\\nimport {JBSplit} from './../structs/JBSplit.sol';\\nimport {IJBController3_0_1} from './IJBController3_0_1.sol';\\nimport {IJBDirectory} from './IJBDirectory.sol';\\nimport {IJBFundAccessConstraintsStore} from './IJBFundAccessConstraintsStore.sol';\\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\\nimport {IJBMigratable} from './IJBMigratable.sol';\\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\\nimport {IJBProjects} from './IJBProjects.sol';\\nimport {IJBSplitsStore} from './IJBSplitsStore.sol';\\nimport {IJBTokenStore} from './IJBTokenStore.sol';\\n\\ninterface IJBController3_1 is IJBController3_0_1, IERC165 {\\n event LaunchProject(uint256 configuration, uint256 projectId, string memo, address caller);\\n\\n event LaunchFundingCycles(uint256 configuration, uint256 projectId, string memo, address caller);\\n\\n event ReconfigureFundingCycles(\\n uint256 configuration,\\n uint256 projectId,\\n string memo,\\n address caller\\n );\\n\\n event DistributeReservedTokens(\\n uint256 indexed fundingCycleConfiguration,\\n uint256 indexed fundingCycleNumber,\\n uint256 indexed projectId,\\n address beneficiary,\\n uint256 tokenCount,\\n uint256 beneficiaryTokenCount,\\n string memo,\\n address caller\\n );\\n\\n event DistributeToReservedTokenSplit(\\n uint256 indexed projectId,\\n uint256 indexed domain,\\n uint256 indexed group,\\n JBSplit split,\\n uint256 tokenCount,\\n address caller\\n );\\n\\n event MintTokens(\\n address indexed beneficiary,\\n uint256 indexed projectId,\\n uint256 tokenCount,\\n uint256 beneficiaryTokenCount,\\n string memo,\\n uint256 reservedRate,\\n address caller\\n );\\n\\n event BurnTokens(\\n address indexed holder,\\n uint256 indexed projectId,\\n uint256 tokenCount,\\n string memo,\\n address caller\\n );\\n\\n event Migrate(uint256 indexed projectId, IJBMigratable to, address caller);\\n\\n event PrepMigration(uint256 indexed projectId, address from, address caller);\\n\\n function projects() external view returns (IJBProjects);\\n\\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\\n\\n function tokenStore() external view returns (IJBTokenStore);\\n\\n function splitsStore() external view returns (IJBSplitsStore);\\n\\n function fundAccessConstraintsStore() external view returns (IJBFundAccessConstraintsStore);\\n\\n function directory() external view returns (IJBDirectory);\\n\\n function reservedTokenBalanceOf(uint256 projectId) external view returns (uint256);\\n\\n function totalOutstandingTokensOf(uint256 projectId) external view returns (uint256);\\n\\n function getFundingCycleOf(\\n uint256 projectId,\\n uint256 configuration\\n )\\n external\\n view\\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata);\\n\\n function latestConfiguredFundingCycleOf(\\n uint256 projectId\\n )\\n external\\n view\\n returns (JBFundingCycle memory, JBFundingCycleMetadata memory metadata, JBBallotState);\\n\\n function currentFundingCycleOf(\\n uint256 projectId\\n )\\n external\\n view\\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata);\\n\\n function queuedFundingCycleOf(\\n uint256 projectId\\n )\\n external\\n view\\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata);\\n\\n function launchProjectFor(\\n address owner,\\n JBProjectMetadata calldata projectMetadata,\\n JBFundingCycleData calldata data,\\n JBFundingCycleMetadata calldata metadata,\\n uint256 mustStartAtOrAfter,\\n JBGroupedSplits[] memory groupedSplits,\\n JBFundAccessConstraints[] memory fundAccessConstraints,\\n IJBPaymentTerminal[] memory terminals,\\n string calldata memo\\n ) external returns (uint256 projectId);\\n\\n function launchFundingCyclesFor(\\n uint256 projectId,\\n JBFundingCycleData calldata data,\\n JBFundingCycleMetadata calldata metadata,\\n uint256 mustStartAtOrAfter,\\n JBGroupedSplits[] memory groupedSplits,\\n JBFundAccessConstraints[] memory fundAccessConstraints,\\n IJBPaymentTerminal[] memory terminals,\\n string calldata memo\\n ) external returns (uint256 configuration);\\n\\n function reconfigureFundingCyclesOf(\\n uint256 projectId,\\n JBFundingCycleData calldata data,\\n JBFundingCycleMetadata calldata metadata,\\n uint256 mustStartAtOrAfter,\\n JBGroupedSplits[] memory groupedSplits,\\n JBFundAccessConstraints[] memory fundAccessConstraints,\\n string calldata memo\\n ) external returns (uint256);\\n\\n function mintTokensOf(\\n uint256 projectId,\\n uint256 tokenCount,\\n address beneficiary,\\n string calldata memo,\\n bool preferClaimedTokens,\\n bool useReservedRate\\n ) external returns (uint256 beneficiaryTokenCount);\\n\\n function burnTokensOf(\\n address holder,\\n uint256 projectId,\\n uint256 tokenCount,\\n string calldata memo,\\n bool preferClaimedTokens\\n ) external;\\n\\n function distributeReservedTokensOf(\\n uint256 projectId,\\n string memory memo\\n ) external returns (uint256);\\n\\n function migrate(uint256 projectId, IJBMigratable to) external;\\n}\\n\",\"keccak256\":\"0xe09f3d0d670a40e5d66d3fddc8a63f51b8ccb24175ffbb703ba95496deb85bdb\",\"license\":\"MIT\"},\"contracts/interfaces/IJBDirectory.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\\nimport {IJBProjects} from './IJBProjects.sol';\\n\\ninterface IJBDirectory {\\n event SetController(uint256 indexed projectId, address indexed controller, address caller);\\n\\n event AddTerminal(uint256 indexed projectId, IJBPaymentTerminal indexed terminal, address caller);\\n\\n event SetTerminals(uint256 indexed projectId, IJBPaymentTerminal[] terminals, address caller);\\n\\n event SetPrimaryTerminal(\\n uint256 indexed projectId,\\n address indexed token,\\n IJBPaymentTerminal indexed terminal,\\n address caller\\n );\\n\\n event SetIsAllowedToSetFirstController(address indexed addr, bool indexed flag, address caller);\\n\\n function projects() external view returns (IJBProjects);\\n\\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\\n\\n function controllerOf(uint256 projectId) external view returns (address);\\n\\n function isAllowedToSetFirstController(address account) external view returns (bool);\\n\\n function terminalsOf(uint256 projectId) external view returns (IJBPaymentTerminal[] memory);\\n\\n function isTerminalOf(\\n uint256 projectId,\\n IJBPaymentTerminal terminal\\n ) external view returns (bool);\\n\\n function primaryTerminalOf(\\n uint256 projectId,\\n address token\\n ) external view returns (IJBPaymentTerminal);\\n\\n function setControllerOf(uint256 projectId, address controller) external;\\n\\n function setTerminalsOf(uint256 projectId, IJBPaymentTerminal[] calldata terminals) external;\\n\\n function setPrimaryTerminalOf(\\n uint256 projectId,\\n address token,\\n IJBPaymentTerminal terminal\\n ) external;\\n\\n function setIsAllowedToSetFirstController(address account, bool flag) external;\\n}\\n\",\"keccak256\":\"0x490d5fe691ee7d9c9179fa19964de279882176513d92f3efc0aa98dc34799d1c\",\"license\":\"MIT\"},\"contracts/interfaces/IJBFundAccessConstraintsStore.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\\nimport {JBFundAccessConstraints} from './../structs/JBFundAccessConstraints.sol';\\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\\n\\ninterface IJBFundAccessConstraintsStore is IERC165 {\\n event SetFundAccessConstraints(\\n uint256 indexed fundingCycleConfiguration,\\n uint256 indexed projectId,\\n JBFundAccessConstraints constraints,\\n address caller\\n );\\n\\n function distributionLimitOf(\\n uint256 projectId,\\n uint256 configuration,\\n IJBPaymentTerminal terminal,\\n address token\\n ) external view returns (uint256 distributionLimit, uint256 distributionLimitCurrency);\\n\\n function overflowAllowanceOf(\\n uint256 projectId,\\n uint256 configuration,\\n IJBPaymentTerminal terminal,\\n address token\\n ) external view returns (uint256 overflowAllowance, uint256 overflowAllowanceCurrency);\\n\\n function setFor(\\n uint256 projectId,\\n uint256 configuration,\\n JBFundAccessConstraints[] memory fundAccessConstaints\\n ) external;\\n}\\n\",\"keccak256\":\"0x82e3daec501e6f4d27ad7b9ab67f449e3cd4ef83a75062cd8b6fbffc17ae634d\",\"license\":\"MIT\"},\"contracts/interfaces/IJBFundingCycleBallot.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\\nimport {JBBallotState} from './../enums/JBBallotState.sol';\\n\\ninterface IJBFundingCycleBallot is IERC165 {\\n function duration() external view returns (uint256);\\n\\n function stateOf(\\n uint256 projectId,\\n uint256 configuration,\\n uint256 start\\n ) external view returns (JBBallotState);\\n}\\n\",\"keccak256\":\"0x729b4a700618f890e434d31ef9252e1cce9d0473fe7f8f070872df5b348bed23\",\"license\":\"MIT\"},\"contracts/interfaces/IJBFundingCycleDataSource3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\\nimport {JBPayDelegateAllocation3_1_1} from './../structs/JBPayDelegateAllocation3_1_1.sol';\\nimport {JBPayParamsData} from './../structs/JBPayParamsData.sol';\\nimport {JBRedeemParamsData} from './../structs/JBRedeemParamsData.sol';\\nimport {JBRedemptionDelegateAllocation3_1_1} from './../structs/JBRedemptionDelegateAllocation3_1_1.sol';\\n\\n/// @title Datasource\\n/// @notice The datasource is called by JBPayoutRedemptionPaymentTerminals on pay and redemption, and provide an extra layer of logic to use a custom weight, a custom memo and/or a pay/redeem delegate\\ninterface IJBFundingCycleDataSource3_1_1 is IERC165 {\\n /// @notice The datasource implementation for JBPaymentTerminal.pay(..)\\n /// @param data the data passed to the data source in terminal.pay(..), as a JBPayParamsData struct:\\n /// @return weight the weight to use to override the funding cycle weight\\n /// @return memo the memo to override the pay(..) memo\\n /// @return delegateAllocations The amount to send to delegates instead of adding to the local balance.\\n function payParams(\\n JBPayParamsData calldata data\\n )\\n external\\n returns (\\n uint256 weight,\\n string memory memo,\\n JBPayDelegateAllocation3_1_1[] memory delegateAllocations\\n );\\n\\n /// @notice The datasource implementation for JBPaymentTerminal.redeemTokensOf(..)\\n /// @param data the data passed to the data source in terminal.redeemTokensOf(..), as a JBRedeemParamsData struct:\\n /// @return reclaimAmount The amount to claim, overriding the terminal logic.\\n /// @return memo The memo to override the redeemTokensOf(..) memo.\\n /// @return delegateAllocations The amount to send to delegates instead of adding to the beneficiary.\\n function redeemParams(\\n JBRedeemParamsData calldata data\\n )\\n external\\n returns (\\n uint256 reclaimAmount,\\n string memory memo,\\n JBRedemptionDelegateAllocation3_1_1[] memory delegateAllocations\\n );\\n}\\n\",\"keccak256\":\"0x7315c10ae1fc6c401704ac3dec2a4c3e60ab4ac3ae051bea581d7db2ded38f34\",\"license\":\"MIT\"},\"contracts/interfaces/IJBFundingCycleStore.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBBallotState} from './../enums/JBBallotState.sol';\\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\\nimport {JBFundingCycleData} from './../structs/JBFundingCycleData.sol';\\n\\ninterface IJBFundingCycleStore {\\n event Configure(\\n uint256 indexed configuration,\\n uint256 indexed projectId,\\n JBFundingCycleData data,\\n uint256 metadata,\\n uint256 mustStartAtOrAfter,\\n address caller\\n );\\n\\n event Init(uint256 indexed configuration, uint256 indexed projectId, uint256 indexed basedOn);\\n\\n function latestConfigurationOf(uint256 projectId) external view returns (uint256);\\n\\n function get(\\n uint256 projectId,\\n uint256 configuration\\n ) external view returns (JBFundingCycle memory);\\n\\n function latestConfiguredOf(\\n uint256 projectId\\n ) external view returns (JBFundingCycle memory fundingCycle, JBBallotState ballotState);\\n\\n function queuedOf(uint256 projectId) external view returns (JBFundingCycle memory fundingCycle);\\n\\n function currentOf(uint256 projectId) external view returns (JBFundingCycle memory fundingCycle);\\n\\n function currentBallotStateOf(uint256 projectId) external view returns (JBBallotState);\\n\\n function configureFor(\\n uint256 projectId,\\n JBFundingCycleData calldata data,\\n uint256 metadata,\\n uint256 mustStartAtOrAfter\\n ) external returns (JBFundingCycle memory fundingCycle);\\n}\\n\",\"keccak256\":\"0x524350f6c6fcb45eaf927f4e6d13cd2f5029c2b858233bb9a338fe411ce34dab\",\"license\":\"MIT\"},\"contracts/interfaces/IJBMigratable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IJBMigratable {\\n function prepForMigrationOf(uint256 projectId, address from) external;\\n}\\n\",\"keccak256\":\"0xdee578477bbb7a66e9a1735e45a7795e95cfd374d85f55b61b3302476844c418\",\"license\":\"MIT\"},\"contracts/interfaces/IJBPayDelegate3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\\nimport {JBDidPayData3_1_1} from './../structs/JBDidPayData3_1_1.sol';\\n\\n/// @title Pay delegate\\n/// @notice Delegate called after JBTerminal.pay(..) logic completion (if passed by the funding cycle datasource)\\ninterface IJBPayDelegate3_1_1 is IERC165 {\\n /// @notice This function is called by JBPaymentTerminal.pay(..), after the execution of its logic\\n /// @dev Critical business logic should be protected by an appropriate access control\\n /// @param data the data passed by the terminal, as a JBDidPayData3_1_1 struct:\\n function didPay(JBDidPayData3_1_1 calldata data) external payable;\\n}\\n\",\"keccak256\":\"0x9448d24cd9c559b44c468c6a76d850f6eaadf31446db903092a2f32503a67294\",\"license\":\"MIT\"},\"contracts/interfaces/IJBPaymentTerminal.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\\n\\ninterface IJBPaymentTerminal is IERC165 {\\n function acceptsToken(address token, uint256 projectId) external view returns (bool);\\n\\n function currencyForToken(address token) external view returns (uint256);\\n\\n function decimalsForToken(address token) external view returns (uint256);\\n\\n // Return value must be a fixed point number with 18 decimals.\\n function currentEthOverflowOf(uint256 projectId) external view returns (uint256);\\n\\n function pay(\\n uint256 projectId,\\n uint256 amount,\\n address token,\\n address beneficiary,\\n uint256 minReturnedTokens,\\n bool preferClaimedTokens,\\n string calldata memo,\\n bytes calldata metadata\\n ) external payable returns (uint256 beneficiaryTokenCount);\\n\\n function addToBalanceOf(\\n uint256 projectId,\\n uint256 amount,\\n address token,\\n string calldata memo,\\n bytes calldata metadata\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x273bc1fa373fac08e5635fce7d38fd92e9fabba353568b3f7a5be54c01fe4d27\",\"license\":\"MIT\"},\"contracts/interfaces/IJBPriceFeed.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IJBPriceFeed {\\n function currentPrice(uint256 targetDecimals) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0x9328b2b52bc112641f3a6167c8cf242831a52c85016ce1310626bdc3489bded7\",\"license\":\"MIT\"},\"contracts/interfaces/IJBPrices.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBPriceFeed} from './IJBPriceFeed.sol';\\n\\ninterface IJBPrices {\\n event AddFeed(uint256 indexed currency, uint256 indexed base, IJBPriceFeed feed);\\n\\n function feedFor(uint256 currency, uint256 base) external view returns (IJBPriceFeed);\\n\\n function priceFor(\\n uint256 currency,\\n uint256 base,\\n uint256 decimals\\n ) external view returns (uint256);\\n\\n function addFeedFor(uint256 currency, uint256 base, IJBPriceFeed priceFeed) external;\\n}\\n\",\"keccak256\":\"0xc1623499fa541b15891e27a59288e03360ce78c7933d28bf575b48b68ce4981c\",\"license\":\"MIT\"},\"contracts/interfaces/IJBProjects.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC721} from '@openzeppelin/contracts/token/ERC721/IERC721.sol';\\nimport {JBProjectMetadata} from './../structs/JBProjectMetadata.sol';\\nimport {IJBTokenUriResolver} from './IJBTokenUriResolver.sol';\\n\\ninterface IJBProjects is IERC721 {\\n event Create(\\n uint256 indexed projectId,\\n address indexed owner,\\n JBProjectMetadata metadata,\\n address caller\\n );\\n\\n event SetMetadata(uint256 indexed projectId, JBProjectMetadata metadata, address caller);\\n\\n event SetTokenUriResolver(IJBTokenUriResolver indexed resolver, address caller);\\n\\n function count() external view returns (uint256);\\n\\n function metadataContentOf(\\n uint256 projectId,\\n uint256 domain\\n ) external view returns (string memory);\\n\\n function tokenUriResolver() external view returns (IJBTokenUriResolver);\\n\\n function createFor(\\n address owner,\\n JBProjectMetadata calldata metadata\\n ) external returns (uint256 projectId);\\n\\n function setMetadataOf(uint256 projectId, JBProjectMetadata calldata metadata) external;\\n\\n function setTokenUriResolver(IJBTokenUriResolver newResolver) external;\\n}\\n\",\"keccak256\":\"0x00235f20975e6a9465ac921076c85125a3834e29893f93f93e287a89f9e6b915\",\"license\":\"MIT\"},\"contracts/interfaces/IJBRedemptionDelegate3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\\nimport {JBDidRedeemData3_1_1} from './../structs/JBDidRedeemData3_1_1.sol';\\n\\n/// @title Redemption delegate\\n/// @notice Delegate called after JBTerminal.redeemTokensOf(..) logic completion (if passed by the funding cycle datasource)\\ninterface IJBRedemptionDelegate3_1_1 is IERC165 {\\n /// @notice This function is called by JBPaymentTerminal.redeemTokensOf(..), after the execution of its logic\\n /// @dev Critical business logic should be protected by an appropriate access control\\n /// @param data the data passed by the terminal, as a JBDidRedeemData struct:\\n function didRedeem(JBDidRedeemData3_1_1 calldata data) external payable;\\n}\\n\",\"keccak256\":\"0x6034773b78e98902625563bd176a97267e729cb5205d25b06e8a2262b131c0d8\",\"license\":\"MIT\"},\"contracts/interfaces/IJBSingleTokenPaymentTerminal.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\\n\\ninterface IJBSingleTokenPaymentTerminal is IJBPaymentTerminal {\\n function token() external view returns (address);\\n\\n function currency() external view returns (uint256);\\n\\n function decimals() external view returns (uint256);\\n}\\n\",\"keccak256\":\"0x8e00670c66dea368dc523615425c2a79fcee10ec3c3355bf94feb82638172b3f\",\"license\":\"MIT\"},\"contracts/interfaces/IJBSingleTokenPaymentTerminalStore3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\\nimport {JBPayDelegateAllocation3_1_1} from './../structs/JBPayDelegateAllocation3_1_1.sol';\\nimport {JBRedemptionDelegateAllocation3_1_1} from './../structs/JBRedemptionDelegateAllocation3_1_1.sol';\\nimport {JBTokenAmount} from './../structs/JBTokenAmount.sol';\\nimport {IJBDirectory} from './IJBDirectory.sol';\\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\\nimport {IJBPrices} from './IJBPrices.sol';\\nimport {IJBSingleTokenPaymentTerminal} from './IJBSingleTokenPaymentTerminal.sol';\\n\\ninterface IJBSingleTokenPaymentTerminalStore3_1_1 {\\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\\n\\n function directory() external view returns (IJBDirectory);\\n\\n function prices() external view returns (IJBPrices);\\n\\n function balanceOf(\\n IJBSingleTokenPaymentTerminal terminal,\\n uint256 projectId\\n ) external view returns (uint256);\\n\\n function usedDistributionLimitOf(\\n IJBSingleTokenPaymentTerminal terminal,\\n uint256 projectId,\\n uint256 fundingCycleNumber\\n ) external view returns (uint256);\\n\\n function usedOverflowAllowanceOf(\\n IJBSingleTokenPaymentTerminal terminal,\\n uint256 projectId,\\n uint256 fundingCycleConfiguration\\n ) external view returns (uint256);\\n\\n function currentOverflowOf(\\n IJBSingleTokenPaymentTerminal terminal,\\n uint256 projectId\\n ) external view returns (uint256);\\n\\n function currentTotalOverflowOf(\\n uint256 projectId,\\n uint256 decimals,\\n uint256 currency\\n ) external view returns (uint256);\\n\\n function currentReclaimableOverflowOf(\\n IJBSingleTokenPaymentTerminal terminal,\\n uint256 projectId,\\n uint256 tokenCount,\\n bool useTotalOverflow\\n ) external view returns (uint256);\\n\\n function currentReclaimableOverflowOf(\\n uint256 projectId,\\n uint256 tokenCount,\\n uint256 totalSupply,\\n uint256 overflow\\n ) external view returns (uint256);\\n\\n function recordPaymentFrom(\\n address payer,\\n JBTokenAmount memory amount,\\n uint256 projectId,\\n uint256 baseWeightCurrency,\\n address beneficiary,\\n string calldata inputMemo,\\n bytes calldata metadata\\n )\\n external\\n returns (\\n JBFundingCycle memory fundingCycle,\\n uint256 tokenCount,\\n JBPayDelegateAllocation3_1_1[] memory delegateAllocations,\\n string memory outputMemo\\n );\\n\\n function recordRedemptionFor(\\n address holder,\\n uint256 projectId,\\n uint256 tokenCount,\\n string calldata inputMemo,\\n bytes calldata metadata\\n )\\n external\\n returns (\\n JBFundingCycle memory fundingCycle,\\n uint256 reclaimAmount,\\n JBRedemptionDelegateAllocation3_1_1[] memory delegateAllocations,\\n string memory outputMemo\\n );\\n\\n function recordDistributionFor(\\n uint256 projectId,\\n uint256 amount,\\n uint256 currency\\n ) external returns (JBFundingCycle memory fundingCycle, uint256 distributedAmount);\\n\\n function recordUsedAllowanceOf(\\n uint256 projectId,\\n uint256 amount,\\n uint256 currency\\n ) external returns (JBFundingCycle memory fundingCycle, uint256 withdrawnAmount);\\n\\n function recordAddedBalanceFor(uint256 projectId, uint256 amount) external;\\n\\n function recordMigration(uint256 projectId) external returns (uint256 balance);\\n}\\n\",\"keccak256\":\"0xf009c9fb787cda2a18805b9a9e2105c7f1309ade1eac3af229816cfd27ba1d64\",\"license\":\"MIT\"},\"contracts/interfaces/IJBSplitAllocator.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\\nimport {JBSplitAllocationData} from '../structs/JBSplitAllocationData.sol';\\n\\n/// @title Split allocator\\n/// @notice Provide a way to process a single split with extra logic\\n/// @dev The contract address should be set as an allocator in the adequate split\\ninterface IJBSplitAllocator is IERC165 {\\n /// @notice This function is called by JBPaymentTerminal.distributePayoutOf(..), during the processing of the split including it\\n /// @dev Critical business logic should be protected by an appropriate access control. The token and/or eth are optimistically transfered to the allocator for its logic.\\n /// @param data the data passed by the terminal, as a JBSplitAllocationData struct:\\n function allocate(JBSplitAllocationData calldata data) external payable;\\n}\\n\",\"keccak256\":\"0x1643b444409d91858eb86f67abf3d757d2deb3ccd7265eb8e68d6ffdac083de6\",\"license\":\"MIT\"},\"contracts/interfaces/IJBSplitsStore.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBGroupedSplits} from './../structs/JBGroupedSplits.sol';\\nimport {JBSplit} from './../structs/JBSplit.sol';\\nimport {IJBDirectory} from './IJBDirectory.sol';\\nimport {IJBProjects} from './IJBProjects.sol';\\n\\ninterface IJBSplitsStore {\\n event SetSplit(\\n uint256 indexed projectId,\\n uint256 indexed domain,\\n uint256 indexed group,\\n JBSplit split,\\n address caller\\n );\\n\\n function projects() external view returns (IJBProjects);\\n\\n function directory() external view returns (IJBDirectory);\\n\\n function splitsOf(\\n uint256 projectId,\\n uint256 domain,\\n uint256 group\\n ) external view returns (JBSplit[] memory);\\n\\n function set(uint256 projectId, uint256 domain, JBGroupedSplits[] memory groupedSplits) external;\\n}\\n\",\"keccak256\":\"0x3ce0eb12f10282481a3bf86e62b368bcff254081088cfabb20353d60cfadbc7a\",\"license\":\"MIT\"},\"contracts/interfaces/IJBToken.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IJBToken {\\n function projectId() external view returns (uint256);\\n\\n function decimals() external view returns (uint8);\\n\\n function totalSupply(uint256 projectId) external view returns (uint256);\\n\\n function balanceOf(address account, uint256 projectId) external view returns (uint256);\\n\\n function mint(uint256 projectId, address account, uint256 amount) external;\\n\\n function burn(uint256 projectId, address account, uint256 amount) external;\\n\\n function approve(uint256, address spender, uint256 amount) external;\\n\\n function transfer(uint256 projectId, address to, uint256 amount) external;\\n\\n function transferFrom(uint256 projectId, address from, address to, uint256 amount) external;\\n}\\n\",\"keccak256\":\"0xeefe58d140e4e13f255d5c7c5cdf5ba66dd00835f04015c446ff224f8ad14c34\",\"license\":\"MIT\"},\"contracts/interfaces/IJBTokenStore.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\\nimport {IJBProjects} from './IJBProjects.sol';\\nimport {IJBToken} from './IJBToken.sol';\\n\\ninterface IJBTokenStore {\\n event Issue(\\n uint256 indexed projectId,\\n IJBToken indexed token,\\n string name,\\n string symbol,\\n address caller\\n );\\n\\n event Mint(\\n address indexed holder,\\n uint256 indexed projectId,\\n uint256 amount,\\n bool tokensWereClaimed,\\n bool preferClaimedTokens,\\n address caller\\n );\\n\\n event Burn(\\n address indexed holder,\\n uint256 indexed projectId,\\n uint256 amount,\\n uint256 initialUnclaimedBalance,\\n uint256 initialClaimedBalance,\\n bool preferClaimedTokens,\\n address caller\\n );\\n\\n event Claim(\\n address indexed holder,\\n uint256 indexed projectId,\\n uint256 initialUnclaimedBalance,\\n uint256 amount,\\n address caller\\n );\\n\\n event Set(uint256 indexed projectId, IJBToken indexed newToken, address caller);\\n\\n event Transfer(\\n address indexed holder,\\n uint256 indexed projectId,\\n address indexed recipient,\\n uint256 amount,\\n address caller\\n );\\n\\n function tokenOf(uint256 projectId) external view returns (IJBToken);\\n\\n function projects() external view returns (IJBProjects);\\n\\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\\n\\n function unclaimedBalanceOf(address holder, uint256 projectId) external view returns (uint256);\\n\\n function unclaimedTotalSupplyOf(uint256 projectId) external view returns (uint256);\\n\\n function totalSupplyOf(uint256 projectId) external view returns (uint256);\\n\\n function balanceOf(address holder, uint256 projectId) external view returns (uint256 result);\\n\\n function issueFor(\\n uint256 projectId,\\n string calldata name,\\n string calldata symbol\\n ) external returns (IJBToken token);\\n\\n function setFor(uint256 projectId, IJBToken token) external;\\n\\n function burnFrom(\\n address holder,\\n uint256 projectId,\\n uint256 amount,\\n bool preferClaimedTokens\\n ) external;\\n\\n function mintFor(\\n address holder,\\n uint256 projectId,\\n uint256 amount,\\n bool preferClaimedTokens\\n ) external;\\n\\n function claimFor(address holder, uint256 projectId, uint256 amount) external;\\n\\n function transferFrom(\\n address holder,\\n uint256 projectId,\\n address recipient,\\n uint256 amount\\n ) external;\\n}\\n\",\"keccak256\":\"0x4db7bb4fe824dc9bfbc997ea3e07f42be8900bcad4e0b991e726c23c2de84ba4\",\"license\":\"MIT\"},\"contracts/interfaces/IJBTokenUriResolver.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IJBTokenUriResolver {\\n function getUri(uint256 projectId) external view returns (string memory tokenUri);\\n}\\n\",\"keccak256\":\"0xc7c9537184a1a36bc30874e5ac29b0fbccf45a99d40806837cfe30d6d9a1c84a\",\"license\":\"MIT\"},\"contracts/libraries/JBConstants.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/// @notice Global constants used across Juicebox contracts.\\nlibrary JBConstants {\\n uint256 public constant MAX_RESERVED_RATE = 10_000;\\n uint256 public constant MAX_REDEMPTION_RATE = 10_000;\\n uint256 public constant MAX_DISCOUNT_RATE = 1_000_000_000;\\n uint256 public constant SPLITS_TOTAL_PERCENT = 1_000_000_000;\\n uint256 public constant MAX_FEE = 1_000_000_000;\\n uint256 public constant MAX_FEE_DISCOUNT = 1_000_000_000;\\n}\\n\",\"keccak256\":\"0x7f2741e86062c5019f51d7e1a7b192ec1880d7e15a9a1589362ae7424de3003b\",\"license\":\"MIT\"},\"contracts/libraries/JBCurrencies.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nlibrary JBCurrencies {\\n uint256 public constant ETH = 1;\\n uint256 public constant USD = 2;\\n}\\n\",\"keccak256\":\"0x7e417ff25c173608ee4fe6d9fc3dcd5e1458c78c889af12bac47b1189a436076\",\"license\":\"MIT\"},\"contracts/libraries/JBFixedPointNumber.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.16;\\n\\nlibrary JBFixedPointNumber {\\n function adjustDecimals(\\n uint256 _value,\\n uint256 _decimals,\\n uint256 _targetDecimals\\n ) internal pure returns (uint256) {\\n // If decimals need adjusting, multiply or divide the price by the decimal adjuster to get the normalized result.\\n if (_targetDecimals == _decimals) return _value;\\n else if (_targetDecimals > _decimals) return _value * 10**(_targetDecimals - _decimals);\\n else return _value / 10**(_decimals - _targetDecimals);\\n }\\n}\\n\",\"keccak256\":\"0x18efac48269f3a3bd7e9a1c770776f950e0afa86769e6f8b128002c3b8c6742c\",\"license\":\"MIT\"},\"contracts/libraries/JBFundingCycleMetadataResolver.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.16;\\n\\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\\nimport {JBFundingCycleMetadata} from './../structs/JBFundingCycleMetadata.sol';\\nimport {JBGlobalFundingCycleMetadata} from './../structs/JBGlobalFundingCycleMetadata.sol';\\nimport {JBConstants} from './JBConstants.sol';\\nimport {JBGlobalFundingCycleMetadataResolver} from './JBGlobalFundingCycleMetadataResolver.sol';\\n\\nlibrary JBFundingCycleMetadataResolver {\\n function global(JBFundingCycle memory _fundingCycle)\\n internal\\n pure\\n returns (JBGlobalFundingCycleMetadata memory)\\n {\\n return JBGlobalFundingCycleMetadataResolver.expandMetadata(uint8(_fundingCycle.metadata >> 8));\\n }\\n\\n function reservedRate(JBFundingCycle memory _fundingCycle) internal pure returns (uint256) {\\n return uint256(uint16(_fundingCycle.metadata >> 24));\\n }\\n\\n function redemptionRate(JBFundingCycle memory _fundingCycle) internal pure returns (uint256) {\\n // Redemption rate is a number 0-10000. It's inverse was stored so the most common case of 100% results in no storage needs.\\n return JBConstants.MAX_REDEMPTION_RATE - uint256(uint16(_fundingCycle.metadata >> 40));\\n }\\n\\n function ballotRedemptionRate(JBFundingCycle memory _fundingCycle)\\n internal\\n pure\\n returns (uint256)\\n {\\n // Redemption rate is a number 0-10000. It's inverse was stored so the most common case of 100% results in no storage needs.\\n return JBConstants.MAX_REDEMPTION_RATE - uint256(uint16(_fundingCycle.metadata >> 56));\\n }\\n\\n function payPaused(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\\n return ((_fundingCycle.metadata >> 72) & 1) == 1;\\n }\\n\\n function distributionsPaused(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\\n return ((_fundingCycle.metadata >> 73) & 1) == 1;\\n }\\n\\n function redeemPaused(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\\n return ((_fundingCycle.metadata >> 74) & 1) == 1;\\n }\\n\\n function burnPaused(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\\n return ((_fundingCycle.metadata >> 75) & 1) == 1;\\n }\\n\\n function mintingAllowed(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\\n return ((_fundingCycle.metadata >> 76) & 1) == 1;\\n }\\n\\n function terminalMigrationAllowed(JBFundingCycle memory _fundingCycle)\\n internal\\n pure\\n returns (bool)\\n {\\n return ((_fundingCycle.metadata >> 77) & 1) == 1;\\n }\\n\\n function controllerMigrationAllowed(JBFundingCycle memory _fundingCycle)\\n internal\\n pure\\n returns (bool)\\n {\\n return ((_fundingCycle.metadata >> 78) & 1) == 1;\\n }\\n\\n function shouldHoldFees(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\\n return ((_fundingCycle.metadata >> 79) & 1) == 1;\\n }\\n\\n function preferClaimedTokenOverride(JBFundingCycle memory _fundingCycle)\\n internal\\n pure\\n returns (bool)\\n {\\n return ((_fundingCycle.metadata >> 80) & 1) == 1;\\n }\\n\\n function useTotalOverflowForRedemptions(JBFundingCycle memory _fundingCycle)\\n internal\\n pure\\n returns (bool)\\n {\\n return ((_fundingCycle.metadata >> 81) & 1) == 1;\\n }\\n\\n function useDataSourceForPay(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\\n return (_fundingCycle.metadata >> 82) & 1 == 1;\\n }\\n\\n function useDataSourceForRedeem(JBFundingCycle memory _fundingCycle)\\n internal\\n pure\\n returns (bool)\\n {\\n return (_fundingCycle.metadata >> 83) & 1 == 1;\\n }\\n\\n function dataSource(JBFundingCycle memory _fundingCycle) internal pure returns (address) {\\n return address(uint160(_fundingCycle.metadata >> 84));\\n }\\n\\n function metadata(JBFundingCycle memory _fundingCycle) internal pure returns (uint256) {\\n return uint256(uint8(_fundingCycle.metadata >> 244));\\n }\\n\\n /// @notice Pack the funding cycle metadata.\\n /// @param _metadata The metadata to validate and pack.\\n /// @return packed The packed uint256 of all metadata params. The first 8 bits specify the version. \\n function packFundingCycleMetadata(JBFundingCycleMetadata memory _metadata)\\n internal\\n pure\\n returns (uint256 packed)\\n {\\n // version 1 in the bits 0-7 (8 bits).\\n packed = 1;\\n // global metadta in bits 8-23 (16 bits).\\n packed |=\\n JBGlobalFundingCycleMetadataResolver.packFundingCycleGlobalMetadata(_metadata.global) <<\\n 8;\\n // reserved rate in bits 24-39 (16 bits).\\n packed |= _metadata.reservedRate << 24;\\n // redemption rate in bits 40-55 (16 bits).\\n // redemption rate is a number 0-10000. Store the reverse so the most common case of 100% results in no storage needs.\\n packed |= (JBConstants.MAX_REDEMPTION_RATE - _metadata.redemptionRate) << 40;\\n // ballot redemption rate rate in bits 56-71 (16 bits).\\n // ballot redemption rate is a number 0-10000. Store the reverse so the most common case of 100% results in no storage needs.\\n packed |= (JBConstants.MAX_REDEMPTION_RATE - _metadata.ballotRedemptionRate) << 56;\\n // pause pay in bit 72.\\n if (_metadata.pausePay) packed |= 1 << 72;\\n // pause tap in bit 73.\\n if (_metadata.pauseDistributions) packed |= 1 << 73;\\n // pause redeem in bit 74.\\n if (_metadata.pauseRedeem) packed |= 1 << 74;\\n // pause burn in bit 75.\\n if (_metadata.pauseBurn) packed |= 1 << 75;\\n // allow minting in bit 76.\\n if (_metadata.allowMinting) packed |= 1 << 76;\\n // allow terminal migration in bit 77.\\n if (_metadata.allowTerminalMigration) packed |= 1 << 77;\\n // allow controller migration in bit 78.\\n if (_metadata.allowControllerMigration) packed |= 1 << 78;\\n // hold fees in bit 79.\\n if (_metadata.holdFees) packed |= 1 << 79;\\n // prefer claimed token override in bit 80.\\n if (_metadata.preferClaimedTokenOverride) packed |= 1 << 80;\\n // useTotalOverflowForRedemptions in bit 81.\\n if (_metadata.useTotalOverflowForRedemptions) packed |= 1 << 81;\\n // use pay data source in bit 82.\\n if (_metadata.useDataSourceForPay) packed |= 1 << 82;\\n // use redeem data source in bit 83.\\n if (_metadata.useDataSourceForRedeem) packed |= 1 << 83;\\n // data source address in bits 84-243.\\n packed |= uint256(uint160(address(_metadata.dataSource))) << 84;\\n // metadata in bits 244-252 (8 bits).\\n packed |= _metadata.metadata << 244;\\n }\\n\\n /// @notice Expand the funding cycle metadata.\\n /// @param _fundingCycle The funding cycle having its metadata expanded.\\n /// @return metadata The metadata object. \\n function expandMetadata(JBFundingCycle memory _fundingCycle)\\n internal\\n pure\\n returns (JBFundingCycleMetadata memory)\\n {\\n return\\n JBFundingCycleMetadata(\\n global(_fundingCycle),\\n reservedRate(_fundingCycle),\\n redemptionRate(_fundingCycle),\\n ballotRedemptionRate(_fundingCycle),\\n payPaused(_fundingCycle),\\n distributionsPaused(_fundingCycle),\\n redeemPaused(_fundingCycle),\\n burnPaused(_fundingCycle),\\n mintingAllowed(_fundingCycle),\\n terminalMigrationAllowed(_fundingCycle),\\n controllerMigrationAllowed(_fundingCycle),\\n shouldHoldFees(_fundingCycle),\\n preferClaimedTokenOverride(_fundingCycle),\\n useTotalOverflowForRedemptions(_fundingCycle),\\n useDataSourceForPay(_fundingCycle),\\n useDataSourceForRedeem(_fundingCycle),\\n dataSource(_fundingCycle),\\n metadata(_fundingCycle)\\n );\\n }\\n}\\n\",\"keccak256\":\"0xedb0b93d5578ca5a21ab55f65274e441513bce982b04ffc76f26e627abfbbe0c\",\"license\":\"MIT\"},\"contracts/libraries/JBGlobalFundingCycleMetadataResolver.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.16;\\n\\nimport {JBFundingCycleMetadata} from './../structs/JBFundingCycleMetadata.sol';\\nimport {JBGlobalFundingCycleMetadata} from './../structs/JBGlobalFundingCycleMetadata.sol';\\n\\nlibrary JBGlobalFundingCycleMetadataResolver {\\n function setTerminalsAllowed(uint8 _data) internal pure returns (bool) {\\n return (_data & 1) == 1;\\n }\\n\\n function setControllerAllowed(uint8 _data) internal pure returns (bool) {\\n return ((_data >> 1) & 1) == 1;\\n }\\n\\n function transfersPaused(uint8 _data) internal pure returns (bool) {\\n return ((_data >> 2) & 1) == 1;\\n }\\n\\n /// @notice Pack the global funding cycle metadata.\\n /// @param _metadata The metadata to validate and pack.\\n /// @return packed The packed uint256 of all global metadata params. The first 8 bits specify the version.\\n function packFundingCycleGlobalMetadata(\\n JBGlobalFundingCycleMetadata memory _metadata\\n ) internal pure returns (uint256 packed) {\\n // allow set terminals in bit 0.\\n if (_metadata.allowSetTerminals) packed |= 1;\\n // allow set controller in bit 1.\\n if (_metadata.allowSetController) packed |= 1 << 1;\\n // pause transfers in bit 2.\\n if (_metadata.pauseTransfers) packed |= 1 << 2;\\n }\\n\\n /// @notice Expand the global funding cycle metadata.\\n /// @param _packedMetadata The packed metadata to expand.\\n /// @return metadata The global metadata object.\\n function expandMetadata(\\n uint8 _packedMetadata\\n ) internal pure returns (JBGlobalFundingCycleMetadata memory metadata) {\\n return\\n JBGlobalFundingCycleMetadata(\\n setTerminalsAllowed(_packedMetadata),\\n setControllerAllowed(_packedMetadata),\\n transfersPaused(_packedMetadata)\\n );\\n }\\n}\\n\",\"keccak256\":\"0x8a016001787db05e3bbd442db7eaa3f49f1d3a3210d2b5c6e52254a241f3b161\",\"license\":\"MIT\"},\"contracts/structs/JBDidPayData3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBTokenAmount} from './JBTokenAmount.sol';\\n\\n/// @custom:member payer The address from which the payment originated.\\n/// @custom:member projectId The ID of the project for which the payment was made.\\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the payment is being made.\\n/// @custom:member amount The amount of the payment. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\\n/// @custom:member forwardedAmount The amount of the payment that is being sent to the delegate. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\\n/// @custom:member projectTokenCount The number of project tokens minted for the beneficiary.\\n/// @custom:member beneficiary The address to which the tokens were minted.\\n/// @custom:member preferClaimedTokens A flag indicating whether the request prefered to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract.\\n/// @custom:member memo The memo that is being emitted alongside the payment.\\n/// @custom:member dataSourceMetadata Extra data to send to the delegate sent by the data source.\\n/// @custom:member payerMetadata Extra data to send to the delegate sent by the payer.\\nstruct JBDidPayData3_1_1 {\\n address payer;\\n uint256 projectId;\\n uint256 currentFundingCycleConfiguration;\\n JBTokenAmount amount;\\n JBTokenAmount forwardedAmount;\\n uint256 projectTokenCount;\\n address beneficiary;\\n bool preferClaimedTokens;\\n string memo;\\n bytes dataSourceMetadata;\\n bytes payerMetadata;\\n}\\n\",\"keccak256\":\"0x2e659555149ff14c045b749b1d1a3156b8296ab08375ac2abec92afc43bf3acf\",\"license\":\"MIT\"},\"contracts/structs/JBDidRedeemData3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBTokenAmount} from './JBTokenAmount.sol';\\n\\n/// @custom:member holder The holder of the tokens being redeemed.\\n/// @custom:member projectId The ID of the project with which the redeemed tokens are associated.\\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the redemption is being made.\\n/// @custom:member projectTokenCount The number of project tokens being redeemed.\\n/// @custom:member reclaimedAmount The amount reclaimed from the treasury. Includes the token being reclaimed, the value, the number of decimals included, and the currency of the amount.\\n/// @custom:member forwardedAmount The amount of the payment that is being sent to the delegate. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\\n/// @custom:member beneficiary The address to which the reclaimed amount will be sent.\\n/// @custom:member memo The memo that is being emitted alongside the redemption.\\n/// @custom:member dataSourceMetadata Extra data to send to the delegate sent by the data source.\\n/// @custom:member redeemerMetadata Extra data to send to the delegate sent by the redeemer.\\nstruct JBDidRedeemData3_1_1 {\\n address holder;\\n uint256 projectId;\\n uint256 currentFundingCycleConfiguration;\\n uint256 projectTokenCount;\\n JBTokenAmount reclaimedAmount;\\n JBTokenAmount forwardedAmount;\\n address payable beneficiary;\\n string memo;\\n bytes dataSourceMetadata;\\n bytes redeemerMetadata;\\n}\\n\",\"keccak256\":\"0x23848d41aa179d16e9b7033befd3a855d43f6a009e24030c2ba1bb5b06cb3924\",\"license\":\"MIT\"},\"contracts/structs/JBFundAccessConstraints.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\\n\\n/// @custom:member terminal The terminal within which the distribution limit and the overflow allowance applies.\\n/// @custom:member token The token for which the fund access constraints apply.\\n/// @custom:member distributionLimit The amount of the distribution limit, as a fixed point number with the same number of decimals as the terminal within which the limit applies.\\n/// @custom:member distributionLimitCurrency The currency of the distribution limit.\\n/// @custom:member overflowAllowance The amount of the allowance, as a fixed point number with the same number of decimals as the terminal within which the allowance applies.\\n/// @custom:member overflowAllowanceCurrency The currency of the overflow allowance.\\nstruct JBFundAccessConstraints {\\n IJBPaymentTerminal terminal;\\n address token;\\n uint256 distributionLimit;\\n uint256 distributionLimitCurrency;\\n uint256 overflowAllowance;\\n uint256 overflowAllowanceCurrency;\\n}\\n\",\"keccak256\":\"0xbef975eb73e58c00eaaa7abbd449db545056b049907bb2034aefcdde10bcf11f\",\"license\":\"MIT\"},\"contracts/structs/JBFundingCycle.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBFundingCycleBallot} from './../interfaces/IJBFundingCycleBallot.sol';\\n\\n/// @custom:member number The funding cycle number for the cycle's project. Each funding cycle has a number that is an increment of the cycle that directly preceded it. Each project's first funding cycle has a number of 1.\\n/// @custom:member configuration The timestamp when the parameters for this funding cycle were configured. This value will stay the same for subsequent funding cycles that roll over from an originally configured cycle.\\n/// @custom:member basedOn The `configuration` of the funding cycle that was active when this cycle was created.\\n/// @custom:member start The timestamp marking the moment from which the funding cycle is considered active. It is a unix timestamp measured in seconds.\\n/// @custom:member duration The number of seconds the funding cycle lasts for, after which a new funding cycle will start. A duration of 0 means that the funding cycle will stay active until the project owner explicitly issues a reconfiguration, at which point a new funding cycle will immediately start with the updated properties. If the duration is greater than 0, a project owner cannot make changes to a funding cycle's parameters while it is active \\u2013 any proposed changes will apply to the subsequent cycle. If no changes are proposed, a funding cycle rolls over to another one with the same properties but new `start` timestamp and a discounted `weight`.\\n/// @custom:member weight A fixed point number with 18 decimals that contracts can use to base arbitrary calculations on. For example, payment terminals can use this to determine how many tokens should be minted when a payment is received.\\n/// @custom:member discountRate A percent by how much the `weight` of the subsequent funding cycle should be reduced, if the project owner hasn't configured the subsequent funding cycle with an explicit `weight`. If it's 0, each funding cycle will have equal weight. If the number is 90%, the next funding cycle will have a 10% smaller weight. This weight is out of `JBConstants.MAX_DISCOUNT_RATE`.\\n/// @custom:member ballot An address of a contract that says whether a proposed reconfiguration should be accepted or rejected. It can be used to create rules around how a project owner can change funding cycle parameters over time.\\n/// @custom:member metadata Extra data that can be associated with a funding cycle.\\nstruct JBFundingCycle {\\n uint256 number;\\n uint256 configuration;\\n uint256 basedOn;\\n uint256 start;\\n uint256 duration;\\n uint256 weight;\\n uint256 discountRate;\\n IJBFundingCycleBallot ballot;\\n uint256 metadata;\\n}\\n\",\"keccak256\":\"0x01d2ee9ae017694097985a08a36421b6801d96badd16e38c6085f3a5ac796ed1\",\"license\":\"MIT\"},\"contracts/structs/JBFundingCycleData.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBFundingCycleBallot} from './../interfaces/IJBFundingCycleBallot.sol';\\n\\n/// @custom:member duration The number of seconds the funding cycle lasts for, after which a new funding cycle will start. A duration of 0 means that the funding cycle will stay active until the project owner explicitly issues a reconfiguration, at which point a new funding cycle will immediately start with the updated properties. If the duration is greater than 0, a project owner cannot make changes to a funding cycle's parameters while it is active \\u2013 any proposed changes will apply to the subsequent cycle. If no changes are proposed, a funding cycle rolls over to another one with the same properties but new `start` timestamp and a discounted `weight`.\\n/// @custom:member weight A fixed point number with 18 decimals that contracts can use to base arbitrary calculations on. For example, payment terminals can use this to determine how many tokens should be minted when a payment is received.\\n/// @custom:member discountRate A percent by how much the `weight` of the subsequent funding cycle should be reduced, if the project owner hasn't configured the subsequent funding cycle with an explicit `weight`. If it's 0, each funding cycle will have equal weight. If the number is 90%, the next funding cycle will have a 10% smaller weight. This weight is out of `JBConstants.MAX_DISCOUNT_RATE`.\\n/// @custom:member ballot An address of a contract that says whether a proposed reconfiguration should be accepted or rejected. It can be used to create rules around how a project owner can change funding cycle parameters over time.\\nstruct JBFundingCycleData {\\n uint256 duration;\\n uint256 weight;\\n uint256 discountRate;\\n IJBFundingCycleBallot ballot;\\n}\\n\",\"keccak256\":\"0x3cd9257969fdd54bee497b01be2c623e33c941306662002b3b88fa0ab8a27db5\",\"license\":\"MIT\"},\"contracts/structs/JBFundingCycleMetadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBGlobalFundingCycleMetadata} from './JBGlobalFundingCycleMetadata.sol';\\n\\n/// @custom:member global Data used globally in non-migratable ecosystem contracts.\\n/// @custom:member reservedRate The reserved rate of the funding cycle. This number is a percentage calculated out of `JBConstants.MAX_RESERVED_RATE`.\\n/// @custom:member redemptionRate The redemption rate of the funding cycle. This number is a percentage calculated out of `JBConstants.MAX_REDEMPTION_RATE`.\\n/// @custom:member ballotRedemptionRate The redemption rate to use during an active ballot of the funding cycle. This number is a percentage calculated out of `JBConstants.MAX_REDEMPTION_RATE`.\\n/// @custom:member pausePay A flag indicating if the pay functionality should be paused during the funding cycle.\\n/// @custom:member pauseDistributions A flag indicating if the distribute functionality should be paused during the funding cycle.\\n/// @custom:member pauseRedeem A flag indicating if the redeem functionality should be paused during the funding cycle.\\n/// @custom:member pauseBurn A flag indicating if the burn functionality should be paused during the funding cycle.\\n/// @custom:member allowMinting A flag indicating if minting tokens should be allowed during this funding cycle.\\n/// @custom:member allowTerminalMigration A flag indicating if migrating terminals should be allowed during this funding cycle.\\n/// @custom:member allowControllerMigration A flag indicating if migrating controllers should be allowed during this funding cycle.\\n/// @custom:member holdFees A flag indicating if fees should be held during this funding cycle.\\n/// @custom:member preferClaimedTokenOverride A flag indicating if claimed tokens should always be prefered to unclaimed tokens when minting.\\n/// @custom:member useTotalOverflowForRedemptions A flag indicating if redemptions should use the project's balance held in all terminals instead of the project's local terminal balance from which the redemption is being fulfilled.\\n/// @custom:member useDataSourceForPay A flag indicating if the data source should be used for pay transactions during this funding cycle.\\n/// @custom:member useDataSourceForRedeem A flag indicating if the data source should be used for redeem transactions during this funding cycle.\\n/// @custom:member dataSource The data source to use during this funding cycle.\\n/// @custom:member metadata Metadata of the metadata, up to uint8 in size.\\nstruct JBFundingCycleMetadata {\\n JBGlobalFundingCycleMetadata global;\\n uint256 reservedRate;\\n uint256 redemptionRate;\\n uint256 ballotRedemptionRate;\\n bool pausePay;\\n bool pauseDistributions;\\n bool pauseRedeem;\\n bool pauseBurn;\\n bool allowMinting;\\n bool allowTerminalMigration;\\n bool allowControllerMigration;\\n bool holdFees;\\n bool preferClaimedTokenOverride;\\n bool useTotalOverflowForRedemptions;\\n bool useDataSourceForPay;\\n bool useDataSourceForRedeem;\\n address dataSource;\\n uint256 metadata;\\n}\\n\",\"keccak256\":\"0x477bbd36c94da3f56fac6c8c60b2e2e3c5b8fc557a880b5359980bc556ccd300\",\"license\":\"MIT\"},\"contracts/structs/JBGlobalFundingCycleMetadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/// @custom:member allowSetTerminals A flag indicating if setting terminals should be allowed during this funding cycle.\\n/// @custom:member allowSetController A flag indicating if setting a new controller should be allowed during this funding cycle.\\n/// @custom:member pauseTransfers A flag indicating if the project token transfer functionality should be paused during the funding cycle.\\nstruct JBGlobalFundingCycleMetadata {\\n bool allowSetTerminals;\\n bool allowSetController;\\n bool pauseTransfers;\\n}\\n\",\"keccak256\":\"0x5f95bce22550c69bb7b1ee17279d51415ae8bae10c5b759c8b88f0b0aba854ed\",\"license\":\"MIT\"},\"contracts/structs/JBGroupedSplits.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBSplit} from './JBSplit.sol';\\n\\n/// @custom:member group The group indentifier.\\n/// @custom:member splits The splits to associate with the group.\\nstruct JBGroupedSplits {\\n uint256 group;\\n JBSplit[] splits;\\n}\\n\",\"keccak256\":\"0x71fcdbff5cd055cee8d06b73568c44cedda8f5a2351e7d8ce9dd71d8a1f914a8\",\"license\":\"MIT\"},\"contracts/structs/JBPayDelegateAllocation3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBPayDelegate3_1_1} from '../interfaces/IJBPayDelegate3_1_1.sol';\\n\\n/// @custom:member delegate A delegate contract to use for subsequent calls.\\n/// @custom:member amount The amount to send to the delegate.\\n/// @custom:member metadata Metadata to pass the delegate.\\nstruct JBPayDelegateAllocation3_1_1 {\\n IJBPayDelegate3_1_1 delegate;\\n uint256 amount;\\n bytes metadata;\\n}\\n\",\"keccak256\":\"0x8d87206a7015af9ec9e5fc059e39bfcea44aa007f8812213c6fd489d0a9c2e17\",\"license\":\"MIT\"},\"contracts/structs/JBPayParamsData.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\\nimport {JBTokenAmount} from './JBTokenAmount.sol';\\n\\n/// @custom:member terminal The terminal that is facilitating the payment.\\n/// @custom:member payer The address from which the payment originated.\\n/// @custom:member amount The amount of the payment. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\\n/// @custom:member projectId The ID of the project being paid.\\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the payment is being made.\\n/// @custom:member beneficiary The specified address that should be the beneficiary of anything that results from the payment.\\n/// @custom:member weight The weight of the funding cycle during which the payment is being made.\\n/// @custom:member reservedRate The reserved rate of the funding cycle during which the payment is being made.\\n/// @custom:member memo The memo that was sent alongside the payment.\\n/// @custom:member metadata Extra data provided by the payer.\\nstruct JBPayParamsData {\\n IJBPaymentTerminal terminal;\\n address payer;\\n JBTokenAmount amount;\\n uint256 projectId;\\n uint256 currentFundingCycleConfiguration;\\n address beneficiary;\\n uint256 weight;\\n uint256 reservedRate;\\n string memo;\\n bytes metadata;\\n}\\n\",\"keccak256\":\"0xc7909dfe6de88faca33a47a588559c80e14d3d1256f2c17e13f5ea6e23ce8732\",\"license\":\"MIT\"},\"contracts/structs/JBProjectMetadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/// @custom:member content The metadata content.\\n/// @custom:member domain The domain within which the metadata applies.\\nstruct JBProjectMetadata {\\n string content;\\n uint256 domain;\\n}\\n\",\"keccak256\":\"0x9545ea42927f3451c9d901a2f7ab7c1aeef3242e5ed2b75521a90225a5a0f891\",\"license\":\"MIT\"},\"contracts/structs/JBRedeemParamsData.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\\nimport {JBTokenAmount} from './JBTokenAmount.sol';\\n\\n/// @custom:member terminal The terminal that is facilitating the redemption.\\n/// @custom:member holder The holder of the tokens being redeemed.\\n/// @custom:member projectId The ID of the project whos tokens are being redeemed.\\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the redemption is being made.\\n/// @custom:member tokenCount The proposed number of tokens being redeemed, as a fixed point number with 18 decimals.\\n/// @custom:member totalSupply The total supply of tokens used in the calculation, as a fixed point number with 18 decimals.\\n/// @custom:member overflow The amount of overflow used in the reclaim amount calculation.\\n/// @custom:member reclaimAmount The amount that should be reclaimed by the redeemer using the protocol's standard bonding curve redemption formula. Includes the token being reclaimed, the reclaim value, the number of decimals included, and the currency of the reclaim amount.\\n/// @custom:member useTotalOverflow If overflow across all of a project's terminals is being used when making redemptions.\\n/// @custom:member redemptionRate The redemption rate of the funding cycle during which the redemption is being made.\\n/// @custom:member memo The proposed memo that is being emitted alongside the redemption.\\n/// @custom:member metadata Extra data provided by the redeemer.\\nstruct JBRedeemParamsData {\\n IJBPaymentTerminal terminal;\\n address holder;\\n uint256 projectId;\\n uint256 currentFundingCycleConfiguration;\\n uint256 tokenCount;\\n uint256 totalSupply;\\n uint256 overflow;\\n JBTokenAmount reclaimAmount;\\n bool useTotalOverflow;\\n uint256 redemptionRate;\\n string memo;\\n bytes metadata;\\n}\\n\",\"keccak256\":\"0x2eada17b425e75bfeffa786dc5b5ef13407b798cc1822597dd0d3389e67e9229\",\"license\":\"MIT\"},\"contracts/structs/JBRedemptionDelegateAllocation3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBRedemptionDelegate3_1_1} from '../interfaces/IJBRedemptionDelegate3_1_1.sol';\\n\\n/// @custom:member delegate A delegate contract to use for subsequent calls.\\n/// @custom:member amount The amount to send to the delegate.\\n/// @custom:member metadata Metadata to pass the delegate.\\nstruct JBRedemptionDelegateAllocation3_1_1 {\\n IJBRedemptionDelegate3_1_1 delegate;\\n uint256 amount;\\n bytes metadata;\\n}\\n\",\"keccak256\":\"0x16d2b586f4591b0d18324f233b4d4a13c6dc687b5f2c5becadbedbbdc373cdc4\",\"license\":\"MIT\"},\"contracts/structs/JBSplit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBSplitAllocator} from './../interfaces/IJBSplitAllocator.sol';\\n\\n/// @custom:member preferClaimed A flag that only has effect if a projectId is also specified, and the project has a token contract attached. If so, this flag indicates if the tokens that result from making a payment to the project should be delivered claimed into the beneficiary's wallet, or unclaimed to save gas.\\n/// @custom:member preferAddToBalance A flag indicating if a distribution to a project should prefer triggering it's addToBalance function instead of its pay function.\\n/// @custom:member percent The percent of the whole group that this split occupies. This number is out of `JBConstants.SPLITS_TOTAL_PERCENT`.\\n/// @custom:member projectId The ID of a project. If an allocator is not set but a projectId is set, funds will be sent to the protocol treasury belonging to the project who's ID is specified. Resulting tokens will be routed to the beneficiary with the claimed token preference respected.\\n/// @custom:member beneficiary An address. The role the of the beneficary depends on whether or not projectId is specified, and whether or not an allocator is specified. If allocator is set, the beneficiary will be forwarded to the allocator for it to use. If allocator is not set but projectId is set, the beneficiary is the address to which the project's tokens will be sent that result from a payment to it. If neither allocator or projectId are set, the beneficiary is where the funds from the split will be sent.\\n/// @custom:member lockedUntil Specifies if the split should be unchangeable until the specified time, with the exception of extending the locked period.\\n/// @custom:member allocator If an allocator is specified, funds will be sent to the allocator contract along with all properties of this split.\\nstruct JBSplit {\\n bool preferClaimed;\\n bool preferAddToBalance;\\n uint256 percent;\\n uint256 projectId;\\n address payable beneficiary;\\n uint256 lockedUntil;\\n IJBSplitAllocator allocator;\\n}\\n\",\"keccak256\":\"0x7bf3f79f95cf6211dcdcf5af68ddc963f2304379ea50a5feaf27c645879fe3fe\",\"license\":\"MIT\"},\"contracts/structs/JBSplitAllocationData.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBSplit} from './JBSplit.sol';\\n\\n/// @custom:member token The token being sent to the split allocator.\\n/// @custom:member amount The amount being sent to the split allocator, as a fixed point number.\\n/// @custom:member decimals The number of decimals in the amount.\\n/// @custom:member projectId The project to which the split belongs.\\n/// @custom:member group The group to which the split belongs.\\n/// @custom:member split The split that caused the allocation.\\nstruct JBSplitAllocationData {\\n address token;\\n uint256 amount;\\n uint256 decimals;\\n uint256 projectId;\\n uint256 group;\\n JBSplit split;\\n}\\n\",\"keccak256\":\"0x85dcbcad02f315a1a3cc44140ffc77fdfbcafed7089eab55ffb66f1bebc2b40b\",\"license\":\"MIT\"},\"contracts/structs/JBTokenAmount.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/// @custom:member token The token the payment was made in.\\n/// @custom:member value The amount of tokens that was paid, as a fixed point number.\\n/// @custom:member decimals The number of decimals included in the value fixed point number.\\n/// @custom:member currency The expected currency of the value.\\nstruct JBTokenAmount {\\n address token;\\n uint256 value;\\n uint256 decimals;\\n uint256 currency;\\n}\\n\",\"keccak256\":\"0x9317f1f47aef544de592a48a4b20fa3d54586d988c8bb7420b40076920ea200d\",\"license\":\"MIT\"},\"prb-math/contracts/PRBMath.sol\":{\"content\":\"// SPDX-License-Identifier: Unlicense\\npragma solidity >=0.8.4;\\n\\n/// @notice Emitted when the result overflows uint256.\\nerror PRBMath__MulDivFixedPointOverflow(uint256 prod1);\\n\\n/// @notice Emitted when the result overflows uint256.\\nerror PRBMath__MulDivOverflow(uint256 prod1, uint256 denominator);\\n\\n/// @notice Emitted when one of the inputs is type(int256).min.\\nerror PRBMath__MulDivSignedInputTooSmall();\\n\\n/// @notice Emitted when the intermediary absolute result overflows int256.\\nerror PRBMath__MulDivSignedOverflow(uint256 rAbs);\\n\\n/// @notice Emitted when the input is MIN_SD59x18.\\nerror PRBMathSD59x18__AbsInputTooSmall();\\n\\n/// @notice Emitted when ceiling a number overflows SD59x18.\\nerror PRBMathSD59x18__CeilOverflow(int256 x);\\n\\n/// @notice Emitted when one of the inputs is MIN_SD59x18.\\nerror PRBMathSD59x18__DivInputTooSmall();\\n\\n/// @notice Emitted when one of the intermediary unsigned results overflows SD59x18.\\nerror PRBMathSD59x18__DivOverflow(uint256 rAbs);\\n\\n/// @notice Emitted when the input is greater than 133.084258667509499441.\\nerror PRBMathSD59x18__ExpInputTooBig(int256 x);\\n\\n/// @notice Emitted when the input is greater than 192.\\nerror PRBMathSD59x18__Exp2InputTooBig(int256 x);\\n\\n/// @notice Emitted when flooring a number underflows SD59x18.\\nerror PRBMathSD59x18__FloorUnderflow(int256 x);\\n\\n/// @notice Emitted when converting a basic integer to the fixed-point format overflows SD59x18.\\nerror PRBMathSD59x18__FromIntOverflow(int256 x);\\n\\n/// @notice Emitted when converting a basic integer to the fixed-point format underflows SD59x18.\\nerror PRBMathSD59x18__FromIntUnderflow(int256 x);\\n\\n/// @notice Emitted when the product of the inputs is negative.\\nerror PRBMathSD59x18__GmNegativeProduct(int256 x, int256 y);\\n\\n/// @notice Emitted when multiplying the inputs overflows SD59x18.\\nerror PRBMathSD59x18__GmOverflow(int256 x, int256 y);\\n\\n/// @notice Emitted when the input is less than or equal to zero.\\nerror PRBMathSD59x18__LogInputTooSmall(int256 x);\\n\\n/// @notice Emitted when one of the inputs is MIN_SD59x18.\\nerror PRBMathSD59x18__MulInputTooSmall();\\n\\n/// @notice Emitted when the intermediary absolute result overflows SD59x18.\\nerror PRBMathSD59x18__MulOverflow(uint256 rAbs);\\n\\n/// @notice Emitted when the intermediary absolute result overflows SD59x18.\\nerror PRBMathSD59x18__PowuOverflow(uint256 rAbs);\\n\\n/// @notice Emitted when the input is negative.\\nerror PRBMathSD59x18__SqrtNegativeInput(int256 x);\\n\\n/// @notice Emitted when the calculating the square root overflows SD59x18.\\nerror PRBMathSD59x18__SqrtOverflow(int256 x);\\n\\n/// @notice Emitted when addition overflows UD60x18.\\nerror PRBMathUD60x18__AddOverflow(uint256 x, uint256 y);\\n\\n/// @notice Emitted when ceiling a number overflows UD60x18.\\nerror PRBMathUD60x18__CeilOverflow(uint256 x);\\n\\n/// @notice Emitted when the input is greater than 133.084258667509499441.\\nerror PRBMathUD60x18__ExpInputTooBig(uint256 x);\\n\\n/// @notice Emitted when the input is greater than 192.\\nerror PRBMathUD60x18__Exp2InputTooBig(uint256 x);\\n\\n/// @notice Emitted when converting a basic integer to the fixed-point format format overflows UD60x18.\\nerror PRBMathUD60x18__FromUintOverflow(uint256 x);\\n\\n/// @notice Emitted when multiplying the inputs overflows UD60x18.\\nerror PRBMathUD60x18__GmOverflow(uint256 x, uint256 y);\\n\\n/// @notice Emitted when the input is less than 1.\\nerror PRBMathUD60x18__LogInputTooSmall(uint256 x);\\n\\n/// @notice Emitted when the calculating the square root overflows UD60x18.\\nerror PRBMathUD60x18__SqrtOverflow(uint256 x);\\n\\n/// @notice Emitted when subtraction underflows UD60x18.\\nerror PRBMathUD60x18__SubUnderflow(uint256 x, uint256 y);\\n\\n/// @dev Common mathematical functions used in both PRBMathSD59x18 and PRBMathUD60x18. Note that this shared library\\n/// does not always assume the signed 59.18-decimal fixed-point or the unsigned 60.18-decimal fixed-point\\n/// representation. When it does not, it is explicitly mentioned in the NatSpec documentation.\\nlibrary PRBMath {\\n /// STRUCTS ///\\n\\n struct SD59x18 {\\n int256 value;\\n }\\n\\n struct UD60x18 {\\n uint256 value;\\n }\\n\\n /// STORAGE ///\\n\\n /// @dev How many trailing decimals can be represented.\\n uint256 internal constant SCALE = 1e18;\\n\\n /// @dev Largest power of two divisor of SCALE.\\n uint256 internal constant SCALE_LPOTD = 262144;\\n\\n /// @dev SCALE inverted mod 2^256.\\n uint256 internal constant SCALE_INVERSE =\\n 78156646155174841979727994598816262306175212592076161876661_508869554232690281;\\n\\n /// FUNCTIONS ///\\n\\n /// @notice Calculates the binary exponent of x using the binary fraction method.\\n /// @dev Has to use 192.64-bit fixed-point numbers.\\n /// See https://ethereum.stackexchange.com/a/96594/24693.\\n /// @param x The exponent as an unsigned 192.64-bit fixed-point number.\\n /// @return result The result as an unsigned 60.18-decimal fixed-point number.\\n function exp2(uint256 x) internal pure returns (uint256 result) {\\n unchecked {\\n // Start from 0.5 in the 192.64-bit fixed-point format.\\n result = 0x800000000000000000000000000000000000000000000000;\\n\\n // Multiply the result by root(2, 2^-i) when the bit at position i is 1. None of the intermediary results overflows\\n // because the initial result is 2^191 and all magic factors are less than 2^65.\\n if (x & 0x8000000000000000 > 0) {\\n result = (result * 0x16A09E667F3BCC909) >> 64;\\n }\\n if (x & 0x4000000000000000 > 0) {\\n result = (result * 0x1306FE0A31B7152DF) >> 64;\\n }\\n if (x & 0x2000000000000000 > 0) {\\n result = (result * 0x1172B83C7D517ADCE) >> 64;\\n }\\n if (x & 0x1000000000000000 > 0) {\\n result = (result * 0x10B5586CF9890F62A) >> 64;\\n }\\n if (x & 0x800000000000000 > 0) {\\n result = (result * 0x1059B0D31585743AE) >> 64;\\n }\\n if (x & 0x400000000000000 > 0) {\\n result = (result * 0x102C9A3E778060EE7) >> 64;\\n }\\n if (x & 0x200000000000000 > 0) {\\n result = (result * 0x10163DA9FB33356D8) >> 64;\\n }\\n if (x & 0x100000000000000 > 0) {\\n result = (result * 0x100B1AFA5ABCBED61) >> 64;\\n }\\n if (x & 0x80000000000000 > 0) {\\n result = (result * 0x10058C86DA1C09EA2) >> 64;\\n }\\n if (x & 0x40000000000000 > 0) {\\n result = (result * 0x1002C605E2E8CEC50) >> 64;\\n }\\n if (x & 0x20000000000000 > 0) {\\n result = (result * 0x100162F3904051FA1) >> 64;\\n }\\n if (x & 0x10000000000000 > 0) {\\n result = (result * 0x1000B175EFFDC76BA) >> 64;\\n }\\n if (x & 0x8000000000000 > 0) {\\n result = (result * 0x100058BA01FB9F96D) >> 64;\\n }\\n if (x & 0x4000000000000 > 0) {\\n result = (result * 0x10002C5CC37DA9492) >> 64;\\n }\\n if (x & 0x2000000000000 > 0) {\\n result = (result * 0x1000162E525EE0547) >> 64;\\n }\\n if (x & 0x1000000000000 > 0) {\\n result = (result * 0x10000B17255775C04) >> 64;\\n }\\n if (x & 0x800000000000 > 0) {\\n result = (result * 0x1000058B91B5BC9AE) >> 64;\\n }\\n if (x & 0x400000000000 > 0) {\\n result = (result * 0x100002C5C89D5EC6D) >> 64;\\n }\\n if (x & 0x200000000000 > 0) {\\n result = (result * 0x10000162E43F4F831) >> 64;\\n }\\n if (x & 0x100000000000 > 0) {\\n result = (result * 0x100000B1721BCFC9A) >> 64;\\n }\\n if (x & 0x80000000000 > 0) {\\n result = (result * 0x10000058B90CF1E6E) >> 64;\\n }\\n if (x & 0x40000000000 > 0) {\\n result = (result * 0x1000002C5C863B73F) >> 64;\\n }\\n if (x & 0x20000000000 > 0) {\\n result = (result * 0x100000162E430E5A2) >> 64;\\n }\\n if (x & 0x10000000000 > 0) {\\n result = (result * 0x1000000B172183551) >> 64;\\n }\\n if (x & 0x8000000000 > 0) {\\n result = (result * 0x100000058B90C0B49) >> 64;\\n }\\n if (x & 0x4000000000 > 0) {\\n result = (result * 0x10000002C5C8601CC) >> 64;\\n }\\n if (x & 0x2000000000 > 0) {\\n result = (result * 0x1000000162E42FFF0) >> 64;\\n }\\n if (x & 0x1000000000 > 0) {\\n result = (result * 0x10000000B17217FBB) >> 64;\\n }\\n if (x & 0x800000000 > 0) {\\n result = (result * 0x1000000058B90BFCE) >> 64;\\n }\\n if (x & 0x400000000 > 0) {\\n result = (result * 0x100000002C5C85FE3) >> 64;\\n }\\n if (x & 0x200000000 > 0) {\\n result = (result * 0x10000000162E42FF1) >> 64;\\n }\\n if (x & 0x100000000 > 0) {\\n result = (result * 0x100000000B17217F8) >> 64;\\n }\\n if (x & 0x80000000 > 0) {\\n result = (result * 0x10000000058B90BFC) >> 64;\\n }\\n if (x & 0x40000000 > 0) {\\n result = (result * 0x1000000002C5C85FE) >> 64;\\n }\\n if (x & 0x20000000 > 0) {\\n result = (result * 0x100000000162E42FF) >> 64;\\n }\\n if (x & 0x10000000 > 0) {\\n result = (result * 0x1000000000B17217F) >> 64;\\n }\\n if (x & 0x8000000 > 0) {\\n result = (result * 0x100000000058B90C0) >> 64;\\n }\\n if (x & 0x4000000 > 0) {\\n result = (result * 0x10000000002C5C860) >> 64;\\n }\\n if (x & 0x2000000 > 0) {\\n result = (result * 0x1000000000162E430) >> 64;\\n }\\n if (x & 0x1000000 > 0) {\\n result = (result * 0x10000000000B17218) >> 64;\\n }\\n if (x & 0x800000 > 0) {\\n result = (result * 0x1000000000058B90C) >> 64;\\n }\\n if (x & 0x400000 > 0) {\\n result = (result * 0x100000000002C5C86) >> 64;\\n }\\n if (x & 0x200000 > 0) {\\n result = (result * 0x10000000000162E43) >> 64;\\n }\\n if (x & 0x100000 > 0) {\\n result = (result * 0x100000000000B1721) >> 64;\\n }\\n if (x & 0x80000 > 0) {\\n result = (result * 0x10000000000058B91) >> 64;\\n }\\n if (x & 0x40000 > 0) {\\n result = (result * 0x1000000000002C5C8) >> 64;\\n }\\n if (x & 0x20000 > 0) {\\n result = (result * 0x100000000000162E4) >> 64;\\n }\\n if (x & 0x10000 > 0) {\\n result = (result * 0x1000000000000B172) >> 64;\\n }\\n if (x & 0x8000 > 0) {\\n result = (result * 0x100000000000058B9) >> 64;\\n }\\n if (x & 0x4000 > 0) {\\n result = (result * 0x10000000000002C5D) >> 64;\\n }\\n if (x & 0x2000 > 0) {\\n result = (result * 0x1000000000000162E) >> 64;\\n }\\n if (x & 0x1000 > 0) {\\n result = (result * 0x10000000000000B17) >> 64;\\n }\\n if (x & 0x800 > 0) {\\n result = (result * 0x1000000000000058C) >> 64;\\n }\\n if (x & 0x400 > 0) {\\n result = (result * 0x100000000000002C6) >> 64;\\n }\\n if (x & 0x200 > 0) {\\n result = (result * 0x10000000000000163) >> 64;\\n }\\n if (x & 0x100 > 0) {\\n result = (result * 0x100000000000000B1) >> 64;\\n }\\n if (x & 0x80 > 0) {\\n result = (result * 0x10000000000000059) >> 64;\\n }\\n if (x & 0x40 > 0) {\\n result = (result * 0x1000000000000002C) >> 64;\\n }\\n if (x & 0x20 > 0) {\\n result = (result * 0x10000000000000016) >> 64;\\n }\\n if (x & 0x10 > 0) {\\n result = (result * 0x1000000000000000B) >> 64;\\n }\\n if (x & 0x8 > 0) {\\n result = (result * 0x10000000000000006) >> 64;\\n }\\n if (x & 0x4 > 0) {\\n result = (result * 0x10000000000000003) >> 64;\\n }\\n if (x & 0x2 > 0) {\\n result = (result * 0x10000000000000001) >> 64;\\n }\\n if (x & 0x1 > 0) {\\n result = (result * 0x10000000000000001) >> 64;\\n }\\n\\n // We're doing two things at the same time:\\n //\\n // 1. Multiply the result by 2^n + 1, where \\\"2^n\\\" is the integer part and the one is added to account for\\n // the fact that we initially set the result to 0.5. This is accomplished by subtracting from 191\\n // rather than 192.\\n // 2. Convert the result to the unsigned 60.18-decimal fixed-point format.\\n //\\n // This works because 2^(191-ip) = 2^ip / 2^191, where \\\"ip\\\" is the integer part \\\"2^n\\\".\\n result *= SCALE;\\n result >>= (191 - (x >> 64));\\n }\\n }\\n\\n /// @notice Finds the zero-based index of the first one in the binary representation of x.\\n /// @dev See the note on msb in the \\\"Find First Set\\\" Wikipedia article https://en.wikipedia.org/wiki/Find_first_set\\n /// @param x The uint256 number for which to find the index of the most significant bit.\\n /// @return msb The index of the most significant bit as an uint256.\\n function mostSignificantBit(uint256 x) internal pure returns (uint256 msb) {\\n if (x >= 2**128) {\\n x >>= 128;\\n msb += 128;\\n }\\n if (x >= 2**64) {\\n x >>= 64;\\n msb += 64;\\n }\\n if (x >= 2**32) {\\n x >>= 32;\\n msb += 32;\\n }\\n if (x >= 2**16) {\\n x >>= 16;\\n msb += 16;\\n }\\n if (x >= 2**8) {\\n x >>= 8;\\n msb += 8;\\n }\\n if (x >= 2**4) {\\n x >>= 4;\\n msb += 4;\\n }\\n if (x >= 2**2) {\\n x >>= 2;\\n msb += 2;\\n }\\n if (x >= 2**1) {\\n // No need to shift x any more.\\n msb += 1;\\n }\\n }\\n\\n /// @notice Calculates floor(x*y\\u00f7denominator) with full precision.\\n ///\\n /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv.\\n ///\\n /// Requirements:\\n /// - The denominator cannot be zero.\\n /// - The result must fit within uint256.\\n ///\\n /// Caveats:\\n /// - This function does not work with fixed-point numbers.\\n ///\\n /// @param x The multiplicand as an uint256.\\n /// @param y The multiplier as an uint256.\\n /// @param denominator The divisor as an uint256.\\n /// @return result The result as an uint256.\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator\\n ) internal pure returns (uint256 result) {\\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\\n // variables such that product = prod1 * 2^256 + prod0.\\n uint256 prod0; // Least significant 256 bits of the product\\n uint256 prod1; // Most significant 256 bits of the product\\n assembly {\\n let mm := mulmod(x, y, not(0))\\n prod0 := mul(x, y)\\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\\n }\\n\\n // Handle non-overflow cases, 256 by 256 division.\\n if (prod1 == 0) {\\n unchecked {\\n result = prod0 / denominator;\\n }\\n return result;\\n }\\n\\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\\n if (prod1 >= denominator) {\\n revert PRBMath__MulDivOverflow(prod1, denominator);\\n }\\n\\n ///////////////////////////////////////////////\\n // 512 by 256 division.\\n ///////////////////////////////////////////////\\n\\n // Make division exact by subtracting the remainder from [prod1 prod0].\\n uint256 remainder;\\n assembly {\\n // Compute remainder using mulmod.\\n remainder := mulmod(x, y, denominator)\\n\\n // Subtract 256 bit number from 512 bit number.\\n prod1 := sub(prod1, gt(remainder, prod0))\\n prod0 := sub(prod0, remainder)\\n }\\n\\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\\n // See https://cs.stackexchange.com/q/138556/92363.\\n unchecked {\\n // Does not overflow because the denominator cannot be zero at this stage in the function.\\n uint256 lpotdod = denominator & (~denominator + 1);\\n assembly {\\n // Divide denominator by lpotdod.\\n denominator := div(denominator, lpotdod)\\n\\n // Divide [prod1 prod0] by lpotdod.\\n prod0 := div(prod0, lpotdod)\\n\\n // Flip lpotdod such that it is 2^256 / lpotdod. If lpotdod is zero, then it becomes one.\\n lpotdod := add(div(sub(0, lpotdod), lpotdod), 1)\\n }\\n\\n // Shift in bits from prod1 into prod0.\\n prod0 |= prod1 * lpotdod;\\n\\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\\n // four bits. That is, denominator * inv = 1 mod 2^4.\\n uint256 inverse = (3 * denominator) ^ 2;\\n\\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\\n // in modular arithmetic, doubling the correct bits in each step.\\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\\n\\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\\n // is no longer required.\\n result = prod0 * inverse;\\n return result;\\n }\\n }\\n\\n /// @notice Calculates floor(x*y\\u00f71e18) with full precision.\\n ///\\n /// @dev Variant of \\\"mulDiv\\\" with constant folding, i.e. in which the denominator is always 1e18. Before returning the\\n /// final result, we add 1 if (x * y) % SCALE >= HALF_SCALE. Without this, 6.6e-19 would be truncated to 0 instead of\\n /// being rounded to 1e-18. See \\\"Listing 6\\\" and text above it at https://accu.org/index.php/journals/1717.\\n ///\\n /// Requirements:\\n /// - The result must fit within uint256.\\n ///\\n /// Caveats:\\n /// - The body is purposely left uncommented; see the NatSpec comments in \\\"PRBMath.mulDiv\\\" to understand how this works.\\n /// - It is assumed that the result can never be type(uint256).max when x and y solve the following two equations:\\n /// 1. x * y = type(uint256).max * SCALE\\n /// 2. (x * y) % SCALE >= SCALE / 2\\n ///\\n /// @param x The multiplicand as an unsigned 60.18-decimal fixed-point number.\\n /// @param y The multiplier as an unsigned 60.18-decimal fixed-point number.\\n /// @return result The result as an unsigned 60.18-decimal fixed-point number.\\n function mulDivFixedPoint(uint256 x, uint256 y) internal pure returns (uint256 result) {\\n uint256 prod0;\\n uint256 prod1;\\n assembly {\\n let mm := mulmod(x, y, not(0))\\n prod0 := mul(x, y)\\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\\n }\\n\\n if (prod1 >= SCALE) {\\n revert PRBMath__MulDivFixedPointOverflow(prod1);\\n }\\n\\n uint256 remainder;\\n uint256 roundUpUnit;\\n assembly {\\n remainder := mulmod(x, y, SCALE)\\n roundUpUnit := gt(remainder, 499999999999999999)\\n }\\n\\n if (prod1 == 0) {\\n unchecked {\\n result = (prod0 / SCALE) + roundUpUnit;\\n return result;\\n }\\n }\\n\\n assembly {\\n result := add(\\n mul(\\n or(\\n div(sub(prod0, remainder), SCALE_LPOTD),\\n mul(sub(prod1, gt(remainder, prod0)), add(div(sub(0, SCALE_LPOTD), SCALE_LPOTD), 1))\\n ),\\n SCALE_INVERSE\\n ),\\n roundUpUnit\\n )\\n }\\n }\\n\\n /// @notice Calculates floor(x*y\\u00f7denominator) with full precision.\\n ///\\n /// @dev An extension of \\\"mulDiv\\\" for signed numbers. Works by computing the signs and the absolute values separately.\\n ///\\n /// Requirements:\\n /// - None of the inputs can be type(int256).min.\\n /// - The result must fit within int256.\\n ///\\n /// @param x The multiplicand as an int256.\\n /// @param y The multiplier as an int256.\\n /// @param denominator The divisor as an int256.\\n /// @return result The result as an int256.\\n function mulDivSigned(\\n int256 x,\\n int256 y,\\n int256 denominator\\n ) internal pure returns (int256 result) {\\n if (x == type(int256).min || y == type(int256).min || denominator == type(int256).min) {\\n revert PRBMath__MulDivSignedInputTooSmall();\\n }\\n\\n // Get hold of the absolute values of x, y and the denominator.\\n uint256 ax;\\n uint256 ay;\\n uint256 ad;\\n unchecked {\\n ax = x < 0 ? uint256(-x) : uint256(x);\\n ay = y < 0 ? uint256(-y) : uint256(y);\\n ad = denominator < 0 ? uint256(-denominator) : uint256(denominator);\\n }\\n\\n // Compute the absolute value of (x*y)\\u00f7denominator. The result must fit within int256.\\n uint256 rAbs = mulDiv(ax, ay, ad);\\n if (rAbs > uint256(type(int256).max)) {\\n revert PRBMath__MulDivSignedOverflow(rAbs);\\n }\\n\\n // Get the signs of x, y and the denominator.\\n uint256 sx;\\n uint256 sy;\\n uint256 sd;\\n assembly {\\n sx := sgt(x, sub(0, 1))\\n sy := sgt(y, sub(0, 1))\\n sd := sgt(denominator, sub(0, 1))\\n }\\n\\n // XOR over sx, sy and sd. This is checking whether there are one or three negative signs in the inputs.\\n // If yes, the result should be negative.\\n result = sx ^ sy ^ sd == 0 ? -int256(rAbs) : int256(rAbs);\\n }\\n\\n /// @notice Calculates the square root of x, rounding down.\\n /// @dev Uses the Babylonian method https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method.\\n ///\\n /// Caveats:\\n /// - This function does not work with fixed-point numbers.\\n ///\\n /// @param x The uint256 number for which to calculate the square root.\\n /// @return result The result as an uint256.\\n function sqrt(uint256 x) internal pure returns (uint256 result) {\\n if (x == 0) {\\n return 0;\\n }\\n\\n // Set the initial guess to the closest power of two that is higher than x.\\n uint256 xAux = uint256(x);\\n result = 1;\\n if (xAux >= 0x100000000000000000000000000000000) {\\n xAux >>= 128;\\n result <<= 64;\\n }\\n if (xAux >= 0x10000000000000000) {\\n xAux >>= 64;\\n result <<= 32;\\n }\\n if (xAux >= 0x100000000) {\\n xAux >>= 32;\\n result <<= 16;\\n }\\n if (xAux >= 0x10000) {\\n xAux >>= 16;\\n result <<= 8;\\n }\\n if (xAux >= 0x100) {\\n xAux >>= 8;\\n result <<= 4;\\n }\\n if (xAux >= 0x10) {\\n xAux >>= 4;\\n result <<= 2;\\n }\\n if (xAux >= 0x8) {\\n result <<= 1;\\n }\\n\\n // The operations can never overflow because the result is max 2^127 when it enters this block.\\n unchecked {\\n result = (result + x / result) >> 1;\\n result = (result + x / result) >> 1;\\n result = (result + x / result) >> 1;\\n result = (result + x / result) >> 1;\\n result = (result + x / result) >> 1;\\n result = (result + x / result) >> 1;\\n result = (result + x / result) >> 1; // Seven iterations should be enough\\n uint256 roundedDownResult = x / result;\\n return result >= roundedDownResult ? roundedDownResult : result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x62cbabae4910e168e99b9c2c3e3b5c9c7ad5e7abd961dcc63b7ea3d83d8ea87e\",\"license\":\"Unlicense\"}},\"version\":1}", + "bytecode": "0x60e06040523480156200001157600080fd5b506040516200366a3803806200366a833981016040819052620000349162000070565b60016000556001600160a01b0392831660805290821660a0521660c052620000c4565b6001600160a01b03811681146200006d57600080fd5b50565b6000806000606084860312156200008657600080fd5b8351620000938162000057565b6020850151909350620000a68162000057565b6040850151909250620000b98162000057565b809150509250925092565b60805160a05160c0516134ea6200018060003960008181610273015281816106d201528181610c1c0152818161214c015261232901526000818161018b0152818161036f0152818161083f01528181610d0601528181610e1c0152818161120d015281816114d7015281816115a0015281816118d901528181611cdf01526123b00152600081816102390152818161041f0152818161105c01528181611782015281816119b201528181611f2201526121c801526134ea6000f3fe608060405234801561001057600080fd5b50600436106100ff5760003560e01c8063c294b2f411610097578063d49031c011610066578063d49031c014610295578063d4c3a8d2146102a8578063e7c8e3e3146102d9578063e8ba563a146102ee57600080fd5b8063c294b2f414610221578063c41c2f2414610234578063c66445971461025b578063d3419bf31461026e57600080fd5b80636bb6a5ad116100d35780636bb6a5ad146101c5578063a2df1f95146101d8578063a57c7f59146101fb578063b753d7e91461020e57600080fd5b8062fdd58e1461010457806325386715146101425780632fa1b39114610163578063557e715514610186575b600080fd5b61012f6101123660046125c3565b600160209081526000928352604080842090915290825290205481565b6040519081526020015b60405180910390f35b6101556101503660046125ef565b61031f565b60405161013992919061267a565b6101766101713660046127fa565b6107f5565b604051610139949392919061290b565b6101ad7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610139565b61012f6101d33660046129bd565b610cc5565b6101eb6101e63660046129d6565b610dd2565b6040516101399493929190612a77565b61012f610209366004612b12565b61149c565b61012f61021c3660046125ef565b611566565b61012f61022f366004612b44565b61157d565b6101ad7f000000000000000000000000000000000000000000000000000000000000000081565b6101556102693660046125ef565b611892565b6101ad7f000000000000000000000000000000000000000000000000000000000000000081565b61012f6102a33660046125c3565b611cd6565b61012f6102b6366004612b93565b600360209081526000938452604080852082529284528284209052825290205481565b6102ec6102e7366004612bc8565b611db4565b005b61012f6102fc366004612b93565b600260209081526000938452604080852082529284528284209052825290205481565b610327612556565b60006002600054036103545760405162461bcd60e51b815260040161034b90612bea565b60405180910390fd5b60026000556040516321d1336160e11b8152600481018690527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906343a266c29060240161012060405180830381865afa1580156103bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103e39190612c31565b336000908152600360209081526040808320898452825280832082850151845290915281205491935090610418908690612cc7565b90506000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635dd8f6aa896040518263ffffffff1660e01b815260040161046b91815260200190565b602060405180830381865afa158015610488573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104ac9190612cda565b6001600160a01b031663a29a68146040518163ffffffff1660e01b8152600401602060405180830381865afa1580156104e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061050d9190612cda565b6001600160a01b0316637a81b56289876020015133336001600160a01b031663fc0c546a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610560573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105849190612cda565b6040518563ffffffff1660e01b81526004016105a39493929190612cf7565b6040805180830381865afa1580156105bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105e39190612d1e565b91509150818311806105f3575081155b1561061157604051635b76558960e11b815260040160405180910390fd5b8086146106315760405163e56ea4e760e01b815260040160405180910390fd5b6000336001600160a01b031663e5a6b10f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610671573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106959190612d42565b90508087146107505761074b886106ae6012600a612e3f565b604051635268657960e11b8152600481018b905260248101859052601260448201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a4d0caf2906064015b602060405180830381865afa158015610722573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107469190612d42565b611dfd565b610752565b875b9450610760338a8884611eca565b851115610780576040516317e53f6760e11b815260040160405180910390fd5b3360008181526003602090815260408083208d845282528083208a83015184528252808320889055928252600181528282208c8352905220546107c4908690612e4b565b3360009081526001602081815260408084209d84529c90529a81209190915598909855509296919550909350505050565b6107fd612556565b60006060806002600054036108245760405162461bcd60e51b815260040161034b90612bea565b60026000556040516321d1336160e11b8152600481018b90527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906343a266c29060240161012060405180830381865afa15801561088f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108b39190612c31565b80519094506000036108d85760405163174b338d60e11b815260040160405180910390fd5b61010084015160481c6001908116036109045760405163a3bb913360e01b815260040160405180910390fd5b61010084015160009060521c600190811614801561093a5750600061092e86610100015160541c90565b6001600160a01b031614155b15610a8c576000604051806101400160405280336001600160a01b031681526020018f6001600160a01b031681526020018e80360381019061097c9190612e5e565b815260208082018f905288015160408201526001600160a01b038c16606082015260a080890151608083015261010089015191019060181c61ffff1681526020018a8a8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050908252506020018890529050610a0d86610100015160541c90565b6001600160a01b031663d46cf171826040518263ffffffff1660e01b8152600401610a389190612ecd565b6000604051808303816000875af1158015610a57573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610a7f9190810190613038565b955093509150610acd9050565b8460a00151905087878080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509294505050505b825160208d01359015610b495760005b8451811015610b47576000858281518110610afa57610afa613169565b602002602001015160200151905080600014610b3e5782811115610b31576040516336a8da9360e11b815260040160405180910390fd5b610b3b8184612e4b565b92505b50600101610add565b505b8c60200135600003610b61575060009350610cae9050565b8015610bc8573360009081526001602090815260408083208f8452909152902054610b8d908290612cc7565b60016000336001600160a01b03166001600160a01b0316815260200190815260200160002060008e8152602001908152602001600020819055505b5080600003610bdb575060009250610cae565b60408c0135600060608e01358c14610c8c57604051635268657960e11b815260608f01356004820152602481018d9052604481018390526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063a4d0caf290606401602060405180830381865afa158015610c63573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c879190612d42565b610c97565b610c9782600a612e3f565b9050610ca88e602001358483611dfd565b95505050505b600160008190555098509850985098945050505050565b6000600260005403610ce95760405162461bcd60e51b815260040161034b90612bea565b600260009081556040516321d1336160e11b8152600481018490527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906343a266c29060240161012060405180830381865afa158015610d56573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d7a9190612c31565b610100810151909150604d1c600190811614610da9576040516373e4f05f60e11b815260040160405180910390fd5b505033600090815260016020818152604080842094845293905291812080549082905591905590565b610dda612556565b6000606080600260005403610e015760405162461bcd60e51b815260040161034b90612bea565b60026000556040516321d1336160e11b8152600481018990527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906343a266c29060240161012060405180830381865afa158015610e6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e909190612c31565b610100810151909450604a1c600190811603610ebf5760405163a97cf58f60e01b815260040160405180910390fd5b610ef3604051806080016040528060006001600160a01b031681526020016000815260200160008152602001600081525090565b6000806000336001600160a01b031663fc0c546a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f5a9190612cda565b90506000336001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f9c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fc09190612d42565b90506000336001600160a01b031663e5a6b10f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611002573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110269190612d42565b6101008b015190915060511c60019081161461104d57611048338f8c84611eca565b611058565b6110588e83836121a5565b94507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635dd8f6aa8f6040518263ffffffff1660e01b81526004016110a891815260200190565b602060405180830381865afa1580156110c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110e99190612cda565b6001600160a01b031663c18f2d318f6040518263ffffffff1660e01b815260040161111691815260200190565b602060405180830381865afa158015611133573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111579190612d42565b9350838d111561117957604051625c579160e91b815260040160405180910390fd5b841561118f5761118c8e8b8f8789612387565b98505b604080516080810182526001600160a01b03949094168452602084018a9052830191909152606082015261010088015190935060531c60019081161480156111ef575060006111e388610100015160541c90565b6001600160a01b031614155b156113c657604051633157d5c760e21b8152600481018c90526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063c55f571c90602401602060405180830381865afa15801561125c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611280919061317f565b90506000604051806101800160405280336001600160a01b031681526020018f6001600160a01b031681526020018e81526020018a6020015181526020018d81526020018481526020018581526020018681526020016112ed8b6101000151600160519190911c81161490565b151581526020016000846002811115611308576113086131a0565b1461131b576113168b6124bf565b611324565b6113248b6124dc565b81526020018c81526020018b815250905061134489610100015160541c90565b6001600160a01b031663a51cfd18826040518263ffffffff1660e01b815260040161136f91906131b6565b6000604051808303816000875af115801561138e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526113b691908101906132ae565b91995090975095506113ca915050565b8893505b50508251849150156114245760005b83518110156114225760008482815181106113f6576113f6613169565b602002602001015160200151905080600014611419576114168184612cc7565b92505b506001016113d9565b505b3360009081526001602090815260408083208c845290915290205481111561145f576040516317e53f6760e11b815260040160405180910390fd5b8015611487573360009081526001602090815260408083208c84529091529020805482900390555b50600160008190555095509550955095915050565b6000816000036114ae5750600061155e565b828411156114be5750600061155e565b6040516321d1336160e11b8152600481018690526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906343a266c29060240161012060405180830381865afa158015611527573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061154b9190612c31565b905061155a8682878787612387565b9150505b949350505050565b60006115738484846121a5565b90505b9392505050565b6040516321d1336160e11b81526004810184905260009081906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906343a266c29060240161012060405180830381865afa1580156115e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061160c9190612c31565b9050600083611687576116828787848a6001600160a01b031663e5a6b10f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611659573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061167d9190612d42565b611eca565b611754565b61175486886001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156116c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116ed9190612d42565b896001600160a01b031663e5a6b10f6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561172b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061174f9190612d42565b6121a5565b9050806000036117695760009250505061155e565b604051632eec7b5560e11b8152600481018790526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635dd8f6aa90602401602060405180830381865afa1580156117d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117f59190612cda565b6001600160a01b031663c18f2d31886040518263ffffffff1660e01b815260040161182291815260200190565b602060405180830381865afa15801561183f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118639190612d42565b905080861115611879576000935050505061155e565b6118868784888486612387565b98975050505050505050565b61189a612556565b60006002600054036118be5760405162461bcd60e51b815260040161034b90612bea565b60026000556040516321d1336160e11b8152600481018690527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906343a266c29060240161012060405180830381865afa158015611929573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061194d9190612c31565b61010081015190925060491c60019081160361197c5760405163861e9dcd60e01b815260040160405180910390fd5b3360009081526002602090815260408083208884528252808320855184529091528120546119ab908690612cc7565b90506000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635dd8f6aa896040518263ffffffff1660e01b81526004016119fe91815260200190565b602060405180830381865afa158015611a1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a3f9190612cda565b6001600160a01b031663a29a68146040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aa09190612cda565b6001600160a01b031663e8db213089876020015133336001600160a01b031663fc0c546a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611af3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b179190612cda565b6040518563ffffffff1660e01b8152600401611b369493929190612cf7565b6040805180830381865afa158015611b52573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b769190612d1e565b9150915081831180611b86575081155b15611ba457604051630236b92b60e21b815260040160405180910390fd5b808614611bc45760405163e56ea4e760e01b815260040160405180910390fd5b6000336001600160a01b031663e5a6b10f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611c04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c289190612d42565b9050808714611c4657611c41886106ae6012600a612e3f565b611c48565b875b3360009081526001602090815260408083208d8452909152902054909550851115611c86576040516317e53f6760e11b815260040160405180910390fd5b50503360008181526002602090815260408083208b845282528083208851845282528083209590955591815260018083528482209982529890915291822080548490039055509490945593915050565b6000611dab83837f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166343a266c2866040518263ffffffff1660e01b8152600401611d2b91815260200190565b61012060405180830381865afa158015611d49573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d6d9190612c31565b866001600160a01b031663e5a6b10f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611659573d6000803e3d6000fd5b90505b92915050565b336000908152600160209081526040808320858452909152902054611dda908290612cc7565b336000908152600160209081526040808320958352949052929092209190915550565b6000808060001985870985870292508281108382030391505080600003611e3757838281611e2d57611e2d6133ce565b0492505050611576565b838110611e6157604051631dcf306360e21b8152600481018290526024810185905260440161034b565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b6001600160a01b0384166000908152600160209081526040808320868452909152812054808203611eff57600091505061155e565b604051632eec7b5560e11b81526004810186905260009081906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690635dd8f6aa90602401602060405180830381865afa158015611f69573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f8d9190612cda565b6001600160a01b031663a29a68146040518163ffffffff1660e01b8152600401602060405180830381865afa158015611fca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fee9190612cda565b6001600160a01b031663e8db21308888602001518b8c6001600160a01b031663fc0c546a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612041573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120659190612cda565b6040518563ffffffff1660e01b81526004016120849493929190612cf7565b6040805180830381865afa1580156120a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120c49190612d1e565b6001600160a01b038a1660009081526002602090815260408083208c845282528083208b518452909152812054929450909250906121029084612e4b565b905080158015906121135750858214155b1561218657612183816121286012600a612e3f565b604051635268657960e11b815260048101869052602481018a9052601260448201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a4d0caf290606401610705565b90505b808411612194576000612198565b8084035b9998505050505050505050565b60405163d175415360e01b81526004810184905260009081906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063d175415390602401600060405180830381865afa15801561220f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261223791908101906133e4565b90506000805b82518110156122e25782818151811061225857612258613169565b60200260200101516001600160a01b031663a32e1e96886040518263ffffffff1660e01b815260040161228d91815260200190565b602060405180830381865afa1580156122aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122ce9190612d42565b6122d89083612cc7565b915060010161223d565b5060006001851461235d57604051635268657960e11b8152600160048201526024810186905260126044820152612358908390670de0b6b3a7640000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063a4d0caf290606401610705565b61235f565b815b90508560121461237a57612375816012886124f9565b61237c565b805b979650505050505050565b60008284036123975750806124b6565b600080604051633157d5c760e21b8152600481018990527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063c55f571c90602401602060405180830381865afa1580156123ff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612423919061317f565b6002811115612434576124346131a0565b1461244757612442866124bf565b612450565b612450866124dc565b9050806000036124645760009150506124b6565b6000612471848787611dfd565b905061271082036124855791506124b69050565b6124b18161249f8861249986612710612e4b565b89611dfd565b6124a99085612cc7565b612710611dfd565b925050505b95945050505050565b60006028826101000151901c61ffff16612710611dae9190612e4b565b60006038826101000151901c61ffff16612710611dae9190612e4b565b6000828203612509575082611576565b828211156125375761251b8383612e4b565b61252690600a612e3f565b6125309085613473565b9050611576565b6125418284612e4b565b61254c90600a612e3f565b6125309085613492565b6040518061012001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b03168152602001600081525090565b6001600160a01b03811681146125c057600080fd5b50565b600080604083850312156125d657600080fd5b82356125e1816125ab565b946020939093013593505050565b60008060006060848603121561260457600080fd5b505081359360208301359350604090920135919050565b805182526020808201519083015260408082015190830152606080820151908301526080808201519083015260a0808201519083015260c0808201519083015260e0808201516001600160a01b03169083015261010090810151910152565b6101408101612689828561261b565b826101208301529392505050565b60008083601f8401126126a957600080fd5b50813567ffffffffffffffff8111156126c157600080fd5b6020830191508360208285010111156126d957600080fd5b9250929050565b634e487b7160e01b600052604160045260246000fd5b604051610120810167ffffffffffffffff8111828210171561271a5761271a6126e0565b60405290565b6040516060810167ffffffffffffffff8111828210171561271a5761271a6126e0565b604051601f8201601f1916810167ffffffffffffffff8111828210171561276c5761276c6126e0565b604052919050565b600067ffffffffffffffff82111561278e5761278e6126e0565b50601f01601f191660200190565b60006127af6127aa84612774565b612743565b90508281528383830111156127c357600080fd5b828260208301376000602084830101529392505050565b600082601f8301126127eb57600080fd5b611dab8383356020850161279c565b600080600080600080600080888a0361014081121561281857600080fd5b8935612823816125ab565b98506080601f198201121561283757600080fd5b5060208901965060a0890135955060c0890135945060e089013561285a816125ab565b935061010089013567ffffffffffffffff8082111561287857600080fd5b6128848c838d01612697565b90955093506101208b013591508082111561289e57600080fd5b506128ab8b828c016127da565b9150509295985092959890939650565b60005b838110156128d65781810151838201526020016128be565b50506000910152565b600081518084526128f78160208601602086016128bb565b601f01601f19169290920160200192915050565b600061018080830161291d848961261b565b61012084018790526101408401919091528451908190526101a080840191600581901b850190910190602080880160005b838110156129a65787850361019f19018652815180516001600160a01b031686528381015184870152604090810151606091870182905290612992818801836128df565b97850197965050509082019060010161294e565b505050508381036101608501526124b181866128df565b6000602082840312156129cf57600080fd5b5035919050565b600080600080600060a086880312156129ee57600080fd5b85356129f9816125ab565b94506020860135935060408601359250606086013567ffffffffffffffff80821115612a2457600080fd5b818801915088601f830112612a3857600080fd5b612a478983356020850161279c565b93506080880135915080821115612a5d57600080fd5b50612a6a888289016127da565b9150509295509295909350565b6000610180808301612a89848961261b565b61012084018790526101408401919091528451908190526101a080840191600581901b850190910190602080880160005b838110156129a65787850361019f19018652815180516001600160a01b031686528381015184870152604090810151606091870182905290612afe818801836128df565b978501979650505090820190600101612aba565b60008060008060808587031215612b2857600080fd5b5050823594602084013594506040840135936060013592509050565b60008060008060808587031215612b5a57600080fd5b8435612b65816125ab565b9350602085013592506040850135915060608501358015158114612b8857600080fd5b939692955090935050565b600080600060608486031215612ba857600080fd5b8335612bb3816125ab565b95602085013595506040909401359392505050565b60008060408385031215612bdb57600080fd5b50508035926020909101359150565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b8051612c2c816125ab565b919050565b60006101208284031215612c4457600080fd5b612c4c6126f6565b825181526020830151602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c0820152612c9860e08401612c21565b60e0820152610100928301519281019290925250919050565b634e487b7160e01b600052601160045260246000fd5b80820180821115611dae57611dae612cb1565b600060208284031215612cec57600080fd5b8151611576816125ab565b93845260208401929092526001600160a01b03908116604084015216606082015260800190565b60008060408385031215612d3157600080fd5b505080516020909101519092909150565b600060208284031215612d5457600080fd5b5051919050565b600181815b80851115612d96578160001904821115612d7c57612d7c612cb1565b80851615612d8957918102915b93841c9390800290612d60565b509250929050565b600082612dad57506001611dae565b81612dba57506000611dae565b8160018114612dd05760028114612dda57612df6565b6001915050611dae565b60ff841115612deb57612deb612cb1565b50506001821b611dae565b5060208310610133831016604e8410600b8410161715612e19575081810a611dae565b612e238383612d5b565b8060001904821115612e3757612e37612cb1565b029392505050565b6000611dab8383612d9e565b81810381811115611dae57611dae612cb1565b600060808284031215612e7057600080fd5b6040516080810181811067ffffffffffffffff82111715612e9357612e936126e0565b6040528235612ea1816125ab565b808252506020830135602082015260408301356040820152606083013560608201528091505092915050565b60208152612ee76020820183516001600160a01b03169052565b60006020830151612f0360408401826001600160a01b03169052565b506040830151612f3d606084018280516001600160a01b031682526020808201519083015260408082015190830152606090810151910152565b50606083015160e08301526080830151610100818185015260a08501519150610120612f73818601846001600160a01b03169052565b60c086015161014086015260e08601516101608601528186015192506101a0915081610180860152612fa96101c08601846128df565b90860151858203601f190183870152909250612fc583826128df565b9695505050505050565b600082601f830112612fe057600080fd5b8151612fee6127aa82612774565b81815284602083860101111561300357600080fd5b61155e8260208301602087016128bb565b600067ffffffffffffffff82111561302e5761302e6126e0565b5060051b60200190565b60008060006060848603121561304d57600080fd5b8351925060208085015167ffffffffffffffff8082111561306d57600080fd5b61307988838901612fcf565b9450604087015191508082111561308f57600080fd5b818701915087601f8301126130a357600080fd5b81516130b16127aa82613014565b81815260059190911b8301840190848101908a8311156130d057600080fd5b8585015b83811015613158578051858111156130ec5760008081fd5b86016060818e03601f190112156131035760008081fd5b61310b612720565b88820151613118816125ab565b81526040820151898201526060820151878111156131365760008081fd5b6131448f8b83860101612fcf565b6040830152508452509186019186016130d4565b508096505050505050509250925092565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561319157600080fd5b81516003811061157657600080fd5b634e487b7160e01b600052602160045260246000fd5b602081526131d06020820183516001600160a01b03169052565b600060208301516131ec60408401826001600160a01b03169052565b506040830151606083015260608301516080830152608083015160a083015260a083015160c083015260c083015160e083015260e083015161010061325a8185018380516001600160a01b031682526020808201519083015260408082015190830152606090810151910152565b8401511515610180840152506101208301516101a08301526101408301516101e06101c084018190526132916102008501836128df565b9150610160850151601f198584030182860152612fc583826128df565b6000806000606084860312156132c357600080fd5b8351925060208085015167ffffffffffffffff808211156132e357600080fd5b6132ef88838901612fcf565b9450604087015191508082111561330557600080fd5b818701915087601f83011261331957600080fd5b81516133276127aa82613014565b81815260059190911b8301840190848101908a83111561334657600080fd5b8585015b83811015613158578051858111156133625760008081fd5b86016060818e03601f190112156133795760008081fd5b613381612720565b8882015161338e816125ab565b81526040820151898201526060820151878111156133ac5760008081fd5b6133ba8f8b83860101612fcf565b60408301525084525091860191860161334a565b634e487b7160e01b600052601260045260246000fd5b600060208083850312156133f757600080fd5b825167ffffffffffffffff81111561340e57600080fd5b8301601f8101851361341f57600080fd5b805161342d6127aa82613014565b81815260059190911b8201830190838101908783111561344c57600080fd5b928401925b8284101561237c578351613464816125ab565b82529284019290840190613451565b600081600019048311821515161561348d5761348d612cb1565b500290565b6000826134af57634e487b7160e01b600052601260045260246000fd5b50049056fea26469706673582212207c0b0d6ef21a30936e47f919249183a609014eddc061713ac513cccd6177f36164736f6c63430008100033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100ff5760003560e01c8063c294b2f411610097578063d49031c011610066578063d49031c014610295578063d4c3a8d2146102a8578063e7c8e3e3146102d9578063e8ba563a146102ee57600080fd5b8063c294b2f414610221578063c41c2f2414610234578063c66445971461025b578063d3419bf31461026e57600080fd5b80636bb6a5ad116100d35780636bb6a5ad146101c5578063a2df1f95146101d8578063a57c7f59146101fb578063b753d7e91461020e57600080fd5b8062fdd58e1461010457806325386715146101425780632fa1b39114610163578063557e715514610186575b600080fd5b61012f6101123660046125c3565b600160209081526000928352604080842090915290825290205481565b6040519081526020015b60405180910390f35b6101556101503660046125ef565b61031f565b60405161013992919061267a565b6101766101713660046127fa565b6107f5565b604051610139949392919061290b565b6101ad7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610139565b61012f6101d33660046129bd565b610cc5565b6101eb6101e63660046129d6565b610dd2565b6040516101399493929190612a77565b61012f610209366004612b12565b61149c565b61012f61021c3660046125ef565b611566565b61012f61022f366004612b44565b61157d565b6101ad7f000000000000000000000000000000000000000000000000000000000000000081565b6101556102693660046125ef565b611892565b6101ad7f000000000000000000000000000000000000000000000000000000000000000081565b61012f6102a33660046125c3565b611cd6565b61012f6102b6366004612b93565b600360209081526000938452604080852082529284528284209052825290205481565b6102ec6102e7366004612bc8565b611db4565b005b61012f6102fc366004612b93565b600260209081526000938452604080852082529284528284209052825290205481565b610327612556565b60006002600054036103545760405162461bcd60e51b815260040161034b90612bea565b60405180910390fd5b60026000556040516321d1336160e11b8152600481018690527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906343a266c29060240161012060405180830381865afa1580156103bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103e39190612c31565b336000908152600360209081526040808320898452825280832082850151845290915281205491935090610418908690612cc7565b90506000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635dd8f6aa896040518263ffffffff1660e01b815260040161046b91815260200190565b602060405180830381865afa158015610488573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104ac9190612cda565b6001600160a01b031663a29a68146040518163ffffffff1660e01b8152600401602060405180830381865afa1580156104e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061050d9190612cda565b6001600160a01b0316637a81b56289876020015133336001600160a01b031663fc0c546a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610560573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105849190612cda565b6040518563ffffffff1660e01b81526004016105a39493929190612cf7565b6040805180830381865afa1580156105bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105e39190612d1e565b91509150818311806105f3575081155b1561061157604051635b76558960e11b815260040160405180910390fd5b8086146106315760405163e56ea4e760e01b815260040160405180910390fd5b6000336001600160a01b031663e5a6b10f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610671573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106959190612d42565b90508087146107505761074b886106ae6012600a612e3f565b604051635268657960e11b8152600481018b905260248101859052601260448201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a4d0caf2906064015b602060405180830381865afa158015610722573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107469190612d42565b611dfd565b610752565b875b9450610760338a8884611eca565b851115610780576040516317e53f6760e11b815260040160405180910390fd5b3360008181526003602090815260408083208d845282528083208a83015184528252808320889055928252600181528282208c8352905220546107c4908690612e4b565b3360009081526001602081815260408084209d84529c90529a81209190915598909855509296919550909350505050565b6107fd612556565b60006060806002600054036108245760405162461bcd60e51b815260040161034b90612bea565b60026000556040516321d1336160e11b8152600481018b90527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906343a266c29060240161012060405180830381865afa15801561088f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108b39190612c31565b80519094506000036108d85760405163174b338d60e11b815260040160405180910390fd5b61010084015160481c6001908116036109045760405163a3bb913360e01b815260040160405180910390fd5b61010084015160009060521c600190811614801561093a5750600061092e86610100015160541c90565b6001600160a01b031614155b15610a8c576000604051806101400160405280336001600160a01b031681526020018f6001600160a01b031681526020018e80360381019061097c9190612e5e565b815260208082018f905288015160408201526001600160a01b038c16606082015260a080890151608083015261010089015191019060181c61ffff1681526020018a8a8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050908252506020018890529050610a0d86610100015160541c90565b6001600160a01b031663d46cf171826040518263ffffffff1660e01b8152600401610a389190612ecd565b6000604051808303816000875af1158015610a57573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610a7f9190810190613038565b955093509150610acd9050565b8460a00151905087878080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509294505050505b825160208d01359015610b495760005b8451811015610b47576000858281518110610afa57610afa613169565b602002602001015160200151905080600014610b3e5782811115610b31576040516336a8da9360e11b815260040160405180910390fd5b610b3b8184612e4b565b92505b50600101610add565b505b8c60200135600003610b61575060009350610cae9050565b8015610bc8573360009081526001602090815260408083208f8452909152902054610b8d908290612cc7565b60016000336001600160a01b03166001600160a01b0316815260200190815260200160002060008e8152602001908152602001600020819055505b5080600003610bdb575060009250610cae565b60408c0135600060608e01358c14610c8c57604051635268657960e11b815260608f01356004820152602481018d9052604481018390526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063a4d0caf290606401602060405180830381865afa158015610c63573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c879190612d42565b610c97565b610c9782600a612e3f565b9050610ca88e602001358483611dfd565b95505050505b600160008190555098509850985098945050505050565b6000600260005403610ce95760405162461bcd60e51b815260040161034b90612bea565b600260009081556040516321d1336160e11b8152600481018490527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906343a266c29060240161012060405180830381865afa158015610d56573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d7a9190612c31565b610100810151909150604d1c600190811614610da9576040516373e4f05f60e11b815260040160405180910390fd5b505033600090815260016020818152604080842094845293905291812080549082905591905590565b610dda612556565b6000606080600260005403610e015760405162461bcd60e51b815260040161034b90612bea565b60026000556040516321d1336160e11b8152600481018990527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906343a266c29060240161012060405180830381865afa158015610e6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e909190612c31565b610100810151909450604a1c600190811603610ebf5760405163a97cf58f60e01b815260040160405180910390fd5b610ef3604051806080016040528060006001600160a01b031681526020016000815260200160008152602001600081525090565b6000806000336001600160a01b031663fc0c546a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f5a9190612cda565b90506000336001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f9c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fc09190612d42565b90506000336001600160a01b031663e5a6b10f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611002573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110269190612d42565b6101008b015190915060511c60019081161461104d57611048338f8c84611eca565b611058565b6110588e83836121a5565b94507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635dd8f6aa8f6040518263ffffffff1660e01b81526004016110a891815260200190565b602060405180830381865afa1580156110c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110e99190612cda565b6001600160a01b031663c18f2d318f6040518263ffffffff1660e01b815260040161111691815260200190565b602060405180830381865afa158015611133573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111579190612d42565b9350838d111561117957604051625c579160e91b815260040160405180910390fd5b841561118f5761118c8e8b8f8789612387565b98505b604080516080810182526001600160a01b03949094168452602084018a9052830191909152606082015261010088015190935060531c60019081161480156111ef575060006111e388610100015160541c90565b6001600160a01b031614155b156113c657604051633157d5c760e21b8152600481018c90526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063c55f571c90602401602060405180830381865afa15801561125c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611280919061317f565b90506000604051806101800160405280336001600160a01b031681526020018f6001600160a01b031681526020018e81526020018a6020015181526020018d81526020018481526020018581526020018681526020016112ed8b6101000151600160519190911c81161490565b151581526020016000846002811115611308576113086131a0565b1461131b576113168b6124bf565b611324565b6113248b6124dc565b81526020018c81526020018b815250905061134489610100015160541c90565b6001600160a01b031663a51cfd18826040518263ffffffff1660e01b815260040161136f91906131b6565b6000604051808303816000875af115801561138e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526113b691908101906132ae565b91995090975095506113ca915050565b8893505b50508251849150156114245760005b83518110156114225760008482815181106113f6576113f6613169565b602002602001015160200151905080600014611419576114168184612cc7565b92505b506001016113d9565b505b3360009081526001602090815260408083208c845290915290205481111561145f576040516317e53f6760e11b815260040160405180910390fd5b8015611487573360009081526001602090815260408083208c84529091529020805482900390555b50600160008190555095509550955095915050565b6000816000036114ae5750600061155e565b828411156114be5750600061155e565b6040516321d1336160e11b8152600481018690526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906343a266c29060240161012060405180830381865afa158015611527573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061154b9190612c31565b905061155a8682878787612387565b9150505b949350505050565b60006115738484846121a5565b90505b9392505050565b6040516321d1336160e11b81526004810184905260009081906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906343a266c29060240161012060405180830381865afa1580156115e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061160c9190612c31565b9050600083611687576116828787848a6001600160a01b031663e5a6b10f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611659573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061167d9190612d42565b611eca565b611754565b61175486886001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156116c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116ed9190612d42565b896001600160a01b031663e5a6b10f6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561172b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061174f9190612d42565b6121a5565b9050806000036117695760009250505061155e565b604051632eec7b5560e11b8152600481018790526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635dd8f6aa90602401602060405180830381865afa1580156117d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117f59190612cda565b6001600160a01b031663c18f2d31886040518263ffffffff1660e01b815260040161182291815260200190565b602060405180830381865afa15801561183f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118639190612d42565b905080861115611879576000935050505061155e565b6118868784888486612387565b98975050505050505050565b61189a612556565b60006002600054036118be5760405162461bcd60e51b815260040161034b90612bea565b60026000556040516321d1336160e11b8152600481018690527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906343a266c29060240161012060405180830381865afa158015611929573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061194d9190612c31565b61010081015190925060491c60019081160361197c5760405163861e9dcd60e01b815260040160405180910390fd5b3360009081526002602090815260408083208884528252808320855184529091528120546119ab908690612cc7565b90506000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635dd8f6aa896040518263ffffffff1660e01b81526004016119fe91815260200190565b602060405180830381865afa158015611a1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a3f9190612cda565b6001600160a01b031663a29a68146040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aa09190612cda565b6001600160a01b031663e8db213089876020015133336001600160a01b031663fc0c546a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611af3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b179190612cda565b6040518563ffffffff1660e01b8152600401611b369493929190612cf7565b6040805180830381865afa158015611b52573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b769190612d1e565b9150915081831180611b86575081155b15611ba457604051630236b92b60e21b815260040160405180910390fd5b808614611bc45760405163e56ea4e760e01b815260040160405180910390fd5b6000336001600160a01b031663e5a6b10f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611c04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c289190612d42565b9050808714611c4657611c41886106ae6012600a612e3f565b611c48565b875b3360009081526001602090815260408083208d8452909152902054909550851115611c86576040516317e53f6760e11b815260040160405180910390fd5b50503360008181526002602090815260408083208b845282528083208851845282528083209590955591815260018083528482209982529890915291822080548490039055509490945593915050565b6000611dab83837f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166343a266c2866040518263ffffffff1660e01b8152600401611d2b91815260200190565b61012060405180830381865afa158015611d49573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d6d9190612c31565b866001600160a01b031663e5a6b10f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611659573d6000803e3d6000fd5b90505b92915050565b336000908152600160209081526040808320858452909152902054611dda908290612cc7565b336000908152600160209081526040808320958352949052929092209190915550565b6000808060001985870985870292508281108382030391505080600003611e3757838281611e2d57611e2d6133ce565b0492505050611576565b838110611e6157604051631dcf306360e21b8152600481018290526024810185905260440161034b565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b6001600160a01b0384166000908152600160209081526040808320868452909152812054808203611eff57600091505061155e565b604051632eec7b5560e11b81526004810186905260009081906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690635dd8f6aa90602401602060405180830381865afa158015611f69573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f8d9190612cda565b6001600160a01b031663a29a68146040518163ffffffff1660e01b8152600401602060405180830381865afa158015611fca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fee9190612cda565b6001600160a01b031663e8db21308888602001518b8c6001600160a01b031663fc0c546a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612041573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120659190612cda565b6040518563ffffffff1660e01b81526004016120849493929190612cf7565b6040805180830381865afa1580156120a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120c49190612d1e565b6001600160a01b038a1660009081526002602090815260408083208c845282528083208b518452909152812054929450909250906121029084612e4b565b905080158015906121135750858214155b1561218657612183816121286012600a612e3f565b604051635268657960e11b815260048101869052602481018a9052601260448201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a4d0caf290606401610705565b90505b808411612194576000612198565b8084035b9998505050505050505050565b60405163d175415360e01b81526004810184905260009081906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063d175415390602401600060405180830381865afa15801561220f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261223791908101906133e4565b90506000805b82518110156122e25782818151811061225857612258613169565b60200260200101516001600160a01b031663a32e1e96886040518263ffffffff1660e01b815260040161228d91815260200190565b602060405180830381865afa1580156122aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122ce9190612d42565b6122d89083612cc7565b915060010161223d565b5060006001851461235d57604051635268657960e11b8152600160048201526024810186905260126044820152612358908390670de0b6b3a7640000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063a4d0caf290606401610705565b61235f565b815b90508560121461237a57612375816012886124f9565b61237c565b805b979650505050505050565b60008284036123975750806124b6565b600080604051633157d5c760e21b8152600481018990527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063c55f571c90602401602060405180830381865afa1580156123ff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612423919061317f565b6002811115612434576124346131a0565b1461244757612442866124bf565b612450565b612450866124dc565b9050806000036124645760009150506124b6565b6000612471848787611dfd565b905061271082036124855791506124b69050565b6124b18161249f8861249986612710612e4b565b89611dfd565b6124a99085612cc7565b612710611dfd565b925050505b95945050505050565b60006028826101000151901c61ffff16612710611dae9190612e4b565b60006038826101000151901c61ffff16612710611dae9190612e4b565b6000828203612509575082611576565b828211156125375761251b8383612e4b565b61252690600a612e3f565b6125309085613473565b9050611576565b6125418284612e4b565b61254c90600a612e3f565b6125309085613492565b6040518061012001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b03168152602001600081525090565b6001600160a01b03811681146125c057600080fd5b50565b600080604083850312156125d657600080fd5b82356125e1816125ab565b946020939093013593505050565b60008060006060848603121561260457600080fd5b505081359360208301359350604090920135919050565b805182526020808201519083015260408082015190830152606080820151908301526080808201519083015260a0808201519083015260c0808201519083015260e0808201516001600160a01b03169083015261010090810151910152565b6101408101612689828561261b565b826101208301529392505050565b60008083601f8401126126a957600080fd5b50813567ffffffffffffffff8111156126c157600080fd5b6020830191508360208285010111156126d957600080fd5b9250929050565b634e487b7160e01b600052604160045260246000fd5b604051610120810167ffffffffffffffff8111828210171561271a5761271a6126e0565b60405290565b6040516060810167ffffffffffffffff8111828210171561271a5761271a6126e0565b604051601f8201601f1916810167ffffffffffffffff8111828210171561276c5761276c6126e0565b604052919050565b600067ffffffffffffffff82111561278e5761278e6126e0565b50601f01601f191660200190565b60006127af6127aa84612774565b612743565b90508281528383830111156127c357600080fd5b828260208301376000602084830101529392505050565b600082601f8301126127eb57600080fd5b611dab8383356020850161279c565b600080600080600080600080888a0361014081121561281857600080fd5b8935612823816125ab565b98506080601f198201121561283757600080fd5b5060208901965060a0890135955060c0890135945060e089013561285a816125ab565b935061010089013567ffffffffffffffff8082111561287857600080fd5b6128848c838d01612697565b90955093506101208b013591508082111561289e57600080fd5b506128ab8b828c016127da565b9150509295985092959890939650565b60005b838110156128d65781810151838201526020016128be565b50506000910152565b600081518084526128f78160208601602086016128bb565b601f01601f19169290920160200192915050565b600061018080830161291d848961261b565b61012084018790526101408401919091528451908190526101a080840191600581901b850190910190602080880160005b838110156129a65787850361019f19018652815180516001600160a01b031686528381015184870152604090810151606091870182905290612992818801836128df565b97850197965050509082019060010161294e565b505050508381036101608501526124b181866128df565b6000602082840312156129cf57600080fd5b5035919050565b600080600080600060a086880312156129ee57600080fd5b85356129f9816125ab565b94506020860135935060408601359250606086013567ffffffffffffffff80821115612a2457600080fd5b818801915088601f830112612a3857600080fd5b612a478983356020850161279c565b93506080880135915080821115612a5d57600080fd5b50612a6a888289016127da565b9150509295509295909350565b6000610180808301612a89848961261b565b61012084018790526101408401919091528451908190526101a080840191600581901b850190910190602080880160005b838110156129a65787850361019f19018652815180516001600160a01b031686528381015184870152604090810151606091870182905290612afe818801836128df565b978501979650505090820190600101612aba565b60008060008060808587031215612b2857600080fd5b5050823594602084013594506040840135936060013592509050565b60008060008060808587031215612b5a57600080fd5b8435612b65816125ab565b9350602085013592506040850135915060608501358015158114612b8857600080fd5b939692955090935050565b600080600060608486031215612ba857600080fd5b8335612bb3816125ab565b95602085013595506040909401359392505050565b60008060408385031215612bdb57600080fd5b50508035926020909101359150565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b8051612c2c816125ab565b919050565b60006101208284031215612c4457600080fd5b612c4c6126f6565b825181526020830151602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c0820152612c9860e08401612c21565b60e0820152610100928301519281019290925250919050565b634e487b7160e01b600052601160045260246000fd5b80820180821115611dae57611dae612cb1565b600060208284031215612cec57600080fd5b8151611576816125ab565b93845260208401929092526001600160a01b03908116604084015216606082015260800190565b60008060408385031215612d3157600080fd5b505080516020909101519092909150565b600060208284031215612d5457600080fd5b5051919050565b600181815b80851115612d96578160001904821115612d7c57612d7c612cb1565b80851615612d8957918102915b93841c9390800290612d60565b509250929050565b600082612dad57506001611dae565b81612dba57506000611dae565b8160018114612dd05760028114612dda57612df6565b6001915050611dae565b60ff841115612deb57612deb612cb1565b50506001821b611dae565b5060208310610133831016604e8410600b8410161715612e19575081810a611dae565b612e238383612d5b565b8060001904821115612e3757612e37612cb1565b029392505050565b6000611dab8383612d9e565b81810381811115611dae57611dae612cb1565b600060808284031215612e7057600080fd5b6040516080810181811067ffffffffffffffff82111715612e9357612e936126e0565b6040528235612ea1816125ab565b808252506020830135602082015260408301356040820152606083013560608201528091505092915050565b60208152612ee76020820183516001600160a01b03169052565b60006020830151612f0360408401826001600160a01b03169052565b506040830151612f3d606084018280516001600160a01b031682526020808201519083015260408082015190830152606090810151910152565b50606083015160e08301526080830151610100818185015260a08501519150610120612f73818601846001600160a01b03169052565b60c086015161014086015260e08601516101608601528186015192506101a0915081610180860152612fa96101c08601846128df565b90860151858203601f190183870152909250612fc583826128df565b9695505050505050565b600082601f830112612fe057600080fd5b8151612fee6127aa82612774565b81815284602083860101111561300357600080fd5b61155e8260208301602087016128bb565b600067ffffffffffffffff82111561302e5761302e6126e0565b5060051b60200190565b60008060006060848603121561304d57600080fd5b8351925060208085015167ffffffffffffffff8082111561306d57600080fd5b61307988838901612fcf565b9450604087015191508082111561308f57600080fd5b818701915087601f8301126130a357600080fd5b81516130b16127aa82613014565b81815260059190911b8301840190848101908a8311156130d057600080fd5b8585015b83811015613158578051858111156130ec5760008081fd5b86016060818e03601f190112156131035760008081fd5b61310b612720565b88820151613118816125ab565b81526040820151898201526060820151878111156131365760008081fd5b6131448f8b83860101612fcf565b6040830152508452509186019186016130d4565b508096505050505050509250925092565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561319157600080fd5b81516003811061157657600080fd5b634e487b7160e01b600052602160045260246000fd5b602081526131d06020820183516001600160a01b03169052565b600060208301516131ec60408401826001600160a01b03169052565b506040830151606083015260608301516080830152608083015160a083015260a083015160c083015260c083015160e083015260e083015161010061325a8185018380516001600160a01b031682526020808201519083015260408082015190830152606090810151910152565b8401511515610180840152506101208301516101a08301526101408301516101e06101c084018190526132916102008501836128df565b9150610160850151601f198584030182860152612fc583826128df565b6000806000606084860312156132c357600080fd5b8351925060208085015167ffffffffffffffff808211156132e357600080fd5b6132ef88838901612fcf565b9450604087015191508082111561330557600080fd5b818701915087601f83011261331957600080fd5b81516133276127aa82613014565b81815260059190911b8301840190848101908a83111561334657600080fd5b8585015b83811015613158578051858111156133625760008081fd5b86016060818e03601f190112156133795760008081fd5b613381612720565b8882015161338e816125ab565b81526040820151898201526060820151878111156133ac5760008081fd5b6133ba8f8b83860101612fcf565b60408301525084525091860191860161334a565b634e487b7160e01b600052601260045260246000fd5b600060208083850312156133f757600080fd5b825167ffffffffffffffff81111561340e57600080fd5b8301601f8101851361341f57600080fd5b805161342d6127aa82613014565b81815260059190911b8201830190838101908783111561344c57600080fd5b928401925b8284101561237c578351613464816125ab565b82529284019290840190613451565b600081600019048311821515161561348d5761348d612cb1565b500290565b6000826134af57634e487b7160e01b600052601260045260246000fd5b50049056fea26469706673582212207c0b0d6ef21a30936e47f919249183a609014eddc061713ac513cccd6177f36164736f6c63430008100033", + "devdoc": { + "details": "This Store expects a project's controller to be an IJBController3_1.", + "kind": "dev", + "methods": { + "constructor": { + "params": { + "_directory": "A contract storing directories of terminals and controllers for each project.", + "_fundingCycleStore": "A contract storing all funding cycle configurations.", + "_prices": "A contract that exposes price feeds." + } + }, + "currentOverflowOf(address,uint256)": { + "details": "The current overflow is represented as a fixed point number with the same amount of decimals as the specified terminal.", + "params": { + "_projectId": "The ID of the project to get overflow for.", + "_terminal": "The terminal for which the overflow is being calculated." + }, + "returns": { + "_0": "The current amount of overflow that project has in the specified terminal." + } + }, + "currentReclaimableOverflowOf(address,uint256,uint256,bool)": { + "details": "If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.The current reclaimable overflow is returned in terms of the specified terminal's currency.The reclaimable overflow is represented as a fixed point number with the same amount of decimals as the specified terminal.", + "params": { + "_projectId": "The ID of the project to get the reclaimable overflow amount for.", + "_terminal": "The terminal from which the reclaimable amount would come.", + "_tokenCount": "The number of tokens to make the calculation with, as a fixed point number with 18 decimals.", + "_useTotalOverflow": "A flag indicating whether the overflow used in the calculation should be summed from all of the project's terminals. If false, overflow should be limited to the amount in the specified `_terminal`." + }, + "returns": { + "_0": "The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_terminal`." + } + }, + "currentReclaimableOverflowOf(uint256,uint256,uint256,uint256)": { + "details": "If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.", + "params": { + "_overflow": "The amount of overflow to make the calculation with, as a fixed point number.", + "_projectId": "The ID of the project to get the reclaimable overflow amount for.", + "_tokenCount": "The number of tokens to make the calculation with, as a fixed point number with 18 decimals.", + "_totalSupply": "The total number of tokens to make the calculation with, as a fixed point number with 18 decimals." + }, + "returns": { + "_0": "The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_overflow`." + } + }, + "currentTotalOverflowOf(uint256,uint256,uint256)": { + "params": { + "_currency": "The currency that the total overflow should be in terms of.", + "_decimals": "The number of decimals that the fixed point overflow should include.", + "_projectId": "The ID of the project to get total overflow for." + }, + "returns": { + "_0": "The current total amount of overflow that project has across all terminals." + } + }, + "recordAddedBalanceFor(uint256,uint256)": { + "details": "The msg.sender must be an IJBSingleTokenPaymentTerminal.", + "params": { + "_amount": "The amount of terminal tokens added, as a fixed point number with the same amount of decimals as its relative terminal.", + "_projectId": "The ID of the project to which the funds being added belong." + } + }, + "recordDistributionFor(uint256,uint256,uint256)": { + "details": "The msg.sender must be an IJBSingleTokenPaymentTerminal.", + "params": { + "_amount": "The amount to use from the distribution limit, as a fixed point number.", + "_currency": "The currency of the `_amount`. This must match the project's current funding cycle's currency.", + "_projectId": "The ID of the project that is having funds distributed." + }, + "returns": { + "distributedAmount": "The amount of terminal tokens distributed, as a fixed point number with the same amount of decimals as its relative terminal.", + "fundingCycle": "The funding cycle during which the distribution was made." + } + }, + "recordMigration(uint256)": { + "details": "The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount returned is in terms of the msg.senders tokens.", + "params": { + "_projectId": "The ID of the project being migrated." + }, + "returns": { + "balance": "The project's migrated balance, as a fixed point number with the same amount of decimals as its relative terminal." + } + }, + "recordPaymentFrom(address,(address,uint256,uint256,uint256),uint256,uint256,address,string,bytes)": { + "details": "Mints the project's tokens according to values provided by a configured data source. If no data source is configured, mints tokens proportional to the amount of the contribution.The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.sender's tokens.", + "params": { + "_amount": "The amount of tokens being paid. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.", + "_baseWeightCurrency": "The currency to base token issuance on.", + "_beneficiary": "The specified address that should be the beneficiary of anything that results from the payment.", + "_memo": "A memo to pass along to the emitted event, and passed along to the funding cycle's data source.", + "_metadata": "Bytes to send along to the data source, if one is provided.", + "_payer": "The original address that sent the payment to the terminal.", + "_projectId": "The ID of the project being paid." + }, + "returns": { + "delegateAllocations": "The amount to send to delegates instead of adding to the local balance.", + "fundingCycle": "The project's funding cycle during which payment was made.", + "memo": "A memo that should be passed along to the emitted event.", + "tokenCount": "The number of project tokens that were minted, as a fixed point number with 18 decimals." + } + }, + "recordRedemptionFor(address,uint256,uint256,string,bytes)": { + "details": "Redeems the project's tokens according to values provided by a configured data source. If no data source is configured, redeems tokens along a redemption bonding curve that is a function of the number of tokens being burned.The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.senders tokens.", + "params": { + "_holder": "The account that is having its tokens redeemed.", + "_memo": "A memo to pass along to the emitted event.", + "_metadata": "Bytes to send along to the data source, if one is provided.", + "_projectId": "The ID of the project to which the tokens being redeemed belong.", + "_tokenCount": "The number of project tokens to redeem, as a fixed point number with 18 decimals." + }, + "returns": { + "delegateAllocations": "The amount to send to delegates instead of sending to the beneficiary.", + "fundingCycle": "The funding cycle during which the redemption was made.", + "memo": "A memo that should be passed along to the emitted event.", + "reclaimAmount": "The amount of terminal tokens reclaimed, as a fixed point number with 18 decimals." + } + }, + "recordUsedAllowanceOf(uint256,uint256,uint256)": { + "details": "The msg.sender must be an IJBSingleTokenPaymentTerminal.", + "params": { + "_amount": "The amount to use from the allowance, as a fixed point number.", + "_currency": "The currency of the `_amount`. Must match the currency of the overflow allowance.", + "_projectId": "The ID of the project to use the allowance of." + }, + "returns": { + "fundingCycle": "The funding cycle during which the overflow allowance is being used.", + "usedAmount": "The amount of terminal tokens used, as a fixed point number with the same amount of decimals as its relative terminal." + } + } + }, + "stateVariables": { + "balanceOf": { + "custom:param": "_terminal The terminal to which the balance applies._projectId The ID of the project to get the balance of.", + "details": "The balance is represented as a fixed point number with the same amount of decimals as its relative terminal." + }, + "usedDistributionLimitOf": { + "custom:param": "_terminal The terminal to which the used distribution limit applies._projectId The ID of the project to get the used distribution limit of._fundingCycleNumber The number of the funding cycle during which the distribution limit was used.", + "details": "Increases as projects use their preconfigured distribution limits.The used distribution limit is represented as a fixed point number with the same amount of decimals as its relative terminal." + }, + "usedOverflowAllowanceOf": { + "custom:param": "_terminal The terminal to which the overflow allowance applies._projectId The ID of the project to get the used overflow allowance of._configuration The configuration of the during which the allowance was used.", + "details": "Increases as projects use their allowance.The used allowance is represented as a fixed point number with the same amount of decimals as its relative terminal." + } + }, + "version": 1 + }, + "userdoc": { + "errors": { + "PRBMath__MulDivOverflow(uint256,uint256)": [ + { + "notice": "Emitted when the result overflows uint256." + } + ] + }, + "kind": "user", + "methods": { + "balanceOf(address,uint256)": { + "notice": "The amount of tokens that each project has for each terminal, in terms of the terminal's token." + }, + "currentOverflowOf(address,uint256)": { + "notice": "Gets the current overflowed amount in a terminal for a specified project." + }, + "currentReclaimableOverflowOf(address,uint256,uint256,bool)": { + "notice": "The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the total token supply and overflow in the ecosystem." + }, + "currentReclaimableOverflowOf(uint256,uint256,uint256,uint256)": { + "notice": "The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the specified total token supply and overflow amounts." + }, + "currentTotalOverflowOf(uint256,uint256,uint256)": { + "notice": "Gets the current overflowed amount for a specified project across all terminals." + }, + "directory()": { + "notice": "The directory of terminals and controllers for projects." + }, + "fundingCycleStore()": { + "notice": "The contract storing all funding cycle configurations." + }, + "prices()": { + "notice": "The contract that exposes price feeds." + }, + "recordAddedBalanceFor(uint256,uint256)": { + "notice": "Records newly added funds for the project." + }, + "recordDistributionFor(uint256,uint256,uint256)": { + "notice": "Records newly distributed funds for a project." + }, + "recordMigration(uint256)": { + "notice": "Records the migration of funds from this store." + }, + "recordPaymentFrom(address,(address,uint256,uint256,uint256),uint256,uint256,address,string,bytes)": { + "notice": "Records newly contributed tokens to a project." + }, + "recordRedemptionFor(address,uint256,uint256,string,bytes)": { + "notice": "Records newly redeemed tokens of a project." + }, + "recordUsedAllowanceOf(uint256,uint256,uint256)": { + "notice": "Records newly used allowance funds of a project." + }, + "usedDistributionLimitOf(address,uint256,uint256)": { + "notice": "The amount of funds that a project has distributed from its limit during the current funding cycle for each terminal, in terms of the distribution limit's currency." + }, + "usedOverflowAllowanceOf(address,uint256,uint256)": { + "notice": "The amount of funds that a project has used from its allowance during the current funding cycle configuration for each terminal, in terms of the overflow allowance's currency." + } + }, + "notice": "Manages all bookkeeping for inflows and outflows of funds from any ISingleTokenPaymentTerminal.", + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 773, + "contract": "contracts/JBSingleTokenPaymentTerminalStore3_1_1.sol:JBSingleTokenPaymentTerminalStore3_1_1", + "label": "_status", + "offset": 0, + "slot": "0", + "type": "t_uint256" + }, + { + "astId": 19905, + "contract": "contracts/JBSingleTokenPaymentTerminalStore3_1_1.sol:JBSingleTokenPaymentTerminalStore3_1_1", + "label": "balanceOf", + "offset": 0, + "slot": "1", + "type": "t_mapping(t_contract(IJBSingleTokenPaymentTerminal)34671,t_mapping(t_uint256,t_uint256))" + }, + { + "astId": 19916, + "contract": "contracts/JBSingleTokenPaymentTerminalStore3_1_1.sol:JBSingleTokenPaymentTerminalStore3_1_1", + "label": "usedDistributionLimitOf", + "offset": 0, + "slot": "2", + "type": "t_mapping(t_contract(IJBSingleTokenPaymentTerminal)34671,t_mapping(t_uint256,t_mapping(t_uint256,t_uint256)))" + }, + { + "astId": 19927, + "contract": "contracts/JBSingleTokenPaymentTerminalStore3_1_1.sol:JBSingleTokenPaymentTerminalStore3_1_1", + "label": "usedOverflowAllowanceOf", + "offset": 0, + "slot": "3", + "type": "t_mapping(t_contract(IJBSingleTokenPaymentTerminal)34671,t_mapping(t_uint256,t_mapping(t_uint256,t_uint256)))" + } + ], + "types": { + "t_contract(IJBSingleTokenPaymentTerminal)34671": { + "encoding": "inplace", + "label": "contract IJBSingleTokenPaymentTerminal", + "numberOfBytes": "20" + }, + "t_mapping(t_contract(IJBSingleTokenPaymentTerminal)34671,t_mapping(t_uint256,t_mapping(t_uint256,t_uint256)))": { + "encoding": "mapping", + "key": "t_contract(IJBSingleTokenPaymentTerminal)34671", + "label": "mapping(contract IJBSingleTokenPaymentTerminal => mapping(uint256 => mapping(uint256 => uint256)))", + "numberOfBytes": "32", + "value": "t_mapping(t_uint256,t_mapping(t_uint256,t_uint256))" + }, + "t_mapping(t_contract(IJBSingleTokenPaymentTerminal)34671,t_mapping(t_uint256,t_uint256))": { + "encoding": "mapping", + "key": "t_contract(IJBSingleTokenPaymentTerminal)34671", + "label": "mapping(contract IJBSingleTokenPaymentTerminal => mapping(uint256 => uint256))", + "numberOfBytes": "32", + "value": "t_mapping(t_uint256,t_uint256)" + }, + "t_mapping(t_uint256,t_mapping(t_uint256,t_uint256))": { + "encoding": "mapping", + "key": "t_uint256", + "label": "mapping(uint256 => mapping(uint256 => uint256))", + "numberOfBytes": "32", + "value": "t_mapping(t_uint256,t_uint256)" + }, + "t_mapping(t_uint256,t_uint256)": { + "encoding": "mapping", + "key": "t_uint256", + "label": "mapping(uint256 => uint256)", + "numberOfBytes": "32", + "value": "t_uint256" + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + } + } + } +} \ No newline at end of file diff --git a/deployments/mainnet/solcInputs/11cb1f66a0f8213d7bf83deb0ae9d2f7.json b/deployments/mainnet/solcInputs/11cb1f66a0f8213d7bf83deb0ae9d2f7.json new file mode 100644 index 000000000..45acfbc43 --- /dev/null +++ b/deployments/mainnet/solcInputs/11cb1f66a0f8213d7bf83deb0ae9d2f7.json @@ -0,0 +1,461 @@ +{ + "language": "Solidity", + "sources": { + "contracts/abstract/JBControllerUtility.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {IJBControllerUtility} from './../interfaces/IJBControllerUtility.sol';\nimport {IJBDirectory} from './../interfaces/IJBDirectory.sol';\n\n/// @notice Provides tools for contracts with functionality that can only be accessed by a project's controller.\nabstract contract JBControllerUtility is IJBControllerUtility {\n //*********************************************************************//\n // --------------------------- custom errors -------------------------- //\n //*********************************************************************//\n error CONTROLLER_UNAUTHORIZED();\n\n //*********************************************************************//\n // ---------------------------- modifiers ---------------------------- //\n //*********************************************************************//\n\n /// @notice Only allows the controller of the specified project to proceed.\n /// @param _projectId The ID of the project.\n modifier onlyController(uint256 _projectId) {\n if (address(directory.controllerOf(_projectId)) != msg.sender) revert CONTROLLER_UNAUTHORIZED();\n _;\n }\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n constructor(IJBDirectory _directory) {\n directory = _directory;\n }\n}\n" + }, + "contracts/interfaces/IJBControllerUtility.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBDirectory} from './IJBDirectory.sol';\n\ninterface IJBControllerUtility {\n function directory() external view returns (IJBDirectory);\n}\n" + }, + "contracts/interfaces/IJBDirectory.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\nimport {IJBProjects} from './IJBProjects.sol';\n\ninterface IJBDirectory {\n event SetController(uint256 indexed projectId, address indexed controller, address caller);\n\n event AddTerminal(uint256 indexed projectId, IJBPaymentTerminal indexed terminal, address caller);\n\n event SetTerminals(uint256 indexed projectId, IJBPaymentTerminal[] terminals, address caller);\n\n event SetPrimaryTerminal(\n uint256 indexed projectId,\n address indexed token,\n IJBPaymentTerminal indexed terminal,\n address caller\n );\n\n event SetIsAllowedToSetFirstController(address indexed addr, bool indexed flag, address caller);\n\n function projects() external view returns (IJBProjects);\n\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\n\n function controllerOf(uint256 projectId) external view returns (address);\n\n function isAllowedToSetFirstController(address account) external view returns (bool);\n\n function terminalsOf(uint256 projectId) external view returns (IJBPaymentTerminal[] memory);\n\n function isTerminalOf(\n uint256 projectId,\n IJBPaymentTerminal terminal\n ) external view returns (bool);\n\n function primaryTerminalOf(\n uint256 projectId,\n address token\n ) external view returns (IJBPaymentTerminal);\n\n function setControllerOf(uint256 projectId, address controller) external;\n\n function setTerminalsOf(uint256 projectId, IJBPaymentTerminal[] calldata terminals) external;\n\n function setPrimaryTerminalOf(\n uint256 projectId,\n address token,\n IJBPaymentTerminal terminal\n ) external;\n\n function setIsAllowedToSetFirstController(address account, bool flag) external;\n}\n" + }, + "contracts/interfaces/IJBFundingCycleStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBBallotState} from './../enums/JBBallotState.sol';\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\nimport {JBFundingCycleData} from './../structs/JBFundingCycleData.sol';\n\ninterface IJBFundingCycleStore {\n event Configure(\n uint256 indexed configuration,\n uint256 indexed projectId,\n JBFundingCycleData data,\n uint256 metadata,\n uint256 mustStartAtOrAfter,\n address caller\n );\n\n event Init(uint256 indexed configuration, uint256 indexed projectId, uint256 indexed basedOn);\n\n function latestConfigurationOf(uint256 projectId) external view returns (uint256);\n\n function get(\n uint256 projectId,\n uint256 configuration\n ) external view returns (JBFundingCycle memory);\n\n function latestConfiguredOf(\n uint256 projectId\n ) external view returns (JBFundingCycle memory fundingCycle, JBBallotState ballotState);\n\n function queuedOf(uint256 projectId) external view returns (JBFundingCycle memory fundingCycle);\n\n function currentOf(uint256 projectId) external view returns (JBFundingCycle memory fundingCycle);\n\n function currentBallotStateOf(uint256 projectId) external view returns (JBBallotState);\n\n function configureFor(\n uint256 projectId,\n JBFundingCycleData calldata data,\n uint256 metadata,\n uint256 mustStartAtOrAfter\n ) external returns (JBFundingCycle memory fundingCycle);\n}\n" + }, + "contracts/interfaces/IJBPaymentTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\n\ninterface IJBPaymentTerminal is IERC165 {\n function acceptsToken(address token, uint256 projectId) external view returns (bool);\n\n function currencyForToken(address token) external view returns (uint256);\n\n function decimalsForToken(address token) external view returns (uint256);\n\n // Return value must be a fixed point number with 18 decimals.\n function currentEthOverflowOf(uint256 projectId) external view returns (uint256);\n\n function pay(\n uint256 projectId,\n uint256 amount,\n address token,\n address beneficiary,\n uint256 minReturnedTokens,\n bool preferClaimedTokens,\n string calldata memo,\n bytes calldata metadata\n ) external payable returns (uint256 beneficiaryTokenCount);\n\n function addToBalanceOf(\n uint256 projectId,\n uint256 amount,\n address token,\n string calldata memo,\n bytes calldata metadata\n ) external payable;\n}\n" + }, + "contracts/interfaces/IJBProjects.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC721} from '@openzeppelin/contracts/token/ERC721/IERC721.sol';\nimport {JBProjectMetadata} from './../structs/JBProjectMetadata.sol';\nimport {IJBTokenUriResolver} from './IJBTokenUriResolver.sol';\n\ninterface IJBProjects is IERC721 {\n event Create(\n uint256 indexed projectId,\n address indexed owner,\n JBProjectMetadata metadata,\n address caller\n );\n\n event SetMetadata(uint256 indexed projectId, JBProjectMetadata metadata, address caller);\n\n event SetTokenUriResolver(IJBTokenUriResolver indexed resolver, address caller);\n\n function count() external view returns (uint256);\n\n function metadataContentOf(\n uint256 projectId,\n uint256 domain\n ) external view returns (string memory);\n\n function tokenUriResolver() external view returns (IJBTokenUriResolver);\n\n function createFor(\n address owner,\n JBProjectMetadata calldata metadata\n ) external returns (uint256 projectId);\n\n function setMetadataOf(uint256 projectId, JBProjectMetadata calldata metadata) external;\n\n function setTokenUriResolver(IJBTokenUriResolver newResolver) external;\n}\n" + }, + "contracts/enums/JBBallotState.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nenum JBBallotState {\n Active,\n Approved,\n Failed\n}\n" + }, + "contracts/structs/JBFundingCycle.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBFundingCycleBallot} from './../interfaces/IJBFundingCycleBallot.sol';\n\n/// @custom:member number The funding cycle number for the cycle's project. Each funding cycle has a number that is an increment of the cycle that directly preceded it. Each project's first funding cycle has a number of 1.\n/// @custom:member configuration The timestamp when the parameters for this funding cycle were configured. This value will stay the same for subsequent funding cycles that roll over from an originally configured cycle.\n/// @custom:member basedOn The `configuration` of the funding cycle that was active when this cycle was created.\n/// @custom:member start The timestamp marking the moment from which the funding cycle is considered active. It is a unix timestamp measured in seconds.\n/// @custom:member duration The number of seconds the funding cycle lasts for, after which a new funding cycle will start. A duration of 0 means that the funding cycle will stay active until the project owner explicitly issues a reconfiguration, at which point a new funding cycle will immediately start with the updated properties. If the duration is greater than 0, a project owner cannot make changes to a funding cycle's parameters while it is active – any proposed changes will apply to the subsequent cycle. If no changes are proposed, a funding cycle rolls over to another one with the same properties but new `start` timestamp and a discounted `weight`.\n/// @custom:member weight A fixed point number with 18 decimals that contracts can use to base arbitrary calculations on. For example, payment terminals can use this to determine how many tokens should be minted when a payment is received.\n/// @custom:member discountRate A percent by how much the `weight` of the subsequent funding cycle should be reduced, if the project owner hasn't configured the subsequent funding cycle with an explicit `weight`. If it's 0, each funding cycle will have equal weight. If the number is 90%, the next funding cycle will have a 10% smaller weight. This weight is out of `JBConstants.MAX_DISCOUNT_RATE`.\n/// @custom:member ballot An address of a contract that says whether a proposed reconfiguration should be accepted or rejected. It can be used to create rules around how a project owner can change funding cycle parameters over time.\n/// @custom:member metadata Extra data that can be associated with a funding cycle.\nstruct JBFundingCycle {\n uint256 number;\n uint256 configuration;\n uint256 basedOn;\n uint256 start;\n uint256 duration;\n uint256 weight;\n uint256 discountRate;\n IJBFundingCycleBallot ballot;\n uint256 metadata;\n}\n" + }, + "contracts/structs/JBFundingCycleData.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBFundingCycleBallot} from './../interfaces/IJBFundingCycleBallot.sol';\n\n/// @custom:member duration The number of seconds the funding cycle lasts for, after which a new funding cycle will start. A duration of 0 means that the funding cycle will stay active until the project owner explicitly issues a reconfiguration, at which point a new funding cycle will immediately start with the updated properties. If the duration is greater than 0, a project owner cannot make changes to a funding cycle's parameters while it is active – any proposed changes will apply to the subsequent cycle. If no changes are proposed, a funding cycle rolls over to another one with the same properties but new `start` timestamp and a discounted `weight`.\n/// @custom:member weight A fixed point number with 18 decimals that contracts can use to base arbitrary calculations on. For example, payment terminals can use this to determine how many tokens should be minted when a payment is received.\n/// @custom:member discountRate A percent by how much the `weight` of the subsequent funding cycle should be reduced, if the project owner hasn't configured the subsequent funding cycle with an explicit `weight`. If it's 0, each funding cycle will have equal weight. If the number is 90%, the next funding cycle will have a 10% smaller weight. This weight is out of `JBConstants.MAX_DISCOUNT_RATE`.\n/// @custom:member ballot An address of a contract that says whether a proposed reconfiguration should be accepted or rejected. It can be used to create rules around how a project owner can change funding cycle parameters over time.\nstruct JBFundingCycleData {\n uint256 duration;\n uint256 weight;\n uint256 discountRate;\n IJBFundingCycleBallot ballot;\n}\n" + }, + "contracts/interfaces/IJBFundingCycleBallot.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBBallotState} from './../enums/JBBallotState.sol';\n\ninterface IJBFundingCycleBallot is IERC165 {\n function duration() external view returns (uint256);\n\n function stateOf(\n uint256 projectId,\n uint256 configuration,\n uint256 start\n ) external view returns (JBBallotState);\n}\n" + }, + "@openzeppelin/contracts/utils/introspection/IERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n" + }, + "@openzeppelin/contracts/token/ERC721/IERC721.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../../utils/introspection/IERC165.sol\";\n\n/**\n * @dev Required interface of an ERC721 compliant contract.\n */\ninterface IERC721 is IERC165 {\n /**\n * @dev Emitted when `tokenId` token is transferred from `from` to `to`.\n */\n event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);\n\n /**\n * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.\n */\n event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);\n\n /**\n * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.\n */\n event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n /**\n * @dev Returns the number of tokens in ``owner``'s account.\n */\n function balanceOf(address owner) external view returns (uint256 balance);\n\n /**\n * @dev Returns the owner of the `tokenId` token.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n */\n function ownerOf(uint256 tokenId) external view returns (address owner);\n\n /**\n * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\n * are aware of the ERC721 protocol to prevent tokens from being forever locked.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must exist and be owned by `from`.\n * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId\n ) external;\n\n /**\n * @dev Transfers `tokenId` token from `from` to `to`.\n *\n * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must be owned by `from`.\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 tokenId\n ) external;\n\n /**\n * @dev Gives permission to `to` to transfer `tokenId` token to another account.\n * The approval is cleared when the token is transferred.\n *\n * Only a single account can be approved at a time, so approving the zero address clears previous approvals.\n *\n * Requirements:\n *\n * - The caller must own the token or be an approved operator.\n * - `tokenId` must exist.\n *\n * Emits an {Approval} event.\n */\n function approve(address to, uint256 tokenId) external;\n\n /**\n * @dev Returns the account approved for `tokenId` token.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n */\n function getApproved(uint256 tokenId) external view returns (address operator);\n\n /**\n * @dev Approve or remove `operator` as an operator for the caller.\n * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.\n *\n * Requirements:\n *\n * - The `operator` cannot be the caller.\n *\n * Emits an {ApprovalForAll} event.\n */\n function setApprovalForAll(address operator, bool _approved) external;\n\n /**\n * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.\n *\n * See {setApprovalForAll}\n */\n function isApprovedForAll(address owner, address operator) external view returns (bool);\n\n /**\n * @dev Safely transfers `tokenId` token from `from` to `to`.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must exist and be owned by `from`.\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId,\n bytes calldata data\n ) external;\n}\n" + }, + "contracts/structs/JBProjectMetadata.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @custom:member content The metadata content.\n/// @custom:member domain The domain within which the metadata applies.\nstruct JBProjectMetadata {\n string content;\n uint256 domain;\n}\n" + }, + "contracts/interfaces/IJBTokenUriResolver.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBTokenUriResolver {\n function getUri(uint256 projectId) external view returns (string memory tokenUri);\n}\n" + }, + "contracts/JBTokenStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {JBControllerUtility} from './abstract/JBControllerUtility.sol';\nimport {JBOperatable} from './abstract/JBOperatable.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {IJBToken} from './interfaces/IJBToken.sol';\nimport {IJBTokenStore} from './interfaces/IJBTokenStore.sol';\nimport {JBFundingCycleMetadataResolver} from './libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBOperations} from './libraries/JBOperations.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\nimport {JBToken} from './JBToken.sol';\n\n/// @notice Manage token minting, burning, and account balances.\n/// @dev Token balances can be either represented internally or claimed as ERC-20s into wallets. This contract manages these two representations and allows claiming.\n/// @dev The total supply of a project's tokens and the balance of each account are calculated in this contract.\n/// @dev Each project can bring their own token if they prefer, and swap between tokens at any time.\ncontract JBTokenStore is JBControllerUtility, JBOperatable, IJBTokenStore {\n // A library that parses the packed funding cycle metadata into a friendlier format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error ALREADY_SET();\n error EMPTY_NAME();\n error EMPTY_SYMBOL();\n error EMPTY_TOKEN();\n error INSUFFICIENT_FUNDS();\n error INSUFFICIENT_UNCLAIMED_TOKENS();\n error PROJECT_ALREADY_HAS_TOKEN();\n error RECIPIENT_ZERO_ADDRESS();\n error TOKEN_NOT_FOUND();\n error TOKENS_MUST_HAVE_18_DECIMALS();\n error TRANSFERS_PAUSED();\n error OVERFLOW_ALERT();\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice Mints ERC-721's that represent project ownership and transfers. \n IJBProjects public immutable override projects;\n\n /// @notice The contract storing all funding cycle configurations. \n IJBFundingCycleStore public immutable override fundingCycleStore;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice Each project's attached token contract.\n /// @custom:param _projectId The ID of the project to which the token belongs. \n mapping(uint256 => IJBToken) public override tokenOf;\n\n /// @notice The total supply of unclaimed tokens for each project.\n /// @custom:param _projectId The ID of the project to which the token belongs. \n mapping(uint256 => uint256) public override unclaimedTotalSupplyOf;\n\n /// @notice Each holder's balance of unclaimed tokens for each project.\n /// @custom:param _holder The holder of balance.\n /// @custom:param _projectId The ID of the project to which the token belongs.\n mapping(address => mapping(uint256 => uint256)) public override unclaimedBalanceOf;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice The total balance of tokens a holder has for a specified project, including claimed and unclaimed tokens.\n /// @param _holder The token holder to get a balance for.\n /// @param _projectId The project to get the `_holder`s balance of.\n /// @return balance The project token balance of the `_holder \n function balanceOf(address _holder, uint256 _projectId)\n external\n view\n override\n returns (uint256 balance)\n {\n // Get a reference to the holder's unclaimed balance for the project.\n balance = unclaimedBalanceOf[_holder][_projectId];\n\n // Get a reference to the project's current token.\n IJBToken _token = tokenOf[_projectId];\n\n // If the project has a current token, add the holder's balance to the total.\n if (_token != IJBToken(address(0))) balance = balance + _token.balanceOf(_holder, _projectId);\n }\n\n //*********************************************************************//\n // --------------------------- public views -------------------------- //\n //*********************************************************************//\n\n /// @notice The total supply of tokens for each project, including claimed and unclaimed tokens.\n /// @param _projectId The ID of the project to get the total token supply of.\n /// @return totalSupply The total supply of the project's tokens.\n function totalSupplyOf(uint256 _projectId) public view override returns (uint256 totalSupply) {\n // Get a reference to the total supply of the project's unclaimed tokens.\n totalSupply = unclaimedTotalSupplyOf[_projectId];\n\n // Get a reference to the project's current token.\n IJBToken _token = tokenOf[_projectId];\n\n // If the project has a current token, add its total supply to the total.\n if (_token != IJBToken(address(0))) totalSupply = totalSupply + _token.totalSupply(_projectId);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _fundingCycleStore A contract storing all funding cycle configurations.\n constructor(\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBFundingCycleStore _fundingCycleStore\n ) JBOperatable(_operatorStore) JBControllerUtility(_directory) {\n projects = _projects;\n fundingCycleStore = _fundingCycleStore;\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Issues a project's ERC-20 tokens that'll be used when claiming tokens.\n /// @dev Deploys a project's ERC-20 token contract.\n /// @dev Only a project's owner or operator can issue its token.\n /// @param _projectId The ID of the project being issued tokens.\n /// @param _name The ERC-20's name.\n /// @param _symbol The ERC-20's symbol.\n /// @return token The token that was issued.\n function issueFor(\n uint256 _projectId,\n string calldata _name,\n string calldata _symbol\n )\n external\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.ISSUE)\n returns (IJBToken token)\n {\n // There must be a name.\n if (bytes(_name).length == 0) revert EMPTY_NAME();\n\n // There must be a symbol.\n if (bytes(_symbol).length == 0) revert EMPTY_SYMBOL();\n \n // The project shouldn't already have a token.\n if (tokenOf[_projectId] != IJBToken(address(0))) revert PROJECT_ALREADY_HAS_TOKEN();\n\n // Deploy the token contract.\n token = new JBToken(_name, _symbol, _projectId);\n\n // Store the token contract.\n tokenOf[_projectId] = token;\n\n emit Issue(_projectId, token, _name, _symbol, msg.sender);\n }\n\n /// @notice Set a project's token if not already set.\n /// @dev Only a project's owner or operator can set its token.\n /// @param _projectId The ID of the project to which the set token belongs.\n /// @param _token The new token. \n function setFor(uint256 _projectId, IJBToken _token)\n external\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.SET_TOKEN)\n {\n // Can't set to the zero address.\n if (_token == IJBToken(address(0))) revert EMPTY_TOKEN();\n\n // Can't set token if already set.\n if (tokenOf[_projectId] != IJBToken(address(0))) revert ALREADY_SET();\n\n // Can't change to a token that doesn't use 18 decimals.\n if (_token.decimals() != 18) revert TOKENS_MUST_HAVE_18_DECIMALS();\n\n // Store the new token.\n tokenOf[_projectId] = _token;\n\n emit Set(_projectId, _token, msg.sender);\n }\n\n /// @notice Mint new project tokens.\n /// @dev Only a project's current controller can mint its tokens.\n /// @param _holder The address receiving the new tokens.\n /// @param _projectId The ID of the project to which the tokens belong.\n /// @param _amount The amount of tokens to mint.\n /// @param _preferClaimedTokens A flag indicating whether there's a preference for minted tokens to be claimed automatically into the `_holder`s wallet if the project currently has a token contract attached.\n function mintFor(\n address _holder,\n uint256 _projectId,\n uint256 _amount,\n bool _preferClaimedTokens\n ) external override onlyController(_projectId) {\n // Get a reference to the project's current token.\n IJBToken _token = tokenOf[_projectId];\n\n // Save a reference to whether there exists a token and the caller prefers these claimed tokens.\n bool _shouldClaimTokens = _preferClaimedTokens && _token != IJBToken(address(0));\n\n if (_shouldClaimTokens)\n // If tokens should be claimed, mint tokens into the holder's wallet.\n _token.mint(_projectId, _holder, _amount);\n else {\n // Otherwise, add the tokens to the unclaimed balance and total supply.\n unclaimedBalanceOf[_holder][_projectId] = unclaimedBalanceOf[_holder][_projectId] + _amount;\n unclaimedTotalSupplyOf[_projectId] = unclaimedTotalSupplyOf[_projectId] + _amount;\n }\n\n // The total supply can't exceed the maximum value storable in a uint224.\n if (totalSupplyOf(_projectId) > type(uint224).max) revert OVERFLOW_ALERT();\n\n emit Mint(_holder, _projectId, _amount, _shouldClaimTokens, _preferClaimedTokens, msg.sender);\n }\n\n /// @notice Burns a project's tokens.\n /// @dev Only a project's current controller can burn its tokens.\n /// @param _holder The address that owns the tokens being burned.\n /// @param _projectId The ID of the project to which the burned tokens belong.\n /// @param _amount The amount of tokens to burn.\n /// @param _preferClaimedTokens A flag indicating whether there's a preference for tokens to burned from the `_holder`s wallet if the project currently has a token contract attached.\n function burnFrom(\n address _holder,\n uint256 _projectId,\n uint256 _amount,\n bool _preferClaimedTokens\n ) external override onlyController(_projectId) {\n // Get a reference to the project's current token.\n IJBToken _token = tokenOf[_projectId];\n\n // Get a reference to the amount of unclaimed project tokens the holder has.\n uint256 _unclaimedBalance = unclaimedBalanceOf[_holder][_projectId];\n\n // Get a reference to the amount of the project's current token the holder has in their wallet.\n uint256 _claimedBalance = _token == IJBToken(address(0))\n ? 0\n : _token.balanceOf(_holder, _projectId);\n\n // There must be adequate tokens to burn across the holder's claimed and unclaimed balance.\n if (_amount > _claimedBalance + _unclaimedBalance) revert INSUFFICIENT_FUNDS();\n\n // The amount of tokens to burn.\n uint256 _claimedTokensToBurn;\n\n // Get a reference to how many claimed tokens should be burned\n if (_claimedBalance != 0)\n if (_preferClaimedTokens)\n // If prefer converted, burn the claimed tokens before the unclaimed.\n _claimedTokensToBurn = _claimedBalance < _amount ? _claimedBalance : _amount;\n // Otherwise, burn unclaimed tokens before claimed tokens.\n else {\n unchecked {\n _claimedTokensToBurn = _unclaimedBalance < _amount ? _amount - _unclaimedBalance : 0;\n }\n }\n\n // The amount of unclaimed tokens to burn.\n uint256 _unclaimedTokensToBurn;\n unchecked {\n _unclaimedTokensToBurn = _amount - _claimedTokensToBurn;\n }\n\n // Subtract the tokens from the unclaimed balance and total supply.\n if (_unclaimedTokensToBurn > 0) {\n // Reduce the holders balance and the total supply.\n unclaimedBalanceOf[_holder][_projectId] =\n unclaimedBalanceOf[_holder][_projectId] -\n _unclaimedTokensToBurn;\n unclaimedTotalSupplyOf[_projectId] =\n unclaimedTotalSupplyOf[_projectId] -\n _unclaimedTokensToBurn;\n }\n\n // Burn the claimed tokens.\n if (_claimedTokensToBurn > 0) _token.burn(_projectId, _holder, _claimedTokensToBurn);\n\n emit Burn(\n _holder,\n _projectId,\n _amount,\n _unclaimedBalance,\n _claimedBalance,\n _preferClaimedTokens,\n msg.sender\n );\n }\n\n /// @notice Claims internally accounted for tokens into a holder's wallet.\n /// @dev Only a token holder or an operator specified by the token holder can claim its unclaimed tokens.\n /// @param _holder The owner of the tokens being claimed.\n /// @param _projectId The ID of the project whose tokens are being claimed.\n /// @param _amount The amount of tokens to claim.\n function claimFor(\n address _holder,\n uint256 _projectId,\n uint256 _amount\n ) external override requirePermission(_holder, _projectId, JBOperations.CLAIM) {\n // Get a reference to the project's current token.\n IJBToken _token = tokenOf[_projectId];\n\n // The project must have a token contract attached.\n if (_token == IJBToken(address(0))) revert TOKEN_NOT_FOUND();\n\n // Get a reference to the amount of unclaimed project tokens the holder has.\n uint256 _unclaimedBalance = unclaimedBalanceOf[_holder][_projectId];\n\n // There must be enough unclaimed tokens to claim.\n if (_unclaimedBalance < _amount) revert INSUFFICIENT_UNCLAIMED_TOKENS();\n\n unchecked {\n // Subtract the claim amount from the holder's unclaimed project token balance.\n unclaimedBalanceOf[_holder][_projectId] = _unclaimedBalance - _amount;\n\n // Subtract the claim amount from the project's unclaimed total supply.\n unclaimedTotalSupplyOf[_projectId] = unclaimedTotalSupplyOf[_projectId] - _amount;\n }\n\n // Mint the equivalent amount of the project's token for the holder.\n _token.mint(_projectId, _holder, _amount);\n\n emit Claim(_holder, _projectId, _unclaimedBalance, _amount, msg.sender);\n }\n\n /// @notice Allows a holder to transfer unclaimed tokens to another account.\n /// @dev Only a token holder or an operator can transfer its unclaimed tokens.\n /// @param _holder The address to transfer tokens from.\n /// @param _projectId The ID of the project whose tokens are being transferred.\n /// @param _recipient The recipient of the tokens.\n /// @param _amount The amount of tokens to transfer.\n function transferFrom(\n address _holder,\n uint256 _projectId,\n address _recipient,\n uint256 _amount\n ) external override requirePermission(_holder, _projectId, JBOperations.TRANSFER) {\n // Get a reference to the current funding cycle for the project.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Must not be paused.\n if (_fundingCycle.global().pauseTransfers) revert TRANSFERS_PAUSED();\n\n // Can't transfer to the zero address.\n if (_recipient == address(0)) revert RECIPIENT_ZERO_ADDRESS();\n\n // Get a reference to the holder's unclaimed project token balance.\n uint256 _unclaimedBalance = unclaimedBalanceOf[_holder][_projectId];\n\n // The holder must have enough unclaimed tokens to transfer.\n if (_amount > _unclaimedBalance) revert INSUFFICIENT_UNCLAIMED_TOKENS();\n\n // Subtract from the holder's unclaimed token balance.\n unchecked {\n unclaimedBalanceOf[_holder][_projectId] = _unclaimedBalance - _amount;\n }\n\n // Add the unclaimed project tokens to the recipient's balance.\n unclaimedBalanceOf[_recipient][_projectId] =\n unclaimedBalanceOf[_recipient][_projectId] +\n _amount;\n\n emit Transfer(_holder, _projectId, _recipient, _amount, msg.sender);\n }\n}\n" + }, + "contracts/abstract/JBOperatable.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {IJBOperatable} from './../interfaces/IJBOperatable.sol';\nimport {IJBOperatorStore} from './../interfaces/IJBOperatorStore.sol';\n\n/// @notice Modifiers to allow access to functions based on the message sender's operator status.\nabstract contract JBOperatable is IJBOperatable {\n //*********************************************************************//\n // --------------------------- custom errors -------------------------- //\n //*********************************************************************//\n error UNAUTHORIZED();\n\n //*********************************************************************//\n // ---------------------------- modifiers ---------------------------- //\n //*********************************************************************//\n\n /// @notice Only allows the speficied account or an operator of the account to proceed.\n /// @param _account The account to check for.\n /// @param _domain The domain namespace to look for an operator within.\n /// @param _permissionIndex The index of the permission to check for.\n modifier requirePermission(\n address _account,\n uint256 _domain,\n uint256 _permissionIndex\n ) {\n _requirePermission(_account, _domain, _permissionIndex);\n _;\n }\n\n /// @notice Only allows the speficied account, an operator of the account to proceed, or a truthy override flag.\n /// @param _account The account to check for.\n /// @param _domain The domain namespace to look for an operator within.\n /// @param _permissionIndex The index of the permission to check for.\n /// @param _override A condition to force allowance for.\n modifier requirePermissionAllowingOverride(\n address _account,\n uint256 _domain,\n uint256 _permissionIndex,\n bool _override\n ) {\n _requirePermissionAllowingOverride(_account, _domain, _permissionIndex, _override);\n _;\n }\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice A contract storing operator assignments.\n IJBOperatorStore public immutable override operatorStore;\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _operatorStore A contract storing operator assignments.\n constructor(IJBOperatorStore _operatorStore) {\n operatorStore = _operatorStore;\n }\n\n //*********************************************************************//\n // -------------------------- internal views ------------------------- //\n //*********************************************************************//\n\n /// @notice Require the message sender is either the account or has the specified permission.\n /// @param _account The account to allow.\n /// @param _domain The domain namespace within which the permission index will be checked.\n /// @param _permissionIndex The permission index that an operator must have within the specified domain to be allowed.\n function _requirePermission(\n address _account,\n uint256 _domain,\n uint256 _permissionIndex\n ) internal view {\n if (\n msg.sender != _account &&\n !operatorStore.hasPermission(msg.sender, _account, _domain, _permissionIndex) &&\n !operatorStore.hasPermission(msg.sender, _account, 0, _permissionIndex)\n ) revert UNAUTHORIZED();\n }\n\n /// @notice Require the message sender is either the account, has the specified permission, or the override condition is true.\n /// @param _account The account to allow.\n /// @param _domain The domain namespace within which the permission index will be checked.\n /// @param _domain The permission index that an operator must have within the specified domain to be allowed.\n /// @param _override The override condition to allow.\n function _requirePermissionAllowingOverride(\n address _account,\n uint256 _domain,\n uint256 _permissionIndex,\n bool _override\n ) internal view {\n if (\n !_override &&\n msg.sender != _account &&\n !operatorStore.hasPermission(msg.sender, _account, _domain, _permissionIndex) &&\n !operatorStore.hasPermission(msg.sender, _account, 0, _permissionIndex)\n ) revert UNAUTHORIZED();\n }\n}\n" + }, + "contracts/interfaces/IJBOperatorStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBOperatorData} from './../structs/JBOperatorData.sol';\n\ninterface IJBOperatorStore {\n event SetOperator(\n address indexed operator,\n address indexed account,\n uint256 indexed domain,\n uint256[] permissionIndexes,\n uint256 packed\n );\n\n function permissionsOf(\n address operator,\n address account,\n uint256 domain\n ) external view returns (uint256);\n\n function hasPermission(\n address operator,\n address account,\n uint256 domain,\n uint256 permissionIndex\n ) external view returns (bool);\n\n function hasPermissions(\n address operator,\n address account,\n uint256 domain,\n uint256[] calldata permissionIndexes\n ) external view returns (bool);\n\n function setOperator(JBOperatorData calldata operatorData) external;\n\n function setOperators(JBOperatorData[] calldata operatorData) external;\n}\n" + }, + "contracts/interfaces/IJBToken.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBToken {\n function projectId() external view returns (uint256);\n\n function decimals() external view returns (uint8);\n\n function totalSupply(uint256 projectId) external view returns (uint256);\n\n function balanceOf(address account, uint256 projectId) external view returns (uint256);\n\n function mint(uint256 projectId, address account, uint256 amount) external;\n\n function burn(uint256 projectId, address account, uint256 amount) external;\n\n function approve(uint256, address spender, uint256 amount) external;\n\n function transfer(uint256 projectId, address to, uint256 amount) external;\n\n function transferFrom(uint256 projectId, address from, address to, uint256 amount) external;\n}\n" + }, + "contracts/interfaces/IJBTokenStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\nimport {IJBProjects} from './IJBProjects.sol';\nimport {IJBToken} from './IJBToken.sol';\n\ninterface IJBTokenStore {\n event Issue(\n uint256 indexed projectId,\n IJBToken indexed token,\n string name,\n string symbol,\n address caller\n );\n\n event Mint(\n address indexed holder,\n uint256 indexed projectId,\n uint256 amount,\n bool tokensWereClaimed,\n bool preferClaimedTokens,\n address caller\n );\n\n event Burn(\n address indexed holder,\n uint256 indexed projectId,\n uint256 amount,\n uint256 initialUnclaimedBalance,\n uint256 initialClaimedBalance,\n bool preferClaimedTokens,\n address caller\n );\n\n event Claim(\n address indexed holder,\n uint256 indexed projectId,\n uint256 initialUnclaimedBalance,\n uint256 amount,\n address caller\n );\n\n event Set(uint256 indexed projectId, IJBToken indexed newToken, address caller);\n\n event Transfer(\n address indexed holder,\n uint256 indexed projectId,\n address indexed recipient,\n uint256 amount,\n address caller\n );\n\n function tokenOf(uint256 projectId) external view returns (IJBToken);\n\n function projects() external view returns (IJBProjects);\n\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\n\n function unclaimedBalanceOf(address holder, uint256 projectId) external view returns (uint256);\n\n function unclaimedTotalSupplyOf(uint256 projectId) external view returns (uint256);\n\n function totalSupplyOf(uint256 projectId) external view returns (uint256);\n\n function balanceOf(address holder, uint256 projectId) external view returns (uint256 result);\n\n function issueFor(\n uint256 projectId,\n string calldata name,\n string calldata symbol\n ) external returns (IJBToken token);\n\n function setFor(uint256 projectId, IJBToken token) external;\n\n function burnFrom(\n address holder,\n uint256 projectId,\n uint256 amount,\n bool preferClaimedTokens\n ) external;\n\n function mintFor(\n address holder,\n uint256 projectId,\n uint256 amount,\n bool preferClaimedTokens\n ) external;\n\n function claimFor(address holder, uint256 projectId, uint256 amount) external;\n\n function transferFrom(\n address holder,\n uint256 projectId,\n address recipient,\n uint256 amount\n ) external;\n}\n" + }, + "contracts/libraries/JBFundingCycleMetadataResolver.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\nimport {JBFundingCycleMetadata} from './../structs/JBFundingCycleMetadata.sol';\nimport {JBGlobalFundingCycleMetadata} from './../structs/JBGlobalFundingCycleMetadata.sol';\nimport {JBConstants} from './JBConstants.sol';\nimport {JBGlobalFundingCycleMetadataResolver} from './JBGlobalFundingCycleMetadataResolver.sol';\n\nlibrary JBFundingCycleMetadataResolver {\n function global(JBFundingCycle memory _fundingCycle)\n internal\n pure\n returns (JBGlobalFundingCycleMetadata memory)\n {\n return JBGlobalFundingCycleMetadataResolver.expandMetadata(uint8(_fundingCycle.metadata >> 8));\n }\n\n function reservedRate(JBFundingCycle memory _fundingCycle) internal pure returns (uint256) {\n return uint256(uint16(_fundingCycle.metadata >> 24));\n }\n\n function redemptionRate(JBFundingCycle memory _fundingCycle) internal pure returns (uint256) {\n // Redemption rate is a number 0-10000. It's inverse was stored so the most common case of 100% results in no storage needs.\n return JBConstants.MAX_REDEMPTION_RATE - uint256(uint16(_fundingCycle.metadata >> 40));\n }\n\n function ballotRedemptionRate(JBFundingCycle memory _fundingCycle)\n internal\n pure\n returns (uint256)\n {\n // Redemption rate is a number 0-10000. It's inverse was stored so the most common case of 100% results in no storage needs.\n return JBConstants.MAX_REDEMPTION_RATE - uint256(uint16(_fundingCycle.metadata >> 56));\n }\n\n function payPaused(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\n return ((_fundingCycle.metadata >> 72) & 1) == 1;\n }\n\n function distributionsPaused(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\n return ((_fundingCycle.metadata >> 73) & 1) == 1;\n }\n\n function redeemPaused(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\n return ((_fundingCycle.metadata >> 74) & 1) == 1;\n }\n\n function burnPaused(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\n return ((_fundingCycle.metadata >> 75) & 1) == 1;\n }\n\n function mintingAllowed(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\n return ((_fundingCycle.metadata >> 76) & 1) == 1;\n }\n\n function terminalMigrationAllowed(JBFundingCycle memory _fundingCycle)\n internal\n pure\n returns (bool)\n {\n return ((_fundingCycle.metadata >> 77) & 1) == 1;\n }\n\n function controllerMigrationAllowed(JBFundingCycle memory _fundingCycle)\n internal\n pure\n returns (bool)\n {\n return ((_fundingCycle.metadata >> 78) & 1) == 1;\n }\n\n function shouldHoldFees(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\n return ((_fundingCycle.metadata >> 79) & 1) == 1;\n }\n\n function preferClaimedTokenOverride(JBFundingCycle memory _fundingCycle)\n internal\n pure\n returns (bool)\n {\n return ((_fundingCycle.metadata >> 80) & 1) == 1;\n }\n\n function useTotalOverflowForRedemptions(JBFundingCycle memory _fundingCycle)\n internal\n pure\n returns (bool)\n {\n return ((_fundingCycle.metadata >> 81) & 1) == 1;\n }\n\n function useDataSourceForPay(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\n return (_fundingCycle.metadata >> 82) & 1 == 1;\n }\n\n function useDataSourceForRedeem(JBFundingCycle memory _fundingCycle)\n internal\n pure\n returns (bool)\n {\n return (_fundingCycle.metadata >> 83) & 1 == 1;\n }\n\n function dataSource(JBFundingCycle memory _fundingCycle) internal pure returns (address) {\n return address(uint160(_fundingCycle.metadata >> 84));\n }\n\n function metadata(JBFundingCycle memory _fundingCycle) internal pure returns (uint256) {\n return uint256(uint8(_fundingCycle.metadata >> 244));\n }\n\n /// @notice Pack the funding cycle metadata.\n /// @param _metadata The metadata to validate and pack.\n /// @return packed The packed uint256 of all metadata params. The first 8 bits specify the version. \n function packFundingCycleMetadata(JBFundingCycleMetadata memory _metadata)\n internal\n pure\n returns (uint256 packed)\n {\n // version 1 in the bits 0-7 (8 bits).\n packed = 1;\n // global metadta in bits 8-23 (16 bits).\n packed |=\n JBGlobalFundingCycleMetadataResolver.packFundingCycleGlobalMetadata(_metadata.global) <<\n 8;\n // reserved rate in bits 24-39 (16 bits).\n packed |= _metadata.reservedRate << 24;\n // redemption rate in bits 40-55 (16 bits).\n // redemption rate is a number 0-10000. Store the reverse so the most common case of 100% results in no storage needs.\n packed |= (JBConstants.MAX_REDEMPTION_RATE - _metadata.redemptionRate) << 40;\n // ballot redemption rate rate in bits 56-71 (16 bits).\n // ballot redemption rate is a number 0-10000. Store the reverse so the most common case of 100% results in no storage needs.\n packed |= (JBConstants.MAX_REDEMPTION_RATE - _metadata.ballotRedemptionRate) << 56;\n // pause pay in bit 72.\n if (_metadata.pausePay) packed |= 1 << 72;\n // pause tap in bit 73.\n if (_metadata.pauseDistributions) packed |= 1 << 73;\n // pause redeem in bit 74.\n if (_metadata.pauseRedeem) packed |= 1 << 74;\n // pause burn in bit 75.\n if (_metadata.pauseBurn) packed |= 1 << 75;\n // allow minting in bit 76.\n if (_metadata.allowMinting) packed |= 1 << 76;\n // allow terminal migration in bit 77.\n if (_metadata.allowTerminalMigration) packed |= 1 << 77;\n // allow controller migration in bit 78.\n if (_metadata.allowControllerMigration) packed |= 1 << 78;\n // hold fees in bit 79.\n if (_metadata.holdFees) packed |= 1 << 79;\n // prefer claimed token override in bit 80.\n if (_metadata.preferClaimedTokenOverride) packed |= 1 << 80;\n // useTotalOverflowForRedemptions in bit 81.\n if (_metadata.useTotalOverflowForRedemptions) packed |= 1 << 81;\n // use pay data source in bit 82.\n if (_metadata.useDataSourceForPay) packed |= 1 << 82;\n // use redeem data source in bit 83.\n if (_metadata.useDataSourceForRedeem) packed |= 1 << 83;\n // data source address in bits 84-243.\n packed |= uint256(uint160(address(_metadata.dataSource))) << 84;\n // metadata in bits 244-252 (8 bits).\n packed |= _metadata.metadata << 244;\n }\n\n /// @notice Expand the funding cycle metadata.\n /// @param _fundingCycle The funding cycle having its metadata expanded.\n /// @return metadata The metadata object. \n function expandMetadata(JBFundingCycle memory _fundingCycle)\n internal\n pure\n returns (JBFundingCycleMetadata memory)\n {\n return\n JBFundingCycleMetadata(\n global(_fundingCycle),\n reservedRate(_fundingCycle),\n redemptionRate(_fundingCycle),\n ballotRedemptionRate(_fundingCycle),\n payPaused(_fundingCycle),\n distributionsPaused(_fundingCycle),\n redeemPaused(_fundingCycle),\n burnPaused(_fundingCycle),\n mintingAllowed(_fundingCycle),\n terminalMigrationAllowed(_fundingCycle),\n controllerMigrationAllowed(_fundingCycle),\n shouldHoldFees(_fundingCycle),\n preferClaimedTokenOverride(_fundingCycle),\n useTotalOverflowForRedemptions(_fundingCycle),\n useDataSourceForPay(_fundingCycle),\n useDataSourceForRedeem(_fundingCycle),\n dataSource(_fundingCycle),\n metadata(_fundingCycle)\n );\n }\n}\n" + }, + "contracts/libraries/JBOperations.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nlibrary JBOperations {\n uint256 public constant RECONFIGURE = 1;\n uint256 public constant REDEEM = 2;\n uint256 public constant MIGRATE_CONTROLLER = 3;\n uint256 public constant MIGRATE_TERMINAL = 4;\n uint256 public constant PROCESS_FEES = 5;\n uint256 public constant SET_METADATA = 6;\n uint256 public constant ISSUE = 7;\n uint256 public constant SET_TOKEN = 8;\n uint256 public constant MINT = 9;\n uint256 public constant BURN = 10;\n uint256 public constant CLAIM = 11;\n uint256 public constant TRANSFER = 12;\n uint256 public constant REQUIRE_CLAIM = 13; // unused in v3\n uint256 public constant SET_CONTROLLER = 14;\n uint256 public constant SET_TERMINALS = 15;\n uint256 public constant SET_PRIMARY_TERMINAL = 16;\n uint256 public constant USE_ALLOWANCE = 17;\n uint256 public constant SET_SPLITS = 18;\n}\n" + }, + "contracts/JBToken.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';\nimport {ERC20Votes, ERC20, ERC20Permit} from '@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.sol';\nimport {IJBToken} from './interfaces/IJBToken.sol';\n\n/// @notice An ERC-20 token that can be used by a project in the `JBTokenStore`.\ncontract JBToken is ERC20Votes, Ownable, IJBToken {\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error BAD_PROJECT();\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The ID of the project that this token should be exclusively used for. Send 0 to support any project.\n uint256 public immutable override projectId;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice The total supply of this ERC20.\n /// @param _projectId the ID of the project to which the token belongs. This is ignored.\n /// @return The total supply of this ERC20, as a fixed point number.\n function totalSupply(uint256 _projectId) external view override returns (uint256) {\n _projectId; // Prevents unused var compiler and natspec complaints.\n\n return super.totalSupply();\n }\n\n /// @notice An account's balance of this ERC20.\n /// @param _account The account to get a balance of.\n /// @param _projectId is the ID of the project to which the token belongs. This is ignored.\n /// @return The balance of the `_account` of this ERC20, as a fixed point number with 18 decimals.\n function balanceOf(\n address _account,\n uint256 _projectId\n ) external view override returns (uint256) {\n _account; // Prevents unused var compiler and natspec complaints.\n _projectId; // Prevents unused var compiler and natspec complaints.\n\n return super.balanceOf(_account);\n }\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice The number of decimals included in the fixed point accounting of this token.\n /// @return The number of decimals.\n function decimals() public view override(ERC20, IJBToken) returns (uint8) {\n return super.decimals();\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _name The name of the token.\n /// @param _symbol The symbol that the token should be represented by.\n /// @param _projectId The ID of the project that this token should be exclusively used for. Send 0 to support any project.\n constructor(\n string memory _name,\n string memory _symbol,\n uint256 _projectId\n ) ERC20(_name, _symbol) ERC20Permit(_name) {\n projectId = _projectId;\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Mints more of the token.\n /// @dev Only the owner of this contract cant mint more of it.\n /// @param _projectId The ID of the project to which the token belongs.\n /// @param _account The account to mint the tokens for.\n /// @param _amount The amount of tokens to mint, as a fixed point number with 18 decimals.\n function mint(uint256 _projectId, address _account, uint256 _amount) external override onlyOwner {\n // Can't mint for a wrong project.\n if (projectId != 0 && _projectId != projectId) revert BAD_PROJECT();\n\n return _mint(_account, _amount);\n }\n\n /// @notice Burn some outstanding tokens.\n /// @dev Only the owner of this contract cant burn some of its supply.\n /// @param _projectId The ID of the project to which the token belongs.\n /// @param _account The account to burn tokens from.\n /// @param _amount The amount of tokens to burn, as a fixed point number with 18 decimals.\n function burn(uint256 _projectId, address _account, uint256 _amount) external override onlyOwner {\n // Can't burn for a wrong project.\n if (projectId != 0 && _projectId != projectId) revert BAD_PROJECT();\n\n return _burn(_account, _amount);\n }\n\n /// @notice Approves an account to spend tokens on the `msg.sender`s behalf.\n /// @param _projectId the ID of the project to which the token belongs.\n /// @param _spender The address that will be spending tokens on the `msg.sender`s behalf.\n /// @param _amount The amount the `_spender` is allowed to spend.\n function approve(uint256 _projectId, address _spender, uint256 _amount) external override {\n // Can't approve for a wrong project.\n if (projectId != 0 && _projectId != projectId) revert BAD_PROJECT();\n\n approve(_spender, _amount);\n }\n\n /// @notice Transfer tokens to an account.\n /// @param _projectId The ID of the project to which the token belongs.\n /// @param _to The destination address.\n /// @param _amount The amount of the transfer, as a fixed point number with 18 decimals.\n function transfer(uint256 _projectId, address _to, uint256 _amount) external override {\n // Can't transfer for a wrong project.\n if (projectId != 0 && _projectId != projectId) revert BAD_PROJECT();\n\n transfer(_to, _amount);\n }\n\n /// @notice Transfer tokens between accounts.\n /// @param _projectId The ID of the project to which the token belongs.\n /// @param _from The originating address.\n /// @param _to The destination address.\n /// @param _amount The amount of the transfer, as a fixed point number with 18 decimals.\n function transferFrom(\n uint256 _projectId,\n address _from,\n address _to,\n uint256 _amount\n ) external override {\n // Can't transfer for a wrong project.\n if (projectId != 0 && _projectId != projectId) revert BAD_PROJECT();\n\n transferFrom(_from, _to, _amount);\n }\n}\n" + }, + "contracts/interfaces/IJBOperatable.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBOperatorStore} from './IJBOperatorStore.sol';\n\ninterface IJBOperatable {\n function operatorStore() external view returns (IJBOperatorStore);\n}\n" + }, + "contracts/structs/JBOperatorData.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @custom:member operator The address of the operator.\n/// @custom:member domain The domain within which the operator is being given permissions. A domain of 0 is a wildcard domain, which gives an operator access to all domains.\n/// @custom:member permissionIndexes The indexes of the permissions the operator is being given.\nstruct JBOperatorData {\n address operator;\n uint256 domain;\n uint256[] permissionIndexes;\n}\n" + }, + "contracts/structs/JBFundingCycleMetadata.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBGlobalFundingCycleMetadata} from './JBGlobalFundingCycleMetadata.sol';\n\n/// @custom:member global Data used globally in non-migratable ecosystem contracts.\n/// @custom:member reservedRate The reserved rate of the funding cycle. This number is a percentage calculated out of `JBConstants.MAX_RESERVED_RATE`.\n/// @custom:member redemptionRate The redemption rate of the funding cycle. This number is a percentage calculated out of `JBConstants.MAX_REDEMPTION_RATE`.\n/// @custom:member ballotRedemptionRate The redemption rate to use during an active ballot of the funding cycle. This number is a percentage calculated out of `JBConstants.MAX_REDEMPTION_RATE`.\n/// @custom:member pausePay A flag indicating if the pay functionality should be paused during the funding cycle.\n/// @custom:member pauseDistributions A flag indicating if the distribute functionality should be paused during the funding cycle.\n/// @custom:member pauseRedeem A flag indicating if the redeem functionality should be paused during the funding cycle.\n/// @custom:member pauseBurn A flag indicating if the burn functionality should be paused during the funding cycle.\n/// @custom:member allowMinting A flag indicating if minting tokens should be allowed during this funding cycle.\n/// @custom:member allowTerminalMigration A flag indicating if migrating terminals should be allowed during this funding cycle.\n/// @custom:member allowControllerMigration A flag indicating if migrating controllers should be allowed during this funding cycle.\n/// @custom:member holdFees A flag indicating if fees should be held during this funding cycle.\n/// @custom:member preferClaimedTokenOverride A flag indicating if claimed tokens should always be prefered to unclaimed tokens when minting.\n/// @custom:member useTotalOverflowForRedemptions A flag indicating if redemptions should use the project's balance held in all terminals instead of the project's local terminal balance from which the redemption is being fulfilled.\n/// @custom:member useDataSourceForPay A flag indicating if the data source should be used for pay transactions during this funding cycle.\n/// @custom:member useDataSourceForRedeem A flag indicating if the data source should be used for redeem transactions during this funding cycle.\n/// @custom:member dataSource The data source to use during this funding cycle.\n/// @custom:member metadata Metadata of the metadata, up to uint8 in size.\nstruct JBFundingCycleMetadata {\n JBGlobalFundingCycleMetadata global;\n uint256 reservedRate;\n uint256 redemptionRate;\n uint256 ballotRedemptionRate;\n bool pausePay;\n bool pauseDistributions;\n bool pauseRedeem;\n bool pauseBurn;\n bool allowMinting;\n bool allowTerminalMigration;\n bool allowControllerMigration;\n bool holdFees;\n bool preferClaimedTokenOverride;\n bool useTotalOverflowForRedemptions;\n bool useDataSourceForPay;\n bool useDataSourceForRedeem;\n address dataSource;\n uint256 metadata;\n}\n" + }, + "contracts/structs/JBGlobalFundingCycleMetadata.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @custom:member allowSetTerminals A flag indicating if setting terminals should be allowed during this funding cycle.\n/// @custom:member allowSetController A flag indicating if setting a new controller should be allowed during this funding cycle.\n/// @custom:member pauseTransfers A flag indicating if the project token transfer functionality should be paused during the funding cycle.\nstruct JBGlobalFundingCycleMetadata {\n bool allowSetTerminals;\n bool allowSetController;\n bool pauseTransfers;\n}\n" + }, + "contracts/libraries/JBConstants.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @notice Global constants used across Juicebox contracts.\nlibrary JBConstants {\n uint256 public constant MAX_RESERVED_RATE = 10_000;\n uint256 public constant MAX_REDEMPTION_RATE = 10_000;\n uint256 public constant MAX_DISCOUNT_RATE = 1_000_000_000;\n uint256 public constant SPLITS_TOTAL_PERCENT = 1_000_000_000;\n uint256 public constant MAX_FEE = 1_000_000_000;\n uint256 public constant MAX_FEE_DISCOUNT = 1_000_000_000;\n}\n" + }, + "contracts/libraries/JBGlobalFundingCycleMetadataResolver.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {JBFundingCycleMetadata} from './../structs/JBFundingCycleMetadata.sol';\nimport {JBGlobalFundingCycleMetadata} from './../structs/JBGlobalFundingCycleMetadata.sol';\n\nlibrary JBGlobalFundingCycleMetadataResolver {\n function setTerminalsAllowed(uint8 _data) internal pure returns (bool) {\n return (_data & 1) == 1;\n }\n\n function setControllerAllowed(uint8 _data) internal pure returns (bool) {\n return ((_data >> 1) & 1) == 1;\n }\n\n function transfersPaused(uint8 _data) internal pure returns (bool) {\n return ((_data >> 2) & 1) == 1;\n }\n\n /// @notice Pack the global funding cycle metadata.\n /// @param _metadata The metadata to validate and pack.\n /// @return packed The packed uint256 of all global metadata params. The first 8 bits specify the version.\n function packFundingCycleGlobalMetadata(\n JBGlobalFundingCycleMetadata memory _metadata\n ) internal pure returns (uint256 packed) {\n // allow set terminals in bit 0.\n if (_metadata.allowSetTerminals) packed |= 1;\n // allow set controller in bit 1.\n if (_metadata.allowSetController) packed |= 1 << 1;\n // pause transfers in bit 2.\n if (_metadata.pauseTransfers) packed |= 1 << 2;\n }\n\n /// @notice Expand the global funding cycle metadata.\n /// @param _packedMetadata The packed metadata to expand.\n /// @return metadata The global metadata object.\n function expandMetadata(\n uint8 _packedMetadata\n ) internal pure returns (JBGlobalFundingCycleMetadata memory metadata) {\n return\n JBGlobalFundingCycleMetadata(\n setTerminalsAllowed(_packedMetadata),\n setControllerAllowed(_packedMetadata),\n transfersPaused(_packedMetadata)\n );\n }\n}\n" + }, + "@openzeppelin/contracts/access/Ownable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n _;\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (token/ERC20/extensions/ERC20Votes.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./draft-ERC20Permit.sol\";\nimport \"../../../utils/math/Math.sol\";\nimport \"../../../governance/utils/IVotes.sol\";\nimport \"../../../utils/math/SafeCast.sol\";\nimport \"../../../utils/cryptography/ECDSA.sol\";\n\n/**\n * @dev Extension of ERC20 to support Compound-like voting and delegation. This version is more generic than Compound's,\n * and supports token supply up to 2^224^ - 1, while COMP is limited to 2^96^ - 1.\n *\n * NOTE: If exact COMP compatibility is required, use the {ERC20VotesComp} variant of this module.\n *\n * This extension keeps a history (checkpoints) of each account's vote power. Vote power can be delegated either\n * by calling the {delegate} function directly, or by providing a signature to be used with {delegateBySig}. Voting\n * power can be queried through the public accessors {getVotes} and {getPastVotes}.\n *\n * By default, token balance does not account for voting power. This makes transfers cheaper. The downside is that it\n * requires users to delegate to themselves in order to activate checkpoints and have their voting power tracked.\n *\n * _Available since v4.2._\n */\nabstract contract ERC20Votes is IVotes, ERC20Permit {\n struct Checkpoint {\n uint32 fromBlock;\n uint224 votes;\n }\n\n bytes32 private constant _DELEGATION_TYPEHASH =\n keccak256(\"Delegation(address delegatee,uint256 nonce,uint256 expiry)\");\n\n mapping(address => address) private _delegates;\n mapping(address => Checkpoint[]) private _checkpoints;\n Checkpoint[] private _totalSupplyCheckpoints;\n\n /**\n * @dev Get the `pos`-th checkpoint for `account`.\n */\n function checkpoints(address account, uint32 pos) public view virtual returns (Checkpoint memory) {\n return _checkpoints[account][pos];\n }\n\n /**\n * @dev Get number of checkpoints for `account`.\n */\n function numCheckpoints(address account) public view virtual returns (uint32) {\n return SafeCast.toUint32(_checkpoints[account].length);\n }\n\n /**\n * @dev Get the address `account` is currently delegating to.\n */\n function delegates(address account) public view virtual override returns (address) {\n return _delegates[account];\n }\n\n /**\n * @dev Gets the current votes balance for `account`\n */\n function getVotes(address account) public view virtual override returns (uint256) {\n uint256 pos = _checkpoints[account].length;\n return pos == 0 ? 0 : _checkpoints[account][pos - 1].votes;\n }\n\n /**\n * @dev Retrieve the number of votes for `account` at the end of `blockNumber`.\n *\n * Requirements:\n *\n * - `blockNumber` must have been already mined\n */\n function getPastVotes(address account, uint256 blockNumber) public view virtual override returns (uint256) {\n require(blockNumber < block.number, \"ERC20Votes: block not yet mined\");\n return _checkpointsLookup(_checkpoints[account], blockNumber);\n }\n\n /**\n * @dev Retrieve the `totalSupply` at the end of `blockNumber`. Note, this value is the sum of all balances.\n * It is but NOT the sum of all the delegated votes!\n *\n * Requirements:\n *\n * - `blockNumber` must have been already mined\n */\n function getPastTotalSupply(uint256 blockNumber) public view virtual override returns (uint256) {\n require(blockNumber < block.number, \"ERC20Votes: block not yet mined\");\n return _checkpointsLookup(_totalSupplyCheckpoints, blockNumber);\n }\n\n /**\n * @dev Lookup a value in a list of (sorted) checkpoints.\n */\n function _checkpointsLookup(Checkpoint[] storage ckpts, uint256 blockNumber) private view returns (uint256) {\n // We run a binary search to look for the earliest checkpoint taken after `blockNumber`.\n //\n // During the loop, the index of the wanted checkpoint remains in the range [low-1, high).\n // With each iteration, either `low` or `high` is moved towards the middle of the range to maintain the invariant.\n // - If the middle checkpoint is after `blockNumber`, we look in [low, mid)\n // - If the middle checkpoint is before or equal to `blockNumber`, we look in [mid+1, high)\n // Once we reach a single value (when low == high), we've found the right checkpoint at the index high-1, if not\n // out of bounds (in which case we're looking too far in the past and the result is 0).\n // Note that if the latest checkpoint available is exactly for `blockNumber`, we end up with an index that is\n // past the end of the array, so we technically don't find a checkpoint after `blockNumber`, but it works out\n // the same.\n uint256 high = ckpts.length;\n uint256 low = 0;\n while (low < high) {\n uint256 mid = Math.average(low, high);\n if (ckpts[mid].fromBlock > blockNumber) {\n high = mid;\n } else {\n low = mid + 1;\n }\n }\n\n return high == 0 ? 0 : ckpts[high - 1].votes;\n }\n\n /**\n * @dev Delegate votes from the sender to `delegatee`.\n */\n function delegate(address delegatee) public virtual override {\n _delegate(_msgSender(), delegatee);\n }\n\n /**\n * @dev Delegates votes from signer to `delegatee`\n */\n function delegateBySig(\n address delegatee,\n uint256 nonce,\n uint256 expiry,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) public virtual override {\n require(block.timestamp <= expiry, \"ERC20Votes: signature expired\");\n address signer = ECDSA.recover(\n _hashTypedDataV4(keccak256(abi.encode(_DELEGATION_TYPEHASH, delegatee, nonce, expiry))),\n v,\n r,\n s\n );\n require(nonce == _useNonce(signer), \"ERC20Votes: invalid nonce\");\n _delegate(signer, delegatee);\n }\n\n /**\n * @dev Maximum token supply. Defaults to `type(uint224).max` (2^224^ - 1).\n */\n function _maxSupply() internal view virtual returns (uint224) {\n return type(uint224).max;\n }\n\n /**\n * @dev Snapshots the totalSupply after it has been increased.\n */\n function _mint(address account, uint256 amount) internal virtual override {\n super._mint(account, amount);\n require(totalSupply() <= _maxSupply(), \"ERC20Votes: total supply risks overflowing votes\");\n\n _writeCheckpoint(_totalSupplyCheckpoints, _add, amount);\n }\n\n /**\n * @dev Snapshots the totalSupply after it has been decreased.\n */\n function _burn(address account, uint256 amount) internal virtual override {\n super._burn(account, amount);\n\n _writeCheckpoint(_totalSupplyCheckpoints, _subtract, amount);\n }\n\n /**\n * @dev Move voting power when tokens are transferred.\n *\n * Emits a {DelegateVotesChanged} event.\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual override {\n super._afterTokenTransfer(from, to, amount);\n\n _moveVotingPower(delegates(from), delegates(to), amount);\n }\n\n /**\n * @dev Change delegation for `delegator` to `delegatee`.\n *\n * Emits events {DelegateChanged} and {DelegateVotesChanged}.\n */\n function _delegate(address delegator, address delegatee) internal virtual {\n address currentDelegate = delegates(delegator);\n uint256 delegatorBalance = balanceOf(delegator);\n _delegates[delegator] = delegatee;\n\n emit DelegateChanged(delegator, currentDelegate, delegatee);\n\n _moveVotingPower(currentDelegate, delegatee, delegatorBalance);\n }\n\n function _moveVotingPower(\n address src,\n address dst,\n uint256 amount\n ) private {\n if (src != dst && amount > 0) {\n if (src != address(0)) {\n (uint256 oldWeight, uint256 newWeight) = _writeCheckpoint(_checkpoints[src], _subtract, amount);\n emit DelegateVotesChanged(src, oldWeight, newWeight);\n }\n\n if (dst != address(0)) {\n (uint256 oldWeight, uint256 newWeight) = _writeCheckpoint(_checkpoints[dst], _add, amount);\n emit DelegateVotesChanged(dst, oldWeight, newWeight);\n }\n }\n }\n\n function _writeCheckpoint(\n Checkpoint[] storage ckpts,\n function(uint256, uint256) view returns (uint256) op,\n uint256 delta\n ) private returns (uint256 oldWeight, uint256 newWeight) {\n uint256 pos = ckpts.length;\n oldWeight = pos == 0 ? 0 : ckpts[pos - 1].votes;\n newWeight = op(oldWeight, delta);\n\n if (pos > 0 && ckpts[pos - 1].fromBlock == block.number) {\n ckpts[pos - 1].votes = SafeCast.toUint224(newWeight);\n } else {\n ckpts.push(Checkpoint({fromBlock: SafeCast.toUint32(block.number), votes: SafeCast.toUint224(newWeight)}));\n }\n }\n\n function _add(uint256 a, uint256 b) private pure returns (uint256) {\n return a + b;\n }\n\n function _subtract(uint256 a, uint256 b) private pure returns (uint256) {\n return a - b;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Context.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-ERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./draft-IERC20Permit.sol\";\nimport \"../ERC20.sol\";\nimport \"../../../utils/cryptography/draft-EIP712.sol\";\nimport \"../../../utils/cryptography/ECDSA.sol\";\nimport \"../../../utils/Counters.sol\";\n\n/**\n * @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * _Available since v3.4._\n */\nabstract contract ERC20Permit is ERC20, IERC20Permit, EIP712 {\n using Counters for Counters.Counter;\n\n mapping(address => Counters.Counter) private _nonces;\n\n // solhint-disable-next-line var-name-mixedcase\n bytes32 private immutable _PERMIT_TYPEHASH =\n keccak256(\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\");\n\n /**\n * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `\"1\"`.\n *\n * It's a good idea to use the same `name` that is defined as the ERC20 token name.\n */\n constructor(string memory name) EIP712(name, \"1\") {}\n\n /**\n * @dev See {IERC20Permit-permit}.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) public virtual override {\n require(block.timestamp <= deadline, \"ERC20Permit: expired deadline\");\n\n bytes32 structHash = keccak256(abi.encode(_PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline));\n\n bytes32 hash = _hashTypedDataV4(structHash);\n\n address signer = ECDSA.recover(hash, v, r, s);\n require(signer == owner, \"ERC20Permit: invalid signature\");\n\n _approve(owner, spender, value);\n }\n\n /**\n * @dev See {IERC20Permit-nonces}.\n */\n function nonces(address owner) public view virtual override returns (uint256) {\n return _nonces[owner].current();\n }\n\n /**\n * @dev See {IERC20Permit-DOMAIN_SEPARATOR}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view override returns (bytes32) {\n return _domainSeparatorV4();\n }\n\n /**\n * @dev \"Consume a nonce\": return the current value and increment.\n *\n * _Available since v4.1._\n */\n function _useNonce(address owner) internal virtual returns (uint256 current) {\n Counters.Counter storage nonce = _nonces[owner];\n current = nonce.current();\n nonce.increment();\n }\n}\n" + }, + "@openzeppelin/contracts/utils/math/Math.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n /**\n * @dev Returns the largest of two numbers.\n */\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\n return a >= b ? a : b;\n }\n\n /**\n * @dev Returns the smallest of two numbers.\n */\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\n return a < b ? a : b;\n }\n\n /**\n * @dev Returns the average of two numbers. The result is rounded towards\n * zero.\n */\n function average(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b) / 2 can overflow.\n return (a & b) + (a ^ b) / 2;\n }\n\n /**\n * @dev Returns the ceiling of the division of two numbers.\n *\n * This differs from standard division with `/` in that it rounds up instead\n * of rounding down.\n */\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b - 1) / b can overflow on addition, so we distribute.\n return a / b + (a % b == 0 ? 0 : 1);\n }\n\n /**\n * @dev Returns the absolute unsigned value of a signed value.\n */\n function abs(int256 n) internal pure returns (uint256) {\n unchecked {\n // must be unchecked in order to support `n = type(int256).min`\n return uint256(n >= 0 ? n : -n);\n }\n }\n}\n" + }, + "@openzeppelin/contracts/governance/utils/IVotes.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (governance/utils/IVotes.sol)\npragma solidity ^0.8.0;\n\n/**\n * @dev Common interface for {ERC20Votes}, {ERC721Votes}, and other {Votes}-enabled contracts.\n *\n * _Available since v4.5._\n */\ninterface IVotes {\n /**\n * @dev Emitted when an account changes their delegate.\n */\n event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);\n\n /**\n * @dev Emitted when a token transfer or delegate change results in changes to a delegate's number of votes.\n */\n event DelegateVotesChanged(address indexed delegate, uint256 previousBalance, uint256 newBalance);\n\n /**\n * @dev Returns the current amount of votes that `account` has.\n */\n function getVotes(address account) external view returns (uint256);\n\n /**\n * @dev Returns the amount of votes that `account` had at the end of a past block (`blockNumber`).\n */\n function getPastVotes(address account, uint256 blockNumber) external view returns (uint256);\n\n /**\n * @dev Returns the total supply of votes available at the end of a past block (`blockNumber`).\n *\n * NOTE: This value is the sum of all available votes, which is not necessarily the sum of all delegated votes.\n * Votes that have not been delegated are still part of total supply, even though they would not participate in a\n * vote.\n */\n function getPastTotalSupply(uint256 blockNumber) external view returns (uint256);\n\n /**\n * @dev Returns the delegate that `account` has chosen.\n */\n function delegates(address account) external view returns (address);\n\n /**\n * @dev Delegates votes from the sender to `delegatee`.\n */\n function delegate(address delegatee) external;\n\n /**\n * @dev Delegates votes from signer to `delegatee`.\n */\n function delegateBySig(\n address delegatee,\n uint256 nonce,\n uint256 expiry,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n}\n" + }, + "@openzeppelin/contracts/utils/math/SafeCast.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeCast.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow\n * checks.\n *\n * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can\n * easily result in undesired exploitation or bugs, since developers usually\n * assume that overflows raise errors. `SafeCast` restores this intuition by\n * reverting the transaction when such an operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n *\n * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing\n * all math on `uint256` and `int256` and then downcasting.\n */\nlibrary SafeCast {\n /**\n * @dev Returns the downcasted uint224 from uint256, reverting on\n * overflow (when the input is greater than largest uint224).\n *\n * Counterpart to Solidity's `uint224` operator.\n *\n * Requirements:\n *\n * - input must fit into 224 bits\n */\n function toUint224(uint256 value) internal pure returns (uint224) {\n require(value <= type(uint224).max, \"SafeCast: value doesn't fit in 224 bits\");\n return uint224(value);\n }\n\n /**\n * @dev Returns the downcasted uint128 from uint256, reverting on\n * overflow (when the input is greater than largest uint128).\n *\n * Counterpart to Solidity's `uint128` operator.\n *\n * Requirements:\n *\n * - input must fit into 128 bits\n */\n function toUint128(uint256 value) internal pure returns (uint128) {\n require(value <= type(uint128).max, \"SafeCast: value doesn't fit in 128 bits\");\n return uint128(value);\n }\n\n /**\n * @dev Returns the downcasted uint96 from uint256, reverting on\n * overflow (when the input is greater than largest uint96).\n *\n * Counterpart to Solidity's `uint96` operator.\n *\n * Requirements:\n *\n * - input must fit into 96 bits\n */\n function toUint96(uint256 value) internal pure returns (uint96) {\n require(value <= type(uint96).max, \"SafeCast: value doesn't fit in 96 bits\");\n return uint96(value);\n }\n\n /**\n * @dev Returns the downcasted uint64 from uint256, reverting on\n * overflow (when the input is greater than largest uint64).\n *\n * Counterpart to Solidity's `uint64` operator.\n *\n * Requirements:\n *\n * - input must fit into 64 bits\n */\n function toUint64(uint256 value) internal pure returns (uint64) {\n require(value <= type(uint64).max, \"SafeCast: value doesn't fit in 64 bits\");\n return uint64(value);\n }\n\n /**\n * @dev Returns the downcasted uint32 from uint256, reverting on\n * overflow (when the input is greater than largest uint32).\n *\n * Counterpart to Solidity's `uint32` operator.\n *\n * Requirements:\n *\n * - input must fit into 32 bits\n */\n function toUint32(uint256 value) internal pure returns (uint32) {\n require(value <= type(uint32).max, \"SafeCast: value doesn't fit in 32 bits\");\n return uint32(value);\n }\n\n /**\n * @dev Returns the downcasted uint16 from uint256, reverting on\n * overflow (when the input is greater than largest uint16).\n *\n * Counterpart to Solidity's `uint16` operator.\n *\n * Requirements:\n *\n * - input must fit into 16 bits\n */\n function toUint16(uint256 value) internal pure returns (uint16) {\n require(value <= type(uint16).max, \"SafeCast: value doesn't fit in 16 bits\");\n return uint16(value);\n }\n\n /**\n * @dev Returns the downcasted uint8 from uint256, reverting on\n * overflow (when the input is greater than largest uint8).\n *\n * Counterpart to Solidity's `uint8` operator.\n *\n * Requirements:\n *\n * - input must fit into 8 bits.\n */\n function toUint8(uint256 value) internal pure returns (uint8) {\n require(value <= type(uint8).max, \"SafeCast: value doesn't fit in 8 bits\");\n return uint8(value);\n }\n\n /**\n * @dev Converts a signed int256 into an unsigned uint256.\n *\n * Requirements:\n *\n * - input must be greater than or equal to 0.\n */\n function toUint256(int256 value) internal pure returns (uint256) {\n require(value >= 0, \"SafeCast: value must be positive\");\n return uint256(value);\n }\n\n /**\n * @dev Returns the downcasted int128 from int256, reverting on\n * overflow (when the input is less than smallest int128 or\n * greater than largest int128).\n *\n * Counterpart to Solidity's `int128` operator.\n *\n * Requirements:\n *\n * - input must fit into 128 bits\n *\n * _Available since v3.1._\n */\n function toInt128(int256 value) internal pure returns (int128) {\n require(value >= type(int128).min && value <= type(int128).max, \"SafeCast: value doesn't fit in 128 bits\");\n return int128(value);\n }\n\n /**\n * @dev Returns the downcasted int64 from int256, reverting on\n * overflow (when the input is less than smallest int64 or\n * greater than largest int64).\n *\n * Counterpart to Solidity's `int64` operator.\n *\n * Requirements:\n *\n * - input must fit into 64 bits\n *\n * _Available since v3.1._\n */\n function toInt64(int256 value) internal pure returns (int64) {\n require(value >= type(int64).min && value <= type(int64).max, \"SafeCast: value doesn't fit in 64 bits\");\n return int64(value);\n }\n\n /**\n * @dev Returns the downcasted int32 from int256, reverting on\n * overflow (when the input is less than smallest int32 or\n * greater than largest int32).\n *\n * Counterpart to Solidity's `int32` operator.\n *\n * Requirements:\n *\n * - input must fit into 32 bits\n *\n * _Available since v3.1._\n */\n function toInt32(int256 value) internal pure returns (int32) {\n require(value >= type(int32).min && value <= type(int32).max, \"SafeCast: value doesn't fit in 32 bits\");\n return int32(value);\n }\n\n /**\n * @dev Returns the downcasted int16 from int256, reverting on\n * overflow (when the input is less than smallest int16 or\n * greater than largest int16).\n *\n * Counterpart to Solidity's `int16` operator.\n *\n * Requirements:\n *\n * - input must fit into 16 bits\n *\n * _Available since v3.1._\n */\n function toInt16(int256 value) internal pure returns (int16) {\n require(value >= type(int16).min && value <= type(int16).max, \"SafeCast: value doesn't fit in 16 bits\");\n return int16(value);\n }\n\n /**\n * @dev Returns the downcasted int8 from int256, reverting on\n * overflow (when the input is less than smallest int8 or\n * greater than largest int8).\n *\n * Counterpart to Solidity's `int8` operator.\n *\n * Requirements:\n *\n * - input must fit into 8 bits.\n *\n * _Available since v3.1._\n */\n function toInt8(int256 value) internal pure returns (int8) {\n require(value >= type(int8).min && value <= type(int8).max, \"SafeCast: value doesn't fit in 8 bits\");\n return int8(value);\n }\n\n /**\n * @dev Converts an unsigned uint256 into a signed int256.\n *\n * Requirements:\n *\n * - input must be less than or equal to maxInt256.\n */\n function toInt256(uint256 value) internal pure returns (int256) {\n // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive\n require(value <= uint256(type(int256).max), \"SafeCast: value doesn't fit in an int256\");\n return int256(value);\n }\n}\n" + }, + "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n // Check the signature length\n // - case 65: r,s,v signature (standard)\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else if (signature.length == 64) {\n bytes32 r;\n bytes32 vs;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n vs := mload(add(signature, 0x40))\n }\n return tryRecover(hash, r, vs);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/ERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `recipient` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address recipient, uint256 amount) public virtual override returns (bool) {\n _transfer(_msgSender(), recipient, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n _approve(_msgSender(), spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `sender` and `recipient` cannot be the zero address.\n * - `sender` must have a balance of at least `amount`.\n * - the caller must have allowance for ``sender``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) public virtual override returns (bool) {\n uint256 currentAllowance = _allowances[sender][_msgSender()];\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: transfer amount exceeds allowance\");\n unchecked {\n _approve(sender, _msgSender(), currentAllowance - amount);\n }\n }\n\n _transfer(sender, recipient, amount);\n\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n _approve(_msgSender(), spender, _allowances[_msgSender()][spender] + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n uint256 currentAllowance = _allowances[_msgSender()][spender];\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(_msgSender(), spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `sender` cannot be the zero address.\n * - `recipient` cannot be the zero address.\n * - `sender` must have a balance of at least `amount`.\n */\n function _transfer(\n address sender,\n address recipient,\n uint256 amount\n ) internal virtual {\n require(sender != address(0), \"ERC20: transfer from the zero address\");\n require(recipient != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(sender, recipient, amount);\n\n uint256 senderBalance = _balances[sender];\n require(senderBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[sender] = senderBalance - amount;\n }\n _balances[recipient] += amount;\n\n emit Transfer(sender, recipient, amount);\n\n _afterTokenTransfer(sender, recipient, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" + }, + "@openzeppelin/contracts/utils/cryptography/draft-EIP712.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/cryptography/draft-EIP712.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./ECDSA.sol\";\n\n/**\n * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.\n *\n * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,\n * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding\n * they need in their contracts using a combination of `abi.encode` and `keccak256`.\n *\n * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding\n * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA\n * ({_hashTypedDataV4}).\n *\n * The implementation of the domain separator was designed to be as efficient as possible while still properly updating\n * the chain id to protect against replay attacks on an eventual fork of the chain.\n *\n * NOTE: This contract implements the version of the encoding known as \"v4\", as implemented by the JSON RPC method\n * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].\n *\n * _Available since v3.4._\n */\nabstract contract EIP712 {\n /* solhint-disable var-name-mixedcase */\n // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to\n // invalidate the cached domain separator if the chain id changes.\n bytes32 private immutable _CACHED_DOMAIN_SEPARATOR;\n uint256 private immutable _CACHED_CHAIN_ID;\n address private immutable _CACHED_THIS;\n\n bytes32 private immutable _HASHED_NAME;\n bytes32 private immutable _HASHED_VERSION;\n bytes32 private immutable _TYPE_HASH;\n\n /* solhint-enable var-name-mixedcase */\n\n /**\n * @dev Initializes the domain separator and parameter caches.\n *\n * The meaning of `name` and `version` is specified in\n * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:\n *\n * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.\n * - `version`: the current major version of the signing domain.\n *\n * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart\n * contract upgrade].\n */\n constructor(string memory name, string memory version) {\n bytes32 hashedName = keccak256(bytes(name));\n bytes32 hashedVersion = keccak256(bytes(version));\n bytes32 typeHash = keccak256(\n \"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\"\n );\n _HASHED_NAME = hashedName;\n _HASHED_VERSION = hashedVersion;\n _CACHED_CHAIN_ID = block.chainid;\n _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion);\n _CACHED_THIS = address(this);\n _TYPE_HASH = typeHash;\n }\n\n /**\n * @dev Returns the domain separator for the current chain.\n */\n function _domainSeparatorV4() internal view returns (bytes32) {\n if (address(this) == _CACHED_THIS && block.chainid == _CACHED_CHAIN_ID) {\n return _CACHED_DOMAIN_SEPARATOR;\n } else {\n return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION);\n }\n }\n\n function _buildDomainSeparator(\n bytes32 typeHash,\n bytes32 nameHash,\n bytes32 versionHash\n ) private view returns (bytes32) {\n return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this)));\n }\n\n /**\n * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this\n * function returns the hash of the fully encoded EIP712 message for this domain.\n *\n * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:\n *\n * ```solidity\n * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(\n * keccak256(\"Mail(address to,string contents)\"),\n * mailTo,\n * keccak256(bytes(mailContents))\n * )));\n * address signer = ECDSA.recover(digest, signature);\n * ```\n */\n function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {\n return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Counters.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Counters.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @title Counters\n * @author Matt Condon (@shrugs)\n * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number\n * of elements in a mapping, issuing ERC721 ids, or counting request ids.\n *\n * Include with `using Counters for Counters.Counter;`\n */\nlibrary Counters {\n struct Counter {\n // This variable should never be directly accessed by users of the library: interactions must be restricted to\n // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add\n // this feature: see https://github.com/ethereum/solidity/issues/4637\n uint256 _value; // default: 0\n }\n\n function current(Counter storage counter) internal view returns (uint256) {\n return counter._value;\n }\n\n function increment(Counter storage counter) internal {\n unchecked {\n counter._value += 1;\n }\n }\n\n function decrement(Counter storage counter) internal {\n uint256 value = counter._value;\n require(value > 0, \"Counter: decrement overflow\");\n unchecked {\n counter._value = value - 1;\n }\n }\n\n function reset(Counter storage counter) internal {\n counter._value = 0;\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/IERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address recipient, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) external returns (bool);\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" + }, + "@openzeppelin/contracts/utils/Strings.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n}\n" + }, + "contracts/JBController3_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {ERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {JBOperatable} from './abstract/JBOperatable.sol';\nimport {JBBallotState} from './enums/JBBallotState.sol';\nimport {IJBController3_0_1} from './interfaces/IJBController3_0_1.sol';\nimport {IJBController3_1} from './interfaces/IJBController3_1.sol';\nimport {IJBController} from './interfaces/IJBController.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBFundAccessConstraintsStore} from './interfaces/IJBFundAccessConstraintsStore.sol';\nimport {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol';\nimport {IJBMigratable} from './interfaces/IJBMigratable.sol';\nimport {IJBOperatable} from './interfaces/IJBOperatable.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {IJBSplitAllocator} from './interfaces/IJBSplitAllocator.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {IJBTokenStore} from './interfaces/IJBTokenStore.sol';\nimport {JBConstants} from './libraries/JBConstants.sol';\nimport {JBFundingCycleMetadataResolver} from './libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBOperations} from './libraries/JBOperations.sol';\nimport {JBSplitsGroups} from './libraries/JBSplitsGroups.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\nimport {JBSplitAllocationData} from './structs/JBSplitAllocationData.sol';\nimport {JBFundAccessConstraints} from './structs/JBFundAccessConstraints.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\nimport {JBFundingCycleData} from './structs/JBFundingCycleData.sol';\nimport {JBFundingCycleMetadata} from './structs/JBFundingCycleMetadata.sol';\nimport {JBGroupedSplits} from './structs/JBGroupedSplits.sol';\nimport {JBProjectMetadata} from './structs/JBProjectMetadata.sol';\nimport {JBSplit} from './structs/JBSplit.sol';\n\n/// @notice Stitches together funding cycles and project tokens, making sure all activity is accounted for and correct.\n/// @dev This Controller has the same functionality as JBController3_0_1, except it is not backwards compatible with the original IJBController view methods.\ncontract JBController3_1 is JBOperatable, ERC165, IJBController3_1, IJBMigratable {\n // A library that parses the packed funding cycle metadata into a more friendly format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n\n error BURN_PAUSED_AND_SENDER_NOT_VALID_TERMINAL_DELEGATE();\n error FUNDING_CYCLE_ALREADY_LAUNCHED();\n error INVALID_BALLOT_REDEMPTION_RATE();\n error INVALID_REDEMPTION_RATE();\n error INVALID_RESERVED_RATE();\n error MIGRATION_NOT_ALLOWED();\n error MINT_NOT_ALLOWED_AND_NOT_TERMINAL_DELEGATE();\n error NO_BURNABLE_TOKENS();\n error NOT_CURRENT_CONTROLLER();\n error ZERO_TOKENS_TO_MINT();\n\n //*********************************************************************//\n // --------------------- internal stored properties ------------------ //\n //*********************************************************************//\n\n /// @notice Data regarding the distribution limit of a project during a configuration.\n /// @dev bits 0-231: The amount of token that a project can distribute per funding cycle.\n /// @dev bits 232-255: The currency of amount that a project can distribute.\n /// @custom:param _projectId The ID of the project to get the packed distribution limit data of.\n /// @custom:param _configuration The configuration during which the packed distribution limit data applies.\n /// @custom:param _terminal The terminal from which distributions are being limited.\n /// @custom:param _token The token for which distributions are being limited.\n mapping(uint256 => mapping(uint256 => mapping(IJBPaymentTerminal => mapping(address => uint256))))\n internal _packedDistributionLimitDataOf;\n\n /// @notice Data regarding the overflow allowance of a project during a configuration.\n /// @dev bits 0-231: The amount of overflow that a project is allowed to tap into on-demand throughout the configuration.\n /// @dev bits 232-255: The currency of the amount of overflow that a project is allowed to tap.\n /// @custom:param _projectId The ID of the project to get the packed overflow allowance data of.\n /// @custom:param _configuration The configuration during which the packed overflow allowance data applies.\n /// @custom:param _terminal The terminal managing the overflow.\n /// @custom:param _token The token for which overflow is being allowed.\n mapping(uint256 => mapping(uint256 => mapping(IJBPaymentTerminal => mapping(address => uint256))))\n internal _packedOverflowAllowanceDataOf;\n\n //*********************************************************************//\n // --------------- public immutable stored properties ---------------- //\n //*********************************************************************//\n\n /// @notice Mints ERC-721's that represent project ownership.\n IJBProjects public immutable override projects;\n\n /// @notice The contract storing all funding cycle configurations.\n IJBFundingCycleStore public immutable override fundingCycleStore;\n\n /// @notice The contract that manages token minting and burning.\n IJBTokenStore public immutable override tokenStore;\n\n /// @notice The contract that stores splits for each project.\n IJBSplitsStore public immutable override splitsStore;\n\n /// @notice A contract that stores fund access constraints for each project.\n IJBFundAccessConstraintsStore public immutable override fundAccessConstraintsStore;\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The current undistributed reserved token balance of.\n mapping(uint256 => uint256) public override reservedTokenBalanceOf;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice A project's funding cycle for the specified configuration along with its metadata.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The funding cycle.\n /// @return metadata The funding cycle's metadata.\n function getFundingCycleOf(\n uint256 _projectId,\n uint256 _configuration\n )\n external\n view\n override\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata)\n {\n fundingCycle = fundingCycleStore.get(_projectId, _configuration);\n metadata = fundingCycle.expandMetadata();\n }\n\n /// @notice A project's latest configured funding cycle along with its metadata and the ballot state of the configuration.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The latest configured funding cycle.\n /// @return metadata The latest configured funding cycle's metadata.\n /// @return ballotState The state of the configuration.\n function latestConfiguredFundingCycleOf(\n uint256 _projectId\n )\n external\n view\n override\n returns (\n JBFundingCycle memory fundingCycle,\n JBFundingCycleMetadata memory metadata,\n JBBallotState ballotState\n )\n {\n (fundingCycle, ballotState) = fundingCycleStore.latestConfiguredOf(_projectId);\n metadata = fundingCycle.expandMetadata();\n }\n\n /// @notice A project's current funding cycle along with its metadata.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The current funding cycle.\n /// @return metadata The current funding cycle's metadata.\n function currentFundingCycleOf(\n uint256 _projectId\n )\n external\n view\n override\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata)\n {\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n metadata = fundingCycle.expandMetadata();\n }\n\n /// @notice A project's queued funding cycle along with its metadata.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The queued funding cycle.\n /// @return metadata The queued funding cycle's metadata.\n function queuedFundingCycleOf(\n uint256 _projectId\n )\n external\n view\n override\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata)\n {\n fundingCycle = fundingCycleStore.queuedOf(_projectId);\n metadata = fundingCycle.expandMetadata();\n }\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice Gets the current total amount of outstanding tokens for a project.\n /// @param _projectId The ID of the project to get total outstanding tokens of.\n /// @return The current total amount of outstanding tokens for the project.\n function totalOutstandingTokensOf(uint256 _projectId) public view override returns (uint256) {\n // Add the reserved tokens to the total supply.\n return tokenStore.totalSupplyOf(_projectId) + reservedTokenBalanceOf[_projectId];\n }\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if the provided interface ID is supported.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(ERC165, IERC165) returns (bool) {\n return\n _interfaceId == type(IJBController3_1).interfaceId ||\n _interfaceId == type(IJBController3_0_1).interfaceId ||\n _interfaceId == type(IJBMigratable).interfaceId ||\n _interfaceId == type(IJBOperatable).interfaceId ||\n super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // ---------------------------- constructor -------------------------- //\n //*********************************************************************//\n\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _fundingCycleStore A contract storing all funding cycle configurations.\n /// @param _tokenStore A contract that manages token minting and burning.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _fundAccessConstraintsStore A contract that stores fund access constraints for each project.\n constructor(\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBFundingCycleStore _fundingCycleStore,\n IJBTokenStore _tokenStore,\n IJBSplitsStore _splitsStore,\n IJBFundAccessConstraintsStore _fundAccessConstraintsStore\n ) JBOperatable(_operatorStore) {\n projects = _projects;\n directory = _directory;\n fundingCycleStore = _fundingCycleStore;\n tokenStore = _tokenStore;\n splitsStore = _splitsStore;\n fundAccessConstraintsStore = _fundAccessConstraintsStore;\n }\n\n //*********************************************************************//\n // --------------------- external transactions ----------------------- //\n //*********************************************************************//\n\n /// @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.\n /// @dev Each operation within this transaction can be done in sequence separately.\n /// @dev Anyone can deploy a project on an owner's behalf.\n /// @param _owner The address to set as the owner of the project. The project ERC-721 will be owned by this address.\n /// @param _projectMetadata Metadata to associate with the project within a particular domain. This can be updated any time by the owner of the project.\n /// @param _data Data that defines the project's first funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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`.\n /// @param _terminals Payment terminals to add for the project.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return projectId The ID of the project.\n function launchProjectFor(\n address _owner,\n JBProjectMetadata calldata _projectMetadata,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] calldata _groupedSplits,\n JBFundAccessConstraints[] calldata _fundAccessConstraints,\n IJBPaymentTerminal[] memory _terminals,\n string memory _memo\n ) external virtual override returns (uint256 projectId) {\n // Keep a reference to the directory.\n IJBDirectory _directory = directory;\n\n // Mint the project into the wallet of the owner.\n projectId = projects.createFor(_owner, _projectMetadata);\n\n // Set this contract as the project's controller in the directory.\n _directory.setControllerOf(projectId, address(this));\n\n // Configure the first funding cycle.\n uint256 _configuration = _configure(\n projectId,\n _data,\n _metadata,\n _mustStartAtOrAfter,\n _groupedSplits,\n _fundAccessConstraints\n );\n\n // Add the provided terminals to the list of terminals.\n if (_terminals.length > 0) _directory.setTerminalsOf(projectId, _terminals);\n\n emit LaunchProject(_configuration, projectId, _memo, msg.sender);\n }\n\n /// @notice Creates a funding cycle for an already existing project ERC-721.\n /// @dev Each operation within this transaction can be done in sequence separately.\n /// @dev Only a project owner or operator can launch its funding cycles.\n /// @param _projectId The ID of the project to launch funding cycles for.\n /// @param _data Data that defines the project's first funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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`.\n /// @param _terminals Payment terminals to add for the project.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return configuration The configuration of the funding cycle that was successfully created.\n function launchFundingCyclesFor(\n uint256 _projectId,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] calldata _groupedSplits,\n JBFundAccessConstraints[] memory _fundAccessConstraints,\n IJBPaymentTerminal[] memory _terminals,\n string memory _memo\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.RECONFIGURE)\n returns (uint256 configuration)\n {\n // If there is a previous configuration, reconfigureFundingCyclesOf should be called instead\n if (fundingCycleStore.latestConfigurationOf(_projectId) > 0)\n revert FUNDING_CYCLE_ALREADY_LAUNCHED();\n\n // Set this contract as the project's controller in the directory.\n directory.setControllerOf(_projectId, address(this));\n\n // Configure the first funding cycle.\n configuration = _configure(\n _projectId,\n _data,\n _metadata,\n _mustStartAtOrAfter,\n _groupedSplits,\n _fundAccessConstraints\n );\n\n // Add the provided terminals to the list of terminals.\n if (_terminals.length > 0) directory.setTerminalsOf(_projectId, _terminals);\n\n emit LaunchFundingCycles(configuration, _projectId, _memo, msg.sender);\n }\n\n /// @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.\n /// @dev Only a project's owner or a designated operator can configure its funding cycles.\n /// @param _projectId The ID of the project whose funding cycles are being reconfigured.\n /// @param _data Data that defines the funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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`.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return configuration The configuration of the funding cycle that was successfully reconfigured.\n function reconfigureFundingCyclesOf(\n uint256 _projectId,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] calldata _groupedSplits,\n JBFundAccessConstraints[] calldata _fundAccessConstraints,\n string calldata _memo\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.RECONFIGURE)\n returns (uint256 configuration)\n {\n // Configure the next funding cycle.\n configuration = _configure(\n _projectId,\n _data,\n _metadata,\n _mustStartAtOrAfter,\n _groupedSplits,\n _fundAccessConstraints\n );\n\n emit ReconfigureFundingCycles(configuration, _projectId, _memo, msg.sender);\n }\n\n /// @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.\n /// @dev Only a project's owner, a designated operator, one of its terminals, or the current data source can mint its tokens.\n /// @param _projectId The ID of the project to which the tokens being minted belong.\n /// @param _tokenCount The amount of tokens to mint in total, counting however many should be reserved.\n /// @param _beneficiary The account that the tokens are being minted for.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _preferClaimedTokens A flag indicating whether a project's attached token contract should be minted if they have been issued.\n /// @param _useReservedRate Whether to use the current funding cycle's reserved rate in the mint calculation.\n /// @return beneficiaryTokenCount The amount of tokens minted for the beneficiary.\n function mintTokensOf(\n uint256 _projectId,\n uint256 _tokenCount,\n address _beneficiary,\n string calldata _memo,\n bool _preferClaimedTokens,\n bool _useReservedRate\n ) external virtual override returns (uint256 beneficiaryTokenCount) {\n // There should be tokens to mint.\n if (_tokenCount == 0) revert ZERO_TOKENS_TO_MINT();\n\n // Define variables that will be needed outside scoped section below.\n // Keep a reference to the reserved rate to use\n uint256 _reservedRate;\n\n // Scoped section prevents stack too deep. `_fundingCycle` only used within scope.\n {\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Minting limited to: project owner, authorized callers, project terminal and current funding cycle data source\n _requirePermissionAllowingOverride(\n projects.ownerOf(_projectId),\n _projectId,\n JBOperations.MINT,\n directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender)) ||\n msg.sender == address(_fundingCycle.dataSource())\n );\n\n // If the message sender is not a terminal or a datasource, the current funding cycle must allow minting.\n if (\n !_fundingCycle.mintingAllowed() &&\n !directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender)) &&\n msg.sender != address(_fundingCycle.dataSource())\n ) revert MINT_NOT_ALLOWED_AND_NOT_TERMINAL_DELEGATE();\n\n // Determine the reserved rate to use.\n _reservedRate = _useReservedRate ? _fundingCycle.reservedRate() : 0;\n\n // Override the claimed token preference with the funding cycle value.\n _preferClaimedTokens = _preferClaimedTokens == true\n ? _preferClaimedTokens\n : _fundingCycle.preferClaimedTokenOverride();\n }\n\n if (_reservedRate != JBConstants.MAX_RESERVED_RATE) {\n // The unreserved token count that will be minted for the beneficiary.\n beneficiaryTokenCount = PRBMath.mulDiv(\n _tokenCount,\n JBConstants.MAX_RESERVED_RATE - _reservedRate,\n JBConstants.MAX_RESERVED_RATE\n );\n\n // Mint the tokens.\n tokenStore.mintFor(_beneficiary, _projectId, beneficiaryTokenCount, _preferClaimedTokens);\n }\n\n // Add reserved tokens if needed\n if (_reservedRate > 0)\n reservedTokenBalanceOf[_projectId] += _tokenCount - beneficiaryTokenCount;\n\n emit MintTokens(\n _beneficiary,\n _projectId,\n _tokenCount,\n beneficiaryTokenCount,\n _memo,\n _reservedRate,\n msg.sender\n );\n }\n\n /// @notice Burns a token holder's supply.\n /// @dev Only a token's holder, a designated operator, or a project's terminal can burn it.\n /// @param _holder The account that is having its tokens burned.\n /// @param _projectId The ID of the project to which the tokens being burned belong.\n /// @param _tokenCount The number of tokens to burn.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _preferClaimedTokens A flag indicating whether a project's attached token contract should be burned first if they have been issued.\n function burnTokensOf(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n string calldata _memo,\n bool _preferClaimedTokens\n )\n external\n virtual\n override\n requirePermissionAllowingOverride(\n _holder,\n _projectId,\n JBOperations.BURN,\n directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender))\n )\n {\n // There should be tokens to burn\n if (_tokenCount == 0) revert NO_BURNABLE_TOKENS();\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // If the message sender is a terminal, the current funding cycle must not be paused.\n if (\n _fundingCycle.burnPaused() &&\n !directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender))\n ) revert BURN_PAUSED_AND_SENDER_NOT_VALID_TERMINAL_DELEGATE();\n\n // Burn the tokens.\n tokenStore.burnFrom(_holder, _projectId, _tokenCount, _preferClaimedTokens);\n\n emit BurnTokens(_holder, _projectId, _tokenCount, _memo, msg.sender);\n }\n\n /// @notice Distributes all outstanding reserved tokens for a project.\n /// @param _projectId The ID of the project to which the reserved tokens belong.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return The amount of minted reserved tokens.\n function distributeReservedTokensOf(\n uint256 _projectId,\n string calldata _memo\n ) external virtual override returns (uint256) {\n return _distributeReservedTokensOf(_projectId, _memo);\n }\n\n /// @notice Allows other controllers to signal to this one that a migration is expected for the specified project.\n /// @dev This controller should not yet be the project's controller.\n /// @param _projectId The ID of the project that will be migrated to this controller.\n /// @param _from The controller being migrated from.\n function prepForMigrationOf(uint256 _projectId, address _from) external virtual override {\n _projectId; // Prevents unused var compiler and natspec complaints.\n _from; // Prevents unused var compiler and natspec complaints.\n }\n\n /// @notice Allows a project to migrate from this controller to another.\n /// @dev Only a project's owner or a designated operator can migrate it.\n /// @param _projectId The ID of the project that will be migrated from this controller.\n /// @param _to The controller to which the project is migrating.\n function migrate(\n uint256 _projectId,\n IJBMigratable _to\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.MIGRATE_CONTROLLER)\n {\n // Keep a reference to the directory.\n IJBDirectory _directory = directory;\n\n // This controller must be the project's current controller.\n if (_directory.controllerOf(_projectId) != address(this)) revert NOT_CURRENT_CONTROLLER();\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Migration must be allowed.\n if (!_fundingCycle.controllerMigrationAllowed()) revert MIGRATION_NOT_ALLOWED();\n\n // All reserved tokens must be minted before migrating.\n if (reservedTokenBalanceOf[_projectId] != 0) _distributeReservedTokensOf(_projectId, '');\n\n // Make sure the new controller is prepped for the migration.\n _to.prepForMigrationOf(_projectId, address(this));\n\n // Set the new controller.\n _directory.setControllerOf(_projectId, address(_to));\n\n emit Migrate(_projectId, _to, msg.sender);\n }\n\n //*********************************************************************//\n // ------------------------ internal functions ----------------------- //\n //*********************************************************************//\n\n /// @notice Distributes all outstanding reserved tokens for a project.\n /// @param _projectId The ID of the project to which the reserved tokens belong.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return tokenCount The amount of minted reserved tokens.\n function _distributeReservedTokensOf(\n uint256 _projectId,\n string memory _memo\n ) internal returns (uint256 tokenCount) {\n // Keep a reference to the token store.\n IJBTokenStore _tokenStore = tokenStore;\n\n // Get the current funding cycle to read the reserved rate from.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Get a reference to the number of tokens that need to be minted.\n tokenCount = reservedTokenBalanceOf[_projectId];\n\n // Reset the reserved token balance\n reservedTokenBalanceOf[_projectId] = 0;\n\n // Get a reference to the project owner.\n address _owner = projects.ownerOf(_projectId);\n\n // Distribute tokens to splits and get a reference to the leftover amount to mint after all splits have gotten their share.\n uint256 _leftoverTokenCount = tokenCount == 0\n ? 0\n : _distributeToReservedTokenSplitsOf(\n _projectId,\n _fundingCycle.configuration,\n JBSplitsGroups.RESERVED_TOKENS,\n tokenCount\n );\n\n // Mint any leftover tokens to the project owner.\n if (_leftoverTokenCount > 0)\n _tokenStore.mintFor(_owner, _projectId, _leftoverTokenCount, false);\n\n emit DistributeReservedTokens(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _owner,\n tokenCount,\n _leftoverTokenCount,\n _memo,\n msg.sender\n );\n }\n\n /// @notice Distribute tokens to the splits according to the specified funding cycle configuration.\n /// @param _projectId The ID of the project for which reserved token splits are being distributed.\n /// @param _domain The domain of the splits to distribute the reserved tokens between.\n /// @param _group The group of the splits to distribute the reserved tokens between.\n /// @param _amount The total amount of tokens to mint.\n /// @return leftoverAmount If the splits percents dont add up to 100%, the leftover amount is returned.\n function _distributeToReservedTokenSplitsOf(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group,\n uint256 _amount\n ) internal returns (uint256 leftoverAmount) {\n // Keep a reference to the token store.\n IJBTokenStore _tokenStore = tokenStore;\n\n // Set the leftover amount to the initial amount.\n leftoverAmount = _amount;\n\n // Get a reference to the project's reserved token splits.\n JBSplit[] memory _splits = splitsStore.splitsOf(_projectId, _domain, _group);\n\n //Transfer between all splits.\n for (uint256 _i; _i < _splits.length; ) {\n // Get a reference to the split being iterated on.\n JBSplit memory _split = _splits[_i];\n\n // The amount to send towards the split.\n uint256 _tokenCount = PRBMath.mulDiv(\n _amount,\n _split.percent,\n JBConstants.SPLITS_TOTAL_PERCENT\n );\n\n // Mints tokens for the split if needed.\n if (_tokenCount > 0) {\n _tokenStore.mintFor(\n // If an allocator is set in the splits, set it as the beneficiary.\n // Otherwise if a projectId is set in the split, set the project's owner as the beneficiary.\n // If the split has a beneficiary send to the split's beneficiary. Otherwise send to the msg.sender.\n _split.allocator != IJBSplitAllocator(address(0))\n ? address(_split.allocator)\n : _split.projectId != 0\n ? projects.ownerOf(_split.projectId)\n : _split.beneficiary != address(0)\n ? _split.beneficiary\n : msg.sender,\n _projectId,\n _tokenCount,\n _split.preferClaimed\n );\n\n // If there's an allocator set, trigger its `allocate` function.\n if (_split.allocator != IJBSplitAllocator(address(0)))\n _split.allocator.allocate(\n JBSplitAllocationData(\n address(_tokenStore.tokenOf(_projectId)),\n _tokenCount,\n 18,\n _projectId,\n _group,\n _split\n )\n );\n\n // Subtract from the amount to be sent to the beneficiary.\n leftoverAmount = leftoverAmount - _tokenCount;\n }\n\n emit DistributeToReservedTokenSplit(\n _projectId,\n _domain,\n _group,\n _split,\n _tokenCount,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n\n /// @notice Configures a funding cycle and stores information pertinent to the configuration.\n /// @param _projectId The ID of the project whose funding cycles are being reconfigured.\n /// @param _data Data that defines the funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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.\n /// @return configuration The configuration of the funding cycle that was successfully reconfigured.\n function _configure(\n uint256 _projectId,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] memory _groupedSplits,\n JBFundAccessConstraints[] memory _fundAccessConstraints\n ) internal returns (uint256) {\n // Make sure the provided reserved rate is valid.\n if (_metadata.reservedRate > JBConstants.MAX_RESERVED_RATE) revert INVALID_RESERVED_RATE();\n\n // Make sure the provided redemption rate is valid.\n if (_metadata.redemptionRate > JBConstants.MAX_REDEMPTION_RATE)\n revert INVALID_REDEMPTION_RATE();\n\n // Make sure the provided ballot redemption rate is valid.\n if (_metadata.ballotRedemptionRate > JBConstants.MAX_REDEMPTION_RATE)\n revert INVALID_BALLOT_REDEMPTION_RATE();\n\n // Configure the funding cycle's properties.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.configureFor(\n _projectId,\n _data,\n JBFundingCycleMetadataResolver.packFundingCycleMetadata(_metadata),\n _mustStartAtOrAfter\n );\n\n // Set splits for the group.\n splitsStore.set(_projectId, _fundingCycle.configuration, _groupedSplits);\n\n // Set the funds access constraints.\n fundAccessConstraintsStore.setFor(\n _projectId,\n _fundingCycle.configuration,\n _fundAccessConstraints\n );\n\n return _fundingCycle.configuration;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/introspection/ERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC165.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n *\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n" + }, + "@paulrberg/contracts/math/PRBMath.sol": { + "content": "// SPDX-License-Identifier: Unlicense\npragma solidity >=0.8.4;\n\nimport \"prb-math/contracts/PRBMath.sol\";\n" + }, + "contracts/interfaces/IJBController3_0_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBController3_0_1 {\n function reservedTokenBalanceOf(uint256 projectId) external view returns (uint256);\n\n function totalOutstandingTokensOf(uint256 projectId) external view returns (uint256);\n}\n" + }, + "contracts/interfaces/IJBController3_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBBallotState} from './../enums/JBBallotState.sol';\nimport {JBFundAccessConstraints} from './../structs/JBFundAccessConstraints.sol';\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\nimport {JBFundingCycleData} from './../structs/JBFundingCycleData.sol';\nimport {JBFundingCycleMetadata} from './../structs/JBFundingCycleMetadata.sol';\nimport {JBGroupedSplits} from './../structs/JBGroupedSplits.sol';\nimport {JBProjectMetadata} from './../structs/JBProjectMetadata.sol';\nimport {JBSplit} from './../structs/JBSplit.sol';\nimport {IJBController3_0_1} from './IJBController3_0_1.sol';\nimport {IJBDirectory} from './IJBDirectory.sol';\nimport {IJBFundAccessConstraintsStore} from './IJBFundAccessConstraintsStore.sol';\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\nimport {IJBMigratable} from './IJBMigratable.sol';\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\nimport {IJBProjects} from './IJBProjects.sol';\nimport {IJBSplitsStore} from './IJBSplitsStore.sol';\nimport {IJBTokenStore} from './IJBTokenStore.sol';\n\ninterface IJBController3_1 is IJBController3_0_1, IERC165 {\n event LaunchProject(uint256 configuration, uint256 projectId, string memo, address caller);\n\n event LaunchFundingCycles(uint256 configuration, uint256 projectId, string memo, address caller);\n\n event ReconfigureFundingCycles(\n uint256 configuration,\n uint256 projectId,\n string memo,\n address caller\n );\n\n event DistributeReservedTokens(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n address beneficiary,\n uint256 tokenCount,\n uint256 beneficiaryTokenCount,\n string memo,\n address caller\n );\n\n event DistributeToReservedTokenSplit(\n uint256 indexed projectId,\n uint256 indexed domain,\n uint256 indexed group,\n JBSplit split,\n uint256 tokenCount,\n address caller\n );\n\n event MintTokens(\n address indexed beneficiary,\n uint256 indexed projectId,\n uint256 tokenCount,\n uint256 beneficiaryTokenCount,\n string memo,\n uint256 reservedRate,\n address caller\n );\n\n event BurnTokens(\n address indexed holder,\n uint256 indexed projectId,\n uint256 tokenCount,\n string memo,\n address caller\n );\n\n event Migrate(uint256 indexed projectId, IJBMigratable to, address caller);\n\n event PrepMigration(uint256 indexed projectId, address from, address caller);\n\n function projects() external view returns (IJBProjects);\n\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\n\n function tokenStore() external view returns (IJBTokenStore);\n\n function splitsStore() external view returns (IJBSplitsStore);\n\n function fundAccessConstraintsStore() external view returns (IJBFundAccessConstraintsStore);\n\n function directory() external view returns (IJBDirectory);\n\n function reservedTokenBalanceOf(uint256 projectId) external view returns (uint256);\n\n function totalOutstandingTokensOf(uint256 projectId) external view returns (uint256);\n\n function getFundingCycleOf(\n uint256 projectId,\n uint256 configuration\n )\n external\n view\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata);\n\n function latestConfiguredFundingCycleOf(\n uint256 projectId\n )\n external\n view\n returns (JBFundingCycle memory, JBFundingCycleMetadata memory metadata, JBBallotState);\n\n function currentFundingCycleOf(\n uint256 projectId\n )\n external\n view\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata);\n\n function queuedFundingCycleOf(\n uint256 projectId\n )\n external\n view\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata);\n\n function launchProjectFor(\n address owner,\n JBProjectMetadata calldata projectMetadata,\n JBFundingCycleData calldata data,\n JBFundingCycleMetadata calldata metadata,\n uint256 mustStartAtOrAfter,\n JBGroupedSplits[] memory groupedSplits,\n JBFundAccessConstraints[] memory fundAccessConstraints,\n IJBPaymentTerminal[] memory terminals,\n string calldata memo\n ) external returns (uint256 projectId);\n\n function launchFundingCyclesFor(\n uint256 projectId,\n JBFundingCycleData calldata data,\n JBFundingCycleMetadata calldata metadata,\n uint256 mustStartAtOrAfter,\n JBGroupedSplits[] memory groupedSplits,\n JBFundAccessConstraints[] memory fundAccessConstraints,\n IJBPaymentTerminal[] memory terminals,\n string calldata memo\n ) external returns (uint256 configuration);\n\n function reconfigureFundingCyclesOf(\n uint256 projectId,\n JBFundingCycleData calldata data,\n JBFundingCycleMetadata calldata metadata,\n uint256 mustStartAtOrAfter,\n JBGroupedSplits[] memory groupedSplits,\n JBFundAccessConstraints[] memory fundAccessConstraints,\n string calldata memo\n ) external returns (uint256);\n\n function mintTokensOf(\n uint256 projectId,\n uint256 tokenCount,\n address beneficiary,\n string calldata memo,\n bool preferClaimedTokens,\n bool useReservedRate\n ) external returns (uint256 beneficiaryTokenCount);\n\n function burnTokensOf(\n address holder,\n uint256 projectId,\n uint256 tokenCount,\n string calldata memo,\n bool preferClaimedTokens\n ) external;\n\n function distributeReservedTokensOf(\n uint256 projectId,\n string memory memo\n ) external returns (uint256);\n\n function migrate(uint256 projectId, IJBMigratable to) external;\n}\n" + }, + "contracts/interfaces/IJBController.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBBallotState} from './../enums/JBBallotState.sol';\nimport {JBFundAccessConstraints} from './../structs/JBFundAccessConstraints.sol';\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\nimport {JBFundingCycleData} from './../structs/JBFundingCycleData.sol';\nimport {JBFundingCycleMetadata} from './../structs/JBFundingCycleMetadata.sol';\nimport {JBGroupedSplits} from './../structs/JBGroupedSplits.sol';\nimport {JBProjectMetadata} from './../structs/JBProjectMetadata.sol';\nimport {JBSplit} from './../structs/JBSplit.sol';\nimport {IJBDirectory} from './IJBDirectory.sol';\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\nimport {IJBMigratable} from './IJBMigratable.sol';\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\nimport {IJBProjects} from './IJBProjects.sol';\nimport {IJBSplitsStore} from './IJBSplitsStore.sol';\nimport {IJBTokenStore} from './IJBTokenStore.sol';\n\ninterface IJBController is IERC165 {\n event LaunchProject(uint256 configuration, uint256 projectId, string memo, address caller);\n\n event LaunchFundingCycles(uint256 configuration, uint256 projectId, string memo, address caller);\n\n event ReconfigureFundingCycles(\n uint256 configuration,\n uint256 projectId,\n string memo,\n address caller\n );\n\n event SetFundAccessConstraints(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n JBFundAccessConstraints constraints,\n address caller\n );\n\n event DistributeReservedTokens(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n address beneficiary,\n uint256 tokenCount,\n uint256 beneficiaryTokenCount,\n string memo,\n address caller\n );\n\n event DistributeToReservedTokenSplit(\n uint256 indexed projectId,\n uint256 indexed domain,\n uint256 indexed group,\n JBSplit split,\n uint256 tokenCount,\n address caller\n );\n\n event MintTokens(\n address indexed beneficiary,\n uint256 indexed projectId,\n uint256 tokenCount,\n uint256 beneficiaryTokenCount,\n string memo,\n uint256 reservedRate,\n address caller\n );\n\n event BurnTokens(\n address indexed holder,\n uint256 indexed projectId,\n uint256 tokenCount,\n string memo,\n address caller\n );\n\n event Migrate(uint256 indexed projectId, IJBMigratable to, address caller);\n\n event PrepMigration(uint256 indexed projectId, address from, address caller);\n\n function projects() external view returns (IJBProjects);\n\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\n\n function tokenStore() external view returns (IJBTokenStore);\n\n function splitsStore() external view returns (IJBSplitsStore);\n\n function directory() external view returns (IJBDirectory);\n\n function reservedTokenBalanceOf(\n uint256 projectId,\n uint256 reservedRate\n ) external view returns (uint256);\n\n function distributionLimitOf(\n uint256 projectId,\n uint256 configuration,\n IJBPaymentTerminal terminal,\n address token\n ) external view returns (uint256 distributionLimit, uint256 distributionLimitCurrency);\n\n function overflowAllowanceOf(\n uint256 projectId,\n uint256 configuration,\n IJBPaymentTerminal terminal,\n address token\n ) external view returns (uint256 overflowAllowance, uint256 overflowAllowanceCurrency);\n\n function totalOutstandingTokensOf(\n uint256 projectId,\n uint256 reservedRate\n ) external view returns (uint256);\n\n function getFundingCycleOf(\n uint256 projectId,\n uint256 configuration\n )\n external\n view\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata);\n\n function latestConfiguredFundingCycleOf(\n uint256 projectId\n )\n external\n view\n returns (JBFundingCycle memory, JBFundingCycleMetadata memory metadata, JBBallotState);\n\n function currentFundingCycleOf(\n uint256 projectId\n )\n external\n view\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata);\n\n function queuedFundingCycleOf(\n uint256 projectId\n )\n external\n view\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata);\n\n function launchProjectFor(\n address owner,\n JBProjectMetadata calldata projectMetadata,\n JBFundingCycleData calldata data,\n JBFundingCycleMetadata calldata metadata,\n uint256 mustStartAtOrAfter,\n JBGroupedSplits[] memory groupedSplits,\n JBFundAccessConstraints[] memory fundAccessConstraints,\n IJBPaymentTerminal[] memory terminals,\n string calldata memo\n ) external returns (uint256 projectId);\n\n function launchFundingCyclesFor(\n uint256 projectId,\n JBFundingCycleData calldata data,\n JBFundingCycleMetadata calldata metadata,\n uint256 mustStartAtOrAfter,\n JBGroupedSplits[] memory groupedSplits,\n JBFundAccessConstraints[] memory fundAccessConstraints,\n IJBPaymentTerminal[] memory terminals,\n string calldata memo\n ) external returns (uint256 configuration);\n\n function reconfigureFundingCyclesOf(\n uint256 projectId,\n JBFundingCycleData calldata data,\n JBFundingCycleMetadata calldata metadata,\n uint256 mustStartAtOrAfter,\n JBGroupedSplits[] memory groupedSplits,\n JBFundAccessConstraints[] memory fundAccessConstraints,\n string calldata memo\n ) external returns (uint256);\n\n function mintTokensOf(\n uint256 projectId,\n uint256 tokenCount,\n address beneficiary,\n string calldata memo,\n bool preferClaimedTokens,\n bool useReservedRate\n ) external returns (uint256 beneficiaryTokenCount);\n\n function burnTokensOf(\n address holder,\n uint256 projectId,\n uint256 tokenCount,\n string calldata memo,\n bool preferClaimedTokens\n ) external;\n\n function distributeReservedTokensOf(\n uint256 projectId,\n string memory memo\n ) external returns (uint256);\n\n function migrate(uint256 projectId, IJBMigratable to) external;\n}\n" + }, + "contracts/interfaces/IJBFundAccessConstraintsStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBFundAccessConstraints} from './../structs/JBFundAccessConstraints.sol';\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\n\ninterface IJBFundAccessConstraintsStore is IERC165 {\n event SetFundAccessConstraints(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed projectId,\n JBFundAccessConstraints constraints,\n address caller\n );\n\n function distributionLimitOf(\n uint256 projectId,\n uint256 configuration,\n IJBPaymentTerminal terminal,\n address token\n ) external view returns (uint256 distributionLimit, uint256 distributionLimitCurrency);\n\n function overflowAllowanceOf(\n uint256 projectId,\n uint256 configuration,\n IJBPaymentTerminal terminal,\n address token\n ) external view returns (uint256 overflowAllowance, uint256 overflowAllowanceCurrency);\n\n function setFor(\n uint256 projectId,\n uint256 configuration,\n JBFundAccessConstraints[] memory fundAccessConstaints\n ) external;\n}\n" + }, + "contracts/interfaces/IJBMigratable.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBMigratable {\n function prepForMigrationOf(uint256 projectId, address from) external;\n}\n" + }, + "contracts/interfaces/IJBSplitAllocator.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBSplitAllocationData} from '../structs/JBSplitAllocationData.sol';\n\n/// @title Split allocator\n/// @notice Provide a way to process a single split with extra logic\n/// @dev The contract address should be set as an allocator in the adequate split\ninterface IJBSplitAllocator is IERC165 {\n /// @notice This function is called by JBPaymentTerminal.distributePayoutOf(..), during the processing of the split including it\n /// @dev Critical business logic should be protected by an appropriate access control. The token and/or eth are optimistically transfered to the allocator for its logic.\n /// @param data the data passed by the terminal, as a JBSplitAllocationData struct:\n function allocate(JBSplitAllocationData calldata data) external payable;\n}\n" + }, + "contracts/interfaces/IJBSplitsStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBGroupedSplits} from './../structs/JBGroupedSplits.sol';\nimport {JBSplit} from './../structs/JBSplit.sol';\nimport {IJBDirectory} from './IJBDirectory.sol';\nimport {IJBProjects} from './IJBProjects.sol';\n\ninterface IJBSplitsStore {\n event SetSplit(\n uint256 indexed projectId,\n uint256 indexed domain,\n uint256 indexed group,\n JBSplit split,\n address caller\n );\n\n function projects() external view returns (IJBProjects);\n\n function directory() external view returns (IJBDirectory);\n\n function splitsOf(\n uint256 projectId,\n uint256 domain,\n uint256 group\n ) external view returns (JBSplit[] memory);\n\n function set(uint256 projectId, uint256 domain, JBGroupedSplits[] memory groupedSplits) external;\n}\n" + }, + "contracts/libraries/JBSplitsGroups.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nlibrary JBSplitsGroups {\n uint256 public constant ETH_PAYOUT = 1;\n uint256 public constant RESERVED_TOKENS = 2;\n}\n" + }, + "contracts/structs/JBSplitAllocationData.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBSplit} from './JBSplit.sol';\n\n/// @custom:member token The token being sent to the split allocator.\n/// @custom:member amount The amount being sent to the split allocator, as a fixed point number.\n/// @custom:member decimals The number of decimals in the amount.\n/// @custom:member projectId The project to which the split belongs.\n/// @custom:member group The group to which the split belongs.\n/// @custom:member split The split that caused the allocation.\nstruct JBSplitAllocationData {\n address token;\n uint256 amount;\n uint256 decimals;\n uint256 projectId;\n uint256 group;\n JBSplit split;\n}\n" + }, + "contracts/structs/JBFundAccessConstraints.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\n\n/// @custom:member terminal The terminal within which the distribution limit and the overflow allowance applies.\n/// @custom:member token The token for which the fund access constraints apply.\n/// @custom:member distributionLimit The amount of the distribution limit, as a fixed point number with the same number of decimals as the terminal within which the limit applies.\n/// @custom:member distributionLimitCurrency The currency of the distribution limit.\n/// @custom:member overflowAllowance The amount of the allowance, as a fixed point number with the same number of decimals as the terminal within which the allowance applies.\n/// @custom:member overflowAllowanceCurrency The currency of the overflow allowance.\nstruct JBFundAccessConstraints {\n IJBPaymentTerminal terminal;\n address token;\n uint256 distributionLimit;\n uint256 distributionLimitCurrency;\n uint256 overflowAllowance;\n uint256 overflowAllowanceCurrency;\n}\n" + }, + "contracts/structs/JBGroupedSplits.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBSplit} from './JBSplit.sol';\n\n/// @custom:member group The group indentifier.\n/// @custom:member splits The splits to associate with the group.\nstruct JBGroupedSplits {\n uint256 group;\n JBSplit[] splits;\n}\n" + }, + "contracts/structs/JBSplit.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBSplitAllocator} from './../interfaces/IJBSplitAllocator.sol';\n\n/// @custom:member preferClaimed A flag that only has effect if a projectId is also specified, and the project has a token contract attached. If so, this flag indicates if the tokens that result from making a payment to the project should be delivered claimed into the beneficiary's wallet, or unclaimed to save gas.\n/// @custom:member preferAddToBalance A flag indicating if a distribution to a project should prefer triggering it's addToBalance function instead of its pay function.\n/// @custom:member percent The percent of the whole group that this split occupies. This number is out of `JBConstants.SPLITS_TOTAL_PERCENT`.\n/// @custom:member projectId The ID of a project. If an allocator is not set but a projectId is set, funds will be sent to the protocol treasury belonging to the project who's ID is specified. Resulting tokens will be routed to the beneficiary with the claimed token preference respected.\n/// @custom:member beneficiary An address. The role the of the beneficary depends on whether or not projectId is specified, and whether or not an allocator is specified. If allocator is set, the beneficiary will be forwarded to the allocator for it to use. If allocator is not set but projectId is set, the beneficiary is the address to which the project's tokens will be sent that result from a payment to it. If neither allocator or projectId are set, the beneficiary is where the funds from the split will be sent.\n/// @custom:member lockedUntil Specifies if the split should be unchangeable until the specified time, with the exception of extending the locked period.\n/// @custom:member allocator If an allocator is specified, funds will be sent to the allocator contract along with all properties of this split.\nstruct JBSplit {\n bool preferClaimed;\n bool preferAddToBalance;\n uint256 percent;\n uint256 projectId;\n address payable beneficiary;\n uint256 lockedUntil;\n IJBSplitAllocator allocator;\n}\n" + }, + "prb-math/contracts/PRBMath.sol": { + "content": "// SPDX-License-Identifier: Unlicense\npragma solidity >=0.8.4;\n\n/// @notice Emitted when the result overflows uint256.\nerror PRBMath__MulDivFixedPointOverflow(uint256 prod1);\n\n/// @notice Emitted when the result overflows uint256.\nerror PRBMath__MulDivOverflow(uint256 prod1, uint256 denominator);\n\n/// @notice Emitted when one of the inputs is type(int256).min.\nerror PRBMath__MulDivSignedInputTooSmall();\n\n/// @notice Emitted when the intermediary absolute result overflows int256.\nerror PRBMath__MulDivSignedOverflow(uint256 rAbs);\n\n/// @notice Emitted when the input is MIN_SD59x18.\nerror PRBMathSD59x18__AbsInputTooSmall();\n\n/// @notice Emitted when ceiling a number overflows SD59x18.\nerror PRBMathSD59x18__CeilOverflow(int256 x);\n\n/// @notice Emitted when one of the inputs is MIN_SD59x18.\nerror PRBMathSD59x18__DivInputTooSmall();\n\n/// @notice Emitted when one of the intermediary unsigned results overflows SD59x18.\nerror PRBMathSD59x18__DivOverflow(uint256 rAbs);\n\n/// @notice Emitted when the input is greater than 133.084258667509499441.\nerror PRBMathSD59x18__ExpInputTooBig(int256 x);\n\n/// @notice Emitted when the input is greater than 192.\nerror PRBMathSD59x18__Exp2InputTooBig(int256 x);\n\n/// @notice Emitted when flooring a number underflows SD59x18.\nerror PRBMathSD59x18__FloorUnderflow(int256 x);\n\n/// @notice Emitted when converting a basic integer to the fixed-point format overflows SD59x18.\nerror PRBMathSD59x18__FromIntOverflow(int256 x);\n\n/// @notice Emitted when converting a basic integer to the fixed-point format underflows SD59x18.\nerror PRBMathSD59x18__FromIntUnderflow(int256 x);\n\n/// @notice Emitted when the product of the inputs is negative.\nerror PRBMathSD59x18__GmNegativeProduct(int256 x, int256 y);\n\n/// @notice Emitted when multiplying the inputs overflows SD59x18.\nerror PRBMathSD59x18__GmOverflow(int256 x, int256 y);\n\n/// @notice Emitted when the input is less than or equal to zero.\nerror PRBMathSD59x18__LogInputTooSmall(int256 x);\n\n/// @notice Emitted when one of the inputs is MIN_SD59x18.\nerror PRBMathSD59x18__MulInputTooSmall();\n\n/// @notice Emitted when the intermediary absolute result overflows SD59x18.\nerror PRBMathSD59x18__MulOverflow(uint256 rAbs);\n\n/// @notice Emitted when the intermediary absolute result overflows SD59x18.\nerror PRBMathSD59x18__PowuOverflow(uint256 rAbs);\n\n/// @notice Emitted when the input is negative.\nerror PRBMathSD59x18__SqrtNegativeInput(int256 x);\n\n/// @notice Emitted when the calculating the square root overflows SD59x18.\nerror PRBMathSD59x18__SqrtOverflow(int256 x);\n\n/// @notice Emitted when addition overflows UD60x18.\nerror PRBMathUD60x18__AddOverflow(uint256 x, uint256 y);\n\n/// @notice Emitted when ceiling a number overflows UD60x18.\nerror PRBMathUD60x18__CeilOverflow(uint256 x);\n\n/// @notice Emitted when the input is greater than 133.084258667509499441.\nerror PRBMathUD60x18__ExpInputTooBig(uint256 x);\n\n/// @notice Emitted when the input is greater than 192.\nerror PRBMathUD60x18__Exp2InputTooBig(uint256 x);\n\n/// @notice Emitted when converting a basic integer to the fixed-point format format overflows UD60x18.\nerror PRBMathUD60x18__FromUintOverflow(uint256 x);\n\n/// @notice Emitted when multiplying the inputs overflows UD60x18.\nerror PRBMathUD60x18__GmOverflow(uint256 x, uint256 y);\n\n/// @notice Emitted when the input is less than 1.\nerror PRBMathUD60x18__LogInputTooSmall(uint256 x);\n\n/// @notice Emitted when the calculating the square root overflows UD60x18.\nerror PRBMathUD60x18__SqrtOverflow(uint256 x);\n\n/// @notice Emitted when subtraction underflows UD60x18.\nerror PRBMathUD60x18__SubUnderflow(uint256 x, uint256 y);\n\n/// @dev Common mathematical functions used in both PRBMathSD59x18 and PRBMathUD60x18. Note that this shared library\n/// does not always assume the signed 59.18-decimal fixed-point or the unsigned 60.18-decimal fixed-point\n/// representation. When it does not, it is explicitly mentioned in the NatSpec documentation.\nlibrary PRBMath {\n /// STRUCTS ///\n\n struct SD59x18 {\n int256 value;\n }\n\n struct UD60x18 {\n uint256 value;\n }\n\n /// STORAGE ///\n\n /// @dev How many trailing decimals can be represented.\n uint256 internal constant SCALE = 1e18;\n\n /// @dev Largest power of two divisor of SCALE.\n uint256 internal constant SCALE_LPOTD = 262144;\n\n /// @dev SCALE inverted mod 2^256.\n uint256 internal constant SCALE_INVERSE =\n 78156646155174841979727994598816262306175212592076161876661_508869554232690281;\n\n /// FUNCTIONS ///\n\n /// @notice Calculates the binary exponent of x using the binary fraction method.\n /// @dev Has to use 192.64-bit fixed-point numbers.\n /// See https://ethereum.stackexchange.com/a/96594/24693.\n /// @param x The exponent as an unsigned 192.64-bit fixed-point number.\n /// @return result The result as an unsigned 60.18-decimal fixed-point number.\n function exp2(uint256 x) internal pure returns (uint256 result) {\n unchecked {\n // Start from 0.5 in the 192.64-bit fixed-point format.\n result = 0x800000000000000000000000000000000000000000000000;\n\n // Multiply the result by root(2, 2^-i) when the bit at position i is 1. None of the intermediary results overflows\n // because the initial result is 2^191 and all magic factors are less than 2^65.\n if (x & 0x8000000000000000 > 0) {\n result = (result * 0x16A09E667F3BCC909) >> 64;\n }\n if (x & 0x4000000000000000 > 0) {\n result = (result * 0x1306FE0A31B7152DF) >> 64;\n }\n if (x & 0x2000000000000000 > 0) {\n result = (result * 0x1172B83C7D517ADCE) >> 64;\n }\n if (x & 0x1000000000000000 > 0) {\n result = (result * 0x10B5586CF9890F62A) >> 64;\n }\n if (x & 0x800000000000000 > 0) {\n result = (result * 0x1059B0D31585743AE) >> 64;\n }\n if (x & 0x400000000000000 > 0) {\n result = (result * 0x102C9A3E778060EE7) >> 64;\n }\n if (x & 0x200000000000000 > 0) {\n result = (result * 0x10163DA9FB33356D8) >> 64;\n }\n if (x & 0x100000000000000 > 0) {\n result = (result * 0x100B1AFA5ABCBED61) >> 64;\n }\n if (x & 0x80000000000000 > 0) {\n result = (result * 0x10058C86DA1C09EA2) >> 64;\n }\n if (x & 0x40000000000000 > 0) {\n result = (result * 0x1002C605E2E8CEC50) >> 64;\n }\n if (x & 0x20000000000000 > 0) {\n result = (result * 0x100162F3904051FA1) >> 64;\n }\n if (x & 0x10000000000000 > 0) {\n result = (result * 0x1000B175EFFDC76BA) >> 64;\n }\n if (x & 0x8000000000000 > 0) {\n result = (result * 0x100058BA01FB9F96D) >> 64;\n }\n if (x & 0x4000000000000 > 0) {\n result = (result * 0x10002C5CC37DA9492) >> 64;\n }\n if (x & 0x2000000000000 > 0) {\n result = (result * 0x1000162E525EE0547) >> 64;\n }\n if (x & 0x1000000000000 > 0) {\n result = (result * 0x10000B17255775C04) >> 64;\n }\n if (x & 0x800000000000 > 0) {\n result = (result * 0x1000058B91B5BC9AE) >> 64;\n }\n if (x & 0x400000000000 > 0) {\n result = (result * 0x100002C5C89D5EC6D) >> 64;\n }\n if (x & 0x200000000000 > 0) {\n result = (result * 0x10000162E43F4F831) >> 64;\n }\n if (x & 0x100000000000 > 0) {\n result = (result * 0x100000B1721BCFC9A) >> 64;\n }\n if (x & 0x80000000000 > 0) {\n result = (result * 0x10000058B90CF1E6E) >> 64;\n }\n if (x & 0x40000000000 > 0) {\n result = (result * 0x1000002C5C863B73F) >> 64;\n }\n if (x & 0x20000000000 > 0) {\n result = (result * 0x100000162E430E5A2) >> 64;\n }\n if (x & 0x10000000000 > 0) {\n result = (result * 0x1000000B172183551) >> 64;\n }\n if (x & 0x8000000000 > 0) {\n result = (result * 0x100000058B90C0B49) >> 64;\n }\n if (x & 0x4000000000 > 0) {\n result = (result * 0x10000002C5C8601CC) >> 64;\n }\n if (x & 0x2000000000 > 0) {\n result = (result * 0x1000000162E42FFF0) >> 64;\n }\n if (x & 0x1000000000 > 0) {\n result = (result * 0x10000000B17217FBB) >> 64;\n }\n if (x & 0x800000000 > 0) {\n result = (result * 0x1000000058B90BFCE) >> 64;\n }\n if (x & 0x400000000 > 0) {\n result = (result * 0x100000002C5C85FE3) >> 64;\n }\n if (x & 0x200000000 > 0) {\n result = (result * 0x10000000162E42FF1) >> 64;\n }\n if (x & 0x100000000 > 0) {\n result = (result * 0x100000000B17217F8) >> 64;\n }\n if (x & 0x80000000 > 0) {\n result = (result * 0x10000000058B90BFC) >> 64;\n }\n if (x & 0x40000000 > 0) {\n result = (result * 0x1000000002C5C85FE) >> 64;\n }\n if (x & 0x20000000 > 0) {\n result = (result * 0x100000000162E42FF) >> 64;\n }\n if (x & 0x10000000 > 0) {\n result = (result * 0x1000000000B17217F) >> 64;\n }\n if (x & 0x8000000 > 0) {\n result = (result * 0x100000000058B90C0) >> 64;\n }\n if (x & 0x4000000 > 0) {\n result = (result * 0x10000000002C5C860) >> 64;\n }\n if (x & 0x2000000 > 0) {\n result = (result * 0x1000000000162E430) >> 64;\n }\n if (x & 0x1000000 > 0) {\n result = (result * 0x10000000000B17218) >> 64;\n }\n if (x & 0x800000 > 0) {\n result = (result * 0x1000000000058B90C) >> 64;\n }\n if (x & 0x400000 > 0) {\n result = (result * 0x100000000002C5C86) >> 64;\n }\n if (x & 0x200000 > 0) {\n result = (result * 0x10000000000162E43) >> 64;\n }\n if (x & 0x100000 > 0) {\n result = (result * 0x100000000000B1721) >> 64;\n }\n if (x & 0x80000 > 0) {\n result = (result * 0x10000000000058B91) >> 64;\n }\n if (x & 0x40000 > 0) {\n result = (result * 0x1000000000002C5C8) >> 64;\n }\n if (x & 0x20000 > 0) {\n result = (result * 0x100000000000162E4) >> 64;\n }\n if (x & 0x10000 > 0) {\n result = (result * 0x1000000000000B172) >> 64;\n }\n if (x & 0x8000 > 0) {\n result = (result * 0x100000000000058B9) >> 64;\n }\n if (x & 0x4000 > 0) {\n result = (result * 0x10000000000002C5D) >> 64;\n }\n if (x & 0x2000 > 0) {\n result = (result * 0x1000000000000162E) >> 64;\n }\n if (x & 0x1000 > 0) {\n result = (result * 0x10000000000000B17) >> 64;\n }\n if (x & 0x800 > 0) {\n result = (result * 0x1000000000000058C) >> 64;\n }\n if (x & 0x400 > 0) {\n result = (result * 0x100000000000002C6) >> 64;\n }\n if (x & 0x200 > 0) {\n result = (result * 0x10000000000000163) >> 64;\n }\n if (x & 0x100 > 0) {\n result = (result * 0x100000000000000B1) >> 64;\n }\n if (x & 0x80 > 0) {\n result = (result * 0x10000000000000059) >> 64;\n }\n if (x & 0x40 > 0) {\n result = (result * 0x1000000000000002C) >> 64;\n }\n if (x & 0x20 > 0) {\n result = (result * 0x10000000000000016) >> 64;\n }\n if (x & 0x10 > 0) {\n result = (result * 0x1000000000000000B) >> 64;\n }\n if (x & 0x8 > 0) {\n result = (result * 0x10000000000000006) >> 64;\n }\n if (x & 0x4 > 0) {\n result = (result * 0x10000000000000003) >> 64;\n }\n if (x & 0x2 > 0) {\n result = (result * 0x10000000000000001) >> 64;\n }\n if (x & 0x1 > 0) {\n result = (result * 0x10000000000000001) >> 64;\n }\n\n // We're doing two things at the same time:\n //\n // 1. Multiply the result by 2^n + 1, where \"2^n\" is the integer part and the one is added to account for\n // the fact that we initially set the result to 0.5. This is accomplished by subtracting from 191\n // rather than 192.\n // 2. Convert the result to the unsigned 60.18-decimal fixed-point format.\n //\n // This works because 2^(191-ip) = 2^ip / 2^191, where \"ip\" is the integer part \"2^n\".\n result *= SCALE;\n result >>= (191 - (x >> 64));\n }\n }\n\n /// @notice Finds the zero-based index of the first one in the binary representation of x.\n /// @dev See the note on msb in the \"Find First Set\" Wikipedia article https://en.wikipedia.org/wiki/Find_first_set\n /// @param x The uint256 number for which to find the index of the most significant bit.\n /// @return msb The index of the most significant bit as an uint256.\n function mostSignificantBit(uint256 x) internal pure returns (uint256 msb) {\n if (x >= 2**128) {\n x >>= 128;\n msb += 128;\n }\n if (x >= 2**64) {\n x >>= 64;\n msb += 64;\n }\n if (x >= 2**32) {\n x >>= 32;\n msb += 32;\n }\n if (x >= 2**16) {\n x >>= 16;\n msb += 16;\n }\n if (x >= 2**8) {\n x >>= 8;\n msb += 8;\n }\n if (x >= 2**4) {\n x >>= 4;\n msb += 4;\n }\n if (x >= 2**2) {\n x >>= 2;\n msb += 2;\n }\n if (x >= 2**1) {\n // No need to shift x any more.\n msb += 1;\n }\n }\n\n /// @notice Calculates floor(x*y÷denominator) with full precision.\n ///\n /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv.\n ///\n /// Requirements:\n /// - The denominator cannot be zero.\n /// - The result must fit within uint256.\n ///\n /// Caveats:\n /// - This function does not work with fixed-point numbers.\n ///\n /// @param x The multiplicand as an uint256.\n /// @param y The multiplier as an uint256.\n /// @param denominator The divisor as an uint256.\n /// @return result The result as an uint256.\n function mulDiv(\n uint256 x,\n uint256 y,\n uint256 denominator\n ) internal pure returns (uint256 result) {\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n // variables such that product = prod1 * 2^256 + prod0.\n uint256 prod0; // Least significant 256 bits of the product\n uint256 prod1; // Most significant 256 bits of the product\n assembly {\n let mm := mulmod(x, y, not(0))\n prod0 := mul(x, y)\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n }\n\n // Handle non-overflow cases, 256 by 256 division.\n if (prod1 == 0) {\n unchecked {\n result = prod0 / denominator;\n }\n return result;\n }\n\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\n if (prod1 >= denominator) {\n revert PRBMath__MulDivOverflow(prod1, denominator);\n }\n\n ///////////////////////////////////////////////\n // 512 by 256 division.\n ///////////////////////////////////////////////\n\n // Make division exact by subtracting the remainder from [prod1 prod0].\n uint256 remainder;\n assembly {\n // Compute remainder using mulmod.\n remainder := mulmod(x, y, denominator)\n\n // Subtract 256 bit number from 512 bit number.\n prod1 := sub(prod1, gt(remainder, prod0))\n prod0 := sub(prod0, remainder)\n }\n\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\n // See https://cs.stackexchange.com/q/138556/92363.\n unchecked {\n // Does not overflow because the denominator cannot be zero at this stage in the function.\n uint256 lpotdod = denominator & (~denominator + 1);\n assembly {\n // Divide denominator by lpotdod.\n denominator := div(denominator, lpotdod)\n\n // Divide [prod1 prod0] by lpotdod.\n prod0 := div(prod0, lpotdod)\n\n // Flip lpotdod such that it is 2^256 / lpotdod. If lpotdod is zero, then it becomes one.\n lpotdod := add(div(sub(0, lpotdod), lpotdod), 1)\n }\n\n // Shift in bits from prod1 into prod0.\n prod0 |= prod1 * lpotdod;\n\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\n // four bits. That is, denominator * inv = 1 mod 2^4.\n uint256 inverse = (3 * denominator) ^ 2;\n\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\n // in modular arithmetic, doubling the correct bits in each step.\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\n\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\n // is no longer required.\n result = prod0 * inverse;\n return result;\n }\n }\n\n /// @notice Calculates floor(x*y÷1e18) with full precision.\n ///\n /// @dev Variant of \"mulDiv\" with constant folding, i.e. in which the denominator is always 1e18. Before returning the\n /// final result, we add 1 if (x * y) % SCALE >= HALF_SCALE. Without this, 6.6e-19 would be truncated to 0 instead of\n /// being rounded to 1e-18. See \"Listing 6\" and text above it at https://accu.org/index.php/journals/1717.\n ///\n /// Requirements:\n /// - The result must fit within uint256.\n ///\n /// Caveats:\n /// - The body is purposely left uncommented; see the NatSpec comments in \"PRBMath.mulDiv\" to understand how this works.\n /// - It is assumed that the result can never be type(uint256).max when x and y solve the following two equations:\n /// 1. x * y = type(uint256).max * SCALE\n /// 2. (x * y) % SCALE >= SCALE / 2\n ///\n /// @param x The multiplicand as an unsigned 60.18-decimal fixed-point number.\n /// @param y The multiplier as an unsigned 60.18-decimal fixed-point number.\n /// @return result The result as an unsigned 60.18-decimal fixed-point number.\n function mulDivFixedPoint(uint256 x, uint256 y) internal pure returns (uint256 result) {\n uint256 prod0;\n uint256 prod1;\n assembly {\n let mm := mulmod(x, y, not(0))\n prod0 := mul(x, y)\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n }\n\n if (prod1 >= SCALE) {\n revert PRBMath__MulDivFixedPointOverflow(prod1);\n }\n\n uint256 remainder;\n uint256 roundUpUnit;\n assembly {\n remainder := mulmod(x, y, SCALE)\n roundUpUnit := gt(remainder, 499999999999999999)\n }\n\n if (prod1 == 0) {\n unchecked {\n result = (prod0 / SCALE) + roundUpUnit;\n return result;\n }\n }\n\n assembly {\n result := add(\n mul(\n or(\n div(sub(prod0, remainder), SCALE_LPOTD),\n mul(sub(prod1, gt(remainder, prod0)), add(div(sub(0, SCALE_LPOTD), SCALE_LPOTD), 1))\n ),\n SCALE_INVERSE\n ),\n roundUpUnit\n )\n }\n }\n\n /// @notice Calculates floor(x*y÷denominator) with full precision.\n ///\n /// @dev An extension of \"mulDiv\" for signed numbers. Works by computing the signs and the absolute values separately.\n ///\n /// Requirements:\n /// - None of the inputs can be type(int256).min.\n /// - The result must fit within int256.\n ///\n /// @param x The multiplicand as an int256.\n /// @param y The multiplier as an int256.\n /// @param denominator The divisor as an int256.\n /// @return result The result as an int256.\n function mulDivSigned(\n int256 x,\n int256 y,\n int256 denominator\n ) internal pure returns (int256 result) {\n if (x == type(int256).min || y == type(int256).min || denominator == type(int256).min) {\n revert PRBMath__MulDivSignedInputTooSmall();\n }\n\n // Get hold of the absolute values of x, y and the denominator.\n uint256 ax;\n uint256 ay;\n uint256 ad;\n unchecked {\n ax = x < 0 ? uint256(-x) : uint256(x);\n ay = y < 0 ? uint256(-y) : uint256(y);\n ad = denominator < 0 ? uint256(-denominator) : uint256(denominator);\n }\n\n // Compute the absolute value of (x*y)÷denominator. The result must fit within int256.\n uint256 rAbs = mulDiv(ax, ay, ad);\n if (rAbs > uint256(type(int256).max)) {\n revert PRBMath__MulDivSignedOverflow(rAbs);\n }\n\n // Get the signs of x, y and the denominator.\n uint256 sx;\n uint256 sy;\n uint256 sd;\n assembly {\n sx := sgt(x, sub(0, 1))\n sy := sgt(y, sub(0, 1))\n sd := sgt(denominator, sub(0, 1))\n }\n\n // XOR over sx, sy and sd. This is checking whether there are one or three negative signs in the inputs.\n // If yes, the result should be negative.\n result = sx ^ sy ^ sd == 0 ? -int256(rAbs) : int256(rAbs);\n }\n\n /// @notice Calculates the square root of x, rounding down.\n /// @dev Uses the Babylonian method https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method.\n ///\n /// Caveats:\n /// - This function does not work with fixed-point numbers.\n ///\n /// @param x The uint256 number for which to calculate the square root.\n /// @return result The result as an uint256.\n function sqrt(uint256 x) internal pure returns (uint256 result) {\n if (x == 0) {\n return 0;\n }\n\n // Set the initial guess to the closest power of two that is higher than x.\n uint256 xAux = uint256(x);\n result = 1;\n if (xAux >= 0x100000000000000000000000000000000) {\n xAux >>= 128;\n result <<= 64;\n }\n if (xAux >= 0x10000000000000000) {\n xAux >>= 64;\n result <<= 32;\n }\n if (xAux >= 0x100000000) {\n xAux >>= 32;\n result <<= 16;\n }\n if (xAux >= 0x10000) {\n xAux >>= 16;\n result <<= 8;\n }\n if (xAux >= 0x100) {\n xAux >>= 8;\n result <<= 4;\n }\n if (xAux >= 0x10) {\n xAux >>= 4;\n result <<= 2;\n }\n if (xAux >= 0x8) {\n result <<= 1;\n }\n\n // The operations can never overflow because the result is max 2^127 when it enters this block.\n unchecked {\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1; // Seven iterations should be enough\n uint256 roundedDownResult = x / result;\n return result >= roundedDownResult ? roundedDownResult : result;\n }\n }\n}\n" + }, + "contracts/JBSplitsStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {JBOperatable} from './abstract/JBOperatable.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {IJBSplitAllocator} from './interfaces/IJBSplitAllocator.sol';\nimport {JBConstants} from './libraries/JBConstants.sol';\nimport {JBOperations} from './libraries/JBOperations.sol';\nimport {JBGroupedSplits} from './structs/JBGroupedSplits.sol';\nimport {JBSplit} from './structs/JBSplit.sol';\n\n/// @notice Stores splits for each project.\ncontract JBSplitsStore is JBOperatable, IJBSplitsStore {\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error INVALID_LOCKED_UNTIL();\n error INVALID_PROJECT_ID();\n error INVALID_SPLIT_PERCENT();\n error INVALID_TOTAL_PERCENT();\n error PREVIOUS_LOCKED_SPLITS_NOT_INCLUDED();\n\n //*********************************************************************//\n // --------------------- private stored properties ------------------- //\n //*********************************************************************//\n\n /// @notice The number of splits currently set for each project ID's configurations.\n /// @custom:param _projectId The ID of the project to get the split count for.\n /// @custom:param _domain An identifier within which the returned splits should be considered active.\n /// @custom:param _group The identifying group of the splits.\n mapping(uint256 => mapping(uint256 => mapping(uint256 => uint256))) private _splitCountOf;\n\n /// @notice Packed data of splits for each project ID's configurations.\n /// @custom:param _projectId The ID of the project to get packed splits data for.\n /// @custom:param _domain An identifier within which the returned splits should be considered active.\n /// @custom:param _group The identifying group of the splits.\n /// @custom:param _index The indexed order that the split was set at.\n mapping(uint256 => mapping(uint256 => mapping(uint256 => mapping(uint256 => uint256))))\n private _packedSplitParts1Of;\n\n /// @notice More packed data of splits for each project ID's configurations.\n /// @dev This packed data is often 0.\n /// @custom:param _projectId The ID of the project to get packed splits data for.\n /// @custom:param _domain An identifier within which the returned splits should be considered active.\n /// @custom:param _group The identifying group of the splits.\n /// @custom:param _index The indexed order that the split was set at.\n mapping(uint256 => mapping(uint256 => mapping(uint256 => mapping(uint256 => uint256))))\n private _packedSplitParts2Of;\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice Mints ERC-721's that represent project ownership and transfers.\n IJBProjects public immutable override projects;\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Get all splits for the specified project ID, within the specified domain, for the specified group.\n /// @param _projectId The ID of the project to get splits for.\n /// @param _domain An identifier within which the returned splits should be considered active.\n /// @param _group The identifying group of the splits.\n /// @return An array of all splits for the project.\n function splitsOf(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group\n ) external view override returns (JBSplit[] memory) {\n return _getStructsFor(_projectId, _domain, _group);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n constructor(\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory\n ) JBOperatable(_operatorStore) {\n projects = _projects;\n directory = _directory;\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Sets a project's splits.\n /// @dev Only the owner or operator of a project, or the current controller contract of the project, can set its splits.\n /// @dev The new splits must include any currently set splits that are locked.\n /// @param _projectId The ID of the project for which splits are being added.\n /// @param _domain An identifier within which the splits should be considered active.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n function set(\n uint256 _projectId,\n uint256 _domain,\n JBGroupedSplits[] calldata _groupedSplits\n )\n external\n override\n requirePermissionAllowingOverride(\n projects.ownerOf(_projectId),\n _projectId,\n JBOperations.SET_SPLITS,\n address(directory.controllerOf(_projectId)) == msg.sender\n )\n {\n // Push array length in stack\n uint256 _groupedSplitsLength = _groupedSplits.length;\n\n // Set each grouped splits.\n for (uint256 _i; _i < _groupedSplitsLength; ) {\n // Get a reference to the grouped split being iterated on.\n JBGroupedSplits memory _groupedSplit = _groupedSplits[_i];\n\n // Set the splits for the group.\n _set(_projectId, _domain, _groupedSplit.group, _groupedSplit.splits);\n\n unchecked {\n ++_i;\n }\n }\n }\n\n //*********************************************************************//\n // --------------------- private helper functions -------------------- //\n //*********************************************************************//\n\n /// @notice Sets a project's splits.\n /// @dev The new splits must include any currently set splits that are locked.\n /// @param _projectId The ID of the project for which splits are being added.\n /// @param _domain An identifier within which the splits should be considered active.\n /// @param _group An identifier between of splits being set. All splits within this _group must add up to within 100%.\n /// @param _splits The splits to set.\n function _set(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group,\n JBSplit[] memory _splits\n ) internal {\n // Get a reference to the project's current splits.\n JBSplit[] memory _currentSplits = _getStructsFor(_projectId, _domain, _group);\n\n // Keep a reference to the number of splits.\n uint256 _currentSplitsLength = _currentSplits.length;\n\n // Check to see if all locked splits are included.\n for (uint256 _i; _i < _currentSplitsLength; ) {\n // If not locked, continue.\n if (\n block.timestamp < _currentSplits[_i].lockedUntil &&\n !_includesLocked(_splits, _currentSplits[_i])\n ) revert PREVIOUS_LOCKED_SPLITS_NOT_INCLUDED();\n\n unchecked {\n ++_i;\n }\n }\n\n // Add up all the percents to make sure they cumulatively are under 100%.\n uint256 _percentTotal;\n\n // Keep a reference to the number of splits.\n uint256 _splitsLength = _splits.length;\n\n for (uint256 _i; _i < _splitsLength; ) {\n // The percent should be greater than 0.\n if (_splits[_i].percent == 0) revert INVALID_SPLIT_PERCENT();\n\n // ProjectId should be within a uint56\n if (_splits[_i].projectId > type(uint56).max) revert INVALID_PROJECT_ID();\n\n // Add to the total percents.\n _percentTotal = _percentTotal + _splits[_i].percent;\n\n // Validate the total does not exceed the expected value.\n if (_percentTotal > JBConstants.SPLITS_TOTAL_PERCENT) revert INVALID_TOTAL_PERCENT();\n\n uint256 _packedSplitParts1;\n\n // prefer claimed in bit 0.\n if (_splits[_i].preferClaimed) _packedSplitParts1 = 1;\n // prefer add to balance in bit 1.\n if (_splits[_i].preferAddToBalance) _packedSplitParts1 |= 1 << 1;\n // percent in bits 2-33.\n _packedSplitParts1 |= _splits[_i].percent << 2;\n // projectId in bits 32-89.\n _packedSplitParts1 |= _splits[_i].projectId << 34;\n // beneficiary in bits 90-249.\n _packedSplitParts1 |= uint256(uint160(address(_splits[_i].beneficiary))) << 90;\n\n // Store the first split part.\n _packedSplitParts1Of[_projectId][_domain][_group][_i] = _packedSplitParts1;\n\n // If there's data to store in the second packed split part, pack and store.\n if (_splits[_i].lockedUntil > 0 || _splits[_i].allocator != IJBSplitAllocator(address(0))) {\n // Locked until should be within a uint48\n if (_splits[_i].lockedUntil > type(uint48).max) revert INVALID_LOCKED_UNTIL();\n\n // lockedUntil in bits 0-47.\n uint256 _packedSplitParts2 = uint48(_splits[_i].lockedUntil);\n // allocator in bits 48-207.\n _packedSplitParts2 |= uint256(uint160(address(_splits[_i].allocator))) << 48;\n\n // Store the second split part.\n _packedSplitParts2Of[_projectId][_domain][_group][_i] = _packedSplitParts2;\n\n // Otherwise if there's a value stored in the indexed position, delete it.\n } else if (_packedSplitParts2Of[_projectId][_domain][_group][_i] > 0)\n delete _packedSplitParts2Of[_projectId][_domain][_group][_i];\n\n emit SetSplit(_projectId, _domain, _group, _splits[_i], msg.sender);\n\n unchecked {\n ++_i;\n }\n }\n\n // Set the new length of the splits.\n _splitCountOf[_projectId][_domain][_group] = _splitsLength;\n }\n\n /// @notice A flag indiciating if the provided splits array includes the locked split.\n /// @param _splits The array of splits to check within.\n /// @param _lockedSplit The locked split.\n /// @return A flag indicating if the `_lockedSplit` is contained in the `_splits`.\n function _includesLocked(\n JBSplit[] memory _splits,\n JBSplit memory _lockedSplit\n ) private pure returns (bool) {\n // Keep a reference to the number of splits.\n uint256 _numberOfSplits = _splits.length;\n\n for (uint256 _i; _i < _numberOfSplits; ) {\n // Check for sameness.\n if (\n _splits[_i].percent == _lockedSplit.percent &&\n _splits[_i].beneficiary == _lockedSplit.beneficiary &&\n _splits[_i].allocator == _lockedSplit.allocator &&\n _splits[_i].projectId == _lockedSplit.projectId &&\n _splits[_i].preferClaimed == _lockedSplit.preferClaimed &&\n _splits[_i].preferAddToBalance == _lockedSplit.preferAddToBalance &&\n // Allow lock extention.\n _splits[_i].lockedUntil >= _lockedSplit.lockedUntil\n ) return true;\n\n unchecked {\n ++_i;\n }\n }\n\n return false;\n }\n\n /// @notice Unpack splits' packed stored values into easy-to-work-with split structs.\n /// @param _projectId The ID of the project to which the split belongs.\n /// @param _domain The identifier within which the returned splits should be considered active.\n /// @param _group The identifying group of the splits.\n /// @return splits The split structs.\n function _getStructsFor(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group\n ) private view returns (JBSplit[] memory) {\n // Get a reference to the number of splits that need to be added to the returned array.\n uint256 _splitCount = _splitCountOf[_projectId][_domain][_group];\n\n // Initialize an array to be returned that has the set length.\n JBSplit[] memory _splits = new JBSplit[](_splitCount);\n\n // Loop through each split and unpack the values into structs.\n for (uint256 _i; _i < _splitCount; ) {\n // Get a reference to the fist packed data.\n uint256 _packedSplitPart1 = _packedSplitParts1Of[_projectId][_domain][_group][_i];\n\n // Populate the split struct.\n JBSplit memory _split;\n\n // prefer claimed in bit 0.\n _split.preferClaimed = _packedSplitPart1 & 1 == 1;\n // prefer add to balance in bit 1.\n _split.preferAddToBalance = (_packedSplitPart1 >> 1) & 1 == 1;\n // percent in bits 2-33.\n _split.percent = uint256(uint32(_packedSplitPart1 >> 2));\n // projectId in bits 32-89.\n _split.projectId = uint256(uint56(_packedSplitPart1 >> 34));\n // beneficiary in bits 90-249.\n _split.beneficiary = payable(address(uint160(_packedSplitPart1 >> 90)));\n\n // Get a reference to the second packed data.\n uint256 _packedSplitPart2 = _packedSplitParts2Of[_projectId][_domain][_group][_i];\n\n // If there's anything in it, unpack.\n if (_packedSplitPart2 > 0) {\n // lockedUntil in bits 0-47.\n _split.lockedUntil = uint256(uint48(_packedSplitPart2));\n // allocator in bits 48-207.\n _split.allocator = IJBSplitAllocator(address(uint160(_packedSplitPart2 >> 48)));\n }\n\n // Add the split to the value being returned.\n _splits[_i] = _split;\n\n unchecked {\n ++_i;\n }\n }\n\n return _splits;\n }\n}\n" + }, + "contracts/JBETHERC20SplitsPayerDeployer.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Clones} from '@openzeppelin/contracts/proxy/Clones.sol';\nimport {IJBETHERC20SplitsPayerDeployer} from './interfaces/IJBETHERC20SplitsPayerDeployer.sol';\nimport {IJBSplitsPayer} from './interfaces/IJBSplitsPayer.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {JBSplit} from './structs/JBSplit.sol';\nimport {JBGroupedSplits} from './structs/JBGroupedSplits.sol';\nimport {JBETHERC20SplitsPayer} from './JBETHERC20SplitsPayer.sol';\n\n/// @notice Deploys splits payer contracts.\ncontract JBETHERC20SplitsPayerDeployer is IJBETHERC20SplitsPayerDeployer {\n //*********************************************************************//\n // --------------- public immutable stored properties ---------------- //\n //*********************************************************************//\n\n /// @notice The implementation contract on which Clones will be based.\n address immutable implementation;\n\n /// @notice The contract that stores splits for each project.\n IJBSplitsStore immutable splitsStore;\n\n //*********************************************************************//\n // ---------------------------- constructor -------------------------- //\n //*********************************************************************//\n\n /// @param _splitsStore The contract that stores splits for each project.\n constructor(IJBSplitsStore _splitsStore) {\n implementation = address(new JBETHERC20SplitsPayer(_splitsStore));\n splitsStore = _splitsStore;\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Allows anyone to deploy a new splits payer contract.\n /// @dev This contract must have Operator permissions over the SET_SPLITS permission of the specified `_defaultSplitsProjectId`.\n /// @param _defaultSplitsProjectId The ID of project for which the default splits are stored.\n /// @param _defaultSplits The splits to payout when this contract receives direct payments.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _defaultProjectId The ID of the project whose treasury should be forwarded the splits payer contract's received payment leftovers after distributing to the default splits group.\n /// @param _defaultBeneficiary The address that'll receive the project's tokens when the splits payer receives payments.\n /// @param _defaultPreferClaimedTokens A flag indicating whether issued tokens from the splits payer's received payments should be automatically claimed into the beneficiary's wallet.\n /// @param _defaultMemo The memo that'll be forwarded with the splits payer's received payments.\n /// @param _defaultMetadata The metadata that'll be forwarded with the splits payer's received payments.\n /// @param _defaultPreferAddToBalance A flag indicating if received payments should call the `pay` function or the `addToBalance` function of a project.\n /// @param _owner The address that will own the splits payer.\n /// @return splitsPayer The splits payer contract.\n function deploySplitsPayerWithSplits(\n uint256 _defaultSplitsProjectId,\n JBSplit[] memory _defaultSplits,\n IJBSplitsStore _splitsStore,\n uint256 _defaultProjectId,\n address payable _defaultBeneficiary,\n bool _defaultPreferClaimedTokens,\n string memory _defaultMemo,\n bytes memory _defaultMetadata,\n bool _defaultPreferAddToBalance,\n address _owner\n ) external override returns (IJBSplitsPayer splitsPayer) {\n // Use this contract's address as the domain.\n uint256 _domain = uint256(uint160(address(this)));\n\n // Create the random hash using data unique to this instance that'll be used as the storage domain.\n uint256 _group = uint256(keccak256(abi.encodePacked(msg.sender, block.number)));\n\n // Set the splits in the store.\n JBGroupedSplits[] memory _groupedSplits;\n _groupedSplits = new JBGroupedSplits[](1);\n _groupedSplits[0] = JBGroupedSplits(_group, _defaultSplits);\n _splitsStore.set(_defaultSplitsProjectId, _domain, _groupedSplits);\n\n return\n deploySplitsPayer(\n _defaultSplitsProjectId,\n _domain,\n _group,\n _defaultProjectId,\n _defaultBeneficiary,\n _defaultPreferClaimedTokens,\n _defaultMemo,\n _defaultMetadata,\n _defaultPreferAddToBalance,\n _owner\n );\n }\n\n //*********************************************************************//\n // ---------------------- public transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Allows anyone to deploy a new splits payer contract.\n /// @param _defaultSplitsProjectId The ID of project for which the default splits are stored.\n /// @param _defaultSplitsDomain The splits domain to payout when this contract receives direct payments.\n /// @param _defaultSplitsGroup The splits group to payout when this contract receives direct payments.\n /// @param _defaultProjectId The ID of the project whose treasury should be forwarded the splits payer contract's received payment leftovers after distributing to the default splits group.\n /// @param _defaultBeneficiary The address that'll receive the project's tokens when the splits payer receives payments.\n /// @param _defaultPreferClaimedTokens A flag indicating whether issued tokens from the splits payer's received payments should be automatically claimed into the beneficiary's wallet.\n /// @param _defaultMemo The memo that'll be forwarded with the splits payer's received payments.\n /// @param _defaultMetadata The metadata that'll be forwarded with the splits payer's received payments.\n /// @param _defaultPreferAddToBalance A flag indicating if received payments should call the `pay` function or the `addToBalance` function of a project.\n /// @param _owner The address that will own the splits payer.\n /// @return splitsPayer The splits payer contract.\n function deploySplitsPayer(\n uint256 _defaultSplitsProjectId,\n uint256 _defaultSplitsDomain,\n uint256 _defaultSplitsGroup,\n uint256 _defaultProjectId,\n address payable _defaultBeneficiary,\n bool _defaultPreferClaimedTokens,\n string memory _defaultMemo,\n bytes memory _defaultMetadata,\n bool _defaultPreferAddToBalance,\n address _owner\n ) public override returns (IJBSplitsPayer splitsPayer) {\n // Deploy the splits payer.\n splitsPayer = IJBSplitsPayer(payable(Clones.clone(implementation)));\n\n splitsPayer.initialize(\n _defaultSplitsProjectId,\n _defaultSplitsDomain,\n _defaultSplitsGroup,\n _defaultProjectId,\n _defaultBeneficiary,\n _defaultPreferClaimedTokens,\n _defaultMemo,\n _defaultMetadata,\n _defaultPreferAddToBalance,\n _owner\n );\n\n emit DeploySplitsPayer(\n splitsPayer,\n _defaultSplitsProjectId,\n _defaultSplitsDomain,\n _defaultSplitsGroup,\n splitsStore,\n _defaultProjectId,\n _defaultBeneficiary,\n _defaultPreferClaimedTokens,\n _defaultMemo,\n _defaultMetadata,\n _defaultPreferAddToBalance,\n _owner,\n msg.sender\n );\n }\n}\n" + }, + "@openzeppelin/contracts/proxy/Clones.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (proxy/Clones.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for\n * deploying minimal proxy contracts, also known as \"clones\".\n *\n * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies\n * > a minimal bytecode implementation that delegates all calls to a known, fixed address.\n *\n * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`\n * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the\n * deterministic method.\n *\n * _Available since v3.4._\n */\nlibrary Clones {\n /**\n * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.\n *\n * This function uses the create opcode, which should never revert.\n */\n function clone(address implementation) internal returns (address instance) {\n assembly {\n let ptr := mload(0x40)\n mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)\n mstore(add(ptr, 0x14), shl(0x60, implementation))\n mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)\n instance := create(0, ptr, 0x37)\n }\n require(instance != address(0), \"ERC1167: create failed\");\n }\n\n /**\n * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.\n *\n * This function uses the create2 opcode and a `salt` to deterministically deploy\n * the clone. Using the same `implementation` and `salt` multiple time will revert, since\n * the clones cannot be deployed twice at the same address.\n */\n function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {\n assembly {\n let ptr := mload(0x40)\n mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)\n mstore(add(ptr, 0x14), shl(0x60, implementation))\n mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)\n instance := create2(0, ptr, 0x37, salt)\n }\n require(instance != address(0), \"ERC1167: create2 failed\");\n }\n\n /**\n * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.\n */\n function predictDeterministicAddress(\n address implementation,\n bytes32 salt,\n address deployer\n ) internal pure returns (address predicted) {\n assembly {\n let ptr := mload(0x40)\n mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)\n mstore(add(ptr, 0x14), shl(0x60, implementation))\n mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf3ff00000000000000000000000000000000)\n mstore(add(ptr, 0x38), shl(0x60, deployer))\n mstore(add(ptr, 0x4c), salt)\n mstore(add(ptr, 0x6c), keccak256(ptr, 0x37))\n predicted := keccak256(add(ptr, 0x37), 0x55)\n }\n }\n\n /**\n * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.\n */\n function predictDeterministicAddress(address implementation, bytes32 salt)\n internal\n view\n returns (address predicted)\n {\n return predictDeterministicAddress(implementation, salt, address(this));\n }\n}\n" + }, + "contracts/interfaces/IJBETHERC20SplitsPayerDeployer.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBSplitsPayer} from './IJBSplitsPayer.sol';\nimport {IJBSplitsStore} from './IJBSplitsStore.sol';\nimport {JBSplit} from './../structs/JBSplit.sol';\n\ninterface IJBETHERC20SplitsPayerDeployer {\n event DeploySplitsPayer(\n IJBSplitsPayer indexed splitsPayer,\n uint256 defaultSplitsProjectId,\n uint256 defaultSplitsDomain,\n uint256 defaultSplitsGroup,\n IJBSplitsStore splitsStore,\n uint256 defaultProjectId,\n address defaultBeneficiary,\n bool defaultPreferClaimedTokens,\n string defaultMemo,\n bytes defaultMetadata,\n bool preferAddToBalance,\n address owner,\n address caller\n );\n\n function deploySplitsPayer(\n uint256 defaultSplitsProjectId,\n uint256 defaultSplitsDomain,\n uint256 defaultSplitsGroup,\n uint256 defaultProjectId,\n address payable defaultBeneficiary,\n bool defaultPreferClaimedTokens,\n string calldata defaultMemo,\n bytes calldata defaultMetadata,\n bool preferAddToBalance,\n address owner\n ) external returns (IJBSplitsPayer splitsPayer);\n\n function deploySplitsPayerWithSplits(\n uint256 defaultSplitsProjectId,\n JBSplit[] memory defaultSplits,\n IJBSplitsStore splitsStore,\n uint256 defaultProjectId,\n address payable defaultBeneficiary,\n bool defaultPreferClaimedTokens,\n string memory defaultMemo,\n bytes memory defaultMetadata,\n bool defaultPreferAddToBalance,\n address owner\n ) external returns (IJBSplitsPayer splitsPayer);\n}\n" + }, + "contracts/interfaces/IJBSplitsPayer.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBSplit} from './../structs/JBSplit.sol';\nimport {JBGroupedSplits} from './../structs/JBGroupedSplits.sol';\nimport {IJBSplitsStore} from './IJBSplitsStore.sol';\n\ninterface IJBSplitsPayer is IERC165 {\n event SetDefaultSplitsReference(\n uint256 indexed projectId,\n uint256 indexed domain,\n uint256 indexed group,\n address caller\n );\n event Pay(\n uint256 indexed projectId,\n address beneficiary,\n address token,\n uint256 amount,\n uint256 decimals,\n uint256 leftoverAmount,\n uint256 minReturnedTokens,\n bool preferClaimedTokens,\n string memo,\n bytes metadata,\n address caller\n );\n\n event AddToBalance(\n uint256 indexed projectId,\n address beneficiary,\n address token,\n uint256 amount,\n uint256 decimals,\n uint256 leftoverAmount,\n string memo,\n bytes metadata,\n address caller\n );\n\n event DistributeToSplitGroup(\n uint256 indexed projectId,\n uint256 indexed domain,\n uint256 indexed group,\n address caller\n );\n\n event DistributeToSplit(\n JBSplit split,\n uint256 amount,\n address defaultBeneficiary,\n address caller\n );\n\n function defaultSplitsProjectId() external view returns (uint256);\n\n function defaultSplitsDomain() external view returns (uint256);\n\n function defaultSplitsGroup() external view returns (uint256);\n\n function splitsStore() external view returns (IJBSplitsStore);\n\n function initialize(\n uint256 defaultSplitsProjectId,\n uint256 defaultSplitsDomain,\n uint256 defaultSplitsGroup,\n uint256 defaultProjectId,\n address payable defaultBeneficiary,\n bool defaultPreferClaimedTokens,\n string memory defaultMemo,\n bytes memory defaultMetadata,\n bool preferAddToBalance,\n address owner\n ) external;\n\n function setDefaultSplitsReference(uint256 projectId, uint256 domain, uint256 group) external;\n\n function setDefaultSplits(\n uint256 projectId,\n uint256 domain,\n uint256 group,\n JBGroupedSplits[] memory splitsGroup\n ) external;\n}\n" + }, + "contracts/JBETHERC20SplitsPayer.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {ReentrancyGuard} from '@openzeppelin/contracts/security/ReentrancyGuard.sol';\nimport {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';\nimport {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';\nimport {Address} from '@openzeppelin/contracts/utils/Address.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {IJBSplitsPayer} from './interfaces/IJBSplitsPayer.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {JBConstants} from './libraries/JBConstants.sol';\nimport {JBETHERC20ProjectPayer} from './JBETHERC20ProjectPayer.sol';\nimport {IJBSplitAllocator} from './interfaces/IJBSplitAllocator.sol';\nimport {JBTokens} from './libraries/JBTokens.sol';\nimport {JBGroupedSplits} from './structs/JBGroupedSplits.sol';\nimport {JBSplit} from './structs/JBSplit.sol';\nimport {JBSplitAllocationData} from './structs/JBSplitAllocationData.sol';\n\n/// @notice Sends ETH or ERC20's to a group of splits as it receives direct payments or has its functions called.\n/// @dev Inherit from this contract or borrow from its logic to forward ETH or ERC20's to a group of splits from within other contracts.\ncontract JBETHERC20SplitsPayer is JBETHERC20ProjectPayer, ReentrancyGuard, IJBSplitsPayer {\n using SafeERC20 for IERC20;\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice The contract that stores splits for each project.\n IJBSplitsStore public immutable override splitsStore;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The ID of project for which the default splits are stored.\n uint256 public override defaultSplitsProjectId;\n\n /// @notice The domain within which the default splits are stored.\n uint256 public override defaultSplitsDomain;\n\n /// @notice The group within which the default splits are stored.\n uint256 public override defaultSplitsGroup;\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if this contract adheres to the specified interface.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(JBETHERC20ProjectPayer, IERC165) returns (bool) {\n return\n _interfaceId == type(IJBSplitsPayer).interfaceId || super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _splitsStore A contract that stores splits for each project.\n constructor(IJBSplitsStore _splitsStore) JBETHERC20ProjectPayer(_splitsStore.directory()) {\n splitsStore = _splitsStore;\n }\n\n /// @dev The re-initialize check is done in the inherited paroject payer\n /// @param _defaultSplitsProjectId The ID of project for which the default splits are stored.\n /// @param _defaultSplitsDomain The splits domain to payout when this contract receives direct payments.\n /// @param _defaultSplitsGroup The splits group to payout when this contract receives direct payments.\n /// @param _defaultProjectId The ID of the project whose treasury should be forwarded the splits payer contract's received payment leftovers after distributing to the default splits group.\n /// @param _defaultBeneficiary The address that'll receive the project's tokens.\n /// @param _defaultPreferClaimedTokens A flag indicating whether issued tokens should be automatically claimed into the beneficiary's wallet.\n /// @param _defaultMemo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _defaultMetadata Bytes to send along to the project's data source and delegate, if provided.\n /// @param _preferAddToBalance A flag indicating if received payments should call the `pay` function or the `addToBalance` function of a project.\n /// @param _owner The address that will own the contract.\n function initialize(\n uint256 _defaultSplitsProjectId,\n uint256 _defaultSplitsDomain,\n uint256 _defaultSplitsGroup,\n uint256 _defaultProjectId,\n address payable _defaultBeneficiary,\n bool _defaultPreferClaimedTokens,\n string memory _defaultMemo,\n bytes memory _defaultMetadata,\n bool _preferAddToBalance,\n address _owner\n ) external override {\n super.initialize(\n _defaultProjectId,\n _defaultBeneficiary,\n _defaultPreferClaimedTokens,\n _defaultMemo,\n _defaultMetadata,\n _preferAddToBalance,\n _owner\n );\n\n defaultSplitsProjectId = _defaultSplitsProjectId;\n defaultSplitsDomain = _defaultSplitsDomain;\n defaultSplitsGroup = _defaultSplitsGroup;\n }\n\n //*********************************************************************//\n // ------------------------- default receive ------------------------- //\n //*********************************************************************//\n\n /// @notice Received funds are paid to the default split group using the stored default properties.\n /// @dev This function is called automatically when the contract receives an ETH payment.\n receive() external payable virtual override nonReentrant {\n // Pay the splits and get a reference to the amount leftover.\n uint256 _leftoverAmount = _payToSplits(\n defaultSplitsProjectId,\n defaultSplitsDomain,\n defaultSplitsGroup,\n JBTokens.ETH,\n address(this).balance,\n 18, // decimals.\n defaultBeneficiary != address(0) ? defaultBeneficiary : tx.origin\n );\n\n // If there is no leftover amount, nothing left to pay.\n if (_leftoverAmount == 0) return;\n\n // If there's a default project ID, try to pay it.\n if (defaultProjectId != 0)\n if (defaultPreferAddToBalance)\n // Pay the project by adding to its balance if prefered.\n _addToBalanceOf(\n defaultProjectId,\n JBTokens.ETH,\n _leftoverAmount,\n 18, // decimals.\n defaultMemo,\n defaultMetadata\n );\n // Otherwise, issue a payment to the project.\n else\n _pay(\n defaultProjectId,\n JBTokens.ETH,\n _leftoverAmount,\n 18, // decimals.\n defaultBeneficiary != address(0) ? defaultBeneficiary : tx.origin,\n 0, // min returned tokens.\n defaultPreferClaimedTokens,\n defaultMemo,\n defaultMetadata\n );\n // If no project was specified, send the funds directly to the beneficiary or the tx.origin.\n else\n Address.sendValue(\n defaultBeneficiary != address(0) ? payable(defaultBeneficiary) : payable(tx.origin),\n _leftoverAmount\n );\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Sets the splits in the splits store that payments this contract receives will be split between.\n /// @param _projectId The ID of project for which the default splits are stored.\n /// @param _domain The domain within which the default splits are stored.\n /// @param _group The group within which the default splits are stored.\n /// @param _groupedSplits The split groups to set.\n function setDefaultSplits(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group,\n JBGroupedSplits[] memory _groupedSplits\n ) external virtual override onlyOwner {\n // Set the splits in the store.\n splitsStore.set(_projectId, _domain, _groupedSplits);\n\n // Set the splits reference.\n setDefaultSplitsReference(_projectId, _domain, _group);\n }\n\n //*********************************************************************//\n // ----------------------- public transactions ----------------------- //\n //*********************************************************************//\n\n /// @notice Sets the location of the splits that payments this contract receives will be split between.\n /// @param _projectId The ID of project for which the default splits are stored.\n /// @param _domain The domain within which the default splits are stored.\n /// @param _group The group within which the default splits are stored.\n function setDefaultSplitsReference(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group\n ) public virtual override onlyOwner {\n // Set the default splits project ID if it's changing.\n if (_projectId != defaultSplitsProjectId) defaultSplitsProjectId = _projectId;\n\n // Set the default splits domain if it's changing.\n if (_domain != defaultSplitsDomain) defaultSplitsDomain = _domain;\n\n // Set the default splits group if it's changing.\n if (_group != defaultSplitsGroup) defaultSplitsGroup = _group;\n\n emit SetDefaultSplitsReference(_projectId, _domain, _group, msg.sender);\n }\n\n /// @notice Make a payment to the specified project after first splitting the amount among the stored default splits.\n /// @param _projectId The ID of the project that is being paid after.\n /// @param _token The token being paid in.\n /// @param _amount The amount of tokens being paid, as a fixed point number. If the token is ETH, this is ignored and msg.value is used in its place.\n /// @param _decimals The number of decimals in the `_amount` fixed point number. If the token is ETH, this is ignored and 18 is used in its place, which corresponds to the amount of decimals expected in msg.value.\n /// @param _beneficiary The address who will receive tokens from the payment made with leftover funds.\n /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with 18 decimals.\n /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\n /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n function pay(\n uint256 _projectId,\n address _token,\n uint256 _amount,\n uint256 _decimals,\n address _beneficiary,\n uint256 _minReturnedTokens,\n bool _preferClaimedTokens,\n string calldata _memo,\n bytes calldata _metadata\n ) public payable virtual override nonReentrant {\n // ETH shouldn't be sent if the token isn't ETH.\n if (address(_token) != JBTokens.ETH) {\n if (msg.value > 0) revert NO_MSG_VALUE_ALLOWED();\n\n // Get a reference to the balance before receiving tokens.\n uint256 _balanceBefore = IERC20(_token).balanceOf(address(this));\n\n // Transfer tokens to this contract from the msg sender.\n IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount);\n\n // The amount should reflect the change in balance.\n _amount = IERC20(_token).balanceOf(address(this)) - _balanceBefore;\n } else {\n // If ETH is being paid, set the amount to the message value, and decimals to 18.\n _amount = msg.value;\n _decimals = 18;\n }\n\n // Pay the splits and get a reference to the amount leftover.\n uint256 _leftoverAmount = _payToSplits(\n defaultSplitsProjectId,\n defaultSplitsDomain,\n defaultSplitsGroup,\n _token,\n _amount,\n _decimals,\n defaultBeneficiary != address(0) ? defaultBeneficiary : tx.origin\n );\n\n // Pay any leftover amount.\n if (_leftoverAmount > 0) {\n // If there's a default project ID, try to pay it.\n if (_projectId != 0) {\n _pay(\n _projectId,\n _token,\n _leftoverAmount,\n _decimals,\n _beneficiary != address(0) ? _beneficiary : defaultBeneficiary != address(0)\n ? defaultBeneficiary\n : tx.origin,\n _minReturnedTokens,\n _preferClaimedTokens,\n _memo,\n _metadata\n );\n }\n // If no project was specified, send the funds directly to the beneficiary or the tx.origin.\n else {\n // Transfer the ETH.\n if (_token == JBTokens.ETH)\n Address.sendValue(\n // If there's a beneficiary, send the funds directly to the beneficiary. Otherwise send to the tx.origin.\n _beneficiary != address(0) ? payable(_beneficiary) : defaultBeneficiary != address(0)\n ? defaultBeneficiary\n : payable(tx.origin),\n _leftoverAmount\n );\n // Or, transfer the ERC20.\n else\n IERC20(_token).safeTransfer(\n // If there's a beneficiary, send the funds directly to the beneficiary. Otherwise send to the tx.origin.\n _beneficiary != address(0) ? _beneficiary : defaultBeneficiary != address(0)\n ? defaultBeneficiary\n : tx.origin,\n _leftoverAmount\n );\n }\n }\n\n emit Pay(\n _projectId,\n _beneficiary != address(0) ? _beneficiary : defaultBeneficiary != address(0)\n ? defaultBeneficiary\n : tx.origin,\n _token,\n _amount,\n _decimals,\n _leftoverAmount,\n _minReturnedTokens,\n _preferClaimedTokens,\n _memo,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Add to the balance of the specified project after first splitting the amount among the stored default splits.\n /// @param _projectId The ID of the project that is being paid after.\n /// @param _token The token being paid in.\n /// @param _amount The amount of tokens being paid, as a fixed point number. If the token is ETH, this is ignored and msg.value is used in its place.\n /// @param _decimals The number of decimals in the `_amount` fixed point number. If the token is ETH, this is ignored and 18 is used in its place, which corresponds to the amount of decimals expected in msg.value.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the terminal.\n function addToBalanceOf(\n uint256 _projectId,\n address _token,\n uint256 _amount,\n uint256 _decimals,\n string calldata _memo,\n bytes calldata _metadata\n ) public payable virtual override nonReentrant {\n // ETH shouldn't be sent if this terminal's token isn't ETH.\n if (address(_token) != JBTokens.ETH) {\n if (msg.value > 0) revert NO_MSG_VALUE_ALLOWED();\n\n // Get a reference to the balance before receiving tokens.\n uint256 _balanceBefore = IERC20(_token).balanceOf(address(this));\n\n // Transfer tokens to this contract from the msg sender.\n IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount);\n\n // The amount should reflect the change in balance.\n _amount = IERC20(_token).balanceOf(address(this)) - _balanceBefore;\n } else {\n // If ETH is being paid, set the amount to the message value, and decimals to 18.\n _amount = msg.value;\n _decimals = 18;\n }\n\n // Pay the splits and get a reference to the amount leftover.\n uint256 _leftoverAmount = _payToSplits(\n defaultSplitsProjectId,\n defaultSplitsDomain,\n defaultSplitsGroup,\n _token,\n _amount,\n _decimals,\n defaultBeneficiary != address(0) ? defaultBeneficiary : tx.origin\n );\n\n // Distribute any leftover amount.\n if (_leftoverAmount > 0) {\n // If there's a default project ID, try to add to its balance.\n if (_projectId != 0)\n // Add to the project's balance.\n _addToBalanceOf(_projectId, _token, _leftoverAmount, _decimals, _memo, _metadata);\n\n // Otherwise, send a payment to the beneficiary.\n else {\n // Transfer the ETH.\n if (_token == JBTokens.ETH)\n Address.sendValue(\n // If there's a default beneficiary, send the funds directly to the beneficiary. Otherwise send to the tx.origin.\n defaultBeneficiary != address(0) ? defaultBeneficiary : payable(tx.origin),\n _leftoverAmount\n );\n // Or, transfer the ERC20.\n else\n IERC20(_token).safeTransfer(\n // If there's a default beneficiary, send the funds directly to the beneficiary. Otherwise send to the tx.origin.\n defaultBeneficiary != address(0) ? defaultBeneficiary : tx.origin,\n _leftoverAmount\n );\n }\n }\n\n emit AddToBalance(\n _projectId,\n defaultBeneficiary != address(0) ? defaultBeneficiary : tx.origin,\n _token,\n _amount,\n _decimals,\n _leftoverAmount,\n _memo,\n _metadata,\n msg.sender\n );\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Split an amount between all splits.\n /// @param _splitsProjectId The ID of the project to which the splits belong.\n /// @param _splitsDomain The splits domain to which the group belongs.\n /// @param _splitsGroup The splits group to pay.\n /// @param _token The token the amonut being split is in.\n /// @param _amount The amount of tokens being split, as a fixed point number. If the `_token` is ETH, this is ignored and msg.value is used in its place.\n /// @param _decimals The number of decimals in the `_amount` fixed point number.\n /// @param _defaultBeneficiary The address that will benefit from any non-specified beneficiaries in splits.\n /// @return leftoverAmount The amount leftover after all splits were paid.\n function _payToSplits(\n uint256 _splitsProjectId,\n uint256 _splitsDomain,\n uint256 _splitsGroup,\n address _token,\n uint256 _amount,\n uint256 _decimals,\n address _defaultBeneficiary\n ) internal virtual returns (uint256 leftoverAmount) {\n // Pay the splits.\n leftoverAmount = _payTo(\n splitsStore.splitsOf(_splitsProjectId, _splitsDomain, _splitsGroup),\n _token,\n _amount,\n _decimals,\n _defaultBeneficiary\n );\n emit DistributeToSplitGroup(_splitsProjectId, _splitsDomain, _splitsGroup, msg.sender);\n }\n\n /// @notice Split an amount between all splits.\n /// @param _splits The splits.\n /// @param _token The token the amonut being split is in.\n /// @param _amount The amount of tokens being split, as a fixed point number. If the `_token` is ETH, this is ignored and msg.value is used in its place.\n /// @param _decimals The number of decimals in the `_amount` fixed point number.\n /// @param _defaultBeneficiary The address that will benefit from any non-specified beneficiaries in splits.\n /// @return leftoverAmount The amount leftover after all splits were paid.\n function _payTo(\n JBSplit[] memory _splits,\n address _token,\n uint256 _amount,\n uint256 _decimals,\n address _defaultBeneficiary\n ) internal virtual returns (uint256 leftoverAmount) {\n // Set the leftover amount to the initial balance.\n leftoverAmount = _amount;\n\n // Settle between all splits.\n for (uint256 i; i < _splits.length; ) {\n // Get a reference to the split being iterated on.\n JBSplit memory _split = _splits[i];\n\n // The amount to send towards the split.\n uint256 _splitAmount = PRBMath.mulDiv(\n _amount,\n _split.percent,\n JBConstants.SPLITS_TOTAL_PERCENT\n );\n\n if (_splitAmount > 0) {\n // Transfer tokens to the split.\n // If there's an allocator set, transfer to its `allocate` function.\n if (_split.allocator != IJBSplitAllocator(address(0))) {\n // Create the data to send to the allocator.\n JBSplitAllocationData memory _data = JBSplitAllocationData(\n _token,\n _splitAmount,\n _decimals,\n defaultProjectId,\n 0,\n _split\n );\n\n // Approve the `_amount` of tokens for the split allocator to transfer tokens from this contract.\n if (_token != JBTokens.ETH)\n IERC20(_token).safeApprove(address(_split.allocator), _splitAmount);\n\n // If the token is ETH, send it in msg.value.\n uint256 _payableValue = _token == JBTokens.ETH ? _splitAmount : 0;\n\n // Trigger the allocator's `allocate` function.\n _split.allocator.allocate{value: _payableValue}(_data);\n\n // Otherwise, if a project is specified, make a payment to it.\n } else if (_split.projectId != 0) {\n if (_split.preferAddToBalance)\n _addToBalanceOf(\n _split.projectId,\n _token,\n _splitAmount,\n _decimals,\n defaultMemo,\n defaultMetadata\n );\n else\n _pay(\n _split.projectId,\n _token,\n _splitAmount,\n _decimals,\n _split.beneficiary != address(0) ? _split.beneficiary : _defaultBeneficiary,\n 0,\n _split.preferClaimed,\n defaultMemo,\n defaultMetadata\n );\n } else {\n // Transfer the ETH.\n if (_token == JBTokens.ETH)\n Address.sendValue(\n // Get a reference to the address receiving the tokens. If there's a beneficiary, send the funds directly to the beneficiary. Otherwise send to _defaultBeneficiary.\n _split.beneficiary != address(0) ? _split.beneficiary : payable(_defaultBeneficiary),\n _splitAmount\n );\n // Or, transfer the ERC20.\n else {\n IERC20(_token).safeTransfer(\n // Get a reference to the address receiving the tokens. If there's a beneficiary, send the funds directly to the beneficiary. Otherwise send to _defaultBeneficiary.\n _split.beneficiary != address(0) ? _split.beneficiary : _defaultBeneficiary,\n _splitAmount\n );\n }\n }\n\n // Subtract from the amount to be sent to the beneficiary.\n leftoverAmount = leftoverAmount - _splitAmount;\n }\n\n emit DistributeToSplit(_split, _splitAmount, _defaultBeneficiary, msg.sender);\n\n unchecked {\n ++i;\n }\n }\n }\n}\n" + }, + "@openzeppelin/contracts/security/ReentrancyGuard.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuard {\n // Booleans are more expensive than uint256 or any type that takes up a full\n // word because each write operation emits an extra SLOAD to first read the\n // slot's contents, replace the bits taken up by the boolean, and then write\n // back. This is the compiler's defense against contract upgrades and\n // pointer aliasing, and it cannot be disabled.\n\n // The values being non-zero value makes deployment a bit more expensive,\n // but in exchange the refund on every call to nonReentrant will be lower in\n // amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to\n // increase the likelihood of the full refund coming into effect.\n uint256 private constant _NOT_ENTERED = 1;\n uint256 private constant _ENTERED = 2;\n\n uint256 private _status;\n\n constructor() {\n _status = _NOT_ENTERED;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a `nonReentrant` function from another `nonReentrant`\n * function is not supported. It is possible to prevent this from happening\n * by making the `nonReentrant` function external, and making it call a\n * `private` function that does the actual work.\n */\n modifier nonReentrant() {\n // On the first call to nonReentrant, _notEntered will be true\n require(_status != _ENTERED, \"ReentrancyGuard: reentrant call\");\n\n // Any calls to nonReentrant after this point will fail\n _status = _ENTERED;\n\n _;\n\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _status = _NOT_ENTERED;\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length > 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Address.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n *\n * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCall(target, data, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n require(isContract(target), \"Address: call to non-contract\");\n\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n require(isContract(target), \"Address: static call to non-contract\");\n\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(isContract(target), \"Address: delegate call to non-contract\");\n\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n }\n}\n" + }, + "contracts/JBETHERC20ProjectPayer.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';\nimport {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';\nimport {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';\nimport {ERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBProjectPayer} from './interfaces/IJBProjectPayer.sol';\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\nimport {JBTokens} from './libraries/JBTokens.sol';\n\n/// @notice Sends ETH or ERC20's to a project treasury as it receives direct payments or has it's functions called.\n/// @dev Inherit from this contract or borrow from its logic to forward ETH or ERC20's to project treasuries from within other contracts.\ncontract JBETHERC20ProjectPayer is Ownable, ERC165, IJBProjectPayer {\n using SafeERC20 for IERC20;\n\n //*********************************************************************//\n // -------------------------- custom errors -------------------------- //\n //*********************************************************************//\n error INCORRECT_DECIMAL_AMOUNT();\n error ALREADY_INITIALIZED();\n error NO_MSG_VALUE_ALLOWED();\n error TERMINAL_NOT_FOUND();\n\n //*********************************************************************//\n // ------------------- public immutable properties ------------------- //\n //*********************************************************************//\n\n /// @notice A contract storing directories of terminals and controllers for each project.\n IJBDirectory public immutable override directory;\n\n /// @notice The deployer associated with this implementation. Used to rule out double initialization.\n address public immutable override projectPayerDeployer;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The ID of the project that should be used to forward this contract's received payments.\n uint256 public override defaultProjectId;\n\n /// @notice The beneficiary that should be used in the payment made when this contract receives payments.\n address payable public override defaultBeneficiary;\n\n /// @notice A flag indicating whether issued tokens should be automatically claimed into the beneficiary's wallet. Leaving tokens unclaimed saves gas.\n bool public override defaultPreferClaimedTokens;\n\n /// @notice The memo that should be used in the payment made when this contract receives payments.\n string public override defaultMemo;\n\n /// @notice The metadata that should be used in the payment made when this contract receives payments.\n bytes public override defaultMetadata;\n\n /// @notice A flag indicating if received payments should call the `pay` function or the `addToBalance` function of a project.\n bool public override defaultPreferAddToBalance;\n\n //*********************************************************************//\n // ------------------------- public views ---------------------------- //\n //*********************************************************************//\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if the provided interface ID is supported.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(ERC165, IERC165) returns (bool) {\n return\n _interfaceId == type(IJBProjectPayer).interfaceId || super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // -------------------------- constructors --------------------------- //\n //*********************************************************************//\n\n /// @dev This is the constructor of the implementation. The directory is shared between project payers and is immutable. If a new JBDirectory is needed, a new JBProjectPayerDeployer should be deployed.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n constructor(IJBDirectory _directory) {\n directory = _directory;\n projectPayerDeployer = msg.sender;\n }\n\n /// @param _defaultProjectId The ID of the project whose treasury should be forwarded this contract's received payments.\n /// @param _defaultBeneficiary The address that'll receive the project's tokens.\n /// @param _defaultPreferClaimedTokens A flag indicating whether issued tokens should be automatically claimed into the beneficiary's wallet.\n /// @param _defaultMemo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _defaultMetadata Bytes to send along to the project's data source and delegate, if provided.\n /// @param _defaultPreferAddToBalance A flag indicating if received payments should call the `pay` function or the `addToBalance` function of a project.\n /// @param _owner The address that will own the contract.\n function initialize(\n uint256 _defaultProjectId,\n address payable _defaultBeneficiary,\n bool _defaultPreferClaimedTokens,\n string memory _defaultMemo,\n bytes memory _defaultMetadata,\n bool _defaultPreferAddToBalance,\n address _owner\n ) public {\n if (msg.sender != projectPayerDeployer) revert ALREADY_INITIALIZED();\n\n defaultProjectId = _defaultProjectId;\n defaultBeneficiary = _defaultBeneficiary;\n defaultPreferClaimedTokens = _defaultPreferClaimedTokens;\n defaultMemo = _defaultMemo;\n defaultMetadata = _defaultMetadata;\n defaultPreferAddToBalance = _defaultPreferAddToBalance;\n _transferOwnership(_owner);\n }\n\n //*********************************************************************//\n // ------------------------- default receive ------------------------- //\n //*********************************************************************//\n\n /// @notice Received funds are paid to the default project ID using the stored default properties.\n /// @dev Use the `addToBalance` function if there's a preference to do so. Otherwise use `pay`.\n /// @dev This function is called automatically when the contract receives an ETH payment.\n receive() external payable virtual override {\n if (defaultPreferAddToBalance)\n _addToBalanceOf(\n defaultProjectId,\n JBTokens.ETH,\n address(this).balance,\n 18, // balance is a fixed point number with 18 decimals.\n defaultMemo,\n defaultMetadata\n );\n else\n _pay(\n defaultProjectId,\n JBTokens.ETH,\n address(this).balance,\n 18, // balance is a fixed point number with 18 decimals.\n defaultBeneficiary == address(0) ? tx.origin : defaultBeneficiary,\n 0, // Can't determine expectation of returned tokens ahead of time.\n defaultPreferClaimedTokens,\n defaultMemo,\n defaultMetadata\n );\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Sets the default values that determine how to interact with a protocol treasury when this contract receives ETH directly.\n /// @param _projectId The ID of the project whose treasury should be forwarded this contract's received payments.\n /// @param _beneficiary The address that'll receive the project's tokens.\n /// @param _preferClaimedTokens A flag indicating whether issued tokens should be automatically claimed into the beneficiary's wallet.\n /// @param _memo The memo that'll be used.\n /// @param _metadata The metadata that'll be sent.\n /// @param _defaultPreferAddToBalance A flag indicating if received payments should call the `pay` function or the `addToBalance` function of a project.\n function setDefaultValues(\n uint256 _projectId,\n address payable _beneficiary,\n bool _preferClaimedTokens,\n string memory _memo,\n bytes memory _metadata,\n bool _defaultPreferAddToBalance\n ) external virtual override onlyOwner {\n // Set the default project ID if it has changed.\n if (_projectId != defaultProjectId) defaultProjectId = _projectId;\n\n // Set the default beneficiary if it has changed.\n if (_beneficiary != defaultBeneficiary) defaultBeneficiary = _beneficiary;\n\n // Set the default claimed token preference if it has changed.\n if (_preferClaimedTokens != defaultPreferClaimedTokens)\n defaultPreferClaimedTokens = _preferClaimedTokens;\n\n // Set the default memo if it has changed.\n if (keccak256(abi.encodePacked(_memo)) != keccak256(abi.encodePacked(defaultMemo)))\n defaultMemo = _memo;\n\n // Set the default metadata if it has changed.\n if (keccak256(abi.encodePacked(_metadata)) != keccak256(abi.encodePacked(defaultMetadata)))\n defaultMetadata = _metadata;\n\n // Set the add to balance preference if it has changed.\n if (_defaultPreferAddToBalance != defaultPreferAddToBalance)\n defaultPreferAddToBalance = _defaultPreferAddToBalance;\n\n emit SetDefaultValues(\n _projectId,\n _beneficiary,\n _preferClaimedTokens,\n _memo,\n _metadata,\n _defaultPreferAddToBalance,\n msg.sender\n );\n }\n\n //*********************************************************************//\n // ----------------------- public transactions ----------------------- //\n //*********************************************************************//\n\n /// @notice Make a payment to the specified project.\n /// @param _projectId The ID of the project that is being paid.\n /// @param _token The token being paid in.\n /// @param _amount The amount of tokens being paid, as a fixed point number. If the token is ETH, this is ignored and msg.value is used in its place.\n /// @param _decimals The number of decimals in the `_amount` fixed point number. If the token is ETH, this is ignored and 18 is used in its place, which corresponds to the amount of decimals expected in msg.value.\n /// @param _beneficiary The address who will receive tokens from the payment.\n /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with 18 decimals.\n /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\n /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n function pay(\n uint256 _projectId,\n address _token,\n uint256 _amount,\n uint256 _decimals,\n address _beneficiary,\n uint256 _minReturnedTokens,\n bool _preferClaimedTokens,\n string calldata _memo,\n bytes calldata _metadata\n ) public payable virtual override {\n // ETH shouldn't be sent if the token isn't ETH.\n if (address(_token) != JBTokens.ETH) {\n if (msg.value > 0) revert NO_MSG_VALUE_ALLOWED();\n\n // Get a reference to the balance before receiving tokens.\n uint256 _balanceBefore = IERC20(_token).balanceOf(address(this));\n\n // Transfer tokens to this contract from the msg sender.\n IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount);\n\n // The amount should reflect the change in balance.\n _amount = IERC20(_token).balanceOf(address(this)) - _balanceBefore;\n } else {\n // If ETH is being paid, set the amount to the message value, and decimals to 18.\n _amount = msg.value;\n _decimals = 18;\n }\n\n _pay(\n _projectId,\n _token,\n _amount,\n _decimals,\n _beneficiary,\n _minReturnedTokens,\n _preferClaimedTokens,\n _memo,\n _metadata\n );\n }\n\n /// @notice Add to the balance of the specified project.\n /// @param _projectId The ID of the project that is being paid.\n /// @param _token The token being paid in.\n /// @param _amount The amount of tokens being paid, as a fixed point number. If the token is ETH, this is ignored and msg.value is used in its place.\n /// @param _decimals The number of decimals in the `_amount` fixed point number. If the token is ETH, this is ignored and 18 is used in its place, which corresponds to the amount of decimals expected in msg.value.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the terminal.\n function addToBalanceOf(\n uint256 _projectId,\n address _token,\n uint256 _amount,\n uint256 _decimals,\n string calldata _memo,\n bytes calldata _metadata\n ) public payable virtual override {\n // ETH shouldn't be sent if the token isn't ETH.\n if (address(_token) != JBTokens.ETH) {\n if (msg.value > 0) revert NO_MSG_VALUE_ALLOWED();\n\n // Get a reference to the balance before receiving tokens.\n uint256 _balanceBefore = IERC20(_token).balanceOf(address(this));\n\n // Transfer tokens to this contract from the msg sender.\n IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount);\n\n // The amount should reflect the change in balance.\n _amount = IERC20(_token).balanceOf(address(this)) - _balanceBefore;\n } else {\n // If ETH is being paid, set the amount to the message value, and decimals to 18.\n _amount = msg.value;\n _decimals = 18;\n }\n\n _addToBalanceOf(_projectId, _token, _amount, _decimals, _memo, _metadata);\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Make a payment to the specified project.\n /// @param _projectId The ID of the project that is being paid.\n /// @param _token The token being paid in.\n /// @param _amount The amount of tokens being paid, as a fixed point number.\n /// @param _decimals The number of decimals in the `_amount` fixed point number.\n /// @param _beneficiary The address who will receive tokens from the payment.\n /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with 18 decimals.\n /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\n /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _metadata Bytes to send along to the data source and delegate, if provided.\n function _pay(\n uint256 _projectId,\n address _token,\n uint256 _amount,\n uint256 _decimals,\n address _beneficiary,\n uint256 _minReturnedTokens,\n bool _preferClaimedTokens,\n string memory _memo,\n bytes memory _metadata\n ) internal virtual {\n // Find the terminal for the specified project.\n IJBPaymentTerminal _terminal = directory.primaryTerminalOf(_projectId, _token);\n\n // There must be a terminal.\n if (_terminal == IJBPaymentTerminal(address(0))) revert TERMINAL_NOT_FOUND();\n\n // The amount's decimals must match the terminal's expected decimals.\n if (_terminal.decimalsForToken(_token) != _decimals) revert INCORRECT_DECIMAL_AMOUNT();\n\n // Approve the `_amount` of tokens from the destination terminal to transfer tokens from this contract.\n if (_token != JBTokens.ETH) IERC20(_token).safeApprove(address(_terminal), _amount);\n\n // If the token is ETH, send it in msg.value.\n uint256 _payableValue = _token == JBTokens.ETH ? _amount : 0;\n\n // Send funds to the terminal.\n // If the token is ETH, send it in msg.value.\n _terminal.pay{value: _payableValue}(\n _projectId,\n _amount, // ignored if the token is JBTokens.ETH.\n _token,\n _beneficiary != address(0) ? _beneficiary : defaultBeneficiary != address(0)\n ? defaultBeneficiary\n : tx.origin,\n _minReturnedTokens,\n _preferClaimedTokens,\n _memo,\n _metadata\n );\n }\n\n /// @notice Add to the balance of the specified project.\n /// @param _projectId The ID of the project that is being paid.\n /// @param _token The token being paid in.\n /// @param _amount The amount of tokens being paid, as a fixed point number. If the token is ETH, this is ignored and msg.value is used in its place.\n /// @param _decimals The number of decimals in the `_amount` fixed point number. If the token is ETH, this is ignored and 18 is used in its place, which corresponds to the amount of decimals expected in msg.value.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the terminal.\n function _addToBalanceOf(\n uint256 _projectId,\n address _token,\n uint256 _amount,\n uint256 _decimals,\n string memory _memo,\n bytes memory _metadata\n ) internal virtual {\n // Find the terminal for the specified project.\n IJBPaymentTerminal _terminal = directory.primaryTerminalOf(_projectId, _token);\n\n // There must be a terminal.\n if (_terminal == IJBPaymentTerminal(address(0))) revert TERMINAL_NOT_FOUND();\n\n // The amount's decimals must match the terminal's expected decimals.\n if (_terminal.decimalsForToken(_token) != _decimals) revert INCORRECT_DECIMAL_AMOUNT();\n\n // Approve the `_amount` of tokens from the destination terminal to transfer tokens from this contract.\n if (_token != JBTokens.ETH) IERC20(_token).safeApprove(address(_terminal), _amount);\n\n // If the token is ETH, send it in msg.value.\n uint256 _payableValue = _token == JBTokens.ETH ? _amount : 0;\n\n // Add to balance so tokens don't get issued.\n _terminal.addToBalanceOf{value: _payableValue}(_projectId, _amount, _token, _memo, _metadata);\n }\n}\n" + }, + "contracts/libraries/JBTokens.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nlibrary JBTokens {\n /// @notice The ETH token address in Juicebox is represented by 0x000000000000000000000000000000000000EEEe.\n address public constant ETH = address(0x000000000000000000000000000000000000EEEe);\n}\n" + }, + "contracts/interfaces/IJBProjectPayer.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {IJBDirectory} from './IJBDirectory.sol';\n\ninterface IJBProjectPayer is IERC165 {\n event SetDefaultValues(\n uint256 indexed projectId,\n address indexed beneficiary,\n bool preferClaimedTokens,\n string memo,\n bytes metadata,\n bool preferAddToBalance,\n address caller\n );\n\n function directory() external view returns (IJBDirectory);\n\n function projectPayerDeployer() external view returns (address);\n\n function defaultProjectId() external view returns (uint256);\n\n function defaultBeneficiary() external view returns (address payable);\n\n function defaultPreferClaimedTokens() external view returns (bool);\n\n function defaultMemo() external view returns (string memory);\n\n function defaultMetadata() external view returns (bytes memory);\n\n function defaultPreferAddToBalance() external view returns (bool);\n\n function initialize(\n uint256 defaultProjectId,\n address payable defaultBeneficiary,\n bool defaultPreferClaimedTokens,\n string memory defaultMemo,\n bytes memory defaultMetadata,\n bool defaultPreferAddToBalance,\n address owner\n ) external;\n\n function setDefaultValues(\n uint256 projectId,\n address payable beneficiary,\n bool preferClaimedTokens,\n string memory memo,\n bytes memory metadata,\n bool defaultPreferAddToBalance\n ) external;\n\n function pay(\n uint256 projectId,\n address token,\n uint256 amount,\n uint256 decimals,\n address beneficiary,\n uint256 minReturnedTokens,\n bool preferClaimedTokens,\n string memory memo,\n bytes memory metadata\n ) external payable;\n\n function addToBalanceOf(\n uint256 projectId,\n address token,\n uint256 amount,\n uint256 decimals,\n string memory memo,\n bytes memory metadata\n ) external payable;\n\n receive() external payable;\n}\n" + }, + "contracts/JBController3_0_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {ERC165, IERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {SafeCast} from '@openzeppelin/contracts/utils/math/SafeCast.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {JBOperatable} from './abstract/JBOperatable.sol';\nimport {JBBallotState} from './enums/JBBallotState.sol';\nimport {IJBController3_0_1} from './interfaces/IJBController3_0_1.sol';\nimport {IJBController} from './interfaces/IJBController.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol';\nimport {IJBMigratable} from './interfaces/IJBMigratable.sol';\nimport {IJBOperatable} from './interfaces/IJBOperatable.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {IJBSplitAllocator} from './interfaces/IJBSplitAllocator.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {IJBTokenStore} from './interfaces/IJBTokenStore.sol';\nimport {JBConstants} from './libraries/JBConstants.sol';\nimport {JBFundingCycleMetadataResolver} from './libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBOperations} from './libraries/JBOperations.sol';\nimport {JBSplitsGroups} from './libraries/JBSplitsGroups.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\nimport {JBSplitAllocationData} from './structs/JBSplitAllocationData.sol';\nimport {JBFundAccessConstraints} from './structs/JBFundAccessConstraints.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\nimport {JBFundingCycleData} from './structs/JBFundingCycleData.sol';\nimport {JBFundingCycleMetadata} from './structs/JBFundingCycleMetadata.sol';\nimport {JBGroupedSplits} from './structs/JBGroupedSplits.sol';\nimport {JBProjectMetadata} from './structs/JBProjectMetadata.sol';\nimport {JBSplit} from './structs/JBSplit.sol';\n\n/// @notice Stitches together funding cycles and project tokens, making sure all activity is accounted for and correct.\n/// @dev This Controller manages a project's reserved tokens explicitly instead of through a passive tracker property.\n/// @dev It is backwards compatible with the original IJBController, and exposes convenience view methods as part of IJBController3_1 for clearer queries.\ncontract JBController3_0_1 is\n JBOperatable,\n ERC165,\n IJBController,\n IJBController3_0_1,\n IJBMigratable\n{\n // A library that parses the packed funding cycle metadata into a more friendly format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error BURN_PAUSED_AND_SENDER_NOT_VALID_TERMINAL_DELEGATE();\n error FUNDING_CYCLE_ALREADY_LAUNCHED();\n error INVALID_BALLOT_REDEMPTION_RATE();\n error INVALID_DISTRIBUTION_LIMIT();\n error INVALID_DISTRIBUTION_LIMIT_CURRENCY();\n error INVALID_OVERFLOW_ALLOWANCE();\n error INVALID_OVERFLOW_ALLOWANCE_CURRENCY();\n error INVALID_REDEMPTION_RATE();\n error INVALID_RESERVED_RATE();\n error MIGRATION_NOT_ALLOWED();\n error MINT_NOT_ALLOWED_AND_NOT_TERMINAL_DELEGATE();\n error NO_BURNABLE_TOKENS();\n error NOT_CURRENT_CONTROLLER();\n error ZERO_TOKENS_TO_MINT();\n\n //*********************************************************************//\n // --------------------- internal stored properties ------------------ //\n //*********************************************************************//\n\n /// @notice Data regarding the distribution limit of a project during a configuration.\n /// @dev bits 0-231: The amount of token that a project can distribute per funding cycle.\n /// @dev bits 232-255: The currency of amount that a project can distribute.\n /// @custom:param _projectId The ID of the project to get the packed distribution limit data of.\n /// @custom:param _configuration The configuration during which the packed distribution limit data applies.\n /// @custom:param _terminal The terminal from which distributions are being limited.\n /// @custom:param _token The token for which distributions are being limited.\n mapping(uint256 => mapping(uint256 => mapping(IJBPaymentTerminal => mapping(address => uint256))))\n internal _packedDistributionLimitDataOf;\n\n /// @notice Data regarding the overflow allowance of a project during a configuration.\n /// @dev bits 0-231: The amount of overflow that a project is allowed to tap into on-demand throughout the configuration.\n /// @dev bits 232-255: The currency of the amount of overflow that a project is allowed to tap.\n /// @custom:param _projectId The ID of the project to get the packed overflow allowance data of.\n /// @custom:param _configuration The configuration during which the packed overflow allowance data applies.\n /// @custom:param _terminal The terminal managing the overflow.\n /// @custom:param _token The token for which overflow is being allowed.\n mapping(uint256 => mapping(uint256 => mapping(IJBPaymentTerminal => mapping(address => uint256))))\n internal _packedOverflowAllowanceDataOf;\n\n /// @notice The current undistributed reserved token balance of.\n /// @custom:param _projectId The ID of the project to get a reserved token balance of.\n mapping(uint256 => uint256) internal _reservedTokenBalanceOf;\n\n //*********************************************************************//\n // --------------- public immutable stored properties ---------------- //\n //*********************************************************************//\n\n /// @notice Mints ERC-721's that represent project ownership.\n IJBProjects public immutable override projects;\n\n /// @notice The contract storing all funding cycle configurations.\n IJBFundingCycleStore public immutable override fundingCycleStore;\n\n /// @notice The contract that manages token minting and burning.\n IJBTokenStore public immutable override tokenStore;\n\n /// @notice The contract that stores splits for each project.\n IJBSplitsStore public immutable override splitsStore;\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice The amount of token that a project can distribute per funding cycle, and the currency it's in terms of.\n /// @dev The number of decimals in the returned fixed point amount is the same as that of the specified terminal.\n /// @param _projectId The ID of the project to get the distribution limit of.\n /// @param _configuration The configuration during which the distribution limit applies.\n /// @param _terminal The terminal from which distributions are being limited.\n /// @param _token The token for which the distribution limit applies.\n /// @return The distribution limit, as a fixed point number with the same number of decimals as the provided terminal.\n /// @return The currency of the distribution limit.\n function distributionLimitOf(\n uint256 _projectId,\n uint256 _configuration,\n IJBPaymentTerminal _terminal,\n address _token\n ) external view override returns (uint256, uint256) {\n // Get a reference to the packed data.\n uint256 _data = _packedDistributionLimitDataOf[_projectId][_configuration][_terminal][_token];\n\n // The limit is in bits 0-231. The currency is in bits 232-255.\n return (uint256(uint232(_data)), _data >> 232);\n }\n\n /// @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.\n /// @dev The number of decimals in the returned fixed point amount is the same as that of the specified terminal.\n /// @param _projectId The ID of the project to get the overflow allowance of.\n /// @param _configuration The configuration of the during which the allowance applies.\n /// @param _terminal The terminal managing the overflow.\n /// @param _token The token for which the overflow allowance applies.\n /// @return The overflow allowance, as a fixed point number with the same number of decimals as the provided terminal.\n /// @return The currency of the overflow allowance.\n function overflowAllowanceOf(\n uint256 _projectId,\n uint256 _configuration,\n IJBPaymentTerminal _terminal,\n address _token\n ) external view override returns (uint256, uint256) {\n // Get a reference to the packed data.\n uint256 _data = _packedOverflowAllowanceDataOf[_projectId][_configuration][_terminal][_token];\n\n // The allowance is in bits 0-231. The currency is in bits 232-255.\n return (uint256(uint232(_data)), _data >> 232);\n }\n\n /// @notice A project's funding cycle for the specified configuration along with its metadata.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The funding cycle.\n /// @return metadata The funding cycle's metadata.\n function getFundingCycleOf(\n uint256 _projectId,\n uint256 _configuration\n )\n external\n view\n override\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata)\n {\n fundingCycle = fundingCycleStore.get(_projectId, _configuration);\n metadata = fundingCycle.expandMetadata();\n }\n\n /// @notice A project's latest configured funding cycle along with its metadata and the ballot state of the configuration.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The latest configured funding cycle.\n /// @return metadata The latest configured funding cycle's metadata.\n /// @return ballotState The state of the configuration.\n function latestConfiguredFundingCycleOf(\n uint256 _projectId\n )\n external\n view\n override\n returns (\n JBFundingCycle memory fundingCycle,\n JBFundingCycleMetadata memory metadata,\n JBBallotState ballotState\n )\n {\n (fundingCycle, ballotState) = fundingCycleStore.latestConfiguredOf(_projectId);\n metadata = fundingCycle.expandMetadata();\n }\n\n /// @notice A project's current funding cycle along with its metadata.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The current funding cycle.\n /// @return metadata The current funding cycle's metadata.\n function currentFundingCycleOf(\n uint256 _projectId\n )\n external\n view\n override\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata)\n {\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n metadata = fundingCycle.expandMetadata();\n }\n\n /// @notice A project's queued funding cycle along with its metadata.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The queued funding cycle.\n /// @return metadata The queued funding cycle's metadata.\n function queuedFundingCycleOf(\n uint256 _projectId\n )\n external\n view\n override\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata)\n {\n fundingCycle = fundingCycleStore.queuedOf(_projectId);\n metadata = fundingCycle.expandMetadata();\n }\n\n /// @notice\tGets the amount of reserved tokens that a project has available to distribute.\n /// @param _projectId The ID of the project to get a reserved token balance of.\n /// @return The current amount of reserved tokens.\n function reservedTokenBalanceOf(uint256 _projectId) external view override returns (uint256) {\n return _reservedTokenBalanceOf[_projectId];\n }\n\n /// @notice\tGets the amount of reserved tokens that a project has available to distribute.\n /// @dev This is just for IJBController backwards compatibility.\n /// @param _projectId The ID of the project to get a reserved token balance of.\n /// @param _reservedRate The reserved rate to use when making the calculation.\n /// @return The current amount of reserved tokens.\n function reservedTokenBalanceOf(\n uint256 _projectId,\n uint256 _reservedRate\n ) external view override returns (uint256) {\n _reservedRate;\n return _reservedTokenBalanceOf[_projectId];\n }\n\n /// @notice\tGets the current total amount of outstanding tokens for a project, given a reserved rate.\n /// @dev This is just for IJBController backwards compatibility.\n /// @param _projectId The ID of the project to get total outstanding tokens of.\n /// @param _reservedRate The reserved rate to use when making the calculation.\n /// @return The current total amount of outstanding tokens for the project.\n function totalOutstandingTokensOf(\n uint256 _projectId,\n uint256 _reservedRate\n ) external view override returns (uint256) {\n _reservedRate;\n // Add the reserved tokens to the total supply.\n return totalOutstandingTokensOf(_projectId);\n }\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice Gets the current total amount of outstanding tokens for a project.\n /// @param _projectId The ID of the project to get total outstanding tokens of.\n /// @return The current total amount of outstanding tokens for the project.\n function totalOutstandingTokensOf(uint256 _projectId) public view override returns (uint256) {\n // Add the reserved tokens to the total supply.\n return tokenStore.totalSupplyOf(_projectId) + _reservedTokenBalanceOf[_projectId];\n }\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if the provided interface ID is supported.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(ERC165, IERC165) returns (bool) {\n return\n _interfaceId == type(IJBController3_0_1).interfaceId ||\n _interfaceId == type(IJBMigratable).interfaceId ||\n _interfaceId == type(IJBOperatable).interfaceId ||\n super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // ---------------------------- constructor -------------------------- //\n //*********************************************************************//\n\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _fundingCycleStore A contract storing all funding cycle configurations.\n /// @param _tokenStore A contract that manages token minting and burning.\n /// @param _splitsStore A contract that stores splits for each project.\n constructor(\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBFundingCycleStore _fundingCycleStore,\n IJBTokenStore _tokenStore,\n IJBSplitsStore _splitsStore\n ) JBOperatable(_operatorStore) {\n projects = _projects;\n directory = _directory;\n fundingCycleStore = _fundingCycleStore;\n tokenStore = _tokenStore;\n splitsStore = _splitsStore;\n }\n\n //*********************************************************************//\n // --------------------- external transactions ----------------------- //\n //*********************************************************************//\n\n /// @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.\n /// @dev Each operation within this transaction can be done in sequence separately.\n /// @dev Anyone can deploy a project on an owner's behalf.\n /// @param _owner The address to set as the owner of the project. The project ERC-721 will be owned by this address.\n /// @param _projectMetadata Metadata to associate with the project within a particular domain. This can be updated any time by the owner of the project.\n /// @param _data Data that defines the project's first funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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`.\n /// @param _terminals Payment terminals to add for the project.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return projectId The ID of the project.\n function launchProjectFor(\n address _owner,\n JBProjectMetadata calldata _projectMetadata,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] calldata _groupedSplits,\n JBFundAccessConstraints[] calldata _fundAccessConstraints,\n IJBPaymentTerminal[] memory _terminals,\n string memory _memo\n ) external virtual override returns (uint256 projectId) {\n // Keep a reference to the directory.\n IJBDirectory _directory = directory;\n\n // Mint the project into the wallet of the owner.\n projectId = projects.createFor(_owner, _projectMetadata);\n\n // Set this contract as the project's controller in the directory.\n _directory.setControllerOf(projectId, address(this));\n\n // Configure the first funding cycle.\n uint256 _configuration = _configure(\n projectId,\n _data,\n _metadata,\n _mustStartAtOrAfter,\n _groupedSplits,\n _fundAccessConstraints\n );\n\n // Add the provided terminals to the list of terminals.\n if (_terminals.length > 0) _directory.setTerminalsOf(projectId, _terminals);\n\n emit LaunchProject(_configuration, projectId, _memo, msg.sender);\n }\n\n /// @notice Creates a funding cycle for an already existing project ERC-721.\n /// @dev Each operation within this transaction can be done in sequence separately.\n /// @dev Only a project owner or operator can launch its funding cycles.\n /// @param _projectId The ID of the project to launch funding cycles for.\n /// @param _data Data that defines the project's first funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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`.\n /// @param _terminals Payment terminals to add for the project.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return configuration The configuration of the funding cycle that was successfully created.\n function launchFundingCyclesFor(\n uint256 _projectId,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] calldata _groupedSplits,\n JBFundAccessConstraints[] memory _fundAccessConstraints,\n IJBPaymentTerminal[] memory _terminals,\n string memory _memo\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.RECONFIGURE)\n returns (uint256 configuration)\n {\n // If there is a previous configuration, reconfigureFundingCyclesOf should be called instead\n if (fundingCycleStore.latestConfigurationOf(_projectId) > 0)\n revert FUNDING_CYCLE_ALREADY_LAUNCHED();\n\n // Set this contract as the project's controller in the directory.\n directory.setControllerOf(_projectId, address(this));\n\n // Configure the first funding cycle.\n configuration = _configure(\n _projectId,\n _data,\n _metadata,\n _mustStartAtOrAfter,\n _groupedSplits,\n _fundAccessConstraints\n );\n\n // Add the provided terminals to the list of terminals.\n if (_terminals.length > 0) directory.setTerminalsOf(_projectId, _terminals);\n\n emit LaunchFundingCycles(configuration, _projectId, _memo, msg.sender);\n }\n\n /// @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.\n /// @dev Only a project's owner or a designated operator can configure its funding cycles.\n /// @param _projectId The ID of the project whose funding cycles are being reconfigured.\n /// @param _data Data that defines the funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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`.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return configuration The configuration of the funding cycle that was successfully reconfigured.\n function reconfigureFundingCyclesOf(\n uint256 _projectId,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] calldata _groupedSplits,\n JBFundAccessConstraints[] calldata _fundAccessConstraints,\n string calldata _memo\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.RECONFIGURE)\n returns (uint256 configuration)\n {\n // Configure the next funding cycle.\n configuration = _configure(\n _projectId,\n _data,\n _metadata,\n _mustStartAtOrAfter,\n _groupedSplits,\n _fundAccessConstraints\n );\n\n emit ReconfigureFundingCycles(configuration, _projectId, _memo, msg.sender);\n }\n\n /// @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.\n /// @dev Only a project's owner, a designated operator, one of its terminals, or the current data source can mint its tokens.\n /// @param _projectId The ID of the project to which the tokens being minted belong.\n /// @param _tokenCount The amount of tokens to mint in total, counting however many should be reserved.\n /// @param _beneficiary The account that the tokens are being minted for.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _preferClaimedTokens A flag indicating whether a project's attached token contract should be minted if they have been issued.\n /// @param _useReservedRate Whether to use the current funding cycle's reserved rate in the mint calculation.\n /// @return beneficiaryTokenCount The amount of tokens minted for the beneficiary.\n function mintTokensOf(\n uint256 _projectId,\n uint256 _tokenCount,\n address _beneficiary,\n string calldata _memo,\n bool _preferClaimedTokens,\n bool _useReservedRate\n ) external virtual override returns (uint256 beneficiaryTokenCount) {\n // There should be tokens to mint.\n if (_tokenCount == 0) revert ZERO_TOKENS_TO_MINT();\n\n // Define variables that will be needed outside scoped section below.\n // Keep a reference to the reserved rate to use\n uint256 _reservedRate;\n\n // Scoped section prevents stack too deep. `_fundingCycle` only used within scope.\n {\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Minting limited to: project owner, authorized callers, project terminal and current funding cycle data source\n _requirePermissionAllowingOverride(\n projects.ownerOf(_projectId),\n _projectId,\n JBOperations.MINT,\n directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender)) ||\n msg.sender == address(_fundingCycle.dataSource())\n );\n\n // If the message sender is not a terminal or a datasource, the current funding cycle must allow minting.\n if (\n !_fundingCycle.mintingAllowed() &&\n !directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender)) &&\n msg.sender != address(_fundingCycle.dataSource())\n ) revert MINT_NOT_ALLOWED_AND_NOT_TERMINAL_DELEGATE();\n\n // Determine the reserved rate to use.\n _reservedRate = _useReservedRate ? _fundingCycle.reservedRate() : 0;\n\n // Override the claimed token preference with the funding cycle value.\n _preferClaimedTokens = _preferClaimedTokens == true\n ? _preferClaimedTokens\n : _fundingCycle.preferClaimedTokenOverride();\n }\n\n if (_reservedRate != JBConstants.MAX_RESERVED_RATE) {\n // The unreserved token count that will be minted for the beneficiary.\n beneficiaryTokenCount = PRBMath.mulDiv(\n _tokenCount,\n JBConstants.MAX_RESERVED_RATE - _reservedRate,\n JBConstants.MAX_RESERVED_RATE\n );\n\n // Mint the tokens.\n tokenStore.mintFor(_beneficiary, _projectId, beneficiaryTokenCount, _preferClaimedTokens);\n }\n\n // Add reserved tokens if needed\n if (_reservedRate > 0)\n _reservedTokenBalanceOf[_projectId] += _tokenCount - beneficiaryTokenCount;\n\n emit MintTokens(\n _beneficiary,\n _projectId,\n _tokenCount,\n beneficiaryTokenCount,\n _memo,\n _reservedRate,\n msg.sender\n );\n }\n\n /// @notice Burns a token holder's supply.\n /// @dev Only a token's holder, a designated operator, or a project's terminal can burn it.\n /// @param _holder The account that is having its tokens burned.\n /// @param _projectId The ID of the project to which the tokens being burned belong.\n /// @param _tokenCount The number of tokens to burn.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _preferClaimedTokens A flag indicating whether a project's attached token contract should be burned first if they have been issued.\n function burnTokensOf(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n string calldata _memo,\n bool _preferClaimedTokens\n )\n external\n virtual\n override\n requirePermissionAllowingOverride(\n _holder,\n _projectId,\n JBOperations.BURN,\n directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender))\n )\n {\n // There should be tokens to burn\n if (_tokenCount == 0) revert NO_BURNABLE_TOKENS();\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // If the message sender is a terminal, the current funding cycle must not be paused.\n if (\n _fundingCycle.burnPaused() &&\n !directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender))\n ) revert BURN_PAUSED_AND_SENDER_NOT_VALID_TERMINAL_DELEGATE();\n\n // Burn the tokens.\n tokenStore.burnFrom(_holder, _projectId, _tokenCount, _preferClaimedTokens);\n\n emit BurnTokens(_holder, _projectId, _tokenCount, _memo, msg.sender);\n }\n\n /// @notice Distributes all outstanding reserved tokens for a project.\n /// @param _projectId The ID of the project to which the reserved tokens belong.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return The amount of minted reserved tokens.\n function distributeReservedTokensOf(\n uint256 _projectId,\n string calldata _memo\n ) external virtual override returns (uint256) {\n return _distributeReservedTokensOf(_projectId, _memo);\n }\n\n /// @notice Allows other controllers to signal to this one that a migration is expected for the specified project.\n /// @dev This controller should not yet be the project's controller.\n /// @param _projectId The ID of the project that will be migrated to this controller.\n /// @param _from The controller being migrated from.\n function prepForMigrationOf(uint256 _projectId, address _from) external virtual override {\n _projectId; // Prevents unused var compiler and natspec complaints.\n _from; // Prevents unused var compiler and natspec complaints.\n }\n\n /// @notice Allows a project to migrate from this controller to another.\n /// @dev Only a project's owner or a designated operator can migrate it.\n /// @param _projectId The ID of the project that will be migrated from this controller.\n /// @param _to The controller to which the project is migrating.\n function migrate(\n uint256 _projectId,\n IJBMigratable _to\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.MIGRATE_CONTROLLER)\n {\n // Keep a reference to the directory.\n IJBDirectory _directory = directory;\n\n // This controller must be the project's current controller.\n if (_directory.controllerOf(_projectId) != address(this)) revert NOT_CURRENT_CONTROLLER();\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Migration must be allowed.\n if (!_fundingCycle.controllerMigrationAllowed()) revert MIGRATION_NOT_ALLOWED();\n\n // All reserved tokens must be minted before migrating.\n if (_reservedTokenBalanceOf[_projectId] != 0) _distributeReservedTokensOf(_projectId, '');\n\n // Make sure the new controller is prepped for the migration.\n _to.prepForMigrationOf(_projectId, address(this));\n\n // Set the new controller.\n _directory.setControllerOf(_projectId, address(_to));\n\n emit Migrate(_projectId, _to, msg.sender);\n }\n\n //*********************************************************************//\n // ------------------------ internal functions ----------------------- //\n //*********************************************************************//\n\n /// @notice Distributes all outstanding reserved tokens for a project.\n /// @param _projectId The ID of the project to which the reserved tokens belong.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return tokenCount The amount of minted reserved tokens.\n function _distributeReservedTokensOf(\n uint256 _projectId,\n string memory _memo\n ) internal returns (uint256 tokenCount) {\n // Keep a reference to the token store.\n IJBTokenStore _tokenStore = tokenStore;\n\n // Get the current funding cycle to read the reserved rate from.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Get a reference to the number of tokens that need to be minted.\n tokenCount = _reservedTokenBalanceOf[_projectId];\n\n // Reset the reserved token balance\n _reservedTokenBalanceOf[_projectId] = 0;\n\n // Get a reference to the project owner.\n address _owner = projects.ownerOf(_projectId);\n\n // Distribute tokens to splits and get a reference to the leftover amount to mint after all splits have gotten their share.\n uint256 _leftoverTokenCount = tokenCount == 0\n ? 0\n : _distributeToReservedTokenSplitsOf(\n _projectId,\n _fundingCycle.configuration,\n JBSplitsGroups.RESERVED_TOKENS,\n tokenCount\n );\n\n // Mint any leftover tokens to the project owner.\n if (_leftoverTokenCount > 0)\n _tokenStore.mintFor(_owner, _projectId, _leftoverTokenCount, false);\n\n emit DistributeReservedTokens(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _owner,\n tokenCount,\n _leftoverTokenCount,\n _memo,\n msg.sender\n );\n }\n\n /// @notice Distribute tokens to the splits according to the specified funding cycle configuration.\n /// @param _projectId The ID of the project for which reserved token splits are being distributed.\n /// @param _domain The domain of the splits to distribute the reserved tokens between.\n /// @param _group The group of the splits to distribute the reserved tokens between.\n /// @param _amount The total amount of tokens to mint.\n /// @return leftoverAmount If the splits percents dont add up to 100%, the leftover amount is returned.\n function _distributeToReservedTokenSplitsOf(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group,\n uint256 _amount\n ) internal returns (uint256 leftoverAmount) {\n // Keep a reference to the token store.\n IJBTokenStore _tokenStore = tokenStore;\n\n // Set the leftover amount to the initial amount.\n leftoverAmount = _amount;\n\n // Get a reference to the project's reserved token splits.\n JBSplit[] memory _splits = splitsStore.splitsOf(_projectId, _domain, _group);\n\n //Transfer between all splits.\n for (uint256 _i; _i < _splits.length; ) {\n // Get a reference to the split being iterated on.\n JBSplit memory _split = _splits[_i];\n\n // The amount to send towards the split.\n uint256 _tokenCount = PRBMath.mulDiv(\n _amount,\n _split.percent,\n JBConstants.SPLITS_TOTAL_PERCENT\n );\n\n // Mints tokens for the split if needed.\n if (_tokenCount > 0) {\n _tokenStore.mintFor(\n // If an allocator is set in the splits, set it as the beneficiary.\n // Otherwise if a projectId is set in the split, set the project's owner as the beneficiary.\n // If the split has a beneficiary send to the split's beneficiary. Otherwise send to the msg.sender.\n _split.allocator != IJBSplitAllocator(address(0))\n ? address(_split.allocator)\n : _split.projectId != 0\n ? projects.ownerOf(_split.projectId)\n : _split.beneficiary != address(0)\n ? _split.beneficiary\n : msg.sender,\n _projectId,\n _tokenCount,\n _split.preferClaimed\n );\n\n // If there's an allocator set, trigger its `allocate` function.\n if (_split.allocator != IJBSplitAllocator(address(0)))\n _split.allocator.allocate(\n JBSplitAllocationData(\n address(_tokenStore.tokenOf(_projectId)),\n _tokenCount,\n 18,\n _projectId,\n _group,\n _split\n )\n );\n\n // Subtract from the amount to be sent to the beneficiary.\n leftoverAmount = leftoverAmount - _tokenCount;\n }\n\n emit DistributeToReservedTokenSplit(\n _projectId,\n _domain,\n _group,\n _split,\n _tokenCount,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n\n /// @notice Configures a funding cycle and stores information pertinent to the configuration.\n /// @param _projectId The ID of the project whose funding cycles are being reconfigured.\n /// @param _data Data that defines the funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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.\n /// @return configuration The configuration of the funding cycle that was successfully reconfigured.\n function _configure(\n uint256 _projectId,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] memory _groupedSplits,\n JBFundAccessConstraints[] memory _fundAccessConstraints\n ) internal returns (uint256) {\n // Make sure the provided reserved rate is valid.\n if (_metadata.reservedRate > JBConstants.MAX_RESERVED_RATE) revert INVALID_RESERVED_RATE();\n\n // Make sure the provided redemption rate is valid.\n if (_metadata.redemptionRate > JBConstants.MAX_REDEMPTION_RATE)\n revert INVALID_REDEMPTION_RATE();\n\n // Make sure the provided ballot redemption rate is valid.\n if (_metadata.ballotRedemptionRate > JBConstants.MAX_REDEMPTION_RATE)\n revert INVALID_BALLOT_REDEMPTION_RATE();\n\n // Configure the funding cycle's properties.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.configureFor(\n _projectId,\n _data,\n JBFundingCycleMetadataResolver.packFundingCycleMetadata(_metadata),\n _mustStartAtOrAfter\n );\n\n // Set splits for the group.\n splitsStore.set(_projectId, _fundingCycle.configuration, _groupedSplits);\n\n // Set distribution limits if there are any.\n for (uint256 _i; _i < _fundAccessConstraints.length; ) {\n JBFundAccessConstraints memory _constraints = _fundAccessConstraints[_i];\n\n // If distribution limit value is larger than 232 bits, revert.\n if (_constraints.distributionLimit > type(uint232).max) revert INVALID_DISTRIBUTION_LIMIT();\n\n // If distribution limit currency value is larger than 24 bits, revert.\n if (_constraints.distributionLimitCurrency > type(uint24).max)\n revert INVALID_DISTRIBUTION_LIMIT_CURRENCY();\n\n // If overflow allowance value is larger than 232 bits, revert.\n if (_constraints.overflowAllowance > type(uint232).max) revert INVALID_OVERFLOW_ALLOWANCE();\n\n // If overflow allowance currency value is larger than 24 bits, revert.\n if (_constraints.overflowAllowanceCurrency > type(uint24).max)\n revert INVALID_OVERFLOW_ALLOWANCE_CURRENCY();\n\n // Set the distribution limit if there is one.\n if (_constraints.distributionLimit > 0)\n _packedDistributionLimitDataOf[_projectId][_fundingCycle.configuration][\n _constraints.terminal\n ][_constraints.token] =\n _constraints.distributionLimit |\n (_constraints.distributionLimitCurrency << 232);\n\n // Set the overflow allowance if there is one.\n if (_constraints.overflowAllowance > 0)\n _packedOverflowAllowanceDataOf[_projectId][_fundingCycle.configuration][\n _constraints.terminal\n ][_constraints.token] =\n _constraints.overflowAllowance |\n (_constraints.overflowAllowanceCurrency << 232);\n\n emit SetFundAccessConstraints(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _constraints,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n\n return _fundingCycle.configuration;\n }\n}\n" + }, + "contracts/JBProjects.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';\nimport {ERC721Votes, ERC721, EIP712} from '@openzeppelin/contracts/token/ERC721/extensions/draft-ERC721Votes.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBOperatable} from './abstract/JBOperatable.sol';\nimport {IJBOperatable} from './interfaces/IJBOperatable.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {IJBTokenUriResolver} from './interfaces/IJBTokenUriResolver.sol';\nimport {JBOperations} from './libraries/JBOperations.sol';\nimport {JBProjectMetadata} from './structs/JBProjectMetadata.sol';\n\n/// @notice Stores project ownership and metadata.\n/// @dev Projects are represented as ERC-721's.\ncontract JBProjects is JBOperatable, ERC721Votes, Ownable, IJBProjects {\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The number of projects that have been created using this contract.\n /// @dev The count is incremented with each new project created.\n /// @dev The resulting ERC-721 token ID for each project is the newly incremented count value.\n uint256 public override count = 0;\n\n /// @notice The metadata for each project, which can be used across several domains.\n /// @custom:param _projectId The ID of the project to which the metadata belongs.\n /// @custom:param _domain The domain within which the metadata applies. Applications can use the domain namespace as they wish.\n mapping(uint256 => mapping(uint256 => string)) public override metadataContentOf;\n\n /// @notice The contract resolving each project ID to its ERC721 URI.\n IJBTokenUriResolver public override tokenUriResolver;\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice Returns the URI where the ERC-721 standard JSON of a project is hosted.\n /// @param _projectId The ID of the project to get a URI of.\n /// @return The token URI to use for the provided `_projectId`.\n function tokenURI(uint256 _projectId) public view override returns (string memory) {\n // Keep a reference to the resolver.\n IJBTokenUriResolver _tokenUriResolver = tokenUriResolver;\n\n // If there's no resolver, there's no URI.\n if (_tokenUriResolver == IJBTokenUriResolver(address(0))) return '';\n\n // Return the resolved URI.\n return _tokenUriResolver.getUri(_projectId);\n }\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if the provided interface ID is supported.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(IERC165, ERC721) returns (bool) {\n return\n _interfaceId == type(IJBProjects).interfaceId ||\n _interfaceId == type(IJBOperatable).interfaceId ||\n super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _operatorStore A contract storing operator assignments.\n constructor(\n IJBOperatorStore _operatorStore\n )\n ERC721('Juicebox Projects', 'JUICEBOX')\n EIP712('Juicebox Projects', '1')\n JBOperatable(_operatorStore)\n // solhint-disable-next-line no-empty-blocks\n {\n\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Create a new project for the specified owner, which mints an NFT (ERC-721) into their wallet.\n /// @dev Anyone can create a project on an owner's behalf.\n /// @param _owner The address that will be the owner of the project.\n /// @param _metadata A struct containing metadata content about the project, and domain within which the metadata applies.\n /// @return projectId The token ID of the newly created project.\n function createFor(\n address _owner,\n JBProjectMetadata calldata _metadata\n ) external override returns (uint256 projectId) {\n // Increment the count, which will be used as the ID.\n projectId = ++count;\n\n // Mint the project.\n _safeMint(_owner, projectId);\n\n // Set the metadata if one was provided.\n if (bytes(_metadata.content).length > 0)\n metadataContentOf[projectId][_metadata.domain] = _metadata.content;\n\n emit Create(projectId, _owner, _metadata, msg.sender);\n }\n\n /// @notice Allows a project owner to set the project's metadata content for a particular domain namespace.\n /// @dev Only a project's owner or operator can set its metadata.\n /// @dev Applications can use the domain namespace as they wish.\n /// @param _projectId The ID of the project who's metadata is being changed.\n /// @param _metadata A struct containing metadata content, and domain within which the metadata applies.\n function setMetadataOf(\n uint256 _projectId,\n JBProjectMetadata calldata _metadata\n )\n external\n override\n requirePermission(ownerOf(_projectId), _projectId, JBOperations.SET_METADATA)\n {\n // Set the project's new metadata content within the specified domain.\n metadataContentOf[_projectId][_metadata.domain] = _metadata.content;\n\n emit SetMetadata(_projectId, _metadata, msg.sender);\n }\n\n /// @notice Sets the address of the resolver used to retrieve the tokenURI of projects.\n /// @param _newResolver The address of the new resolver.\n function setTokenUriResolver(IJBTokenUriResolver _newResolver) external override onlyOwner {\n // Store the new resolver.\n tokenUriResolver = _newResolver;\n\n emit SetTokenUriResolver(_newResolver, msg.sender);\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC721/extensions/draft-ERC721Votes.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (token/ERC721/extensions/draft-ERC721Votes.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../ERC721.sol\";\nimport \"../../../governance/utils/Votes.sol\";\n\n/**\n * @dev Extension of ERC721 to support voting and delegation as implemented by {Votes}, where each individual NFT counts\n * as 1 vote unit.\n *\n * Tokens do not count as votes until they are delegated, because votes must be tracked which incurs an additional cost\n * on every transfer. Token holders can either delegate to a trusted representative who will decide how to make use of\n * the votes in governance decisions, or they can delegate to themselves to be their own representative.\n *\n * _Available since v4.5._\n */\nabstract contract ERC721Votes is ERC721, Votes {\n /**\n * @dev Adjusts votes when tokens are transferred.\n *\n * Emits a {Votes-DelegateVotesChanged} event.\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 tokenId\n ) internal virtual override {\n _transferVotingUnits(from, to, 1);\n super._afterTokenTransfer(from, to, tokenId);\n }\n\n /**\n * @dev Returns the balance of `account`.\n */\n function _getVotingUnits(address account) internal virtual override returns (uint256) {\n return balanceOf(account);\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC721/ERC721.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (token/ERC721/ERC721.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC721.sol\";\nimport \"./IERC721Receiver.sol\";\nimport \"./extensions/IERC721Metadata.sol\";\nimport \"../../utils/Address.sol\";\nimport \"../../utils/Context.sol\";\nimport \"../../utils/Strings.sol\";\nimport \"../../utils/introspection/ERC165.sol\";\n\n/**\n * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including\n * the Metadata extension, but not including the Enumerable extension, which is available separately as\n * {ERC721Enumerable}.\n */\ncontract ERC721 is Context, ERC165, IERC721, IERC721Metadata {\n using Address for address;\n using Strings for uint256;\n\n // Token name\n string private _name;\n\n // Token symbol\n string private _symbol;\n\n // Mapping from token ID to owner address\n mapping(uint256 => address) private _owners;\n\n // Mapping owner address to token count\n mapping(address => uint256) private _balances;\n\n // Mapping from token ID to approved address\n mapping(uint256 => address) private _tokenApprovals;\n\n // Mapping from owner to operator approvals\n mapping(address => mapping(address => bool)) private _operatorApprovals;\n\n /**\n * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {\n return\n interfaceId == type(IERC721).interfaceId ||\n interfaceId == type(IERC721Metadata).interfaceId ||\n super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev See {IERC721-balanceOf}.\n */\n function balanceOf(address owner) public view virtual override returns (uint256) {\n require(owner != address(0), \"ERC721: balance query for the zero address\");\n return _balances[owner];\n }\n\n /**\n * @dev See {IERC721-ownerOf}.\n */\n function ownerOf(uint256 tokenId) public view virtual override returns (address) {\n address owner = _owners[tokenId];\n require(owner != address(0), \"ERC721: owner query for nonexistent token\");\n return owner;\n }\n\n /**\n * @dev See {IERC721Metadata-name}.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev See {IERC721Metadata-symbol}.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev See {IERC721Metadata-tokenURI}.\n */\n function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {\n require(_exists(tokenId), \"ERC721Metadata: URI query for nonexistent token\");\n\n string memory baseURI = _baseURI();\n return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : \"\";\n }\n\n /**\n * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each\n * token will be the concatenation of the `baseURI` and the `tokenId`. Empty\n * by default, can be overriden in child contracts.\n */\n function _baseURI() internal view virtual returns (string memory) {\n return \"\";\n }\n\n /**\n * @dev See {IERC721-approve}.\n */\n function approve(address to, uint256 tokenId) public virtual override {\n address owner = ERC721.ownerOf(tokenId);\n require(to != owner, \"ERC721: approval to current owner\");\n\n require(\n _msgSender() == owner || isApprovedForAll(owner, _msgSender()),\n \"ERC721: approve caller is not owner nor approved for all\"\n );\n\n _approve(to, tokenId);\n }\n\n /**\n * @dev See {IERC721-getApproved}.\n */\n function getApproved(uint256 tokenId) public view virtual override returns (address) {\n require(_exists(tokenId), \"ERC721: approved query for nonexistent token\");\n\n return _tokenApprovals[tokenId];\n }\n\n /**\n * @dev See {IERC721-setApprovalForAll}.\n */\n function setApprovalForAll(address operator, bool approved) public virtual override {\n _setApprovalForAll(_msgSender(), operator, approved);\n }\n\n /**\n * @dev See {IERC721-isApprovedForAll}.\n */\n function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {\n return _operatorApprovals[owner][operator];\n }\n\n /**\n * @dev See {IERC721-transferFrom}.\n */\n function transferFrom(\n address from,\n address to,\n uint256 tokenId\n ) public virtual override {\n //solhint-disable-next-line max-line-length\n require(_isApprovedOrOwner(_msgSender(), tokenId), \"ERC721: transfer caller is not owner nor approved\");\n\n _transfer(from, to, tokenId);\n }\n\n /**\n * @dev See {IERC721-safeTransferFrom}.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId\n ) public virtual override {\n safeTransferFrom(from, to, tokenId, \"\");\n }\n\n /**\n * @dev See {IERC721-safeTransferFrom}.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId,\n bytes memory _data\n ) public virtual override {\n require(_isApprovedOrOwner(_msgSender(), tokenId), \"ERC721: transfer caller is not owner nor approved\");\n _safeTransfer(from, to, tokenId, _data);\n }\n\n /**\n * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\n * are aware of the ERC721 protocol to prevent tokens from being forever locked.\n *\n * `_data` is additional data, it has no specified format and it is sent in call to `to`.\n *\n * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.\n * implement alternative mechanisms to perform token transfer, such as signature-based.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must exist and be owned by `from`.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function _safeTransfer(\n address from,\n address to,\n uint256 tokenId,\n bytes memory _data\n ) internal virtual {\n _transfer(from, to, tokenId);\n require(_checkOnERC721Received(from, to, tokenId, _data), \"ERC721: transfer to non ERC721Receiver implementer\");\n }\n\n /**\n * @dev Returns whether `tokenId` exists.\n *\n * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.\n *\n * Tokens start existing when they are minted (`_mint`),\n * and stop existing when they are burned (`_burn`).\n */\n function _exists(uint256 tokenId) internal view virtual returns (bool) {\n return _owners[tokenId] != address(0);\n }\n\n /**\n * @dev Returns whether `spender` is allowed to manage `tokenId`.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n */\n function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {\n require(_exists(tokenId), \"ERC721: operator query for nonexistent token\");\n address owner = ERC721.ownerOf(tokenId);\n return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));\n }\n\n /**\n * @dev Safely mints `tokenId` and transfers it to `to`.\n *\n * Requirements:\n *\n * - `tokenId` must not exist.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function _safeMint(address to, uint256 tokenId) internal virtual {\n _safeMint(to, tokenId, \"\");\n }\n\n /**\n * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is\n * forwarded in {IERC721Receiver-onERC721Received} to contract recipients.\n */\n function _safeMint(\n address to,\n uint256 tokenId,\n bytes memory _data\n ) internal virtual {\n _mint(to, tokenId);\n require(\n _checkOnERC721Received(address(0), to, tokenId, _data),\n \"ERC721: transfer to non ERC721Receiver implementer\"\n );\n }\n\n /**\n * @dev Mints `tokenId` and transfers it to `to`.\n *\n * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible\n *\n * Requirements:\n *\n * - `tokenId` must not exist.\n * - `to` cannot be the zero address.\n *\n * Emits a {Transfer} event.\n */\n function _mint(address to, uint256 tokenId) internal virtual {\n require(to != address(0), \"ERC721: mint to the zero address\");\n require(!_exists(tokenId), \"ERC721: token already minted\");\n\n _beforeTokenTransfer(address(0), to, tokenId);\n\n _balances[to] += 1;\n _owners[tokenId] = to;\n\n emit Transfer(address(0), to, tokenId);\n\n _afterTokenTransfer(address(0), to, tokenId);\n }\n\n /**\n * @dev Destroys `tokenId`.\n * The approval is cleared when the token is burned.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n *\n * Emits a {Transfer} event.\n */\n function _burn(uint256 tokenId) internal virtual {\n address owner = ERC721.ownerOf(tokenId);\n\n _beforeTokenTransfer(owner, address(0), tokenId);\n\n // Clear approvals\n _approve(address(0), tokenId);\n\n _balances[owner] -= 1;\n delete _owners[tokenId];\n\n emit Transfer(owner, address(0), tokenId);\n\n _afterTokenTransfer(owner, address(0), tokenId);\n }\n\n /**\n * @dev Transfers `tokenId` from `from` to `to`.\n * As opposed to {transferFrom}, this imposes no restrictions on msg.sender.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - `tokenId` token must be owned by `from`.\n *\n * Emits a {Transfer} event.\n */\n function _transfer(\n address from,\n address to,\n uint256 tokenId\n ) internal virtual {\n require(ERC721.ownerOf(tokenId) == from, \"ERC721: transfer from incorrect owner\");\n require(to != address(0), \"ERC721: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, tokenId);\n\n // Clear approvals from the previous owner\n _approve(address(0), tokenId);\n\n _balances[from] -= 1;\n _balances[to] += 1;\n _owners[tokenId] = to;\n\n emit Transfer(from, to, tokenId);\n\n _afterTokenTransfer(from, to, tokenId);\n }\n\n /**\n * @dev Approve `to` to operate on `tokenId`\n *\n * Emits a {Approval} event.\n */\n function _approve(address to, uint256 tokenId) internal virtual {\n _tokenApprovals[tokenId] = to;\n emit Approval(ERC721.ownerOf(tokenId), to, tokenId);\n }\n\n /**\n * @dev Approve `operator` to operate on all of `owner` tokens\n *\n * Emits a {ApprovalForAll} event.\n */\n function _setApprovalForAll(\n address owner,\n address operator,\n bool approved\n ) internal virtual {\n require(owner != operator, \"ERC721: approve to caller\");\n _operatorApprovals[owner][operator] = approved;\n emit ApprovalForAll(owner, operator, approved);\n }\n\n /**\n * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.\n * The call is not executed if the target address is not a contract.\n *\n * @param from address representing the previous owner of the given token ID\n * @param to target address that will receive the tokens\n * @param tokenId uint256 ID of the token to be transferred\n * @param _data bytes optional data to send along with the call\n * @return bool whether the call correctly returned the expected magic value\n */\n function _checkOnERC721Received(\n address from,\n address to,\n uint256 tokenId,\n bytes memory _data\n ) private returns (bool) {\n if (to.isContract()) {\n try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) {\n return retval == IERC721Receiver.onERC721Received.selector;\n } catch (bytes memory reason) {\n if (reason.length == 0) {\n revert(\"ERC721: transfer to non ERC721Receiver implementer\");\n } else {\n assembly {\n revert(add(32, reason), mload(reason))\n }\n }\n }\n } else {\n return true;\n }\n }\n\n /**\n * @dev Hook that is called before any token transfer. This includes minting\n * and burning.\n *\n * Calling conditions:\n *\n * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be\n * transferred to `to`.\n * - When `from` is zero, `tokenId` will be minted for `to`.\n * - When `to` is zero, ``from``'s `tokenId` will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 tokenId\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 tokenId\n ) internal virtual {}\n}\n" + }, + "@openzeppelin/contracts/governance/utils/Votes.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (governance/utils/Votes.sol)\npragma solidity ^0.8.0;\n\nimport \"../../utils/Context.sol\";\nimport \"../../utils/Counters.sol\";\nimport \"../../utils/Checkpoints.sol\";\nimport \"../../utils/cryptography/draft-EIP712.sol\";\nimport \"./IVotes.sol\";\n\n/**\n * @dev This is a base abstract contract that tracks voting units, which are a measure of voting power that can be\n * transferred, and provides a system of vote delegation, where an account can delegate its voting units to a sort of\n * \"representative\" that will pool delegated voting units from different accounts and can then use it to vote in\n * decisions. In fact, voting units _must_ be delegated in order to count as actual votes, and an account has to\n * delegate those votes to itself if it wishes to participate in decisions and does not have a trusted representative.\n *\n * This contract is often combined with a token contract such that voting units correspond to token units. For an\n * example, see {ERC721Votes}.\n *\n * The full history of delegate votes is tracked on-chain so that governance protocols can consider votes as distributed\n * at a particular block number to protect against flash loans and double voting. The opt-in delegate system makes the\n * cost of this history tracking optional.\n *\n * When using this module the derived contract must implement {_getVotingUnits} (for example, make it return\n * {ERC721-balanceOf}), and can use {_transferVotingUnits} to track a change in the distribution of those units (in the\n * previous example, it would be included in {ERC721-_beforeTokenTransfer}).\n *\n * _Available since v4.5._\n */\nabstract contract Votes is IVotes, Context, EIP712 {\n using Checkpoints for Checkpoints.History;\n using Counters for Counters.Counter;\n\n bytes32 private constant _DELEGATION_TYPEHASH =\n keccak256(\"Delegation(address delegatee,uint256 nonce,uint256 expiry)\");\n\n mapping(address => address) private _delegation;\n mapping(address => Checkpoints.History) private _delegateCheckpoints;\n Checkpoints.History private _totalCheckpoints;\n\n mapping(address => Counters.Counter) private _nonces;\n\n /**\n * @dev Returns the current amount of votes that `account` has.\n */\n function getVotes(address account) public view virtual override returns (uint256) {\n return _delegateCheckpoints[account].latest();\n }\n\n /**\n * @dev Returns the amount of votes that `account` had at the end of a past block (`blockNumber`).\n *\n * Requirements:\n *\n * - `blockNumber` must have been already mined\n */\n function getPastVotes(address account, uint256 blockNumber) public view virtual override returns (uint256) {\n return _delegateCheckpoints[account].getAtBlock(blockNumber);\n }\n\n /**\n * @dev Returns the total supply of votes available at the end of a past block (`blockNumber`).\n *\n * NOTE: This value is the sum of all available votes, which is not necessarily the sum of all delegated votes.\n * Votes that have not been delegated are still part of total supply, even though they would not participate in a\n * vote.\n *\n * Requirements:\n *\n * - `blockNumber` must have been already mined\n */\n function getPastTotalSupply(uint256 blockNumber) public view virtual override returns (uint256) {\n require(blockNumber < block.number, \"Votes: block not yet mined\");\n return _totalCheckpoints.getAtBlock(blockNumber);\n }\n\n /**\n * @dev Returns the current total supply of votes.\n */\n function _getTotalSupply() internal view virtual returns (uint256) {\n return _totalCheckpoints.latest();\n }\n\n /**\n * @dev Returns the delegate that `account` has chosen.\n */\n function delegates(address account) public view virtual override returns (address) {\n return _delegation[account];\n }\n\n /**\n * @dev Delegates votes from the sender to `delegatee`.\n */\n function delegate(address delegatee) public virtual override {\n address account = _msgSender();\n _delegate(account, delegatee);\n }\n\n /**\n * @dev Delegates votes from signer to `delegatee`.\n */\n function delegateBySig(\n address delegatee,\n uint256 nonce,\n uint256 expiry,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) public virtual override {\n require(block.timestamp <= expiry, \"Votes: signature expired\");\n address signer = ECDSA.recover(\n _hashTypedDataV4(keccak256(abi.encode(_DELEGATION_TYPEHASH, delegatee, nonce, expiry))),\n v,\n r,\n s\n );\n require(nonce == _useNonce(signer), \"Votes: invalid nonce\");\n _delegate(signer, delegatee);\n }\n\n /**\n * @dev Delegate all of `account`'s voting units to `delegatee`.\n *\n * Emits events {DelegateChanged} and {DelegateVotesChanged}.\n */\n function _delegate(address account, address delegatee) internal virtual {\n address oldDelegate = delegates(account);\n _delegation[account] = delegatee;\n\n emit DelegateChanged(account, oldDelegate, delegatee);\n _moveDelegateVotes(oldDelegate, delegatee, _getVotingUnits(account));\n }\n\n /**\n * @dev Transfers, mints, or burns voting units. To register a mint, `from` should be zero. To register a burn, `to`\n * should be zero. Total supply of voting units will be adjusted with mints and burns.\n */\n function _transferVotingUnits(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n if (from == address(0)) {\n _totalCheckpoints.push(_add, amount);\n }\n if (to == address(0)) {\n _totalCheckpoints.push(_subtract, amount);\n }\n _moveDelegateVotes(delegates(from), delegates(to), amount);\n }\n\n /**\n * @dev Moves delegated votes from one delegate to another.\n */\n function _moveDelegateVotes(\n address from,\n address to,\n uint256 amount\n ) private {\n if (from != to && amount > 0) {\n if (from != address(0)) {\n (uint256 oldValue, uint256 newValue) = _delegateCheckpoints[from].push(_subtract, amount);\n emit DelegateVotesChanged(from, oldValue, newValue);\n }\n if (to != address(0)) {\n (uint256 oldValue, uint256 newValue) = _delegateCheckpoints[to].push(_add, amount);\n emit DelegateVotesChanged(to, oldValue, newValue);\n }\n }\n }\n\n function _add(uint256 a, uint256 b) private pure returns (uint256) {\n return a + b;\n }\n\n function _subtract(uint256 a, uint256 b) private pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Consumes a nonce.\n *\n * Returns the current value and increments nonce.\n */\n function _useNonce(address owner) internal virtual returns (uint256 current) {\n Counters.Counter storage nonce = _nonces[owner];\n current = nonce.current();\n nonce.increment();\n }\n\n /**\n * @dev Returns an address nonce.\n */\n function nonces(address owner) public view virtual returns (uint256) {\n return _nonces[owner].current();\n }\n\n /**\n * @dev Returns the contract's {EIP712} domain separator.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32) {\n return _domainSeparatorV4();\n }\n\n /**\n * @dev Must return the voting units held by an account.\n */\n function _getVotingUnits(address) internal virtual returns (uint256);\n}\n" + }, + "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721Receiver.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @title ERC721 token receiver interface\n * @dev Interface for any contract that wants to support safeTransfers\n * from ERC721 asset contracts.\n */\ninterface IERC721Receiver {\n /**\n * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}\n * by `operator` from `from`, this function is called.\n *\n * It must return its Solidity selector to confirm the token transfer.\n * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.\n *\n * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`.\n */\n function onERC721Received(\n address operator,\n address from,\n uint256 tokenId,\n bytes calldata data\n ) external returns (bytes4);\n}\n" + }, + "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC721.sol\";\n\n/**\n * @title ERC-721 Non-Fungible Token Standard, optional metadata extension\n * @dev See https://eips.ethereum.org/EIPS/eip-721\n */\ninterface IERC721Metadata is IERC721 {\n /**\n * @dev Returns the token collection name.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the token collection symbol.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.\n */\n function tokenURI(uint256 tokenId) external view returns (string memory);\n}\n" + }, + "@openzeppelin/contracts/utils/Checkpoints.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (utils/Checkpoints.sol)\npragma solidity ^0.8.0;\n\nimport \"./math/Math.sol\";\nimport \"./math/SafeCast.sol\";\n\n/**\n * @dev This library defines the `History` struct, for checkpointing values as they change at different points in\n * time, and later looking up past values by block number. See {Votes} as an example.\n *\n * To create a history of checkpoints define a variable type `Checkpoints.History` in your contract, and store a new\n * checkpoint for the current transaction block using the {push} function.\n *\n * _Available since v4.5._\n */\nlibrary Checkpoints {\n struct Checkpoint {\n uint32 _blockNumber;\n uint224 _value;\n }\n\n struct History {\n Checkpoint[] _checkpoints;\n }\n\n /**\n * @dev Returns the value in the latest checkpoint, or zero if there are no checkpoints.\n */\n function latest(History storage self) internal view returns (uint256) {\n uint256 pos = self._checkpoints.length;\n return pos == 0 ? 0 : self._checkpoints[pos - 1]._value;\n }\n\n /**\n * @dev Returns the value at a given block number. If a checkpoint is not available at that block, the closest one\n * before it is returned, or zero otherwise.\n */\n function getAtBlock(History storage self, uint256 blockNumber) internal view returns (uint256) {\n require(blockNumber < block.number, \"Checkpoints: block not yet mined\");\n\n uint256 high = self._checkpoints.length;\n uint256 low = 0;\n while (low < high) {\n uint256 mid = Math.average(low, high);\n if (self._checkpoints[mid]._blockNumber > blockNumber) {\n high = mid;\n } else {\n low = mid + 1;\n }\n }\n return high == 0 ? 0 : self._checkpoints[high - 1]._value;\n }\n\n /**\n * @dev Pushes a value onto a History so that it is stored as the checkpoint for the current block.\n *\n * Returns previous value and new value.\n */\n function push(History storage self, uint256 value) internal returns (uint256, uint256) {\n uint256 pos = self._checkpoints.length;\n uint256 old = latest(self);\n if (pos > 0 && self._checkpoints[pos - 1]._blockNumber == block.number) {\n self._checkpoints[pos - 1]._value = SafeCast.toUint224(value);\n } else {\n self._checkpoints.push(\n Checkpoint({_blockNumber: SafeCast.toUint32(block.number), _value: SafeCast.toUint224(value)})\n );\n }\n return (old, value);\n }\n\n /**\n * @dev Pushes a value onto a History, by updating the latest value using binary operation `op`. The new value will\n * be set to `op(latest, delta)`.\n *\n * Returns previous value and new value.\n */\n function push(\n History storage self,\n function(uint256, uint256) view returns (uint256) op,\n uint256 delta\n ) internal returns (uint256, uint256) {\n return push(self, op(latest(self), delta));\n }\n}\n" + }, + "contracts/JBDirectory.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';\nimport {JBOperatable} from './abstract/JBOperatable.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {JBFundingCycleMetadataResolver} from './libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBOperations} from './libraries/JBOperations.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\n\n/// @notice Keeps a reference of which terminal contracts each project is currently accepting funds through, and which controller contract is managing each project's tokens and funding cycles.\ncontract JBDirectory is JBOperatable, Ownable, IJBDirectory {\n // A library that parses the packed funding cycle metadata into a friendlier format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error DUPLICATE_TERMINALS();\n error INVALID_PROJECT_ID_IN_DIRECTORY();\n error SET_CONTROLLER_NOT_ALLOWED();\n error SET_TERMINALS_NOT_ALLOWED();\n error TOKEN_NOT_ACCEPTED();\n\n //*********************************************************************//\n // --------------------- private stored properties ------------------- //\n //*********************************************************************//\n\n /// @notice For each project ID, the terminals that are currently managing its funds.\n /// @custom:member _projectId The ID of the project to get terminals of.\n mapping(uint256 => IJBPaymentTerminal[]) private _terminalsOf;\n\n /// @notice The project's primary terminal for a token.\n /// @custom:member _projectId The ID of the project to get the primary terminal of.\n /// @custom:member _token The token to get the project's primary terminal of.\n mapping(uint256 => mapping(address => IJBPaymentTerminal)) private _primaryTerminalOf;\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice Mints ERC-721's that represent project ownership and transfers.\n IJBProjects public immutable override projects;\n\n /// @notice The contract storing all funding cycle configurations.\n IJBFundingCycleStore public immutable override fundingCycleStore;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice For each project ID, the controller that manages how terminals interact with tokens and funding cycles.\n /// @custom:member _projectId The ID of the project to get the controller of.\n mapping(uint256 => address) public override controllerOf;\n\n /// @notice Addresses that can set a project's first controller on their behalf. These addresses/contracts have been vetted and verified by this contract's owner.\n /// @custom:param _address The address that is either allowed or not.\n mapping(address => bool) public override isAllowedToSetFirstController;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice For each project ID, the terminals that are currently managing its funds.\n /// @param _projectId The ID of the project to get terminals of.\n /// @return An array of terminal addresses.\n function terminalsOf(uint256 _projectId)\n external\n view\n override\n returns (IJBPaymentTerminal[] memory)\n {\n return _terminalsOf[_projectId];\n }\n\n /// @notice The primary terminal that is managing funds for a project for a specified token.\n /// @dev The zero address is returned if a terminal isn't found for the specified token.\n /// @param _projectId The ID of the project to get a terminal for.\n /// @param _token The token the terminal accepts.\n /// @return The primary terminal for the project for the specified token.\n function primaryTerminalOf(uint256 _projectId, address _token)\n external\n view\n override\n returns (IJBPaymentTerminal)\n {\n // Keep a reference to the primary terminal for the provided project ID and token.\n IJBPaymentTerminal _primaryTerminal = _primaryTerminalOf[_projectId][_token];\n\n // If a primary terminal for the token was specifically set and it's one of the project's terminals, return it.\n if (\n _primaryTerminal != IJBPaymentTerminal(address(0)) &&\n isTerminalOf(_projectId, _primaryTerminal)\n ) return _primaryTerminal;\n\n // Keep a reference to the number of terminals the project has.\n uint256 _numberOfTerminals = _terminalsOf[_projectId].length;\n\n // Return the first terminal which accepts the specified token.\n for (uint256 _i; _i < _numberOfTerminals; ) {\n // Keep a reference to the terminal being iterated on.\n IJBPaymentTerminal _terminal = _terminalsOf[_projectId][_i];\n\n // If the terminal accepts the specified token, return it.\n if (_terminal.acceptsToken(_token, _projectId)) return _terminal;\n\n unchecked {\n ++_i;\n }\n }\n\n // Not found.\n return IJBPaymentTerminal(address(0));\n }\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice Whether or not a specified terminal is a terminal of the specified project.\n /// @param _projectId The ID of the project to check within.\n /// @param _terminal The address of the terminal to check for.\n /// @return A flag indicating whether or not the specified terminal is a terminal of the specified project.\n function isTerminalOf(uint256 _projectId, IJBPaymentTerminal _terminal)\n public\n view\n override\n returns (bool)\n {\n // Keep a reference to the number of terminals the project has.\n uint256 _numberOfTerminals = _terminalsOf[_projectId].length;\n\n // Loop through and return true if the terminal is contained.\n for (uint256 _i; _i < _numberOfTerminals; ) {\n // If the terminal being iterated on matches the provided terminal, return true.\n if (_terminalsOf[_projectId][_i] == _terminal) return true;\n\n unchecked {\n ++_i;\n }\n }\n\n // Otherwise, return false.\n return false;\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _fundingCycleStore A contract storing all funding cycle configurations.\n /// @param _owner The address that will own the contract.\n constructor(\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBFundingCycleStore _fundingCycleStore,\n address _owner\n ) JBOperatable(_operatorStore) {\n projects = _projects;\n fundingCycleStore = _fundingCycleStore;\n\n _transferOwnership(_owner);\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Update the controller that manages how terminals interact with the ecosystem.\n /// @dev A controller can be set if:\n /// @dev - the message sender is the project owner or an operator having the correct authorization.\n /// @dev - the message sender is the project's current controller.\n /// @dev - or, an allowedlisted address is setting a controller for a project that doesn't already have a controller.\n /// @param _projectId The ID of the project to set a new controller for.\n /// @param _controller The new controller to set.\n function setControllerOf(uint256 _projectId, address _controller)\n external\n override\n requirePermissionAllowingOverride(\n projects.ownerOf(_projectId),\n _projectId,\n JBOperations.SET_CONTROLLER,\n (msg.sender == address(controllerOf[_projectId]) ||\n (isAllowedToSetFirstController[msg.sender] && controllerOf[_projectId] == address(0)))\n )\n {\n // The project must exist.\n if (projects.count() < _projectId) revert INVALID_PROJECT_ID_IN_DIRECTORY();\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Setting controller is allowed if called from the current controller, or if the project doesn't have a current controller, or if the project's funding cycle allows setting the controller. Revert otherwise.\n if (\n msg.sender != address(controllerOf[_projectId]) &&\n controllerOf[_projectId] != address(0) &&\n !_fundingCycle.global().allowSetController\n ) revert SET_CONTROLLER_NOT_ALLOWED();\n\n // Set the new controller.\n controllerOf[_projectId] = _controller;\n\n emit SetController(_projectId, _controller, msg.sender);\n }\n\n /// @notice Set a project's terminals.\n /// @dev Only a project owner, an operator, or its controller can set its terminals.\n /// @param _projectId The ID of the project having terminals set.\n /// @param _terminals The terminal to set.\n function setTerminalsOf(uint256 _projectId, IJBPaymentTerminal[] calldata _terminals)\n external\n override\n requirePermissionAllowingOverride(\n projects.ownerOf(_projectId),\n _projectId,\n JBOperations.SET_TERMINALS,\n msg.sender == address(controllerOf[_projectId])\n )\n {\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Setting terminals must be allowed if not called from the current controller.\n if (\n msg.sender != address(controllerOf[_projectId]) && !_fundingCycle.global().allowSetTerminals\n ) revert SET_TERMINALS_NOT_ALLOWED();\n\n // Set the stored terminals for the project.\n _terminalsOf[_projectId] = _terminals;\n\n // Make sure duplicates were not added.\n if (_terminals.length > 1) {\n for (uint256 _i; _i < _terminals.length; ) {\n for (uint256 _j = _i + 1; _j < _terminals.length; ) {\n if (_terminals[_i] == _terminals[_j]) revert DUPLICATE_TERMINALS();\n\n unchecked {\n ++_j;\n }\n }\n\n unchecked {\n ++_i;\n }\n }\n }\n emit SetTerminals(_projectId, _terminals, msg.sender);\n }\n\n /// @notice Project's can set which terminal should be their primary for a particular token. \n /// @dev This is useful in case a project has several terminals connected for a particular token.\n /// @dev The terminal will be set as the primary terminal where ecosystem contracts should route tokens.\n /// @dev If setting a newly added terminal and the funding cycle doesn't allow new terminals, the caller must be the current controller.\n /// @param _projectId The ID of the project for which a primary token is being set.\n /// @param _token The token to set the primary terminal of.\n /// @param _terminal The terminal to make primary.\n function setPrimaryTerminalOf(\n uint256 _projectId,\n address _token,\n IJBPaymentTerminal _terminal\n )\n external\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.SET_PRIMARY_TERMINAL)\n {\n // Can't set the primary terminal for a token if it doesn't accept the token.\n if (!_terminal.acceptsToken(_token, _projectId)) revert TOKEN_NOT_ACCEPTED();\n\n // Add the terminal to the project if it hasn't been already.\n _addTerminalIfNeeded(_projectId, _terminal);\n\n // Store the terminal as the primary for the particular token.\n _primaryTerminalOf[_projectId][_token] = _terminal;\n\n emit SetPrimaryTerminal(_projectId, _token, _terminal, msg.sender);\n }\n\n /// @notice Set a contract to the list of trusted addresses that can set a first controller for any project.\t\n /// @dev The owner can add addresses which are allowed to change projects' first controllers. \n /// @dev These addresses are known and vetted controllers as well as contracts designed to launch new projects. \n /// @dev A project can set its own controller without it being on the allow list.\n /// @dev If you would like an address/contract allowlisted, please reach out to the contract owner.\n /// @param _address The address to allow or revoke allowance from.\n /// @param _flag Whether allowance is being added or revoked.\n function setIsAllowedToSetFirstController(address _address, bool _flag)\n external\n override\n onlyOwner\n {\n // Set the flag in the allowlist.\n isAllowedToSetFirstController[_address] = _flag;\n\n emit SetIsAllowedToSetFirstController(_address, _flag, msg.sender);\n }\n\n //*********************************************************************//\n // --------------------- private helper functions -------------------- //\n //*********************************************************************//\n\n /// @notice Add a terminal to a project's list of terminals if it hasn't been already.\n /// @param _projectId The ID of the project having a terminal added.\n /// @param _terminal The terminal to add.\n function _addTerminalIfNeeded(uint256 _projectId, IJBPaymentTerminal _terminal) private {\n // Check that the terminal has not already been added.\n if (isTerminalOf(_projectId, _terminal)) return;\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Setting terminals must be allowed if not called from the current controller.\n if (\n msg.sender != address(controllerOf[_projectId]) && !_fundingCycle.global().allowSetTerminals\n ) revert SET_TERMINALS_NOT_ALLOWED();\n\n // Add the new terminal.\n _terminalsOf[_projectId].push(_terminal);\n\n emit AddTerminal(_projectId, _terminal, msg.sender);\n }\n}\n" + }, + "contracts/JBSingleTokenPaymentTerminalStore3_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {ReentrancyGuard} from '@openzeppelin/contracts/security/ReentrancyGuard.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {JBBallotState} from './enums/JBBallotState.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBController3_1} from './interfaces/IJBController3_1.sol';\nimport {IJBFundingCycleDataSource} from './interfaces/IJBFundingCycleDataSource.sol';\nimport {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol';\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\nimport {IJBSingleTokenPaymentTerminal} from './interfaces/IJBSingleTokenPaymentTerminal.sol';\nimport {IJBSingleTokenPaymentTerminalStore} from './interfaces/IJBSingleTokenPaymentTerminalStore.sol';\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\nimport {JBConstants} from './libraries/JBConstants.sol';\nimport {JBCurrencies} from './libraries/JBCurrencies.sol';\nimport {JBFixedPointNumber} from './libraries/JBFixedPointNumber.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\nimport {JBFundingCycleMetadataResolver} from './libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBPayDelegateAllocation} from './structs/JBPayDelegateAllocation.sol';\nimport {JBPayParamsData} from './structs/JBPayParamsData.sol';\nimport {JBRedeemParamsData} from './structs/JBRedeemParamsData.sol';\nimport {JBRedemptionDelegateAllocation} from './structs/JBRedemptionDelegateAllocation.sol';\nimport {JBTokenAmount} from './structs/JBTokenAmount.sol';\n\n/// @notice Manages all bookkeeping for inflows and outflows of funds from any ISingleTokenPaymentTerminal.\n/// @dev This Store expects a project's controller to be an IJBController3_1. This is the only difference between this version and the original.\ncontract JBSingleTokenPaymentTerminalStore3_1 is\n ReentrancyGuard,\n IJBSingleTokenPaymentTerminalStore\n{\n // A library that parses the packed funding cycle metadata into a friendlier format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error INVALID_AMOUNT_TO_SEND_DELEGATE();\n error CURRENCY_MISMATCH();\n error DISTRIBUTION_AMOUNT_LIMIT_REACHED();\n error FUNDING_CYCLE_PAYMENT_PAUSED();\n error FUNDING_CYCLE_DISTRIBUTION_PAUSED();\n error FUNDING_CYCLE_REDEEM_PAUSED();\n error INADEQUATE_CONTROLLER_ALLOWANCE();\n error INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n error INSUFFICIENT_TOKENS();\n error INVALID_FUNDING_CYCLE();\n error PAYMENT_TERMINAL_MIGRATION_NOT_ALLOWED();\n\n //*********************************************************************//\n // -------------------------- private constants ---------------------- //\n //*********************************************************************//\n\n /// @notice Ensures a maximum number of decimal points of persisted fidelity on mulDiv operations of fixed point numbers.\n uint256 private constant _MAX_FIXED_POINT_FIDELITY = 18;\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n /// @notice The contract storing all funding cycle configurations.\n IJBFundingCycleStore public immutable override fundingCycleStore;\n\n /// @notice The contract that exposes price feeds.\n IJBPrices public immutable override prices;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The amount of tokens that each project has for each terminal, in terms of the terminal's token.\n /// @dev The used distribution limit is represented as a fixed point number with the same amount of decimals as its relative terminal.\n /// @custom:param _terminal The terminal to which the balance applies.\n /// @custom:param _projectId The ID of the project to get the balance of.\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => uint256)) public override balanceOf;\n\n /// @notice The amount of funds that a project has distributed from its limit during the current funding cycle for each terminal, in terms of the distribution limit's currency.\n /// @dev Increases as projects use their preconfigured distribution limits.\n /// @dev The used distribution limit is represented as a fixed point number with the same amount of decimals as its relative terminal.\n /// @custom:param _terminal The terminal to which the used distribution limit applies.\n /// @custom:param _projectId The ID of the project to get the used distribution limit of.\n /// @custom:param _fundingCycleNumber The number of the funding cycle during which the distribution limit was used.\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => mapping(uint256 => uint256)))\n public\n override usedDistributionLimitOf;\n\n /// @notice The amount of funds that a project has used from its allowance during the current funding cycle configuration for each terminal, in terms of the overflow allowance's currency.\n /// @dev Increases as projects use their allowance.\n /// @dev The used allowance is represented as a fixed point number with the same amount of decimals as its relative terminal.\n /// @custom:param _terminal The terminal to which the overflow allowance applies.\n /// @custom:param _projectId The ID of the project to get the used overflow allowance of.\n /// @custom:param _configuration The configuration of the during which the allowance was used.\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => mapping(uint256 => uint256)))\n public\n override usedOverflowAllowanceOf;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Gets the current overflowed amount in a terminal for a specified project.\n /// @dev The current overflow is represented as a fixed point number with the same amount of decimals as the specified terminal.\n /// @param _terminal The terminal for which the overflow is being calculated.\n /// @param _projectId The ID of the project to get overflow for.\n /// @return The current amount of overflow that project has in the specified terminal.\n function currentOverflowOf(\n IJBSingleTokenPaymentTerminal _terminal,\n uint256 _projectId\n ) external view override returns (uint256) {\n // Return the overflow during the project's current funding cycle.\n return\n _overflowDuring(\n _terminal,\n _projectId,\n fundingCycleStore.currentOf(_projectId),\n _terminal.currency()\n );\n }\n\n /// @notice Gets the current overflowed amount for a specified project across all terminals.\n /// @param _projectId The ID of the project to get total overflow for.\n /// @param _decimals The number of decimals that the fixed point overflow should include.\n /// @param _currency The currency that the total overflow should be in terms of.\n /// @return The current total amount of overflow that project has across all terminals.\n function currentTotalOverflowOf(\n uint256 _projectId,\n uint256 _decimals,\n uint256 _currency\n ) external view override returns (uint256) {\n return _currentTotalOverflowOf(_projectId, _decimals, _currency);\n }\n\n /// @notice The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the total token supply and overflow in the ecosystem.\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\n /// @dev The current reclaimable overflow is returned in terms of the specified terminal's currency.\n /// @dev The reclaimable overflow is represented as a fixed point number with the same amount of decimals as the specified terminal.\n /// @param _terminal The terminal from which the reclaimable amount would come.\n /// @param _projectId The ID of the project to get the reclaimable overflow amount for.\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _useTotalOverflow A flag indicating whether the overflow used in the calculation should be summed from all of the project's terminals. If false, overflow should be limited to the amount in the specified `_terminal`.\n /// @return The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_terminal`.\n function currentReclaimableOverflowOf(\n IJBSingleTokenPaymentTerminal _terminal,\n uint256 _projectId,\n uint256 _tokenCount,\n bool _useTotalOverflow\n ) external view override returns (uint256) {\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Get the amount of current overflow.\n // Use the project's total overflow across all of its terminals if the flag species specifies so. Otherwise, use the overflow local to the specified terminal.\n uint256 _currentOverflow = _useTotalOverflow\n ? _currentTotalOverflowOf(_projectId, _terminal.decimals(), _terminal.currency())\n : _overflowDuring(_terminal, _projectId, _fundingCycle, _terminal.currency());\n\n // If there's no overflow, there's no reclaimable overflow.\n if (_currentOverflow == 0) return 0;\n\n // Get the number of outstanding tokens the project has.\n uint256 _totalSupply = IJBController3_1(directory.controllerOf(_projectId))\n .totalOutstandingTokensOf(_projectId);\n\n // Can't redeem more tokens that is in the supply.\n if (_tokenCount > _totalSupply) return 0;\n\n // Return the reclaimable overflow amount.\n return\n _reclaimableOverflowDuring(\n _projectId,\n _fundingCycle,\n _tokenCount,\n _totalSupply,\n _currentOverflow\n );\n }\n\n /// @notice The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the specified total token supply and overflow amounts.\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\n /// @param _projectId The ID of the project to get the reclaimable overflow amount for.\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _totalSupply The total number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _overflow The amount of overflow to make the calculation with, as a fixed point number.\n /// @return The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_overflow`.\n function currentReclaimableOverflowOf(\n uint256 _projectId,\n uint256 _tokenCount,\n uint256 _totalSupply,\n uint256 _overflow\n ) external view override returns (uint256) {\n // If there's no overflow, there's no reclaimable overflow.\n if (_overflow == 0) return 0;\n\n // Can't redeem more tokens that is in the supply.\n if (_tokenCount > _totalSupply) return 0;\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Return the reclaimable overflow amount.\n return\n _reclaimableOverflowDuring(_projectId, _fundingCycle, _tokenCount, _totalSupply, _overflow);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _fundingCycleStore A contract storing all funding cycle configurations.\n /// @param _prices A contract that exposes price feeds.\n constructor(IJBDirectory _directory, IJBFundingCycleStore _fundingCycleStore, IJBPrices _prices) {\n directory = _directory;\n fundingCycleStore = _fundingCycleStore;\n prices = _prices;\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Records newly contributed tokens to a project.\n /// @dev Mints the project's tokens according to values provided by a configured data source. If no data source is configured, mints tokens proportional to the amount of the contribution.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.sender's tokens.\n /// @param _payer The original address that sent the payment to the terminal.\n /// @param _amount The amount of tokens being paid. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\n /// @param _projectId The ID of the project being paid.\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _beneficiary The specified address that should be the beneficiary of anything that results from the payment.\n /// @param _memo A memo to pass along to the emitted event, and passed along to the funding cycle's data source.\n /// @param _metadata Bytes to send along to the data source, if one is provided.\n /// @return fundingCycle The project's funding cycle during which payment was made.\n /// @return tokenCount The number of project tokens that were minted, as a fixed point number with 18 decimals.\n /// @return delegateAllocations The amount to send to delegates instead of adding to the local balance.\n /// @return memo A memo that should be passed along to the emitted event.\n function recordPaymentFrom(\n address _payer,\n JBTokenAmount calldata _amount,\n uint256 _projectId,\n uint256 _baseWeightCurrency,\n address _beneficiary,\n string calldata _memo,\n bytes memory _metadata\n )\n external\n override\n nonReentrant\n returns (\n JBFundingCycle memory fundingCycle,\n uint256 tokenCount,\n JBPayDelegateAllocation[] memory delegateAllocations,\n string memory memo\n )\n {\n // Get a reference to the current funding cycle for the project.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // The project must have a funding cycle configured.\n if (fundingCycle.number == 0) revert INVALID_FUNDING_CYCLE();\n\n // Must not be paused.\n if (fundingCycle.payPaused()) revert FUNDING_CYCLE_PAYMENT_PAUSED();\n\n // The weight according to which new token supply is to be minted, as a fixed point number with 18 decimals.\n uint256 _weight;\n\n // If the funding cycle has configured a data source, use it to derive a weight and memo.\n if (fundingCycle.useDataSourceForPay() && fundingCycle.dataSource() != address(0)) {\n // Create the params that'll be sent to the data source.\n JBPayParamsData memory _data = JBPayParamsData(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _payer,\n _amount,\n _projectId,\n fundingCycle.configuration,\n _beneficiary,\n fundingCycle.weight,\n fundingCycle.reservedRate(),\n _memo,\n _metadata\n );\n (_weight, memo, delegateAllocations) = IJBFundingCycleDataSource(fundingCycle.dataSource())\n .payParams(_data);\n }\n // Otherwise use the funding cycle's weight\n else {\n _weight = fundingCycle.weight;\n memo = _memo;\n }\n\n // Scoped section prevents stack too deep. `_balanceDiff` only used within scope.\n {\n // Keep a reference to the amount that should be added to the project's balance.\n uint256 _balanceDiff = _amount.value;\n\n // Validate all delegated amounts. This needs to be done before returning the delegate allocations to ensure valid delegated amounts.\n if (delegateAllocations.length != 0) {\n for (uint256 _i; _i < delegateAllocations.length; ) {\n // Get a reference to the amount to be delegated.\n uint256 _delegatedAmount = delegateAllocations[_i].amount;\n\n // Validate if non-zero.\n if (_delegatedAmount != 0) {\n // Can't delegate more than was paid.\n if (_delegatedAmount > _balanceDiff) revert INVALID_AMOUNT_TO_SEND_DELEGATE();\n\n // Decrement the total amount being added to the balance.\n _balanceDiff = _balanceDiff - _delegatedAmount;\n }\n\n unchecked {\n ++_i;\n }\n }\n }\n\n // If there's no amount being recorded, there's nothing left to do.\n if (_amount.value == 0) return (fundingCycle, 0, delegateAllocations, memo);\n\n // Add the correct balance difference to the token balance of the project.\n if (_balanceDiff != 0)\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] +\n _balanceDiff;\n }\n\n // If there's no weight, token count must be 0 so there's nothing left to do.\n if (_weight == 0) return (fundingCycle, 0, delegateAllocations, memo);\n\n // Get a reference to the number of decimals in the amount. (prevents stack too deep).\n uint256 _decimals = _amount.decimals;\n\n // If the terminal should base its weight on a different currency from the terminal's currency, determine the factor.\n // The weight is always a fixed point mumber with 18 decimals. To ensure this, the ratio should use the same number of decimals as the `_amount`.\n uint256 _weightRatio = _amount.currency == _baseWeightCurrency\n ? 10 ** _decimals\n : prices.priceFor(_amount.currency, _baseWeightCurrency, _decimals);\n\n // Find the number of tokens to mint, as a fixed point number with as many decimals as `weight` has.\n tokenCount = PRBMath.mulDiv(_amount.value, _weight, _weightRatio);\n }\n\n /// @notice Records newly redeemed tokens of a project.\n /// @dev Redeems the project's tokens according to values provided by a configured data source. If no data source is configured, redeems tokens along a redemption bonding curve that is a function of the number of tokens being burned.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.senders tokens.\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the data source, if one is provided.\n /// @return fundingCycle The funding cycle during which the redemption was made.\n /// @return reclaimAmount The amount of terminal tokens reclaimed, as a fixed point number with 18 decimals.\n /// @return delegateAllocations The amount to send to delegates instead of sending to the beneficiary.\n /// @return memo A memo that should be passed along to the emitted event.\n function recordRedemptionFor(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n string memory _memo,\n bytes memory _metadata\n )\n external\n override\n nonReentrant\n returns (\n JBFundingCycle memory fundingCycle,\n uint256 reclaimAmount,\n JBRedemptionDelegateAllocation[] memory delegateAllocations,\n string memory memo\n )\n {\n // Get a reference to the project's current funding cycle.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // The current funding cycle must not be paused.\n if (fundingCycle.redeemPaused()) revert FUNDING_CYCLE_REDEEM_PAUSED();\n\n // Scoped section prevents stack too deep. `_reclaimedTokenAmount`, `_currentOverflow`, and `_totalSupply` only used within scope.\n {\n // Get a reference to the reclaimed token amount struct, the current overflow, and the total token supply.\n JBTokenAmount memory _reclaimedTokenAmount;\n uint256 _currentOverflow;\n uint256 _totalSupply;\n\n // Another scoped section prevents stack too deep. `_token`, `_decimals`, and `_currency` only used within scope.\n {\n // Get a reference to the terminal's tokens.\n address _token = IJBSingleTokenPaymentTerminal(msg.sender).token();\n\n // Get a reference to the terminal's decimals.\n uint256 _decimals = IJBSingleTokenPaymentTerminal(msg.sender).decimals();\n\n // Get areference to the terminal's currency.\n uint256 _currency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\n\n // Get the amount of current overflow.\n // Use the local overflow if the funding cycle specifies that it should be used. Otherwise, use the project's total overflow across all of its terminals.\n _currentOverflow = fundingCycle.useTotalOverflowForRedemptions()\n ? _currentTotalOverflowOf(_projectId, _decimals, _currency)\n : _overflowDuring(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _projectId,\n fundingCycle,\n _currency\n );\n\n // Get the number of outstanding tokens the project has.\n _totalSupply = IJBController3_1(directory.controllerOf(_projectId))\n .totalOutstandingTokensOf(_projectId);\n\n // Can't redeem more tokens that is in the supply.\n if (_tokenCount > _totalSupply) revert INSUFFICIENT_TOKENS();\n\n if (_currentOverflow != 0)\n // Calculate reclaim amount using the current overflow amount.\n reclaimAmount = _reclaimableOverflowDuring(\n _projectId,\n fundingCycle,\n _tokenCount,\n _totalSupply,\n _currentOverflow\n );\n\n _reclaimedTokenAmount = JBTokenAmount(_token, reclaimAmount, _decimals, _currency);\n }\n\n // If the funding cycle has configured a data source, use it to derive a claim amount and memo.\n if (fundingCycle.useDataSourceForRedeem() && fundingCycle.dataSource() != address(0)) {\n // Yet another scoped section prevents stack too deep. `_state` only used within scope.\n {\n // Get a reference to the ballot state.\n JBBallotState _state = fundingCycleStore.currentBallotStateOf(_projectId);\n\n // Create the params that'll be sent to the data source.\n JBRedeemParamsData memory _data = JBRedeemParamsData(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _holder,\n _projectId,\n fundingCycle.configuration,\n _tokenCount,\n _totalSupply,\n _currentOverflow,\n _reclaimedTokenAmount,\n fundingCycle.useTotalOverflowForRedemptions(),\n _state == JBBallotState.Active\n ? fundingCycle.ballotRedemptionRate()\n : fundingCycle.redemptionRate(),\n _memo,\n _metadata\n );\n (reclaimAmount, memo, delegateAllocations) = IJBFundingCycleDataSource(\n fundingCycle.dataSource()\n ).redeemParams(_data);\n }\n } else {\n memo = _memo;\n }\n }\n\n // Keep a reference to the amount that should be subtracted from the project's balance.\n uint256 _balanceDiff = reclaimAmount;\n\n if (delegateAllocations.length != 0) {\n // Validate all delegated amounts.\n for (uint256 _i; _i < delegateAllocations.length; ) {\n // Get a reference to the amount to be delegated.\n uint256 _delegatedAmount = delegateAllocations[_i].amount;\n\n // Validate if non-zero.\n if (_delegatedAmount != 0)\n // Increment the total amount being subtracted from the balance.\n _balanceDiff = _balanceDiff + _delegatedAmount;\n\n unchecked {\n ++_i;\n }\n }\n }\n\n // The amount being reclaimed must be within the project's balance.\n if (_balanceDiff > balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId])\n revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n\n // Remove the reclaimed funds from the project's balance.\n if (_balanceDiff != 0) {\n unchecked {\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\n _balanceDiff;\n }\n }\n }\n\n /// @notice Records newly distributed funds for a project.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\n /// @param _projectId The ID of the project that is having funds distributed.\n /// @param _amount The amount to use from the distribution limit, as a fixed point number.\n /// @param _currency The currency of the `_amount`. This must match the project's current funding cycle's currency.\n /// @return fundingCycle The funding cycle during which the distribution was made.\n /// @return distributedAmount The amount of terminal tokens distributed, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordDistributionFor(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency\n )\n external\n override\n nonReentrant\n returns (JBFundingCycle memory fundingCycle, uint256 distributedAmount)\n {\n // Get a reference to the project's current funding cycle.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // The funding cycle must not be configured to have distributions paused.\n if (fundingCycle.distributionsPaused()) revert FUNDING_CYCLE_DISTRIBUTION_PAUSED();\n\n // The new total amount that has been distributed during this funding cycle.\n uint256 _newUsedDistributionLimitOf = usedDistributionLimitOf[\n IJBSingleTokenPaymentTerminal(msg.sender)\n ][_projectId][fundingCycle.number] + _amount;\n\n // Amount must be within what is still distributable.\n (uint256 _distributionLimitOf, uint256 _distributionLimitCurrencyOf) = IJBController3_1(\n directory.controllerOf(_projectId)\n ).fundAccessConstraintsStore().distributionLimitOf(\n _projectId,\n fundingCycle.configuration,\n IJBSingleTokenPaymentTerminal(msg.sender),\n IJBSingleTokenPaymentTerminal(msg.sender).token()\n );\n\n // Make sure the new used amount is within the distribution limit.\n if (_newUsedDistributionLimitOf > _distributionLimitOf || _distributionLimitOf == 0)\n revert DISTRIBUTION_AMOUNT_LIMIT_REACHED();\n\n // Make sure the currencies match.\n if (_currency != _distributionLimitCurrencyOf) revert CURRENCY_MISMATCH();\n\n // Get a reference to the terminal's currency.\n uint256 _balanceCurrency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\n\n // Convert the amount to the balance's currency.\n distributedAmount = (_currency == _balanceCurrency)\n ? _amount\n : PRBMath.mulDiv(\n _amount,\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\n prices.priceFor(_currency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\n );\n\n // The amount being distributed must be available.\n if (distributedAmount > balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId])\n revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n\n // Store the new amount.\n usedDistributionLimitOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId][\n fundingCycle.number\n ] = _newUsedDistributionLimitOf;\n\n // Removed the distributed funds from the project's token balance.\n unchecked {\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\n distributedAmount;\n }\n }\n\n /// @notice Records newly used allowance funds of a project.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\n /// @param _projectId The ID of the project to use the allowance of.\n /// @param _amount The amount to use from the allowance, as a fixed point number.\n /// @param _currency The currency of the `_amount`. Must match the currency of the overflow allowance.\n /// @return fundingCycle The funding cycle during which the overflow allowance is being used.\n /// @return usedAmount The amount of terminal tokens used, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordUsedAllowanceOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency\n )\n external\n override\n nonReentrant\n returns (JBFundingCycle memory fundingCycle, uint256 usedAmount)\n {\n // Get a reference to the project's current funding cycle.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Get a reference to the new used overflow allowance for this funding cycle configuration.\n uint256 _newUsedOverflowAllowanceOf = usedOverflowAllowanceOf[\n IJBSingleTokenPaymentTerminal(msg.sender)\n ][_projectId][fundingCycle.configuration] + _amount;\n\n // There must be sufficient allowance available.\n (uint256 _overflowAllowanceOf, uint256 _overflowAllowanceCurrency) = IJBController3_1(\n directory.controllerOf(_projectId)\n ).fundAccessConstraintsStore().overflowAllowanceOf(\n _projectId,\n fundingCycle.configuration,\n IJBSingleTokenPaymentTerminal(msg.sender),\n IJBSingleTokenPaymentTerminal(msg.sender).token()\n );\n\n // Make sure the new used amount is within the allowance.\n if (_newUsedOverflowAllowanceOf > _overflowAllowanceOf || _overflowAllowanceOf == 0)\n revert INADEQUATE_CONTROLLER_ALLOWANCE();\n\n // Make sure the currencies match.\n if (_currency != _overflowAllowanceCurrency) revert CURRENCY_MISMATCH();\n\n // Get a reference to the terminal's currency.\n uint256 _balanceCurrency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\n\n // Convert the amount to this store's terminal's token.\n usedAmount = (_currency == _balanceCurrency)\n ? _amount\n : PRBMath.mulDiv(\n _amount,\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\n prices.priceFor(_currency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\n );\n\n // The amount being distributed must be available in the overflow.\n if (\n usedAmount >\n _overflowDuring(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _projectId,\n fundingCycle,\n _balanceCurrency\n )\n ) revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n\n // Store the incremented value.\n usedOverflowAllowanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId][\n fundingCycle.configuration\n ] = _newUsedOverflowAllowanceOf;\n\n // Update the project's balance.\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\n usedAmount;\n }\n\n /// @notice Records newly added funds for the project.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\n /// @param _projectId The ID of the project to which the funds being added belong.\n /// @param _amount The amount of terminal tokens added, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordAddedBalanceFor(uint256 _projectId, uint256 _amount) external override {\n // Increment the balance.\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] +\n _amount;\n }\n\n /// @notice Records the migration of funds from this store.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount returned is in terms of the msg.senders tokens.\n /// @param _projectId The ID of the project being migrated.\n /// @return balance The project's migrated balance, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordMigration(\n uint256 _projectId\n ) external override nonReentrant returns (uint256 balance) {\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n // Migration must be allowed.\n if (!_fundingCycle.terminalMigrationAllowed()) revert PAYMENT_TERMINAL_MIGRATION_NOT_ALLOWED();\n\n // Return the current balance.\n balance = balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId];\n\n // Set the balance to 0.\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] = 0;\n }\n\n //*********************************************************************//\n // --------------------- private helper functions -------------------- //\n //*********************************************************************//\n\n /// @notice The amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens when measured from the specified.\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\n /// @param _projectId The ID of the project to get the reclaimable overflow amount for.\n /// @param _fundingCycle The funding cycle during which reclaimable overflow is being calculated.\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _totalSupply The total supply of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _overflow The amount of overflow to make the calculation with.\n /// @return The amount of overflowed tokens that can be reclaimed.\n function _reclaimableOverflowDuring(\n uint256 _projectId,\n JBFundingCycle memory _fundingCycle,\n uint256 _tokenCount,\n uint256 _totalSupply,\n uint256 _overflow\n ) private view returns (uint256) {\n // If the amount being redeemed is the total supply, return the rest of the overflow.\n if (_tokenCount == _totalSupply) return _overflow;\n\n // Use the ballot redemption rate if the queued cycle is pending approval according to the previous funding cycle's ballot.\n uint256 _redemptionRate = fundingCycleStore.currentBallotStateOf(_projectId) ==\n JBBallotState.Active\n ? _fundingCycle.ballotRedemptionRate()\n : _fundingCycle.redemptionRate();\n\n // If the redemption rate is 0, nothing is claimable.\n if (_redemptionRate == 0) return 0;\n\n // Get a reference to the linear proportion.\n uint256 _base = PRBMath.mulDiv(_overflow, _tokenCount, _totalSupply);\n\n // These conditions are all part of the same curve. Edge conditions are separated because fewer operation are necessary.\n if (_redemptionRate == JBConstants.MAX_REDEMPTION_RATE) return _base;\n\n return\n PRBMath.mulDiv(\n _base,\n _redemptionRate +\n PRBMath.mulDiv(\n _tokenCount,\n JBConstants.MAX_REDEMPTION_RATE - _redemptionRate,\n _totalSupply\n ),\n JBConstants.MAX_REDEMPTION_RATE\n );\n }\n\n /// @notice Gets the amount that is overflowing when measured from the specified funding cycle.\n /// @dev This amount changes as the value of the balance changes in relation to the currency being used to measure the distribution limit.\n /// @param _terminal The terminal for which the overflow is being calculated.\n /// @param _fundingCycle The ID of the funding cycle to base the overflow on.\n /// @param _balanceCurrency The currency that the stored balance is expected to be in terms of.\n /// @return overflow The overflow of funds, as a fixed point number with 18 decimals.\n function _overflowDuring(\n IJBSingleTokenPaymentTerminal _terminal,\n uint256 _projectId,\n JBFundingCycle memory _fundingCycle,\n uint256 _balanceCurrency\n ) private view returns (uint256) {\n // Get the current balance of the project.\n uint256 _balanceOf = balanceOf[_terminal][_projectId];\n\n // If there's no balance, there's no overflow.\n if (_balanceOf == 0) return 0;\n\n // Get a reference to the distribution limit during the funding cycle.\n (uint256 _distributionLimit, uint256 _distributionLimitCurrency) = IJBController3_1(\n directory.controllerOf(_projectId)\n ).fundAccessConstraintsStore().distributionLimitOf(\n _projectId,\n _fundingCycle.configuration,\n _terminal,\n _terminal.token()\n );\n\n // Get a reference to the amount still distributable during the funding cycle.\n uint256 _distributionLimitRemaining = _distributionLimit -\n usedDistributionLimitOf[_terminal][_projectId][_fundingCycle.number];\n\n // Convert the _distributionRemaining to be in terms of the provided currency.\n if (_distributionLimitRemaining != 0 && _distributionLimitCurrency != _balanceCurrency)\n _distributionLimitRemaining = PRBMath.mulDiv(\n _distributionLimitRemaining,\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\n prices.priceFor(_distributionLimitCurrency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\n );\n\n // Overflow is the balance of this project minus the amount that can still be distributed.\n unchecked {\n return\n _balanceOf > _distributionLimitRemaining ? _balanceOf - _distributionLimitRemaining : 0;\n }\n }\n\n /// @notice Gets the amount that is currently overflowing across all of a project's terminals.\n /// @dev This amount changes as the value of the balances changes in relation to the currency being used to measure the project's distribution limits.\n /// @param _projectId The ID of the project to get the total overflow for.\n /// @param _decimals The number of decimals that the fixed point overflow should include.\n /// @param _currency The currency that the overflow should be in terms of.\n /// @return overflow The total overflow of a project's funds.\n function _currentTotalOverflowOf(\n uint256 _projectId,\n uint256 _decimals,\n uint256 _currency\n ) private view returns (uint256) {\n // Get a reference to the project's terminals.\n IJBPaymentTerminal[] memory _terminals = directory.terminalsOf(_projectId);\n\n // Keep a reference to the ETH overflow across all terminals, as a fixed point number with 18 decimals.\n uint256 _ethOverflow;\n\n // Add the current ETH overflow for each terminal.\n for (uint256 _i; _i < _terminals.length; ) {\n _ethOverflow = _ethOverflow + _terminals[_i].currentEthOverflowOf(_projectId);\n unchecked {\n ++_i;\n }\n }\n\n // Convert the ETH overflow to the specified currency if needed, maintaining a fixed point number with 18 decimals.\n uint256 _totalOverflow18Decimal = _currency == JBCurrencies.ETH\n ? _ethOverflow\n : PRBMath.mulDiv(_ethOverflow, 10 ** 18, prices.priceFor(JBCurrencies.ETH, _currency, 18));\n\n // Adjust the decimals of the fixed point number if needed to match the target decimals.\n return\n (_decimals == 18)\n ? _totalOverflow18Decimal\n : JBFixedPointNumber.adjustDecimals(_totalOverflow18Decimal, 18, _decimals);\n }\n}\n" + }, + "contracts/interfaces/IJBFundingCycleDataSource.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBPayDelegateAllocation} from './../structs/JBPayDelegateAllocation.sol';\nimport {JBPayParamsData} from './../structs/JBPayParamsData.sol';\nimport {JBRedeemParamsData} from './../structs/JBRedeemParamsData.sol';\nimport {JBRedemptionDelegateAllocation} from './../structs/JBRedemptionDelegateAllocation.sol';\n\n/// @title Datasource\n/// @notice The datasource is called by JBPayoutRedemptionPaymentTerminals on pay and redemption, and provide an extra layer of logic to use a custom weight, a custom memo and/or a pay/redeem delegate\ninterface IJBFundingCycleDataSource is IERC165 {\n /// @notice The datasource implementation for JBPaymentTerminal.pay(..)\n /// @param data the data passed to the data source in terminal.pay(..), as a JBPayParamsData struct:\n /// @return weight the weight to use to override the funding cycle weight\n /// @return memo the memo to override the pay(..) memo\n /// @return delegateAllocations The amount to send to delegates instead of adding to the local balance.\n function payParams(\n JBPayParamsData calldata data\n )\n external\n returns (\n uint256 weight,\n string memory memo,\n JBPayDelegateAllocation[] memory delegateAllocations\n );\n\n /// @notice The datasource implementation for JBPaymentTerminal.redeemTokensOf(..)\n /// @param data the data passed to the data source in terminal.redeemTokensOf(..), as a JBRedeemParamsData struct:\n /// @return reclaimAmount The amount to claim, overriding the terminal logic.\n /// @return memo The memo to override the redeemTokensOf(..) memo.\n /// @return delegateAllocations The amount to send to delegates instead of adding to the beneficiary.\n function redeemParams(\n JBRedeemParamsData calldata data\n )\n external\n returns (\n uint256 reclaimAmount,\n string memory memo,\n JBRedemptionDelegateAllocation[] memory delegateAllocations\n );\n}\n" + }, + "contracts/interfaces/IJBSingleTokenPaymentTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\n\ninterface IJBSingleTokenPaymentTerminal is IJBPaymentTerminal {\n function token() external view returns (address);\n\n function currency() external view returns (uint256);\n\n function decimals() external view returns (uint256);\n}\n" + }, + "contracts/interfaces/IJBSingleTokenPaymentTerminalStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\nimport {JBPayDelegateAllocation} from './../structs/JBPayDelegateAllocation.sol';\nimport {JBRedemptionDelegateAllocation} from './../structs/JBRedemptionDelegateAllocation.sol';\nimport {JBTokenAmount} from './../structs/JBTokenAmount.sol';\nimport {IJBDirectory} from './IJBDirectory.sol';\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\nimport {IJBPrices} from './IJBPrices.sol';\nimport {IJBSingleTokenPaymentTerminal} from './IJBSingleTokenPaymentTerminal.sol';\n\ninterface IJBSingleTokenPaymentTerminalStore {\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\n\n function directory() external view returns (IJBDirectory);\n\n function prices() external view returns (IJBPrices);\n\n function balanceOf(\n IJBSingleTokenPaymentTerminal terminal,\n uint256 projectId\n ) external view returns (uint256);\n\n function usedDistributionLimitOf(\n IJBSingleTokenPaymentTerminal terminal,\n uint256 projectId,\n uint256 fundingCycleNumber\n ) external view returns (uint256);\n\n function usedOverflowAllowanceOf(\n IJBSingleTokenPaymentTerminal terminal,\n uint256 projectId,\n uint256 fundingCycleConfiguration\n ) external view returns (uint256);\n\n function currentOverflowOf(\n IJBSingleTokenPaymentTerminal terminal,\n uint256 projectId\n ) external view returns (uint256);\n\n function currentTotalOverflowOf(\n uint256 projectId,\n uint256 decimals,\n uint256 currency\n ) external view returns (uint256);\n\n function currentReclaimableOverflowOf(\n IJBSingleTokenPaymentTerminal terminal,\n uint256 projectId,\n uint256 tokenCount,\n bool useTotalOverflow\n ) external view returns (uint256);\n\n function currentReclaimableOverflowOf(\n uint256 projectId,\n uint256 tokenCount,\n uint256 totalSupply,\n uint256 overflow\n ) external view returns (uint256);\n\n function recordPaymentFrom(\n address payer,\n JBTokenAmount memory amount,\n uint256 projectId,\n uint256 baseWeightCurrency,\n address beneficiary,\n string calldata inputMemo,\n bytes calldata metadata\n )\n external\n returns (\n JBFundingCycle memory fundingCycle,\n uint256 tokenCount,\n JBPayDelegateAllocation[] memory delegateAllocations,\n string memory outputMemo\n );\n\n function recordRedemptionFor(\n address holder,\n uint256 projectId,\n uint256 tokenCount,\n string calldata inputMemo,\n bytes calldata metadata\n )\n external\n returns (\n JBFundingCycle memory fundingCycle,\n uint256 reclaimAmount,\n JBRedemptionDelegateAllocation[] memory delegateAllocations,\n string memory outputMemo\n );\n\n function recordDistributionFor(\n uint256 projectId,\n uint256 amount,\n uint256 currency\n ) external returns (JBFundingCycle memory fundingCycle, uint256 distributedAmount);\n\n function recordUsedAllowanceOf(\n uint256 projectId,\n uint256 amount,\n uint256 currency\n ) external returns (JBFundingCycle memory fundingCycle, uint256 withdrawnAmount);\n\n function recordAddedBalanceFor(uint256 projectId, uint256 amount) external;\n\n function recordMigration(uint256 projectId) external returns (uint256 balance);\n}\n" + }, + "contracts/interfaces/IJBPrices.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBPriceFeed} from './IJBPriceFeed.sol';\n\ninterface IJBPrices {\n event AddFeed(uint256 indexed currency, uint256 indexed base, IJBPriceFeed feed);\n\n function feedFor(uint256 currency, uint256 base) external view returns (IJBPriceFeed);\n\n function priceFor(\n uint256 currency,\n uint256 base,\n uint256 decimals\n ) external view returns (uint256);\n\n function addFeedFor(uint256 currency, uint256 base, IJBPriceFeed priceFeed) external;\n}\n" + }, + "contracts/libraries/JBCurrencies.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nlibrary JBCurrencies {\n uint256 public constant ETH = 1;\n uint256 public constant USD = 2;\n}\n" + }, + "contracts/libraries/JBFixedPointNumber.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nlibrary JBFixedPointNumber {\n function adjustDecimals(\n uint256 _value,\n uint256 _decimals,\n uint256 _targetDecimals\n ) internal pure returns (uint256) {\n // If decimals need adjusting, multiply or divide the price by the decimal adjuster to get the normalized result.\n if (_targetDecimals == _decimals) return _value;\n else if (_targetDecimals > _decimals) return _value * 10**(_targetDecimals - _decimals);\n else return _value / 10**(_decimals - _targetDecimals);\n }\n}\n" + }, + "contracts/structs/JBPayDelegateAllocation.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBPayDelegate} from '../interfaces/IJBPayDelegate.sol';\n\n/// @custom:member delegate A delegate contract to use for subsequent calls.\n/// @custom:member amount The amount to send to the delegate.\nstruct JBPayDelegateAllocation {\n IJBPayDelegate delegate;\n uint256 amount;\n}\n" + }, + "contracts/structs/JBPayParamsData.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\nimport {JBTokenAmount} from './JBTokenAmount.sol';\n\n/// @custom:member terminal The terminal that is facilitating the payment.\n/// @custom:member payer The address from which the payment originated.\n/// @custom:member amount The amount of the payment. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\n/// @custom:member projectId The ID of the project being paid.\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the payment is being made.\n/// @custom:member beneficiary The specified address that should be the beneficiary of anything that results from the payment.\n/// @custom:member weight The weight of the funding cycle during which the payment is being made.\n/// @custom:member reservedRate The reserved rate of the funding cycle during which the payment is being made.\n/// @custom:member memo The memo that was sent alongside the payment.\n/// @custom:member metadata Extra data provided by the payer.\nstruct JBPayParamsData {\n IJBPaymentTerminal terminal;\n address payer;\n JBTokenAmount amount;\n uint256 projectId;\n uint256 currentFundingCycleConfiguration;\n address beneficiary;\n uint256 weight;\n uint256 reservedRate;\n string memo;\n bytes metadata;\n}\n" + }, + "contracts/structs/JBRedeemParamsData.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\nimport {JBTokenAmount} from './JBTokenAmount.sol';\n\n/// @custom:member terminal The terminal that is facilitating the redemption.\n/// @custom:member holder The holder of the tokens being redeemed.\n/// @custom:member projectId The ID of the project whos tokens are being redeemed.\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the redemption is being made.\n/// @custom:member tokenCount The proposed number of tokens being redeemed, as a fixed point number with 18 decimals.\n/// @custom:member totalSupply The total supply of tokens used in the calculation, as a fixed point number with 18 decimals.\n/// @custom:member overflow The amount of overflow used in the reclaim amount calculation.\n/// @custom:member reclaimAmount The amount that should be reclaimed by the redeemer using the protocol's standard bonding curve redemption formula. Includes the token being reclaimed, the reclaim value, the number of decimals included, and the currency of the reclaim amount.\n/// @custom:member useTotalOverflow If overflow across all of a project's terminals is being used when making redemptions.\n/// @custom:member redemptionRate The redemption rate of the funding cycle during which the redemption is being made.\n/// @custom:member memo The proposed memo that is being emitted alongside the redemption.\n/// @custom:member metadata Extra data provided by the redeemer.\nstruct JBRedeemParamsData {\n IJBPaymentTerminal terminal;\n address holder;\n uint256 projectId;\n uint256 currentFundingCycleConfiguration;\n uint256 tokenCount;\n uint256 totalSupply;\n uint256 overflow;\n JBTokenAmount reclaimAmount;\n bool useTotalOverflow;\n uint256 redemptionRate;\n string memo;\n bytes metadata;\n}\n" + }, + "contracts/structs/JBRedemptionDelegateAllocation.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBRedemptionDelegate} from '../interfaces/IJBRedemptionDelegate.sol';\n\n/// @custom:member delegate A delegate contract to use for subsequent calls.\n/// @custom:member amount The amount to send to the delegate.\nstruct JBRedemptionDelegateAllocation {\n IJBRedemptionDelegate delegate;\n uint256 amount;\n}\n" + }, + "contracts/structs/JBTokenAmount.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @custom:member token The token the payment was made in.\n/// @custom:member value The amount of tokens that was paid, as a fixed point number.\n/// @custom:member decimals The number of decimals included in the value fixed point number.\n/// @custom:member currency The expected currency of the value.\nstruct JBTokenAmount {\n address token;\n uint256 value;\n uint256 decimals;\n uint256 currency;\n}\n" + }, + "contracts/interfaces/IJBPayDelegate.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBDidPayData} from './../structs/JBDidPayData.sol';\n\n/// @title Pay delegate\n/// @notice Delegate called after JBTerminal.pay(..) logic completion (if passed by the funding cycle datasource)\ninterface IJBPayDelegate is IERC165 {\n /// @notice This function is called by JBPaymentTerminal.pay(..), after the execution of its logic\n /// @dev Critical business logic should be protected by an appropriate access control\n /// @param data the data passed by the terminal, as a JBDidPayData struct:\n function didPay(JBDidPayData calldata data) external payable;\n}\n" + }, + "contracts/structs/JBDidPayData.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBTokenAmount} from './JBTokenAmount.sol';\n\n/// @custom:member payer The address from which the payment originated.\n/// @custom:member projectId The ID of the project for which the payment was made.\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the payment is being made.\n/// @custom:member amount The amount of the payment. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\n/// @custom:member forwardedAmount The amount of the payment that is being sent to the delegate. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\n/// @custom:member projectTokenCount The number of project tokens minted for the beneficiary.\n/// @custom:member beneficiary The address to which the tokens were minted.\n/// @custom:member preferClaimedTokens A flag indicating whether the request prefered to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract.\n/// @custom:member memo The memo that is being emitted alongside the payment.\n/// @custom:member metadata Extra data to send to the delegate.\nstruct JBDidPayData {\n address payer;\n uint256 projectId;\n uint256 currentFundingCycleConfiguration;\n JBTokenAmount amount;\n JBTokenAmount forwardedAmount;\n uint256 projectTokenCount;\n address beneficiary;\n bool preferClaimedTokens;\n string memo;\n bytes metadata;\n}\n" + }, + "contracts/interfaces/IJBRedemptionDelegate.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBDidRedeemData} from './../structs/JBDidRedeemData.sol';\n\n/// @title Redemption delegate\n/// @notice Delegate called after JBTerminal.redeemTokensOf(..) logic completion (if passed by the funding cycle datasource)\ninterface IJBRedemptionDelegate is IERC165 {\n /// @notice This function is called by JBPaymentTerminal.redeemTokensOf(..), after the execution of its logic\n /// @dev Critical business logic should be protected by an appropriate access control\n /// @param data the data passed by the terminal, as a JBDidRedeemData struct:\n function didRedeem(JBDidRedeemData calldata data) external payable;\n}\n" + }, + "contracts/structs/JBDidRedeemData.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBTokenAmount} from './JBTokenAmount.sol';\n\n/// @custom:member holder The holder of the tokens being redeemed.\n/// @custom:member projectId The ID of the project with which the redeemed tokens are associated.\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the redemption is being made.\n/// @custom:member projectTokenCount The number of project tokens being redeemed.\n/// @custom:member reclaimedAmount The amount reclaimed from the treasury. Includes the token being reclaimed, the value, the number of decimals included, and the currency of the amount.\n/// @custom:member forwardedAmount The amount of the payment that is being sent to the delegate. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\n/// @custom:member beneficiary The address to which the reclaimed amount will be sent.\n/// @custom:member memo The memo that is being emitted alongside the redemption.\n/// @custom:member metadata Extra data to send to the delegate.\nstruct JBDidRedeemData {\n address holder;\n uint256 projectId;\n uint256 currentFundingCycleConfiguration;\n uint256 projectTokenCount;\n JBTokenAmount reclaimedAmount;\n JBTokenAmount forwardedAmount;\n address payable beneficiary;\n string memo;\n bytes metadata;\n}\n" + }, + "contracts/interfaces/IJBPriceFeed.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBPriceFeed {\n function currentPrice(uint256 targetDecimals) external view returns (uint256);\n}\n" + }, + "contracts/JBSingleTokenPaymentTerminalStore3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {ReentrancyGuard} from '@openzeppelin/contracts/security/ReentrancyGuard.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {JBBallotState} from './enums/JBBallotState.sol';\nimport {IJBController3_1} from './interfaces/IJBController3_1.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBFundingCycleDataSource3_1_1} from './interfaces/IJBFundingCycleDataSource3_1_1.sol';\nimport {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol';\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\nimport {IJBSingleTokenPaymentTerminal} from './interfaces/IJBSingleTokenPaymentTerminal.sol';\nimport {IJBSingleTokenPaymentTerminalStore3_1_1} from './interfaces/IJBSingleTokenPaymentTerminalStore3_1_1.sol';\nimport {JBConstants} from './libraries/JBConstants.sol';\nimport {JBCurrencies} from './libraries/JBCurrencies.sol';\nimport {JBFixedPointNumber} from './libraries/JBFixedPointNumber.sol';\nimport {JBFundingCycleMetadataResolver} from './libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\nimport {JBPayDelegateAllocation3_1_1} from './structs/JBPayDelegateAllocation3_1_1.sol';\nimport {JBPayParamsData} from './structs/JBPayParamsData.sol';\nimport {JBRedeemParamsData} from './structs/JBRedeemParamsData.sol';\nimport {JBRedemptionDelegateAllocation3_1_1} from './structs/JBRedemptionDelegateAllocation3_1_1.sol';\nimport {JBTokenAmount} from './structs/JBTokenAmount.sol';\n\n/// @notice Manages all bookkeeping for inflows and outflows of funds from any ISingleTokenPaymentTerminal.\n/// @dev This Store expects a project's controller to be an IJBController3_1.\ncontract JBSingleTokenPaymentTerminalStore3_1_1 is\n ReentrancyGuard,\n IJBSingleTokenPaymentTerminalStore3_1_1\n{\n // A library that parses the packed funding cycle metadata into a friendlier format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error INVALID_AMOUNT_TO_SEND_DELEGATE();\n error CURRENCY_MISMATCH();\n error DISTRIBUTION_AMOUNT_LIMIT_REACHED();\n error FUNDING_CYCLE_PAYMENT_PAUSED();\n error FUNDING_CYCLE_DISTRIBUTION_PAUSED();\n error FUNDING_CYCLE_REDEEM_PAUSED();\n error INADEQUATE_CONTROLLER_ALLOWANCE();\n error INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n error INSUFFICIENT_TOKENS();\n error INVALID_FUNDING_CYCLE();\n error PAYMENT_TERMINAL_MIGRATION_NOT_ALLOWED();\n\n //*********************************************************************//\n // -------------------------- private constants ---------------------- //\n //*********************************************************************//\n\n /// @notice Ensures a maximum number of decimal points of persisted fidelity on mulDiv operations of fixed point numbers.\n uint256 private constant _MAX_FIXED_POINT_FIDELITY = 18;\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n /// @notice The contract storing all funding cycle configurations.\n IJBFundingCycleStore public immutable override fundingCycleStore;\n\n /// @notice The contract that exposes price feeds.\n IJBPrices public immutable override prices;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The amount of tokens that each project has for each terminal, in terms of the terminal's token.\n /// @dev The balance is represented as a fixed point number with the same amount of decimals as its relative terminal.\n /// @custom:param _terminal The terminal to which the balance applies.\n /// @custom:param _projectId The ID of the project to get the balance of.\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => uint256)) public override balanceOf;\n\n /// @notice The amount of funds that a project has distributed from its limit during the current funding cycle for each terminal, in terms of the distribution limit's currency.\n /// @dev Increases as projects use their preconfigured distribution limits.\n /// @dev The used distribution limit is represented as a fixed point number with the same amount of decimals as its relative terminal.\n /// @custom:param _terminal The terminal to which the used distribution limit applies.\n /// @custom:param _projectId The ID of the project to get the used distribution limit of.\n /// @custom:param _fundingCycleNumber The number of the funding cycle during which the distribution limit was used.\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => mapping(uint256 => uint256)))\n public\n override usedDistributionLimitOf;\n\n /// @notice The amount of funds that a project has used from its allowance during the current funding cycle configuration for each terminal, in terms of the overflow allowance's currency.\n /// @dev Increases as projects use their allowance.\n /// @dev The used allowance is represented as a fixed point number with the same amount of decimals as its relative terminal.\n /// @custom:param _terminal The terminal to which the overflow allowance applies.\n /// @custom:param _projectId The ID of the project to get the used overflow allowance of.\n /// @custom:param _configuration The configuration of the during which the allowance was used.\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => mapping(uint256 => uint256)))\n public\n override usedOverflowAllowanceOf;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Gets the current overflowed amount in a terminal for a specified project.\n /// @dev The current overflow is represented as a fixed point number with the same amount of decimals as the specified terminal.\n /// @param _terminal The terminal for which the overflow is being calculated.\n /// @param _projectId The ID of the project to get overflow for.\n /// @return The current amount of overflow that project has in the specified terminal.\n function currentOverflowOf(\n IJBSingleTokenPaymentTerminal _terminal,\n uint256 _projectId\n ) external view override returns (uint256) {\n // Return the overflow during the project's current funding cycle.\n return\n _overflowDuring(\n _terminal,\n _projectId,\n fundingCycleStore.currentOf(_projectId),\n _terminal.currency()\n );\n }\n\n /// @notice Gets the current overflowed amount for a specified project across all terminals.\n /// @param _projectId The ID of the project to get total overflow for.\n /// @param _decimals The number of decimals that the fixed point overflow should include.\n /// @param _currency The currency that the total overflow should be in terms of.\n /// @return The current total amount of overflow that project has across all terminals.\n function currentTotalOverflowOf(\n uint256 _projectId,\n uint256 _decimals,\n uint256 _currency\n ) external view override returns (uint256) {\n return _currentTotalOverflowOf(_projectId, _decimals, _currency);\n }\n\n /// @notice The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the total token supply and overflow in the ecosystem.\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\n /// @dev The current reclaimable overflow is returned in terms of the specified terminal's currency.\n /// @dev The reclaimable overflow is represented as a fixed point number with the same amount of decimals as the specified terminal.\n /// @param _terminal The terminal from which the reclaimable amount would come.\n /// @param _projectId The ID of the project to get the reclaimable overflow amount for.\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _useTotalOverflow A flag indicating whether the overflow used in the calculation should be summed from all of the project's terminals. If false, overflow should be limited to the amount in the specified `_terminal`.\n /// @return The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_terminal`.\n function currentReclaimableOverflowOf(\n IJBSingleTokenPaymentTerminal _terminal,\n uint256 _projectId,\n uint256 _tokenCount,\n bool _useTotalOverflow\n ) external view override returns (uint256) {\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Get the amount of current overflow.\n // Use the project's total overflow across all of its terminals if the flag species specifies so. Otherwise, use the overflow local to the specified terminal.\n uint256 _currentOverflow = _useTotalOverflow\n ? _currentTotalOverflowOf(_projectId, _terminal.decimals(), _terminal.currency())\n : _overflowDuring(_terminal, _projectId, _fundingCycle, _terminal.currency());\n\n // If there's no overflow, there's no reclaimable overflow.\n if (_currentOverflow == 0) return 0;\n\n // Get the number of outstanding tokens the project has.\n uint256 _totalSupply = IJBController3_1(directory.controllerOf(_projectId))\n .totalOutstandingTokensOf(_projectId);\n\n // Can't redeem more tokens that is in the supply.\n if (_tokenCount > _totalSupply) return 0;\n\n // Return the reclaimable overflow amount.\n return\n _reclaimableOverflowDuring(\n _projectId,\n _fundingCycle,\n _tokenCount,\n _totalSupply,\n _currentOverflow\n );\n }\n\n /// @notice The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the specified total token supply and overflow amounts.\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\n /// @param _projectId The ID of the project to get the reclaimable overflow amount for.\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _totalSupply The total number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _overflow The amount of overflow to make the calculation with, as a fixed point number.\n /// @return The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_overflow`.\n function currentReclaimableOverflowOf(\n uint256 _projectId,\n uint256 _tokenCount,\n uint256 _totalSupply,\n uint256 _overflow\n ) external view override returns (uint256) {\n // If there's no overflow, there's no reclaimable overflow.\n if (_overflow == 0) return 0;\n\n // Can't redeem more tokens that is in the supply.\n if (_tokenCount > _totalSupply) return 0;\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Return the reclaimable overflow amount.\n return\n _reclaimableOverflowDuring(_projectId, _fundingCycle, _tokenCount, _totalSupply, _overflow);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _fundingCycleStore A contract storing all funding cycle configurations.\n /// @param _prices A contract that exposes price feeds.\n constructor(IJBDirectory _directory, IJBFundingCycleStore _fundingCycleStore, IJBPrices _prices) {\n directory = _directory;\n fundingCycleStore = _fundingCycleStore;\n prices = _prices;\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Records newly contributed tokens to a project.\n /// @dev Mints the project's tokens according to values provided by a configured data source. If no data source is configured, mints tokens proportional to the amount of the contribution.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.sender's tokens.\n /// @param _payer The original address that sent the payment to the terminal.\n /// @param _amount The amount of tokens being paid. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\n /// @param _projectId The ID of the project being paid.\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _beneficiary The specified address that should be the beneficiary of anything that results from the payment.\n /// @param _memo A memo to pass along to the emitted event, and passed along to the funding cycle's data source.\n /// @param _metadata Bytes to send along to the data source, if one is provided.\n /// @return fundingCycle The project's funding cycle during which payment was made.\n /// @return tokenCount The number of project tokens that were minted, as a fixed point number with 18 decimals.\n /// @return delegateAllocations The amount to send to delegates instead of adding to the local balance.\n /// @return memo A memo that should be passed along to the emitted event.\n function recordPaymentFrom(\n address _payer,\n JBTokenAmount calldata _amount,\n uint256 _projectId,\n uint256 _baseWeightCurrency,\n address _beneficiary,\n string calldata _memo,\n bytes memory _metadata\n )\n external\n override\n nonReentrant\n returns (\n JBFundingCycle memory fundingCycle,\n uint256 tokenCount,\n JBPayDelegateAllocation3_1_1[] memory delegateAllocations,\n string memory memo\n )\n {\n // Get a reference to the current funding cycle for the project.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // The project must have a funding cycle configured.\n if (fundingCycle.number == 0) revert INVALID_FUNDING_CYCLE();\n\n // Must not be paused.\n if (fundingCycle.payPaused()) revert FUNDING_CYCLE_PAYMENT_PAUSED();\n\n // The weight according to which new token supply is to be minted, as a fixed point number with 18 decimals.\n uint256 _weight;\n\n // If the funding cycle has configured a data source, use it to derive a weight and memo.\n if (fundingCycle.useDataSourceForPay() && fundingCycle.dataSource() != address(0)) {\n // Create the params that'll be sent to the data source.\n JBPayParamsData memory _data = JBPayParamsData(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _payer,\n _amount,\n _projectId,\n fundingCycle.configuration,\n _beneficiary,\n fundingCycle.weight,\n fundingCycle.reservedRate(),\n _memo,\n _metadata\n );\n (_weight, memo, delegateAllocations) = IJBFundingCycleDataSource3_1_1(\n fundingCycle.dataSource()\n ).payParams(_data);\n }\n // Otherwise use the funding cycle's weight\n else {\n _weight = fundingCycle.weight;\n memo = _memo;\n }\n\n // Scoped section prevents stack too deep. `_balanceDiff` only used within scope.\n {\n // Keep a reference to the amount that should be added to the project's balance.\n uint256 _balanceDiff = _amount.value;\n\n // Validate all delegated amounts. This needs to be done before returning the delegate allocations to ensure valid delegated amounts.\n if (delegateAllocations.length != 0) {\n for (uint256 _i; _i < delegateAllocations.length; ) {\n // Get a reference to the amount to be delegated.\n uint256 _delegatedAmount = delegateAllocations[_i].amount;\n\n // Validate if non-zero.\n if (_delegatedAmount != 0) {\n // Can't delegate more than was paid.\n if (_delegatedAmount > _balanceDiff) revert INVALID_AMOUNT_TO_SEND_DELEGATE();\n\n // Decrement the total amount being added to the balance.\n _balanceDiff = _balanceDiff - _delegatedAmount;\n }\n\n unchecked {\n ++_i;\n }\n }\n }\n\n // If there's no amount being recorded, there's nothing left to do.\n if (_amount.value == 0) return (fundingCycle, 0, delegateAllocations, memo);\n\n // Add the correct balance difference to the token balance of the project.\n if (_balanceDiff != 0)\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] +\n _balanceDiff;\n }\n\n // If there's no weight, token count must be 0 so there's nothing left to do.\n if (_weight == 0) return (fundingCycle, 0, delegateAllocations, memo);\n\n // Get a reference to the number of decimals in the amount. (prevents stack too deep).\n uint256 _decimals = _amount.decimals;\n\n // If the terminal should base its weight on a different currency from the terminal's currency, determine the factor.\n // The weight is always a fixed point mumber with 18 decimals. To ensure this, the ratio should use the same number of decimals as the `_amount`.\n uint256 _weightRatio = _amount.currency == _baseWeightCurrency\n ? 10 ** _decimals\n : prices.priceFor(_amount.currency, _baseWeightCurrency, _decimals);\n\n // Find the number of tokens to mint, as a fixed point number with as many decimals as `weight` has.\n tokenCount = PRBMath.mulDiv(_amount.value, _weight, _weightRatio);\n }\n\n /// @notice Records newly redeemed tokens of a project.\n /// @dev Redeems the project's tokens according to values provided by a configured data source. If no data source is configured, redeems tokens along a redemption bonding curve that is a function of the number of tokens being burned.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.senders tokens.\n /// @param _holder The account that is having its tokens redeemed.\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\n /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the data source, if one is provided.\n /// @return fundingCycle The funding cycle during which the redemption was made.\n /// @return reclaimAmount The amount of terminal tokens reclaimed, as a fixed point number with 18 decimals.\n /// @return delegateAllocations The amount to send to delegates instead of sending to the beneficiary.\n /// @return memo A memo that should be passed along to the emitted event.\n function recordRedemptionFor(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n string memory _memo,\n bytes memory _metadata\n )\n external\n override\n nonReentrant\n returns (\n JBFundingCycle memory fundingCycle,\n uint256 reclaimAmount,\n JBRedemptionDelegateAllocation3_1_1[] memory delegateAllocations,\n string memory memo\n )\n {\n // Get a reference to the project's current funding cycle.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // The current funding cycle must not be paused.\n if (fundingCycle.redeemPaused()) revert FUNDING_CYCLE_REDEEM_PAUSED();\n\n // Scoped section prevents stack too deep. `_reclaimedTokenAmount`, `_currentOverflow`, and `_totalSupply` only used within scope.\n {\n // Get a reference to the reclaimed token amount struct, the current overflow, and the total token supply.\n JBTokenAmount memory _reclaimedTokenAmount;\n uint256 _currentOverflow;\n uint256 _totalSupply;\n\n // Another scoped section prevents stack too deep. `_token`, `_decimals`, and `_currency` only used within scope.\n {\n // Get a reference to the terminal's tokens.\n address _token = IJBSingleTokenPaymentTerminal(msg.sender).token();\n\n // Get a reference to the terminal's decimals.\n uint256 _decimals = IJBSingleTokenPaymentTerminal(msg.sender).decimals();\n\n // Get areference to the terminal's currency.\n uint256 _currency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\n\n // Get the amount of current overflow.\n // Use the local overflow if the funding cycle specifies that it should be used. Otherwise, use the project's total overflow across all of its terminals.\n _currentOverflow = fundingCycle.useTotalOverflowForRedemptions()\n ? _currentTotalOverflowOf(_projectId, _decimals, _currency)\n : _overflowDuring(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _projectId,\n fundingCycle,\n _currency\n );\n\n // Get the number of outstanding tokens the project has.\n _totalSupply = IJBController3_1(directory.controllerOf(_projectId))\n .totalOutstandingTokensOf(_projectId);\n\n // Can't redeem more tokens that is in the supply.\n if (_tokenCount > _totalSupply) revert INSUFFICIENT_TOKENS();\n\n if (_currentOverflow != 0)\n // Calculate reclaim amount using the current overflow amount.\n reclaimAmount = _reclaimableOverflowDuring(\n _projectId,\n fundingCycle,\n _tokenCount,\n _totalSupply,\n _currentOverflow\n );\n\n _reclaimedTokenAmount = JBTokenAmount(_token, reclaimAmount, _decimals, _currency);\n }\n\n // If the funding cycle has configured a data source, use it to derive a claim amount and memo.\n if (fundingCycle.useDataSourceForRedeem() && fundingCycle.dataSource() != address(0)) {\n // Yet another scoped section prevents stack too deep. `_state` only used within scope.\n {\n // Get a reference to the ballot state.\n JBBallotState _state = fundingCycleStore.currentBallotStateOf(_projectId);\n\n // Create the params that'll be sent to the data source.\n JBRedeemParamsData memory _data = JBRedeemParamsData(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _holder,\n _projectId,\n fundingCycle.configuration,\n _tokenCount,\n _totalSupply,\n _currentOverflow,\n _reclaimedTokenAmount,\n fundingCycle.useTotalOverflowForRedemptions(),\n _state == JBBallotState.Active\n ? fundingCycle.ballotRedemptionRate()\n : fundingCycle.redemptionRate(),\n _memo,\n _metadata\n );\n (reclaimAmount, memo, delegateAllocations) = IJBFundingCycleDataSource3_1_1(\n fundingCycle.dataSource()\n ).redeemParams(_data);\n }\n } else {\n memo = _memo;\n }\n }\n\n // Keep a reference to the amount that should be subtracted from the project's balance.\n uint256 _balanceDiff = reclaimAmount;\n\n if (delegateAllocations.length != 0) {\n // Validate all delegated amounts.\n for (uint256 _i; _i < delegateAllocations.length; ) {\n // Get a reference to the amount to be delegated.\n uint256 _delegatedAmount = delegateAllocations[_i].amount;\n\n // Validate if non-zero.\n if (_delegatedAmount != 0)\n // Increment the total amount being subtracted from the balance.\n _balanceDiff = _balanceDiff + _delegatedAmount;\n\n unchecked {\n ++_i;\n }\n }\n }\n\n // The amount being reclaimed must be within the project's balance.\n if (_balanceDiff > balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId])\n revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n\n // Remove the reclaimed funds from the project's balance.\n if (_balanceDiff != 0) {\n unchecked {\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\n _balanceDiff;\n }\n }\n }\n\n /// @notice Records newly distributed funds for a project.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\n /// @param _projectId The ID of the project that is having funds distributed.\n /// @param _amount The amount to use from the distribution limit, as a fixed point number.\n /// @param _currency The currency of the `_amount`. This must match the project's current funding cycle's currency.\n /// @return fundingCycle The funding cycle during which the distribution was made.\n /// @return distributedAmount The amount of terminal tokens distributed, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordDistributionFor(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency\n )\n external\n override\n nonReentrant\n returns (JBFundingCycle memory fundingCycle, uint256 distributedAmount)\n {\n // Get a reference to the project's current funding cycle.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // The funding cycle must not be configured to have distributions paused.\n if (fundingCycle.distributionsPaused()) revert FUNDING_CYCLE_DISTRIBUTION_PAUSED();\n\n // The new total amount that has been distributed during this funding cycle.\n uint256 _newUsedDistributionLimitOf = usedDistributionLimitOf[\n IJBSingleTokenPaymentTerminal(msg.sender)\n ][_projectId][fundingCycle.number] + _amount;\n\n // Amount must be within what is still distributable.\n (uint256 _distributionLimitOf, uint256 _distributionLimitCurrencyOf) = IJBController3_1(\n directory.controllerOf(_projectId)\n ).fundAccessConstraintsStore().distributionLimitOf(\n _projectId,\n fundingCycle.configuration,\n IJBSingleTokenPaymentTerminal(msg.sender),\n IJBSingleTokenPaymentTerminal(msg.sender).token()\n );\n\n // Make sure the new used amount is within the distribution limit.\n if (_newUsedDistributionLimitOf > _distributionLimitOf || _distributionLimitOf == 0)\n revert DISTRIBUTION_AMOUNT_LIMIT_REACHED();\n\n // Make sure the currencies match.\n if (_currency != _distributionLimitCurrencyOf) revert CURRENCY_MISMATCH();\n\n // Get a reference to the terminal's currency.\n uint256 _balanceCurrency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\n\n // Convert the amount to the balance's currency.\n distributedAmount = (_currency == _balanceCurrency)\n ? _amount\n : PRBMath.mulDiv(\n _amount,\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\n prices.priceFor(_currency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\n );\n\n // The amount being distributed must be available.\n if (distributedAmount > balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId])\n revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n\n // Store the new amount.\n usedDistributionLimitOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId][\n fundingCycle.number\n ] = _newUsedDistributionLimitOf;\n\n // Removed the distributed funds from the project's token balance.\n unchecked {\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\n distributedAmount;\n }\n }\n\n /// @notice Records newly used allowance funds of a project.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\n /// @param _projectId The ID of the project to use the allowance of.\n /// @param _amount The amount to use from the allowance, as a fixed point number.\n /// @param _currency The currency of the `_amount`. Must match the currency of the overflow allowance.\n /// @return fundingCycle The funding cycle during which the overflow allowance is being used.\n /// @return usedAmount The amount of terminal tokens used, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordUsedAllowanceOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency\n )\n external\n override\n nonReentrant\n returns (JBFundingCycle memory fundingCycle, uint256 usedAmount)\n {\n // Get a reference to the project's current funding cycle.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Get a reference to the new used overflow allowance for this funding cycle configuration.\n uint256 _newUsedOverflowAllowanceOf = usedOverflowAllowanceOf[\n IJBSingleTokenPaymentTerminal(msg.sender)\n ][_projectId][fundingCycle.configuration] + _amount;\n\n // There must be sufficient allowance available.\n (uint256 _overflowAllowanceOf, uint256 _overflowAllowanceCurrency) = IJBController3_1(\n directory.controllerOf(_projectId)\n ).fundAccessConstraintsStore().overflowAllowanceOf(\n _projectId,\n fundingCycle.configuration,\n IJBSingleTokenPaymentTerminal(msg.sender),\n IJBSingleTokenPaymentTerminal(msg.sender).token()\n );\n\n // Make sure the new used amount is within the allowance.\n if (_newUsedOverflowAllowanceOf > _overflowAllowanceOf || _overflowAllowanceOf == 0)\n revert INADEQUATE_CONTROLLER_ALLOWANCE();\n\n // Make sure the currencies match.\n if (_currency != _overflowAllowanceCurrency) revert CURRENCY_MISMATCH();\n\n // Get a reference to the terminal's currency.\n uint256 _balanceCurrency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\n\n // Convert the amount to this store's terminal's token.\n usedAmount = (_currency == _balanceCurrency)\n ? _amount\n : PRBMath.mulDiv(\n _amount,\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\n prices.priceFor(_currency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\n );\n\n // The amount being distributed must be available in the overflow.\n if (\n usedAmount >\n _overflowDuring(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _projectId,\n fundingCycle,\n _balanceCurrency\n )\n ) revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n\n // Store the incremented value.\n usedOverflowAllowanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId][\n fundingCycle.configuration\n ] = _newUsedOverflowAllowanceOf;\n\n // Update the project's balance.\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\n usedAmount;\n }\n\n /// @notice Records newly added funds for the project.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\n /// @param _projectId The ID of the project to which the funds being added belong.\n /// @param _amount The amount of terminal tokens added, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordAddedBalanceFor(uint256 _projectId, uint256 _amount) external override {\n // Increment the balance.\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] +\n _amount;\n }\n\n /// @notice Records the migration of funds from this store.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount returned is in terms of the msg.senders tokens.\n /// @param _projectId The ID of the project being migrated.\n /// @return balance The project's migrated balance, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordMigration(\n uint256 _projectId\n ) external override nonReentrant returns (uint256 balance) {\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Migration must be allowed.\n if (!_fundingCycle.terminalMigrationAllowed()) revert PAYMENT_TERMINAL_MIGRATION_NOT_ALLOWED();\n\n // Return the current balance.\n balance = balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId];\n\n // Set the balance to 0.\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] = 0;\n }\n\n //*********************************************************************//\n // --------------------- private helper functions -------------------- //\n //*********************************************************************//\n\n /// @notice The amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens when measured from the specified.\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\n /// @param _projectId The ID of the project to get the reclaimable overflow amount for.\n /// @param _fundingCycle The funding cycle during which reclaimable overflow is being calculated.\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _totalSupply The total supply of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _overflow The amount of overflow to make the calculation with.\n /// @return The amount of overflowed tokens that can be reclaimed.\n function _reclaimableOverflowDuring(\n uint256 _projectId,\n JBFundingCycle memory _fundingCycle,\n uint256 _tokenCount,\n uint256 _totalSupply,\n uint256 _overflow\n ) private view returns (uint256) {\n // If the amount being redeemed is the total supply, return the rest of the overflow.\n if (_tokenCount == _totalSupply) return _overflow;\n\n // Use the ballot redemption rate if the queued cycle is pending approval according to the previous funding cycle's ballot.\n uint256 _redemptionRate = fundingCycleStore.currentBallotStateOf(_projectId) ==\n JBBallotState.Active\n ? _fundingCycle.ballotRedemptionRate()\n : _fundingCycle.redemptionRate();\n\n // If the redemption rate is 0, nothing is claimable.\n if (_redemptionRate == 0) return 0;\n\n // Get a reference to the linear proportion.\n uint256 _base = PRBMath.mulDiv(_overflow, _tokenCount, _totalSupply);\n\n // These conditions are all part of the same curve. Edge conditions are separated because fewer operation are necessary.\n if (_redemptionRate == JBConstants.MAX_REDEMPTION_RATE) return _base;\n\n return\n PRBMath.mulDiv(\n _base,\n _redemptionRate +\n PRBMath.mulDiv(\n _tokenCount,\n JBConstants.MAX_REDEMPTION_RATE - _redemptionRate,\n _totalSupply\n ),\n JBConstants.MAX_REDEMPTION_RATE\n );\n }\n\n /// @notice Gets the amount that is overflowing when measured from the specified funding cycle.\n /// @dev This amount changes as the value of the balance changes in relation to the currency being used to measure the distribution limit.\n /// @param _terminal The terminal for which the overflow is being calculated.\n /// @param _projectId The ID of the project to get overflow for.\n /// @param _fundingCycle The ID of the funding cycle to base the overflow on.\n /// @param _balanceCurrency The currency that the stored balance is expected to be in terms of.\n /// @return overflow The overflow of funds, as a fixed point number with 18 decimals.\n function _overflowDuring(\n IJBSingleTokenPaymentTerminal _terminal,\n uint256 _projectId,\n JBFundingCycle memory _fundingCycle,\n uint256 _balanceCurrency\n ) private view returns (uint256) {\n // Get the current balance of the project.\n uint256 _balanceOf = balanceOf[_terminal][_projectId];\n\n // If there's no balance, there's no overflow.\n if (_balanceOf == 0) return 0;\n\n // Get a reference to the distribution limit during the funding cycle.\n (uint256 _distributionLimit, uint256 _distributionLimitCurrency) = IJBController3_1(\n directory.controllerOf(_projectId)\n ).fundAccessConstraintsStore().distributionLimitOf(\n _projectId,\n _fundingCycle.configuration,\n _terminal,\n _terminal.token()\n );\n\n // Get a reference to the amount still distributable during the funding cycle.\n uint256 _distributionLimitRemaining = _distributionLimit -\n usedDistributionLimitOf[_terminal][_projectId][_fundingCycle.number];\n\n // Convert the _distributionRemaining to be in terms of the provided currency.\n if (_distributionLimitRemaining != 0 && _distributionLimitCurrency != _balanceCurrency)\n _distributionLimitRemaining = PRBMath.mulDiv(\n _distributionLimitRemaining,\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\n prices.priceFor(_distributionLimitCurrency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\n );\n\n // Overflow is the balance of this project minus the amount that can still be distributed.\n unchecked {\n return\n _balanceOf > _distributionLimitRemaining ? _balanceOf - _distributionLimitRemaining : 0;\n }\n }\n\n /// @notice Gets the amount that is currently overflowing across all of a project's terminals.\n /// @dev This amount changes as the value of the balances changes in relation to the currency being used to measure the project's distribution limits.\n /// @param _projectId The ID of the project to get the total overflow for.\n /// @param _decimals The number of decimals that the fixed point overflow should include.\n /// @param _currency The currency that the overflow should be in terms of.\n /// @return overflow The total overflow of a project's funds.\n function _currentTotalOverflowOf(\n uint256 _projectId,\n uint256 _decimals,\n uint256 _currency\n ) private view returns (uint256) {\n // Get a reference to the project's terminals.\n IJBPaymentTerminal[] memory _terminals = directory.terminalsOf(_projectId);\n\n // Keep a reference to the ETH overflow across all terminals, as a fixed point number with 18 decimals.\n uint256 _ethOverflow;\n\n // Add the current ETH overflow for each terminal.\n for (uint256 _i; _i < _terminals.length; ) {\n _ethOverflow = _ethOverflow + _terminals[_i].currentEthOverflowOf(_projectId);\n unchecked {\n ++_i;\n }\n }\n\n // Convert the ETH overflow to the specified currency if needed, maintaining a fixed point number with 18 decimals.\n uint256 _totalOverflow18Decimal = _currency == JBCurrencies.ETH\n ? _ethOverflow\n : PRBMath.mulDiv(_ethOverflow, 10 ** 18, prices.priceFor(JBCurrencies.ETH, _currency, 18));\n\n // Adjust the decimals of the fixed point number if needed to match the target decimals.\n return\n (_decimals == 18)\n ? _totalOverflow18Decimal\n : JBFixedPointNumber.adjustDecimals(_totalOverflow18Decimal, 18, _decimals);\n }\n}\n" + }, + "contracts/interfaces/IJBFundingCycleDataSource3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBPayDelegateAllocation3_1_1} from './../structs/JBPayDelegateAllocation3_1_1.sol';\nimport {JBPayParamsData} from './../structs/JBPayParamsData.sol';\nimport {JBRedeemParamsData} from './../structs/JBRedeemParamsData.sol';\nimport {JBRedemptionDelegateAllocation3_1_1} from './../structs/JBRedemptionDelegateAllocation3_1_1.sol';\n\n/// @title Datasource\n/// @notice The datasource is called by JBPayoutRedemptionPaymentTerminals on pay and redemption, and provide an extra layer of logic to use a custom weight, a custom memo and/or a pay/redeem delegate\ninterface IJBFundingCycleDataSource3_1_1 is IERC165 {\n /// @notice The datasource implementation for JBPaymentTerminal.pay(..)\n /// @param data the data passed to the data source in terminal.pay(..), as a JBPayParamsData struct:\n /// @return weight the weight to use to override the funding cycle weight\n /// @return memo the memo to override the pay(..) memo\n /// @return delegateAllocations The amount to send to delegates instead of adding to the local balance.\n function payParams(\n JBPayParamsData calldata data\n )\n external\n returns (\n uint256 weight,\n string memory memo,\n JBPayDelegateAllocation3_1_1[] memory delegateAllocations\n );\n\n /// @notice The datasource implementation for JBPaymentTerminal.redeemTokensOf(..)\n /// @param data the data passed to the data source in terminal.redeemTokensOf(..), as a JBRedeemParamsData struct:\n /// @return reclaimAmount The amount to claim, overriding the terminal logic.\n /// @return memo The memo to override the redeemTokensOf(..) memo.\n /// @return delegateAllocations The amount to send to delegates instead of adding to the beneficiary.\n function redeemParams(\n JBRedeemParamsData calldata data\n )\n external\n returns (\n uint256 reclaimAmount,\n string memory memo,\n JBRedemptionDelegateAllocation3_1_1[] memory delegateAllocations\n );\n}\n" + }, + "contracts/interfaces/IJBSingleTokenPaymentTerminalStore3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\nimport {JBPayDelegateAllocation3_1_1} from './../structs/JBPayDelegateAllocation3_1_1.sol';\nimport {JBRedemptionDelegateAllocation3_1_1} from './../structs/JBRedemptionDelegateAllocation3_1_1.sol';\nimport {JBTokenAmount} from './../structs/JBTokenAmount.sol';\nimport {IJBDirectory} from './IJBDirectory.sol';\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\nimport {IJBPrices} from './IJBPrices.sol';\nimport {IJBSingleTokenPaymentTerminal} from './IJBSingleTokenPaymentTerminal.sol';\n\ninterface IJBSingleTokenPaymentTerminalStore3_1_1 {\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\n\n function directory() external view returns (IJBDirectory);\n\n function prices() external view returns (IJBPrices);\n\n function balanceOf(\n IJBSingleTokenPaymentTerminal terminal,\n uint256 projectId\n ) external view returns (uint256);\n\n function usedDistributionLimitOf(\n IJBSingleTokenPaymentTerminal terminal,\n uint256 projectId,\n uint256 fundingCycleNumber\n ) external view returns (uint256);\n\n function usedOverflowAllowanceOf(\n IJBSingleTokenPaymentTerminal terminal,\n uint256 projectId,\n uint256 fundingCycleConfiguration\n ) external view returns (uint256);\n\n function currentOverflowOf(\n IJBSingleTokenPaymentTerminal terminal,\n uint256 projectId\n ) external view returns (uint256);\n\n function currentTotalOverflowOf(\n uint256 projectId,\n uint256 decimals,\n uint256 currency\n ) external view returns (uint256);\n\n function currentReclaimableOverflowOf(\n IJBSingleTokenPaymentTerminal terminal,\n uint256 projectId,\n uint256 tokenCount,\n bool useTotalOverflow\n ) external view returns (uint256);\n\n function currentReclaimableOverflowOf(\n uint256 projectId,\n uint256 tokenCount,\n uint256 totalSupply,\n uint256 overflow\n ) external view returns (uint256);\n\n function recordPaymentFrom(\n address payer,\n JBTokenAmount memory amount,\n uint256 projectId,\n uint256 baseWeightCurrency,\n address beneficiary,\n string calldata inputMemo,\n bytes calldata metadata\n )\n external\n returns (\n JBFundingCycle memory fundingCycle,\n uint256 tokenCount,\n JBPayDelegateAllocation3_1_1[] memory delegateAllocations,\n string memory outputMemo\n );\n\n function recordRedemptionFor(\n address holder,\n uint256 projectId,\n uint256 tokenCount,\n string calldata inputMemo,\n bytes calldata metadata\n )\n external\n returns (\n JBFundingCycle memory fundingCycle,\n uint256 reclaimAmount,\n JBRedemptionDelegateAllocation3_1_1[] memory delegateAllocations,\n string memory outputMemo\n );\n\n function recordDistributionFor(\n uint256 projectId,\n uint256 amount,\n uint256 currency\n ) external returns (JBFundingCycle memory fundingCycle, uint256 distributedAmount);\n\n function recordUsedAllowanceOf(\n uint256 projectId,\n uint256 amount,\n uint256 currency\n ) external returns (JBFundingCycle memory fundingCycle, uint256 withdrawnAmount);\n\n function recordAddedBalanceFor(uint256 projectId, uint256 amount) external;\n\n function recordMigration(uint256 projectId) external returns (uint256 balance);\n}\n" + }, + "contracts/structs/JBPayDelegateAllocation3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBPayDelegate3_1_1} from '../interfaces/IJBPayDelegate3_1_1.sol';\n\n/// @custom:member delegate A delegate contract to use for subsequent calls.\n/// @custom:member amount The amount to send to the delegate.\n/// @custom:member metadata Metadata to pass the delegate.\nstruct JBPayDelegateAllocation3_1_1 {\n IJBPayDelegate3_1_1 delegate;\n uint256 amount;\n bytes metadata;\n}\n" + }, + "contracts/structs/JBRedemptionDelegateAllocation3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBRedemptionDelegate3_1_1} from '../interfaces/IJBRedemptionDelegate3_1_1.sol';\n\n/// @custom:member delegate A delegate contract to use for subsequent calls.\n/// @custom:member amount The amount to send to the delegate.\n/// @custom:member metadata Metadata to pass the delegate.\nstruct JBRedemptionDelegateAllocation3_1_1 {\n IJBRedemptionDelegate3_1_1 delegate;\n uint256 amount;\n bytes metadata;\n}\n" + }, + "contracts/interfaces/IJBPayDelegate3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBDidPayData3_1_1} from './../structs/JBDidPayData3_1_1.sol';\n\n/// @title Pay delegate\n/// @notice Delegate called after JBTerminal.pay(..) logic completion (if passed by the funding cycle datasource)\ninterface IJBPayDelegate3_1_1 is IERC165 {\n /// @notice This function is called by JBPaymentTerminal.pay(..), after the execution of its logic\n /// @dev Critical business logic should be protected by an appropriate access control\n /// @param data the data passed by the terminal, as a JBDidPayData3_1_1 struct:\n function didPay(JBDidPayData3_1_1 calldata data) external payable;\n}\n" + }, + "contracts/structs/JBDidPayData3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBTokenAmount} from './JBTokenAmount.sol';\n\n/// @custom:member payer The address from which the payment originated.\n/// @custom:member projectId The ID of the project for which the payment was made.\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the payment is being made.\n/// @custom:member amount The amount of the payment. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\n/// @custom:member forwardedAmount The amount of the payment that is being sent to the delegate. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\n/// @custom:member projectTokenCount The number of project tokens minted for the beneficiary.\n/// @custom:member beneficiary The address to which the tokens were minted.\n/// @custom:member preferClaimedTokens A flag indicating whether the request prefered to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract.\n/// @custom:member memo The memo that is being emitted alongside the payment.\n/// @custom:member dataSourceMetadata Extra data to send to the delegate sent by the data source.\n/// @custom:member payerMetadata Extra data to send to the delegate sent by the payer.\nstruct JBDidPayData3_1_1 {\n address payer;\n uint256 projectId;\n uint256 currentFundingCycleConfiguration;\n JBTokenAmount amount;\n JBTokenAmount forwardedAmount;\n uint256 projectTokenCount;\n address beneficiary;\n bool preferClaimedTokens;\n string memo;\n bytes dataSourceMetadata;\n bytes payerMetadata;\n}\n" + }, + "contracts/interfaces/IJBRedemptionDelegate3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBDidRedeemData3_1_1} from './../structs/JBDidRedeemData3_1_1.sol';\n\n/// @title Redemption delegate\n/// @notice Delegate called after JBTerminal.redeemTokensOf(..) logic completion (if passed by the funding cycle datasource)\ninterface IJBRedemptionDelegate3_1_1 is IERC165 {\n /// @notice This function is called by JBPaymentTerminal.redeemTokensOf(..), after the execution of its logic\n /// @dev Critical business logic should be protected by an appropriate access control\n /// @param data the data passed by the terminal, as a JBDidRedeemData struct:\n function didRedeem(JBDidRedeemData3_1_1 calldata data) external payable;\n}\n" + }, + "contracts/structs/JBDidRedeemData3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBTokenAmount} from './JBTokenAmount.sol';\n\n/// @custom:member holder The holder of the tokens being redeemed.\n/// @custom:member projectId The ID of the project with which the redeemed tokens are associated.\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the redemption is being made.\n/// @custom:member projectTokenCount The number of project tokens being redeemed.\n/// @custom:member reclaimedAmount The amount reclaimed from the treasury. Includes the token being reclaimed, the value, the number of decimals included, and the currency of the amount.\n/// @custom:member forwardedAmount The amount of the payment that is being sent to the delegate. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\n/// @custom:member beneficiary The address to which the reclaimed amount will be sent.\n/// @custom:member memo The memo that is being emitted alongside the redemption.\n/// @custom:member dataSourceMetadata Extra data to send to the delegate sent by the data source.\n/// @custom:member redeemerMetadata Extra data to send to the delegate sent by the redeemer.\nstruct JBDidRedeemData3_1_1 {\n address holder;\n uint256 projectId;\n uint256 currentFundingCycleConfiguration;\n uint256 projectTokenCount;\n JBTokenAmount reclaimedAmount;\n JBTokenAmount forwardedAmount;\n address payable beneficiary;\n string memo;\n bytes dataSourceMetadata;\n bytes redeemerMetadata;\n}\n" + }, + "contracts/JBSingleTokenPaymentTerminalStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {ReentrancyGuard} from '@openzeppelin/contracts/security/ReentrancyGuard.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {JBBallotState} from './enums/JBBallotState.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBController} from './interfaces/IJBController.sol';\nimport {IJBFundingCycleDataSource} from './interfaces/IJBFundingCycleDataSource.sol';\nimport {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol';\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\nimport {IJBSingleTokenPaymentTerminal} from './interfaces/IJBSingleTokenPaymentTerminal.sol';\nimport {IJBSingleTokenPaymentTerminalStore} from './interfaces/IJBSingleTokenPaymentTerminalStore.sol';\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\nimport {JBConstants} from './libraries/JBConstants.sol';\nimport {JBCurrencies} from './libraries/JBCurrencies.sol';\nimport {JBFixedPointNumber} from './libraries/JBFixedPointNumber.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\nimport {JBFundingCycleMetadataResolver} from './libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBPayDelegateAllocation} from './structs/JBPayDelegateAllocation.sol';\nimport {JBPayParamsData} from './structs/JBPayParamsData.sol';\nimport {JBRedeemParamsData} from './structs/JBRedeemParamsData.sol';\nimport {JBRedemptionDelegateAllocation} from './structs/JBRedemptionDelegateAllocation.sol';\nimport {JBTokenAmount} from './structs/JBTokenAmount.sol';\n\n/// @notice Manages all bookkeeping for inflows and outflows of funds from any ISingleTokenPaymentTerminal.\ncontract JBSingleTokenPaymentTerminalStore is ReentrancyGuard, IJBSingleTokenPaymentTerminalStore {\n // A library that parses the packed funding cycle metadata into a friendlier format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error INVALID_AMOUNT_TO_SEND_DELEGATE();\n error CURRENCY_MISMATCH();\n error DISTRIBUTION_AMOUNT_LIMIT_REACHED();\n error FUNDING_CYCLE_PAYMENT_PAUSED();\n error FUNDING_CYCLE_DISTRIBUTION_PAUSED();\n error FUNDING_CYCLE_REDEEM_PAUSED();\n error INADEQUATE_CONTROLLER_ALLOWANCE();\n error INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n error INSUFFICIENT_TOKENS();\n error INVALID_FUNDING_CYCLE();\n error PAYMENT_TERMINAL_MIGRATION_NOT_ALLOWED();\n\n //*********************************************************************//\n // -------------------------- private constants ---------------------- //\n //*********************************************************************//\n\n /// @notice Ensures a maximum number of decimal points of persisted fidelity on mulDiv operations of fixed point numbers.\n uint256 private constant _MAX_FIXED_POINT_FIDELITY = 18;\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n /// @notice The contract storing all funding cycle configurations.\n IJBFundingCycleStore public immutable override fundingCycleStore;\n\n /// @notice The contract that exposes price feeds.\n IJBPrices public immutable override prices;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The amount of tokens that each project has for each terminal, in terms of the terminal's token.\n /// @dev The used distribution limit is represented as a fixed point number with the same amount of decimals as its relative terminal.\n /// @custom:param _terminal The terminal to which the balance applies.\n /// @custom:param _projectId The ID of the project to get the balance of.\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => uint256)) public override balanceOf;\n\n /// @notice The amount of funds that a project has distributed from its limit during the current funding cycle for each terminal, in terms of the distribution limit's currency.\n /// @dev Increases as projects use their preconfigured distribution limits.\n /// @dev The used distribution limit is represented as a fixed point number with the same amount of decimals as its relative terminal.\n /// @custom:param _terminal The terminal to which the used distribution limit applies.\n /// @custom:param _projectId The ID of the project to get the used distribution limit of.\n /// @custom:param _fundingCycleNumber The number of the funding cycle during which the distribution limit was used.\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => mapping(uint256 => uint256)))\n public\n override usedDistributionLimitOf;\n\n /// @notice The amount of funds that a project has used from its allowance during the current funding cycle configuration for each terminal, in terms of the overflow allowance's currency.\n /// @dev Increases as projects use their allowance.\n /// @dev The used allowance is represented as a fixed point number with the same amount of decimals as its relative terminal.\n /// @custom:param _terminal The terminal to which the overflow allowance applies.\n /// @custom:param _projectId The ID of the project to get the used overflow allowance of.\n /// @custom:param _configuration The configuration of the during which the allowance was used.\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => mapping(uint256 => uint256)))\n public\n override usedOverflowAllowanceOf;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Gets the current overflowed amount in a terminal for a specified project.\n /// @dev The current overflow is represented as a fixed point number with the same amount of decimals as the specified terminal.\n /// @param _terminal The terminal for which the overflow is being calculated.\n /// @param _projectId The ID of the project to get overflow for.\n /// @return The current amount of overflow that project has in the specified terminal.\n function currentOverflowOf(\n IJBSingleTokenPaymentTerminal _terminal,\n uint256 _projectId\n ) external view override returns (uint256) {\n // Return the overflow during the project's current funding cycle.\n return\n _overflowDuring(\n _terminal,\n _projectId,\n fundingCycleStore.currentOf(_projectId),\n _terminal.currency()\n );\n }\n\n /// @notice Gets the current overflowed amount for a specified project across all terminals.\n /// @param _projectId The ID of the project to get total overflow for.\n /// @param _decimals The number of decimals that the fixed point overflow should include.\n /// @param _currency The currency that the total overflow should be in terms of.\n /// @return The current total amount of overflow that project has across all terminals.\n function currentTotalOverflowOf(\n uint256 _projectId,\n uint256 _decimals,\n uint256 _currency\n ) external view override returns (uint256) {\n return _currentTotalOverflowOf(_projectId, _decimals, _currency);\n }\n\n /// @notice The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the total token supply and overflow in the ecosystem.\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\n /// @dev The current reclaimable overflow is returned in terms of the specified terminal's currency.\n /// @dev The reclaimable overflow is represented as a fixed point number with the same amount of decimals as the specified terminal.\n /// @param _terminal The terminal from which the reclaimable amount would come.\n /// @param _projectId The ID of the project to get the reclaimable overflow amount for.\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _useTotalOverflow A flag indicating whether the overflow used in the calculation should be summed from all of the project's terminals. If false, overflow should be limited to the amount in the specified `_terminal`.\n /// @return The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_terminal`.\n function currentReclaimableOverflowOf(\n IJBSingleTokenPaymentTerminal _terminal,\n uint256 _projectId,\n uint256 _tokenCount,\n bool _useTotalOverflow\n ) external view override returns (uint256) {\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Get the amount of current overflow.\n // Use the project's total overflow across all of its terminals if the flag species specifies so. Otherwise, use the overflow local to the specified terminal.\n uint256 _currentOverflow = _useTotalOverflow\n ? _currentTotalOverflowOf(_projectId, _terminal.decimals(), _terminal.currency())\n : _overflowDuring(_terminal, _projectId, _fundingCycle, _terminal.currency());\n\n // If there's no overflow, there's no reclaimable overflow.\n if (_currentOverflow == 0) return 0;\n\n // Get the number of outstanding tokens the project has.\n uint256 _totalSupply = IJBController(directory.controllerOf(_projectId))\n .totalOutstandingTokensOf(_projectId, _fundingCycle.reservedRate());\n\n // Can't redeem more tokens that is in the supply.\n if (_tokenCount > _totalSupply) return 0;\n\n // Return the reclaimable overflow amount.\n return\n _reclaimableOverflowDuring(\n _projectId,\n _fundingCycle,\n _tokenCount,\n _totalSupply,\n _currentOverflow\n );\n }\n\n /// @notice The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the specified total token supply and overflow amounts.\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\n /// @param _projectId The ID of the project for which the reclaimable overflow applies.\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _totalSupply The total number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _overflow The amount of overflow to make the calculation with, as a fixed point number.\n /// @return The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_overflow`.\n function currentReclaimableOverflowOf(\n uint256 _projectId,\n uint256 _tokenCount,\n uint256 _totalSupply,\n uint256 _overflow\n ) external view override returns (uint256) {\n // If there's no overflow, there's no reclaimable overflow.\n if (_overflow == 0) return 0;\n\n // Can't redeem more tokens that is in the supply.\n if (_tokenCount > _totalSupply) return 0;\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Return the reclaimable overflow amount.\n return\n _reclaimableOverflowDuring(_projectId, _fundingCycle, _tokenCount, _totalSupply, _overflow);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _fundingCycleStore A contract storing all funding cycle configurations.\n /// @param _prices A contract that exposes price feeds.\n constructor(IJBDirectory _directory, IJBFundingCycleStore _fundingCycleStore, IJBPrices _prices) {\n directory = _directory;\n fundingCycleStore = _fundingCycleStore;\n prices = _prices;\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Records newly contributed tokens to a project.\n /// @dev Mints the project's tokens according to values provided by a configured data source. If no data source is configured, mints tokens proportional to the amount of the contribution.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.sender's tokens.\n /// @param _payer The original address that sent the payment to the terminal.\n /// @param _amount The amount of tokens being paid. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\n /// @param _projectId The ID of the project being paid.\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _beneficiary The specified address that should be the beneficiary of anything that results from the payment.\n /// @param _memo A memo to pass along to the emitted event, and passed along to the funding cycle's data source.\n /// @param _metadata Bytes to send along to the data source, if one is provided.\n /// @return fundingCycle The project's funding cycle during which payment was made.\n /// @return tokenCount The number of project tokens that were minted, as a fixed point number with 18 decimals.\n /// @return delegateAllocations The amount to send to delegates instead of adding to the local balance.\n /// @return memo A memo that should be passed along to the emitted event.\n function recordPaymentFrom(\n address _payer,\n JBTokenAmount calldata _amount,\n uint256 _projectId,\n uint256 _baseWeightCurrency,\n address _beneficiary,\n string calldata _memo,\n bytes memory _metadata\n )\n external\n override\n nonReentrant\n returns (\n JBFundingCycle memory fundingCycle,\n uint256 tokenCount,\n JBPayDelegateAllocation[] memory delegateAllocations,\n string memory memo\n )\n {\n // Get a reference to the current funding cycle for the project.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // The project must have a funding cycle configured.\n if (fundingCycle.number == 0) revert INVALID_FUNDING_CYCLE();\n\n // Must not be paused.\n if (fundingCycle.payPaused()) revert FUNDING_CYCLE_PAYMENT_PAUSED();\n\n // The weight according to which new token supply is to be minted, as a fixed point number with 18 decimals.\n uint256 _weight;\n\n // If the funding cycle has configured a data source, use it to derive a weight and memo.\n if (fundingCycle.useDataSourceForPay() && fundingCycle.dataSource() != address(0)) {\n // Create the params that'll be sent to the data source.\n JBPayParamsData memory _data = JBPayParamsData(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _payer,\n _amount,\n _projectId,\n fundingCycle.configuration,\n _beneficiary,\n fundingCycle.weight,\n fundingCycle.reservedRate(),\n _memo,\n _metadata\n );\n (_weight, memo, delegateAllocations) = IJBFundingCycleDataSource(fundingCycle.dataSource())\n .payParams(_data);\n }\n // Otherwise use the funding cycle's weight\n else {\n _weight = fundingCycle.weight;\n memo = _memo;\n }\n\n // Scoped section prevents stack too deep. `_balanceDiff` only used within scope.\n {\n // Keep a reference to the amount that should be added to the project's balance.\n uint256 _balanceDiff = _amount.value;\n\n // Validate all delegated amounts. This needs to be done before returning the delegate allocations to ensure valid delegated amounts.\n if (delegateAllocations.length != 0) {\n for (uint256 _i; _i < delegateAllocations.length; ) {\n // Get a reference to the amount to be delegated.\n uint256 _delegatedAmount = delegateAllocations[_i].amount;\n\n // Validate if non-zero.\n if (_delegatedAmount != 0) {\n // Can't delegate more than was paid.\n if (_delegatedAmount > _balanceDiff) revert INVALID_AMOUNT_TO_SEND_DELEGATE();\n\n // Decrement the total amount being added to the balance.\n _balanceDiff = _balanceDiff - _delegatedAmount;\n }\n\n unchecked {\n ++_i;\n }\n }\n }\n\n // If there's no amount being recorded, there's nothing left to do.\n if (_amount.value == 0) return (fundingCycle, 0, delegateAllocations, memo);\n\n // Add the correct balance difference to the token balance of the project.\n if (_balanceDiff != 0)\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] +\n _balanceDiff;\n }\n\n // If there's no weight, token count must be 0 so there's nothing left to do.\n if (_weight == 0) return (fundingCycle, 0, delegateAllocations, memo);\n\n // Get a reference to the number of decimals in the amount. (prevents stack too deep).\n uint256 _decimals = _amount.decimals;\n\n // If the terminal should base its weight on a different currency from the terminal's currency, determine the factor.\n // The weight is always a fixed point mumber with 18 decimals. To ensure this, the ratio should use the same number of decimals as the `_amount`.\n uint256 _weightRatio = _amount.currency == _baseWeightCurrency\n ? 10 ** _decimals\n : prices.priceFor(_amount.currency, _baseWeightCurrency, _decimals);\n\n // Find the number of tokens to mint, as a fixed point number with as many decimals as `weight` has.\n tokenCount = PRBMath.mulDiv(_amount.value, _weight, _weightRatio);\n }\n\n /// @notice Records newly redeemed tokens of a project.\n /// @dev Redeems the project's tokens according to values provided by a configured data source. If no data source is configured, redeems tokens along a redemption bonding curve that is a function of the number of tokens being burned.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.senders tokens.\n /// @param _holder The account that is having its tokens redeemed.\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\n /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the data source, if one is provided.\n /// @return fundingCycle The funding cycle during which the redemption was made.\n /// @return reclaimAmount The amount of terminal tokens reclaimed, as a fixed point number with 18 decimals.\n /// @return delegateAllocations The amount to send to delegates instead of sending to the beneficiary.\n /// @return memo A memo that should be passed along to the emitted event.\n function recordRedemptionFor(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n string memory _memo,\n bytes memory _metadata\n )\n external\n override\n nonReentrant\n returns (\n JBFundingCycle memory fundingCycle,\n uint256 reclaimAmount,\n JBRedemptionDelegateAllocation[] memory delegateAllocations,\n string memory memo\n )\n {\n // Get a reference to the project's current funding cycle.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // The current funding cycle must not be paused.\n if (fundingCycle.redeemPaused()) revert FUNDING_CYCLE_REDEEM_PAUSED();\n\n // Scoped section prevents stack too deep. `_reclaimedTokenAmount`, `_currentOverflow`, and `_totalSupply` only used within scope.\n {\n // Get a reference to the reclaimed token amount struct, the current overflow, and the total token supply.\n JBTokenAmount memory _reclaimedTokenAmount;\n uint256 _currentOverflow;\n uint256 _totalSupply;\n\n // Another scoped section prevents stack too deep. `_token`, `_decimals`, and `_currency` only used within scope.\n {\n // Get a reference to the terminal's tokens.\n address _token = IJBSingleTokenPaymentTerminal(msg.sender).token();\n\n // Get a reference to the terminal's decimals.\n uint256 _decimals = IJBSingleTokenPaymentTerminal(msg.sender).decimals();\n\n // Get areference to the terminal's currency.\n uint256 _currency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\n\n // Get the amount of current overflow.\n // Use the local overflow if the funding cycle specifies that it should be used. Otherwise, use the project's total overflow across all of its terminals.\n _currentOverflow = fundingCycle.useTotalOverflowForRedemptions()\n ? _currentTotalOverflowOf(_projectId, _decimals, _currency)\n : _overflowDuring(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _projectId,\n fundingCycle,\n _currency\n );\n\n // Get the number of outstanding tokens the project has.\n _totalSupply = IJBController(directory.controllerOf(_projectId)).totalOutstandingTokensOf(\n _projectId,\n fundingCycle.reservedRate()\n );\n\n // Can't redeem more tokens that is in the supply.\n if (_tokenCount > _totalSupply) revert INSUFFICIENT_TOKENS();\n\n if (_currentOverflow != 0)\n // Calculate reclaim amount using the current overflow amount.\n reclaimAmount = _reclaimableOverflowDuring(\n _projectId,\n fundingCycle,\n _tokenCount,\n _totalSupply,\n _currentOverflow\n );\n\n _reclaimedTokenAmount = JBTokenAmount(_token, reclaimAmount, _decimals, _currency);\n }\n\n // If the funding cycle has configured a data source, use it to derive a claim amount and memo.\n if (fundingCycle.useDataSourceForRedeem() && fundingCycle.dataSource() != address(0)) {\n // Yet another scoped section prevents stack too deep. `_state` only used within scope.\n {\n // Get a reference to the ballot state.\n JBBallotState _state = fundingCycleStore.currentBallotStateOf(_projectId);\n\n // Create the params that'll be sent to the data source.\n JBRedeemParamsData memory _data = JBRedeemParamsData(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _holder,\n _projectId,\n fundingCycle.configuration,\n _tokenCount,\n _totalSupply,\n _currentOverflow,\n _reclaimedTokenAmount,\n fundingCycle.useTotalOverflowForRedemptions(),\n _state == JBBallotState.Active\n ? fundingCycle.ballotRedemptionRate()\n : fundingCycle.redemptionRate(),\n _memo,\n _metadata\n );\n (reclaimAmount, memo, delegateAllocations) = IJBFundingCycleDataSource(\n fundingCycle.dataSource()\n ).redeemParams(_data);\n }\n } else {\n memo = _memo;\n }\n }\n\n // Keep a reference to the amount that should be subtracted from the project's balance.\n uint256 _balanceDiff = reclaimAmount;\n\n if (delegateAllocations.length != 0) {\n // Validate all delegated amounts.\n for (uint256 _i; _i < delegateAllocations.length; ) {\n // Get a reference to the amount to be delegated.\n uint256 _delegatedAmount = delegateAllocations[_i].amount;\n\n // Validate if non-zero.\n if (_delegatedAmount != 0)\n // Increment the total amount being subtracted from the balance.\n _balanceDiff = _balanceDiff + _delegatedAmount;\n\n unchecked {\n ++_i;\n }\n }\n }\n\n // The amount being reclaimed must be within the project's balance.\n if (_balanceDiff > balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId])\n revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n\n // Remove the reclaimed funds from the project's balance.\n if (_balanceDiff != 0) {\n unchecked {\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\n _balanceDiff;\n }\n }\n }\n\n /// @notice Records newly distributed funds for a project.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\n /// @param _projectId The ID of the project that is having funds distributed.\n /// @param _amount The amount to use from the distribution limit, as a fixed point number.\n /// @param _currency The currency of the `_amount`. This must match the project's current funding cycle's currency.\n /// @return fundingCycle The funding cycle during which the distribution was made.\n /// @return distributedAmount The amount of terminal tokens distributed, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordDistributionFor(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency\n )\n external\n override\n nonReentrant\n returns (JBFundingCycle memory fundingCycle, uint256 distributedAmount)\n {\n // Get a reference to the project's current funding cycle.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // The funding cycle must not be configured to have distributions paused.\n if (fundingCycle.distributionsPaused()) revert FUNDING_CYCLE_DISTRIBUTION_PAUSED();\n\n // The new total amount that has been distributed during this funding cycle.\n uint256 _newUsedDistributionLimitOf = usedDistributionLimitOf[\n IJBSingleTokenPaymentTerminal(msg.sender)\n ][_projectId][fundingCycle.number] + _amount;\n\n // Amount must be within what is still distributable.\n (uint256 _distributionLimitOf, uint256 _distributionLimitCurrencyOf) = IJBController(\n directory.controllerOf(_projectId)\n ).distributionLimitOf(\n _projectId,\n fundingCycle.configuration,\n IJBSingleTokenPaymentTerminal(msg.sender),\n IJBSingleTokenPaymentTerminal(msg.sender).token()\n );\n\n // Make sure the new used amount is within the distribution limit.\n if (_newUsedDistributionLimitOf > _distributionLimitOf || _distributionLimitOf == 0)\n revert DISTRIBUTION_AMOUNT_LIMIT_REACHED();\n\n // Make sure the currencies match.\n if (_currency != _distributionLimitCurrencyOf) revert CURRENCY_MISMATCH();\n\n // Get a reference to the terminal's currency.\n uint256 _balanceCurrency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\n\n // Convert the amount to the balance's currency.\n distributedAmount = (_currency == _balanceCurrency)\n ? _amount\n : PRBMath.mulDiv(\n _amount,\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\n prices.priceFor(_currency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\n );\n\n // The amount being distributed must be available.\n if (distributedAmount > balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId])\n revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n\n // Store the new amount.\n usedDistributionLimitOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId][\n fundingCycle.number\n ] = _newUsedDistributionLimitOf;\n\n // Removed the distributed funds from the project's token balance.\n unchecked {\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\n distributedAmount;\n }\n }\n\n /// @notice Records newly used allowance funds of a project.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\n /// @param _projectId The ID of the project to use the allowance of.\n /// @param _amount The amount to use from the allowance, as a fixed point number.\n /// @param _currency The currency of the `_amount`. Must match the currency of the overflow allowance.\n /// @return fundingCycle The funding cycle during which the overflow allowance is being used.\n /// @return usedAmount The amount of terminal tokens used, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordUsedAllowanceOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency\n )\n external\n override\n nonReentrant\n returns (JBFundingCycle memory fundingCycle, uint256 usedAmount)\n {\n // Get a reference to the project's current funding cycle.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Get a reference to the new used overflow allowance for this funding cycle configuration.\n uint256 _newUsedOverflowAllowanceOf = usedOverflowAllowanceOf[\n IJBSingleTokenPaymentTerminal(msg.sender)\n ][_projectId][fundingCycle.configuration] + _amount;\n\n // There must be sufficient allowance available.\n (uint256 _overflowAllowanceOf, uint256 _overflowAllowanceCurrency) = IJBController(\n directory.controllerOf(_projectId)\n ).overflowAllowanceOf(\n _projectId,\n fundingCycle.configuration,\n IJBSingleTokenPaymentTerminal(msg.sender),\n IJBSingleTokenPaymentTerminal(msg.sender).token()\n );\n\n // Make sure the new used amount is within the allowance.\n if (_newUsedOverflowAllowanceOf > _overflowAllowanceOf || _overflowAllowanceOf == 0)\n revert INADEQUATE_CONTROLLER_ALLOWANCE();\n\n // Make sure the currencies match.\n if (_currency != _overflowAllowanceCurrency) revert CURRENCY_MISMATCH();\n\n // Get a reference to the terminal's currency.\n uint256 _balanceCurrency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\n\n // Convert the amount to this store's terminal's token.\n usedAmount = (_currency == _balanceCurrency)\n ? _amount\n : PRBMath.mulDiv(\n _amount,\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\n prices.priceFor(_currency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\n );\n\n // The amount being distributed must be available in the overflow.\n if (\n usedAmount >\n _overflowDuring(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _projectId,\n fundingCycle,\n _balanceCurrency\n )\n ) revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n\n // Store the incremented value.\n usedOverflowAllowanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId][\n fundingCycle.configuration\n ] = _newUsedOverflowAllowanceOf;\n\n // Update the project's balance.\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\n usedAmount;\n }\n\n /// @notice Records newly added funds for the project.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\n /// @param _projectId The ID of the project to which the funds being added belong.\n /// @param _amount The amount of terminal tokens added, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordAddedBalanceFor(uint256 _projectId, uint256 _amount) external override {\n // Increment the balance.\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] +\n _amount;\n }\n\n /// @notice Records the migration of funds from this store.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount returned is in terms of the msg.senders tokens.\n /// @param _projectId The ID of the project being migrated.\n /// @return balance The project's migrated balance, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordMigration(\n uint256 _projectId\n ) external override nonReentrant returns (uint256 balance) {\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Migration must be allowed.\n if (!_fundingCycle.terminalMigrationAllowed()) revert PAYMENT_TERMINAL_MIGRATION_NOT_ALLOWED();\n\n // Return the current balance.\n balance = balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId];\n\n // Set the balance to 0.\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] = 0;\n }\n\n //*********************************************************************//\n // --------------------- private helper functions -------------------- //\n //*********************************************************************//\n\n /// @notice The amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens when measured from the specified.\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\n /// @param _projectId The ID of the project to get the reclaimable overflow amount for.\n /// @param _fundingCycle The funding cycle during which reclaimable overflow is being calculated.\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _totalSupply The total supply of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _overflow The amount of overflow to make the calculation with.\n /// @return The amount of overflowed tokens that can be reclaimed.\n function _reclaimableOverflowDuring(\n uint256 _projectId,\n JBFundingCycle memory _fundingCycle,\n uint256 _tokenCount,\n uint256 _totalSupply,\n uint256 _overflow\n ) private view returns (uint256) {\n // If the amount being redeemed is the total supply, return the rest of the overflow.\n if (_tokenCount == _totalSupply) return _overflow;\n\n // Use the ballot redemption rate if the queued cycle is pending approval according to the previous funding cycle's ballot.\n uint256 _redemptionRate = fundingCycleStore.currentBallotStateOf(_projectId) ==\n JBBallotState.Active\n ? _fundingCycle.ballotRedemptionRate()\n : _fundingCycle.redemptionRate();\n\n // If the redemption rate is 0, nothing is claimable.\n if (_redemptionRate == 0) return 0;\n\n // Get a reference to the linear proportion.\n uint256 _base = PRBMath.mulDiv(_overflow, _tokenCount, _totalSupply);\n\n // These conditions are all part of the same curve. Edge conditions are separated because fewer operation are necessary.\n if (_redemptionRate == JBConstants.MAX_REDEMPTION_RATE) return _base;\n\n return\n PRBMath.mulDiv(\n _base,\n _redemptionRate +\n PRBMath.mulDiv(\n _tokenCount,\n JBConstants.MAX_REDEMPTION_RATE - _redemptionRate,\n _totalSupply\n ),\n JBConstants.MAX_REDEMPTION_RATE\n );\n }\n\n /// @notice Gets the amount that is overflowing when measured from the specified funding cycle.\n /// @dev This amount changes as the value of the balance changes in relation to the currency being used to measure the distribution limit.\n /// @param _terminal The terminal for which the overflow is being calculated.\n /// @param _projectId The ID of the project to get overflow for.\n /// @param _fundingCycle The ID of the funding cycle to base the overflow on.\n /// @param _balanceCurrency The currency that the stored balance is expected to be in terms of.\n /// @return overflow The overflow of funds, as a fixed point number with 18 decimals.\n function _overflowDuring(\n IJBSingleTokenPaymentTerminal _terminal,\n uint256 _projectId,\n JBFundingCycle memory _fundingCycle,\n uint256 _balanceCurrency\n ) private view returns (uint256) {\n // Get the current balance of the project.\n uint256 _balanceOf = balanceOf[_terminal][_projectId];\n\n // If there's no balance, there's no overflow.\n if (_balanceOf == 0) return 0;\n\n // Get a reference to the distribution limit during the funding cycle.\n (uint256 _distributionLimit, uint256 _distributionLimitCurrency) = IJBController(\n directory.controllerOf(_projectId)\n ).distributionLimitOf(_projectId, _fundingCycle.configuration, _terminal, _terminal.token());\n\n // Get a reference to the amount still distributable during the funding cycle.\n uint256 _distributionLimitRemaining = _distributionLimit -\n usedDistributionLimitOf[_terminal][_projectId][_fundingCycle.number];\n\n // Convert the _distributionRemaining to be in terms of the provided currency.\n if (_distributionLimitRemaining != 0 && _distributionLimitCurrency != _balanceCurrency)\n _distributionLimitRemaining = PRBMath.mulDiv(\n _distributionLimitRemaining,\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\n prices.priceFor(_distributionLimitCurrency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\n );\n\n // Overflow is the balance of this project minus the amount that can still be distributed.\n unchecked {\n return\n _balanceOf > _distributionLimitRemaining ? _balanceOf - _distributionLimitRemaining : 0;\n }\n }\n\n /// @notice Gets the amount that is currently overflowing across all of a project's terminals.\n /// @dev This amount changes as the value of the balances changes in relation to the currency being used to measure the project's distribution limits.\n /// @param _projectId The ID of the project to get the total overflow for.\n /// @param _decimals The number of decimals that the fixed point overflow should include.\n /// @param _currency The currency that the overflow should be in terms of.\n /// @return overflow The total overflow of a project's funds.\n function _currentTotalOverflowOf(\n uint256 _projectId,\n uint256 _decimals,\n uint256 _currency\n ) private view returns (uint256) {\n // Get a reference to the project's terminals.\n IJBPaymentTerminal[] memory _terminals = directory.terminalsOf(_projectId);\n\n // Keep a reference to the ETH overflow across all terminals, as a fixed point number with 18 decimals.\n uint256 _ethOverflow;\n\n // Add the current ETH overflow for each terminal.\n for (uint256 _i; _i < _terminals.length; ) {\n _ethOverflow = _ethOverflow + _terminals[_i].currentEthOverflowOf(_projectId);\n unchecked {\n ++_i;\n }\n }\n\n // Convert the ETH overflow to the specified currency if needed, maintaining a fixed point number with 18 decimals.\n uint256 _totalOverflow18Decimal = _currency == JBCurrencies.ETH\n ? _ethOverflow\n : PRBMath.mulDiv(_ethOverflow, 10 ** 18, prices.priceFor(JBCurrencies.ETH, _currency, 18));\n\n // Adjust the decimals of the fixed point number if needed to match the target decimals.\n return\n (_decimals == 18)\n ? _totalOverflow18Decimal\n : JBFixedPointNumber.adjustDecimals(_totalOverflow18Decimal, 18, _decimals);\n }\n}\n" + }, + "contracts/JBMigrationOperator.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {IJBController} from './interfaces/IJBController.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBMigratable} from './interfaces/IJBMigratable.sol';\nimport {IJBPayoutRedemptionPaymentTerminal} from './interfaces/IJBPayoutRedemptionPaymentTerminal.sol';\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\n\n/// @notice Allows projects to migrate their controller & terminal to 3.1 version\ncontract JBMigrationOperator {\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error UNAUTHORIZED();\n\n //*********************************************************************//\n // --------------- public immutable stored properties ---------------- //\n //*********************************************************************//\n\n /// @notice directory instance which keeps a track of which controller is linked to which project.\n IJBDirectory public immutable directory;\n\n /// @notice The NFT granting ownership to a Juicebox project\n IJBProjects public immutable projects;\n\n //*********************************************************************//\n // ---------------------------- constructor -------------------------- //\n //*********************************************************************//\n\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n constructor(IJBDirectory _directory) {\n directory = _directory;\n projects = IJBProjects(_directory.projects());\n }\n\n //*********************************************************************//\n // --------------------- external transactions ----------------------- //\n //*********************************************************************//\n\n /// @notice Allows project owners to migrate the controller & terminal linked to their project to the latest version.\n /// @param _projectId The project id whose controller & terminal are to be migrated\n /// @param _newController Controller 3.1 address to migrate to.\n /// @param _newJbTerminal Terminal 3.1 address to migrate to.\n /// @param _oldJbTerminal Old terminal address to migrate from.\n function migrate(\n uint256 _projectId,\n IJBMigratable _newController,\n IJBPaymentTerminal _newJbTerminal,\n IJBPayoutRedemptionPaymentTerminal _oldJbTerminal\n ) external {\n // Only allow the project owner to migrate\n if (projects.ownerOf(_projectId) != msg.sender) revert UNAUTHORIZED();\n\n // controller migration\n address _oldController = directory.controllerOf(_projectId);\n\n // assuming the project owner has reconfigured the funding cycle with allowControllerMigration\n IJBController(_oldController).migrate(_projectId, _newController);\n\n // terminal migration\n IJBPaymentTerminal[] memory _newTerminals = new IJBPaymentTerminal[](1);\n _newTerminals[0] = IJBPaymentTerminal(address(_newJbTerminal));\n\n // assuming the project owner has reconfigured the funding cycle with allowTerminalMigration & global.allowSetTerminals\n directory.setTerminalsOf(_projectId, _newTerminals);\n _oldJbTerminal.migrate(_projectId, _newJbTerminal);\n }\n}\n" + }, + "contracts/interfaces/IJBPayoutRedemptionPaymentTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBFee} from './../structs/JBFee.sol';\nimport {IJBAllowanceTerminal} from './IJBAllowanceTerminal.sol';\nimport {IJBDirectory} from './IJBDirectory.sol';\nimport {IJBPayDelegate} from './IJBPayDelegate.sol';\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\nimport {IJBPayoutTerminal} from './IJBPayoutTerminal.sol';\nimport {IJBPrices} from './IJBPrices.sol';\nimport {IJBProjects} from './IJBProjects.sol';\nimport {IJBRedemptionDelegate} from './IJBRedemptionDelegate.sol';\nimport {IJBRedemptionTerminal} from './IJBRedemptionTerminal.sol';\nimport {IJBSplitsStore} from './IJBSplitsStore.sol';\nimport {JBDidPayData} from './../structs/JBDidPayData.sol';\nimport {JBDidRedeemData} from './../structs/JBDidRedeemData.sol';\nimport {JBSplit} from './../structs/JBSplit.sol';\n\ninterface IJBPayoutRedemptionPaymentTerminal is\n IJBPaymentTerminal,\n IJBPayoutTerminal,\n IJBAllowanceTerminal,\n IJBRedemptionTerminal\n{\n event AddToBalance(\n uint256 indexed projectId,\n uint256 amount,\n uint256 refundedFees,\n string memo,\n bytes metadata,\n address caller\n );\n\n event Migrate(\n uint256 indexed projectId,\n IJBPaymentTerminal indexed to,\n uint256 amount,\n address caller\n );\n\n event DistributePayouts(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n address beneficiary,\n uint256 amount,\n uint256 distributedAmount,\n uint256 fee,\n uint256 beneficiaryDistributionAmount,\n string memo,\n address caller\n );\n\n event UseAllowance(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n address beneficiary,\n uint256 amount,\n uint256 distributedAmount,\n uint256 netDistributedamount,\n string memo,\n address caller\n );\n\n event HoldFee(\n uint256 indexed projectId,\n uint256 indexed amount,\n uint256 indexed fee,\n uint256 feeDiscount,\n address beneficiary,\n address caller\n );\n\n event ProcessFee(\n uint256 indexed projectId,\n uint256 indexed amount,\n bool indexed wasHeld,\n address beneficiary,\n address caller\n );\n\n event RefundHeldFees(\n uint256 indexed projectId,\n uint256 indexed amount,\n uint256 indexed refundedFees,\n uint256 leftoverAmount,\n address caller\n );\n\n event Pay(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n address payer,\n address beneficiary,\n uint256 amount,\n uint256 beneficiaryTokenCount,\n string memo,\n bytes metadata,\n address caller\n );\n\n event DelegateDidPay(\n IJBPayDelegate indexed delegate,\n JBDidPayData data,\n uint256 delegatedAmount,\n address caller\n );\n\n event RedeemTokens(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n address holder,\n address beneficiary,\n uint256 tokenCount,\n uint256 reclaimedAmount,\n string memo,\n bytes metadata,\n address caller\n );\n\n event DelegateDidRedeem(\n IJBRedemptionDelegate indexed delegate,\n JBDidRedeemData data,\n uint256 delegatedAmount,\n address caller\n );\n\n event DistributeToPayoutSplit(\n uint256 indexed projectId,\n uint256 indexed domain,\n uint256 indexed group,\n JBSplit split,\n uint256 amount,\n address caller\n );\n\n event SetFee(uint256 fee, address caller);\n\n event SetFeeGauge(address indexed feeGauge, address caller);\n\n event SetFeelessAddress(address indexed addrs, bool indexed flag, address caller);\n\n function projects() external view returns (IJBProjects);\n\n function splitsStore() external view returns (IJBSplitsStore);\n\n function directory() external view returns (IJBDirectory);\n\n function prices() external view returns (IJBPrices);\n\n function store() external view returns (address);\n\n function baseWeightCurrency() external view returns (uint256);\n\n function payoutSplitsGroup() external view returns (uint256);\n\n function heldFeesOf(uint256 projectId) external view returns (JBFee[] memory);\n\n function fee() external view returns (uint256);\n\n function feeGauge() external view returns (address);\n\n function isFeelessAddress(address account) external view returns (bool);\n\n function migrate(uint256 projectId, IJBPaymentTerminal _to) external returns (uint256 balance);\n\n function processFees(uint256 projectId) external;\n\n function setFee(uint256 fee) external;\n\n function setFeeGauge(address feeGauge) external;\n\n function setFeelessAddress(address account, bool flag) external;\n}\n" + }, + "contracts/structs/JBFee.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @custom:member amount The total amount the fee was taken from, as a fixed point number with the same number of decimals as the terminal in which this struct was created.\n/// @custom:member fee The percent of the fee, out of MAX_FEE.\n/// @custom:member feeDiscount The discount of the fee.\n/// @custom:member beneficiary The address that will receive the tokens that are minted as a result of the fee payment.\nstruct JBFee {\n uint256 amount;\n uint32 fee;\n uint32 feeDiscount;\n address beneficiary;\n}\n" + }, + "contracts/interfaces/IJBAllowanceTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBAllowanceTerminal {\n function useAllowanceOf(\n uint256 projectId,\n uint256 amount,\n uint256 currency,\n address token,\n uint256 minReturnedTokens,\n address payable beneficiary,\n string calldata memo\n ) external returns (uint256 netDistributedAmount);\n}\n" + }, + "contracts/interfaces/IJBPayoutTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBPayoutTerminal {\n function distributePayoutsOf(\n uint256 projectId,\n uint256 amount,\n uint256 currency,\n address token,\n uint256 minReturnedTokens,\n string calldata memo\n ) external returns (uint256 netLeftoverDistributionAmount);\n}\n" + }, + "contracts/interfaces/IJBRedemptionTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBRedemptionTerminal {\n function redeemTokensOf(\n address holder,\n uint256 projectId,\n uint256 tokenCount,\n address token,\n uint256 minReturnedTokens,\n address payable beneficiary,\n string calldata memo,\n bytes calldata metadata\n ) external returns (uint256 reclaimAmount);\n}\n" + }, + "contracts/JBETHPaymentTerminal3_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Address} from '@openzeppelin/contracts/utils/Address.sol';\nimport {JBPayoutRedemptionPaymentTerminal3_1} from './abstract/JBPayoutRedemptionPaymentTerminal3_1.sol';\nimport {JBSplitsGroups} from './libraries/JBSplitsGroups.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {JBCurrencies} from './libraries/JBCurrencies.sol';\nimport {JBTokens} from './libraries/JBTokens.sol';\n\n/// @notice Manages all inflows and outflows of ETH funds into the protocol ecosystem.\ncontract JBETHPaymentTerminal3_1 is JBPayoutRedemptionPaymentTerminal3_1 {\n //*********************************************************************//\n // -------------------------- internal views ------------------------- //\n //*********************************************************************//\n\n /// @notice Checks the balance of tokens in this contract.\n /// @return The contract's balance, as a fixed point number with the same amount of decimals as this terminal.\n function _balance() internal view override returns (uint256) {\n return address(this).balance;\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _prices A contract that exposes price feeds.\n /// @param _store A contract that stores the terminal's data.\n /// @param _owner The address that will own this contract.\n constructor(\n uint256 _baseWeightCurrency,\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBSplitsStore _splitsStore,\n IJBPrices _prices,\n address _store,\n address _owner\n )\n JBPayoutRedemptionPaymentTerminal3_1(\n JBTokens.ETH,\n 18, // 18 decimals.\n JBCurrencies.ETH,\n _baseWeightCurrency,\n JBSplitsGroups.ETH_PAYOUT,\n _operatorStore,\n _projects,\n _directory,\n _splitsStore,\n _prices,\n _store,\n _owner\n )\n // solhint-disable-next-line no-empty-blocks\n {\n\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Transfers tokens.\n /// @param _from The address from which the transfer should originate.\n /// @param _to The address to which the transfer should go.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _transferFrom(address _from, address payable _to, uint256 _amount) internal override {\n _from; // Prevents unused var compiler and natspec complaints.\n\n Address.sendValue(_to, _amount);\n }\n}\n" + }, + "contracts/abstract/JBPayoutRedemptionPaymentTerminal3_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {ERC165Checker} from '@openzeppelin/contracts/utils/introspection/ERC165Checker.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {IJBAllowanceTerminal3_1} from './../interfaces/IJBAllowanceTerminal3_1.sol';\nimport {IJBController} from './../interfaces/IJBController.sol';\nimport {IJBDirectory} from './../interfaces/IJBDirectory.sol';\nimport {IJBFeeGauge} from './../interfaces/IJBFeeGauge.sol';\nimport {IJBPayoutRedemptionPaymentTerminal3_1} from './../interfaces/IJBPayoutRedemptionPaymentTerminal3_1.sol';\nimport {IJBSplitAllocator} from './../interfaces/IJBSplitAllocator.sol';\nimport {IJBOperatable} from './../interfaces/IJBOperatable.sol';\nimport {IJBOperatorStore} from './../interfaces/IJBOperatorStore.sol';\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\nimport {IJBPayoutTerminal3_1} from './../interfaces/IJBPayoutTerminal3_1.sol';\nimport {IJBPrices} from './../interfaces/IJBPrices.sol';\nimport {IJBProjects} from './../interfaces/IJBProjects.sol';\nimport {IJBRedemptionTerminal} from './../interfaces/IJBRedemptionTerminal.sol';\nimport {IJBSingleTokenPaymentTerminalStore} from './../interfaces/IJBSingleTokenPaymentTerminalStore.sol';\nimport {IJBSplitsStore} from './../interfaces/IJBSplitsStore.sol';\nimport {JBConstants} from './../libraries/JBConstants.sol';\nimport {JBCurrencies} from './../libraries/JBCurrencies.sol';\nimport {JBFixedPointNumber} from './../libraries/JBFixedPointNumber.sol';\nimport {JBFundingCycleMetadataResolver} from './../libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBOperations} from './../libraries/JBOperations.sol';\nimport {JBTokens} from './../libraries/JBTokens.sol';\nimport {JBDidPayData} from './../structs/JBDidPayData.sol';\nimport {JBDidRedeemData} from './../structs/JBDidRedeemData.sol';\nimport {JBFee} from './../structs/JBFee.sol';\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\nimport {JBPayDelegateAllocation} from './../structs/JBPayDelegateAllocation.sol';\nimport {JBTokenAmount} from './../structs/JBTokenAmount.sol';\nimport {JBRedemptionDelegateAllocation} from './../structs/JBRedemptionDelegateAllocation.sol';\nimport {JBSplit} from './../structs/JBSplit.sol';\nimport {JBSplitAllocationData} from './../structs/JBSplitAllocationData.sol';\nimport {JBOperatable} from './JBOperatable.sol';\nimport {JBSingleTokenPaymentTerminal} from './JBSingleTokenPaymentTerminal.sol';\n\n/// @notice Generic terminal managing all inflows and outflows of funds into the protocol ecosystem.\nabstract contract JBPayoutRedemptionPaymentTerminal3_1 is\n JBSingleTokenPaymentTerminal,\n JBOperatable,\n Ownable,\n IJBPayoutRedemptionPaymentTerminal3_1\n{\n // A library that parses the packed funding cycle metadata into a friendlier format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error FEE_TOO_HIGH();\n error INADEQUATE_DISTRIBUTION_AMOUNT();\n error INADEQUATE_RECLAIM_AMOUNT();\n error INADEQUATE_TOKEN_COUNT();\n error NO_MSG_VALUE_ALLOWED();\n error PAY_TO_ZERO_ADDRESS();\n error PROJECT_TERMINAL_MISMATCH();\n error REDEEM_TO_ZERO_ADDRESS();\n error TERMINAL_IN_SPLIT_ZERO_ADDRESS();\n error TERMINAL_TOKENS_INCOMPATIBLE();\n\n //*********************************************************************//\n // ---------------------------- modifiers ---------------------------- //\n //*********************************************************************//\n\n /// @notice A modifier that verifies this terminal is a terminal of provided project ID.\n modifier isTerminalOf(uint256 _projectId) {\n if (!directory.isTerminalOf(_projectId, this)) revert PROJECT_TERMINAL_MISMATCH();\n _;\n }\n\n //*********************************************************************//\n // --------------------- internal stored constants ------------------- //\n //*********************************************************************//\n\n /// @notice Maximum fee that can be set for a funding cycle configuration.\n /// @dev Out of MAX_FEE (50_000_000 / 1_000_000_000).\n uint256 internal constant _FEE_CAP = 50_000_000;\n\n /// @notice The fee beneficiary project ID is 1, as it should be the first project launched during the deployment process.\n uint256 internal constant _FEE_BENEFICIARY_PROJECT_ID = 1;\n\n //*********************************************************************//\n // --------------------- internal stored properties ------------------ //\n //*********************************************************************//\n\n /// @notice Fees that are being held to be processed later.\n /// @custom:param _projectId The ID of the project for which fees are being held.\n mapping(uint256 => JBFee[]) internal _heldFeesOf;\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice Mints ERC-721's that represent project ownership and transfers.\n IJBProjects public immutable override projects;\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n /// @notice The contract that stores splits for each project.\n IJBSplitsStore public immutable override splitsStore;\n\n /// @notice The contract that exposes price feeds.\n IJBPrices public immutable override prices;\n\n /// @notice The contract that stores and manages the terminal's data.\n address public immutable override store;\n\n /// @notice The currency to base token issuance on.\n /// @dev If this differs from `currency`, there must be a price feed available to convert `currency` to `baseWeightCurrency`.\n uint256 public immutable override baseWeightCurrency;\n\n /// @notice The group that payout splits coming from this terminal are identified by.\n uint256 public immutable override payoutSplitsGroup;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The platform fee percent.\n /// @dev Out of MAX_FEE (25_000_000 / 1_000_000_000)\n uint256 public override fee = 25_000_000; // 2.5%\n\n /// @notice The data source that returns a discount to apply to a project's fee.\n address public override feeGauge;\n\n /// @notice Addresses that can be paid towards from this terminal without incurring a fee.\n /// @dev Only addresses that are considered to be contained within the ecosystem can be feeless. Funds sent outside the ecosystem may incur fees despite being stored as feeless.\n /// @custom:param _address The address that can be paid toward.\n mapping(address => bool) public override isFeelessAddress;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Gets the current overflowed amount in this terminal for a specified project, in terms of ETH.\n /// @dev The current overflow is represented as a fixed point number with 18 decimals.\n /// @param _projectId The ID of the project to get overflow for.\n /// @return The current amount of ETH overflow that project has in this terminal, as a fixed point number with 18 decimals.\n function currentEthOverflowOf(\n uint256 _projectId\n ) external view virtual override returns (uint256) {\n // Get this terminal's current overflow.\n uint256 _overflow = IJBSingleTokenPaymentTerminalStore(store).currentOverflowOf(\n this,\n _projectId\n );\n\n // Adjust the decimals of the fixed point number if needed to have 18 decimals.\n uint256 _adjustedOverflow = (decimals == 18)\n ? _overflow\n : JBFixedPointNumber.adjustDecimals(_overflow, decimals, 18);\n\n // Return the amount converted to ETH.\n return\n (currency == JBCurrencies.ETH)\n ? _adjustedOverflow\n : PRBMath.mulDiv(\n _adjustedOverflow,\n 10 ** decimals,\n prices.priceFor(currency, JBCurrencies.ETH, decimals)\n );\n }\n\n /// @notice The fees that are currently being held to be processed later for each project.\n /// @param _projectId The ID of the project for which fees are being held.\n /// @return An array of fees that are being held.\n function heldFeesOf(uint256 _projectId) external view override returns (JBFee[] memory) {\n return _heldFeesOf[_projectId];\n }\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if the provided interface ID is supported.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(JBSingleTokenPaymentTerminal, IERC165) returns (bool) {\n return\n _interfaceId == type(IJBPayoutRedemptionPaymentTerminal3_1).interfaceId ||\n _interfaceId == type(IJBPayoutTerminal3_1).interfaceId ||\n _interfaceId == type(IJBAllowanceTerminal3_1).interfaceId ||\n _interfaceId == type(IJBRedemptionTerminal).interfaceId ||\n _interfaceId == type(IJBOperatable).interfaceId ||\n super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // -------------------------- internal views ------------------------- //\n //*********************************************************************//\n\n /// @notice Checks the balance of tokens in this contract.\n /// @return The contract's balance.\n function _balance() internal view virtual returns (uint256);\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _decimals The number of decimals the token fixed point amounts are expected to have.\n /// @param _currency The currency that this terminal's token adheres to for price feeds.\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _payoutSplitsGroup The group that denotes payout splits from this terminal in the splits store.\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _prices A contract that exposes price feeds.\n /// @param _store A contract that stores the terminal's data.\n /// @param _owner The address that will own this contract.\n constructor(\n // payable constructor save the gas used to check msg.value==0\n address _token,\n uint256 _decimals,\n uint256 _currency,\n uint256 _baseWeightCurrency,\n uint256 _payoutSplitsGroup,\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBSplitsStore _splitsStore,\n IJBPrices _prices,\n address _store,\n address _owner\n )\n payable\n JBSingleTokenPaymentTerminal(_token, _decimals, _currency)\n JBOperatable(_operatorStore)\n {\n baseWeightCurrency = _baseWeightCurrency;\n payoutSplitsGroup = _payoutSplitsGroup;\n projects = _projects;\n directory = _directory;\n splitsStore = _splitsStore;\n prices = _prices;\n store = _store;\n\n transferOwnership(_owner);\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Contribute tokens to a project.\n /// @param _projectId The ID of the project being paid.\n /// @param _amount The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place.\n /// @param _token The token being paid. This terminal ignores this property since it only manages one token.\n /// @param _beneficiary The address to mint tokens for and pass along to the funding cycle's data source and delegate.\n /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\n /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals.\n function pay(\n uint256 _projectId,\n uint256 _amount,\n address _token,\n address _beneficiary,\n uint256 _minReturnedTokens,\n bool _preferClaimedTokens,\n string calldata _memo,\n bytes calldata _metadata\n ) external payable virtual override isTerminalOf(_projectId) returns (uint256) {\n _token; // Prevents unused var compiler and natspec complaints.\n\n // ETH shouldn't be sent if this terminal's token isn't ETH.\n if (token != JBTokens.ETH) {\n if (msg.value > 0) revert NO_MSG_VALUE_ALLOWED();\n\n // Get a reference to the balance before receiving tokens.\n uint256 _balanceBefore = _balance();\n\n // Transfer tokens to this terminal from the msg sender.\n _transferFrom(msg.sender, payable(address(this)), _amount);\n\n // The amount should reflect the change in balance.\n _amount = _balance() - _balanceBefore;\n }\n // If this terminal's token is ETH, override _amount with msg.value.\n else _amount = msg.value;\n\n return\n _pay(\n _amount,\n msg.sender,\n _projectId,\n _beneficiary,\n _minReturnedTokens,\n _preferClaimedTokens,\n _memo,\n _metadata\n );\n }\n\n /// @notice Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source.\n /// @dev Only a token holder or a designated operator can redeem its tokens.\n /// @param _holder The account to redeem tokens for.\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\n /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals.\n /// @param _token The token being reclaimed. This terminal ignores this property since it only manages one token.\n /// @param _minReturnedTokens The minimum amount of terminal tokens expected in return, as a fixed point number with the same amount of decimals as the terminal.\n /// @param _beneficiary The address to send the terminal tokens to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return reclaimAmount The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals.\n function redeemTokensOf(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n address _token,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo,\n bytes memory _metadata\n )\n external\n virtual\n override\n requirePermission(_holder, _projectId, JBOperations.REDEEM)\n returns (uint256 reclaimAmount)\n {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return\n _redeemTokensOf(\n _holder,\n _projectId,\n _tokenCount,\n _minReturnedTokens,\n _beneficiary,\n _memo,\n _metadata\n );\n }\n\n /// @notice Distributes payouts for a project with the distribution limit of its current funding cycle.\n /// @dev Payouts are sent to the preprogrammed splits. Any leftover is sent to the project's owner.\n /// @dev 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.\n /// @dev All funds distributed outside of this contract or any feeless terminals incure the protocol fee.\n /// @param _projectId The ID of the project having its payouts distributed.\n /// @param _amount The amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency.\n /// @param _token The token being distributed. This terminal ignores this property since it only manages one token.\n /// @param _minReturnedTokens 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.\n /// @param _metadata Bytes to send along to the emitted event, if provided.\n /// @return netLeftoverDistributionAmount The amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal.\n function distributePayoutsOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n address _token,\n uint256 _minReturnedTokens,\n bytes calldata _metadata\n ) external virtual override returns (uint256 netLeftoverDistributionAmount) {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return _distributePayoutsOf(_projectId, _amount, _currency, _minReturnedTokens, _metadata);\n }\n\n /// @notice Only a project's owner or a designated operator can use its allowance.\n /// @dev Incurs the protocol fee.\n /// @param _projectId The ID of the project to use the allowance of.\n /// @param _amount The amount of terminal tokens to use from this project's current allowance, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's overflow allowance currency.\n /// @param _token The token being distributed. This terminal ignores this property since it only manages one token.\n /// @param _minReturnedTokens The minimum number of tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with 18 decimals.\n /// @param _beneficiary The address to send the funds to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the emitted event, if provided.\n /// @return netDistributedAmount The amount of tokens that was distributed to the beneficiary, as a fixed point number with the same amount of decimals as the terminal.\n function useAllowanceOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n address _token,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo,\n bytes calldata _metadata\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.USE_ALLOWANCE)\n returns (uint256 netDistributedAmount)\n {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return\n _useAllowanceOf(\n _projectId,\n _amount,\n _currency,\n _minReturnedTokens,\n _beneficiary,\n _memo,\n _metadata\n );\n }\n\n /// @notice Allows a project owner to migrate its funds and operations to a new terminal that accepts the same token type.\n /// @dev Only a project's owner or a designated operator can migrate it.\n /// @param _projectId The ID of the project being migrated.\n /// @param _to The terminal contract that will gain the project's funds.\n /// @return balance The amount of funds that were migrated, as a fixed point number with the same amount of decimals as this terminal.\n function migrate(\n uint256 _projectId,\n IJBPaymentTerminal _to\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.MIGRATE_TERMINAL)\n returns (uint256 balance)\n {\n // The terminal being migrated to must accept the same token as this terminal.\n if (!_to.acceptsToken(token, _projectId)) revert TERMINAL_TOKENS_INCOMPATIBLE();\n\n // Record the migration in the store.\n balance = IJBSingleTokenPaymentTerminalStore(store).recordMigration(_projectId);\n\n // Transfer the balance if needed.\n if (balance > 0) {\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_to), balance);\n\n // If this terminal's token is ETH, send it in msg.value.\n uint256 _payableValue = token == JBTokens.ETH ? balance : 0;\n\n // Withdraw the balance to transfer to the new terminal;\n _to.addToBalanceOf{value: _payableValue}(_projectId, balance, token, '', bytes(''));\n }\n\n emit Migrate(_projectId, _to, balance, msg.sender);\n }\n\n /// @notice Receives funds belonging to the specified project.\n /// @param _projectId The ID of the project to which the funds received belong.\n /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\n /// @param _token The token being paid. This terminal ignores this property since it only manages one currency.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the emitted event.\n function addToBalanceOf(\n uint256 _projectId,\n uint256 _amount,\n address _token,\n string calldata _memo,\n bytes calldata _metadata\n ) external payable virtual override isTerminalOf(_projectId) {\n // Do not refund held fees by default.\n addToBalanceOf(_projectId, _amount, _token, false, _memo, _metadata);\n }\n\n /// @notice Process any fees that are being held for the project.\n /// @dev Only a project owner, an operator, or the contract's owner can process held fees.\n /// @param _projectId The ID of the project whos held fees should be processed.\n function processFees(\n uint256 _projectId\n )\n external\n virtual\n override\n requirePermissionAllowingOverride(\n projects.ownerOf(_projectId),\n _projectId,\n JBOperations.PROCESS_FEES,\n msg.sender == owner()\n )\n {\n // Get a reference to the project's held fees.\n JBFee[] memory _heldFees = _heldFeesOf[_projectId];\n\n // Delete the held fees.\n delete _heldFeesOf[_projectId];\n\n // Push array length in stack\n uint256 _heldFeeLength = _heldFees.length;\n\n // Process each fee.\n for (uint256 _i; _i < _heldFeeLength; ) {\n // Get the fee amount.\n uint256 _amount = _feeAmount(\n _heldFees[_i].amount,\n _heldFees[_i].fee,\n _heldFees[_i].feeDiscount\n );\n\n // Process the fee.\n _processFee(_amount, _heldFees[_i].beneficiary, _projectId);\n\n emit ProcessFee(_projectId, _amount, true, _heldFees[_i].beneficiary, msg.sender);\n\n unchecked {\n ++_i;\n }\n }\n }\n\n /// @notice Allows the fee to be updated.\n /// @dev Only the owner of this contract can change the fee.\n /// @param _fee The new fee, out of MAX_FEE.\n function setFee(uint256 _fee) external virtual override onlyOwner {\n // The provided fee must be within the max.\n if (_fee > _FEE_CAP) revert FEE_TOO_HIGH();\n\n // Store the new fee.\n fee = _fee;\n\n emit SetFee(_fee, msg.sender);\n }\n\n /// @notice Allows the fee gauge to be updated.\n /// @dev Only the owner of this contract can change the fee gauge.\n /// @param _feeGauge The new fee gauge.\n function setFeeGauge(address _feeGauge) external virtual override onlyOwner {\n // Store the new fee gauge.\n feeGauge = _feeGauge;\n\n emit SetFeeGauge(_feeGauge, msg.sender);\n }\n\n /// @notice Sets whether projects operating on this terminal can pay towards the specified address without incurring a fee.\n /// @param _address The address that can be paid towards while still bypassing fees.\n /// @param _flag A flag indicating whether the terminal should be feeless or not.\n function setFeelessAddress(address _address, bool _flag) external virtual override onlyOwner {\n // Set the flag value.\n isFeelessAddress[_address] = _flag;\n\n emit SetFeelessAddress(_address, _flag, msg.sender);\n }\n\n //*********************************************************************//\n // ----------------------- public transactions ----------------------- //\n //*********************************************************************//\n\n /// @notice Receives funds belonging to the specified project.\n /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\n /// @param _token The token being paid. This terminal ignores this property since it only manages one currency.\n /// @param _shouldRefundHeldFees A flag indicating if held fees should be refunded based on the amount being added.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the emitted event.\n function addToBalanceOf(\n uint256 _projectId,\n uint256 _amount,\n address _token,\n bool _shouldRefundHeldFees,\n string calldata _memo,\n bytes calldata _metadata\n ) public payable virtual override isTerminalOf(_projectId) {\n _token; // Prevents unused var compiler and natspec complaints.\n\n // If this terminal's token isn't ETH, make sure no msg.value was sent, then transfer the tokens in from msg.sender.\n if (token != JBTokens.ETH) {\n // Amount must be greater than 0.\n if (msg.value > 0) revert NO_MSG_VALUE_ALLOWED();\n\n // Get a reference to the balance before receiving tokens.\n uint256 _balanceBefore = _balance();\n\n // Transfer tokens to this terminal from the msg sender.\n _transferFrom(msg.sender, payable(address(this)), _amount);\n\n // The amount should reflect the change in balance.\n _amount = _balance() - _balanceBefore;\n }\n // If the terminal's token is ETH, override `_amount` with msg.value.\n else _amount = msg.value;\n\n // Add to balance.\n _addToBalanceOf(_projectId, _amount, _shouldRefundHeldFees, _memo, _metadata);\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Transfers tokens.\n /// @param _from The address from which the transfer should originate.\n /// @param _to The address to which the transfer should go.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _transferFrom(address _from, address payable _to, uint256 _amount) internal virtual {\n _from; // Prevents unused var compiler and natspec complaints.\n _to; // Prevents unused var compiler and natspec complaints.\n _amount; // Prevents unused var compiler and natspec complaints.\n }\n\n /// @notice Logic to be triggered before transferring tokens from this terminal.\n /// @param _to The address to which the transfer is going.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _beforeTransferTo(address _to, uint256 _amount) internal virtual {\n _to; // Prevents unused var compiler and natspec complaints.\n _amount; // Prevents unused var compiler and natspec complaints.\n }\n\n /// @notice Logic to be triggered if a transfer should be undone\n /// @param _to The address to which the transfer went.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _cancelTransferTo(address _to, uint256 _amount) internal virtual {\n _to; // Prevents unused var compiler and natspec complaints.\n _amount; // Prevents unused var compiler and natspec complaints.\n }\n\n /// @notice Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source.\n /// @dev Only a token holder or a designated operator can redeem its tokens.\n /// @param _holder The account to redeem tokens for.\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\n /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals.\n /// @param _minReturnedTokens The minimum amount of terminal tokens expected in return, as a fixed point number with the same amount of decimals as the terminal.\n /// @param _beneficiary The address to send the terminal tokens to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return reclaimAmount The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals.\n function _redeemTokensOf(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo,\n bytes memory _metadata\n ) internal returns (uint256 reclaimAmount) {\n // Can't send reclaimed funds to the zero address.\n if (_beneficiary == address(0)) revert REDEEM_TO_ZERO_ADDRESS();\n\n // Define variables that will be needed outside the scoped section below.\n // Keep a reference to the funding cycle during which the redemption is being made.\n JBFundingCycle memory _fundingCycle;\n\n // Scoped section prevents stack too deep. `_delegateAllocations` only used within scope.\n {\n JBRedemptionDelegateAllocation[] memory _delegateAllocations;\n\n // Record the redemption.\n (\n _fundingCycle,\n reclaimAmount,\n _delegateAllocations,\n _memo\n ) = IJBSingleTokenPaymentTerminalStore(store).recordRedemptionFor(\n _holder,\n _projectId,\n _tokenCount,\n _memo,\n _metadata\n );\n\n // The amount being reclaimed must be at least as much as was expected.\n if (reclaimAmount < _minReturnedTokens) revert INADEQUATE_RECLAIM_AMOUNT();\n\n // Burn the project tokens.\n if (_tokenCount > 0)\n IJBController(directory.controllerOf(_projectId)).burnTokensOf(\n _holder,\n _projectId,\n _tokenCount,\n '',\n false\n );\n\n // If delegate allocations were specified by the data source, fulfill them.\n if (_delegateAllocations.length != 0) {\n // Keep a reference to the token amount being forwarded to the delegate.\n JBTokenAmount memory _forwardedAmount = JBTokenAmount(token, 0, decimals, currency);\n\n JBDidRedeemData memory _data = JBDidRedeemData(\n _holder,\n _projectId,\n _fundingCycle.configuration,\n _tokenCount,\n JBTokenAmount(token, reclaimAmount, decimals, currency),\n _forwardedAmount,\n _beneficiary,\n _memo,\n _metadata\n );\n\n uint256 _numDelegates = _delegateAllocations.length;\n\n for (uint256 _i; _i < _numDelegates; ) {\n // Get a reference to the delegate being iterated on.\n JBRedemptionDelegateAllocation memory _delegateAllocation = _delegateAllocations[_i];\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_delegateAllocation.delegate), _delegateAllocation.amount);\n\n // Keep track of the msg.value to use in the delegate call\n uint256 _payableValue;\n\n // If this terminal's token is ETH, send it in msg.value.\n if (token == JBTokens.ETH) _payableValue = _delegateAllocation.amount;\n\n // Pass the correct token forwardedAmount to the delegate\n _data.forwardedAmount.value = _delegateAllocation.amount;\n\n _delegateAllocation.delegate.didRedeem{value: _payableValue}(_data);\n\n emit DelegateDidRedeem(\n _delegateAllocation.delegate,\n _data,\n _delegateAllocation.amount,\n msg.sender\n );\n unchecked {\n ++_i;\n }\n }\n }\n }\n\n // Send the reclaimed funds to the beneficiary.\n if (reclaimAmount > 0) _transferFrom(address(this), _beneficiary, reclaimAmount);\n\n emit RedeemTokens(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _holder,\n _beneficiary,\n _tokenCount,\n reclaimAmount,\n _memo,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Distributes payouts for a project with the distribution limit of its current funding cycle.\n /// @dev Payouts are sent to the preprogrammed splits. Any leftover is sent to the project's owner.\n /// @dev 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.\n /// @dev All funds distributed outside of this contract or any feeless terminals incure the protocol fee.\n /// @param _projectId The ID of the project having its payouts distributed.\n /// @param _amount The amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency.\n /// @param _minReturnedTokens 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.\n /// @param _metadata Bytes to send along to the emitted event, if provided.\n /// @return netLeftoverDistributionAmount The amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal.\n function _distributePayoutsOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n uint256 _minReturnedTokens,\n bytes calldata _metadata\n ) internal returns (uint256 netLeftoverDistributionAmount) {\n // Record the distribution.\n (\n JBFundingCycle memory _fundingCycle,\n uint256 _distributedAmount\n ) = IJBSingleTokenPaymentTerminalStore(store).recordDistributionFor(\n _projectId,\n _amount,\n _currency\n );\n\n // The amount being distributed must be at least as much as was expected.\n if (_distributedAmount < _minReturnedTokens) revert INADEQUATE_DISTRIBUTION_AMOUNT();\n\n // Get a reference to the project owner, which will receive tokens from paying the platform fee\n // and receive any extra distributable funds not allocated to payout splits.\n address payable _projectOwner = payable(projects.ownerOf(_projectId));\n\n // Define variables that will be needed outside the scoped section below.\n // Keep a reference to the fee amount that was paid.\n uint256 _fee;\n\n // Scoped section prevents stack too deep. `_feeDiscount`, `_feeEligibleDistributionAmount`, and `_leftoverDistributionAmount` only used within scope.\n {\n // Get the amount of discount that should be applied to any fees taken.\n // If the fee is zero, set the discount to 100% for convenience.\n uint256 _feeDiscount = fee == 0\n ? JBConstants.MAX_FEE_DISCOUNT\n : _currentFeeDiscount(_projectId);\n\n // The amount distributed that is eligible for incurring fees.\n uint256 _feeEligibleDistributionAmount;\n\n // The amount leftover after distributing to the splits.\n uint256 _leftoverDistributionAmount;\n\n // Payout to splits and get a reference to the leftover transfer amount after all splits have been paid.\n // Also get a reference to the amount that was distributed to splits from which fees should be taken.\n (_leftoverDistributionAmount, _feeEligibleDistributionAmount) = _distributeToPayoutSplitsOf(\n _projectId,\n _fundingCycle.configuration,\n payoutSplitsGroup,\n _distributedAmount,\n _feeDiscount\n );\n\n if (_feeDiscount != JBConstants.MAX_FEE_DISCOUNT) {\n // Leftover distribution amount is also eligible for a fee since the funds are going out of the ecosystem to _beneficiary.\n unchecked {\n _feeEligibleDistributionAmount += _leftoverDistributionAmount;\n }\n }\n\n // Take the fee.\n _fee = _feeEligibleDistributionAmount != 0\n ? _takeFeeFrom(\n _projectId,\n _fundingCycle,\n _feeEligibleDistributionAmount,\n _projectOwner,\n _feeDiscount\n )\n : 0;\n\n // Transfer any remaining balance to the project owner and update returned leftover accordingly.\n if (_leftoverDistributionAmount != 0) {\n // Subtract the fee from the net leftover amount.\n netLeftoverDistributionAmount =\n _leftoverDistributionAmount -\n _feeAmount(_leftoverDistributionAmount, fee, _feeDiscount);\n\n // Transfer the amount to the project owner.\n _transferFrom(address(this), _projectOwner, netLeftoverDistributionAmount);\n }\n }\n\n emit DistributePayouts(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _projectOwner,\n _amount,\n _distributedAmount,\n _fee,\n netLeftoverDistributionAmount,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Allows a project to send funds from its overflow up to the preconfigured allowance.\n /// @dev Only a project's owner or a designated operator can use its allowance.\n /// @dev Incurs the protocol fee.\n /// @param _projectId The ID of the project to use the allowance of.\n /// @param _amount The amount of terminal tokens to use from this project's current allowance, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's overflow allowance currency.\n /// @param _minReturnedTokens The minimum number of tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with 18 decimals.\n /// @param _beneficiary The address to send the funds to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the emitted event, if provided.\n /// @return netDistributedAmount The amount of tokens that was distributed to the beneficiary, as a fixed point number with the same amount of decimals as the terminal.\n function _useAllowanceOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo,\n bytes calldata _metadata\n ) internal returns (uint256 netDistributedAmount) {\n // Record the use of the allowance.\n (\n JBFundingCycle memory _fundingCycle,\n uint256 _distributedAmount\n ) = IJBSingleTokenPaymentTerminalStore(store).recordUsedAllowanceOf(\n _projectId,\n _amount,\n _currency\n );\n\n // The amount being withdrawn must be at least as much as was expected.\n if (_distributedAmount < _minReturnedTokens) revert INADEQUATE_DISTRIBUTION_AMOUNT();\n\n // Scoped section prevents stack too deep. `_fee`, `_projectOwner`, `_feeDiscount`, and `_netAmount` only used within scope.\n {\n // Keep a reference to the fee amount that was paid.\n uint256 _fee;\n\n // Get a reference to the project owner, which will receive tokens from paying the platform fee.\n address _projectOwner = projects.ownerOf(_projectId);\n\n // Get the amount of discount that should be applied to any fees taken.\n // 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.\n uint256 _feeDiscount = fee == 0 || isFeelessAddress[msg.sender]\n ? JBConstants.MAX_FEE_DISCOUNT\n : _currentFeeDiscount(_projectId);\n\n // Take a fee from the `_distributedAmount`, if needed.\n _fee = _feeDiscount == JBConstants.MAX_FEE_DISCOUNT\n ? 0\n : _takeFeeFrom(_projectId, _fundingCycle, _distributedAmount, _projectOwner, _feeDiscount);\n\n unchecked {\n // The net amount is the withdrawn amount without the fee.\n netDistributedAmount = _distributedAmount - _fee;\n }\n\n // Transfer any remaining balance to the beneficiary.\n if (netDistributedAmount > 0)\n _transferFrom(address(this), _beneficiary, netDistributedAmount);\n }\n\n emit UseAllowance(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _beneficiary,\n _amount,\n _distributedAmount,\n netDistributedAmount,\n _memo,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Pays out splits for a project's funding cycle configuration.\n /// @param _projectId The ID of the project for which payout splits are being distributed.\n /// @param _domain The domain of the splits to distribute the payout between.\n /// @param _group The group of the splits to distribute the payout between.\n /// @param _amount The total amount being distributed, as a fixed point number with the same number of decimals as this terminal.\n /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE.\n /// @return leftoverAmount If the leftover amount if the splits don't add up to 100%.\n /// @return feeEligibleDistributionAmount The total amount of distributions that are eligible to have fees taken from.\n function _distributeToPayoutSplitsOf(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group,\n uint256 _amount,\n uint256 _feeDiscount\n ) internal returns (uint256 leftoverAmount, uint256 feeEligibleDistributionAmount) {\n // Set the leftover amount to the initial amount.\n leftoverAmount = _amount;\n // The total percentage available to split\n uint256 leftoverPercentage = JBConstants.SPLITS_TOTAL_PERCENT;\n\n // Get a reference to the project's payout splits.\n JBSplit[] memory _splits = splitsStore.splitsOf(_projectId, _domain, _group);\n\n // Transfer between all splits.\n for (uint256 _i; _i < _splits.length; ) {\n // Get a reference to the split being iterated on.\n JBSplit memory _split = _splits[_i];\n\n // The amount to send towards the split.\n uint256 _payoutAmount = _split.percent == leftoverPercentage\n ? leftoverAmount\n : PRBMath.mulDiv(_amount, _split.percent, JBConstants.SPLITS_TOTAL_PERCENT);\n\n // Decrement the leftover percentage.\n leftoverPercentage -= _split.percent;\n\n // The payout amount substracting any applicable incurred fees.\n uint256 _netPayoutAmount = _distributeToPayoutSplit(\n _split,\n _projectId,\n _group,\n _payoutAmount,\n _feeDiscount\n );\n\n // If the split allocator is set as feeless, this distribution is not eligible for a fee.\n if (_netPayoutAmount != 0 && _netPayoutAmount != _payoutAmount)\n feeEligibleDistributionAmount += _payoutAmount;\n\n if (_payoutAmount > 0) {\n // Subtract from the amount to be sent to the beneficiary.\n unchecked {\n leftoverAmount = leftoverAmount - _payoutAmount;\n }\n }\n\n emit DistributeToPayoutSplit(\n _projectId,\n _domain,\n _group,\n _split,\n _payoutAmount,\n _netPayoutAmount,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n\n /// @notice Pays out a split for a project's funding cycle configuration.\n /// @param _split The split to distribute payouts to.\n /// @param _amount The total amount being distributed to the split, as a fixed point number with the same number of decimals as this terminal.\n /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE.\n /// @return netPayoutAmount The amount sent to the split after subtracting fees.\n function _distributeToPayoutSplit(\n JBSplit memory _split,\n uint256 _projectId,\n uint256 _group,\n uint256 _amount,\n uint256 _feeDiscount\n ) internal returns (uint256 netPayoutAmount) {\n // If there's an allocator set, transfer to its `allocate` function.\n if (_split.allocator != IJBSplitAllocator(address(0))) {\n // If the split allocator is set as feeless, this distribution is not eligible for a fee.\n if (\n _feeDiscount == JBConstants.MAX_FEE_DISCOUNT || isFeelessAddress[address(_split.allocator)]\n )\n netPayoutAmount = _amount;\n // This distribution is eligible for a fee since the funds are leaving this contract and the allocator isn't listed as feeless.\n else {\n unchecked {\n netPayoutAmount = _amount - _feeAmount(_amount, fee, _feeDiscount);\n }\n }\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_split.allocator), netPayoutAmount);\n\n // Create the data to send to the allocator.\n JBSplitAllocationData memory _data = JBSplitAllocationData(\n token,\n netPayoutAmount,\n decimals,\n _projectId,\n _group,\n _split\n );\n\n // Trigger the allocator's `allocate` function.\n uint256 _error;\n bytes memory _reason;\n\n if (\n ERC165Checker.supportsInterface(\n address(_split.allocator),\n type(IJBSplitAllocator).interfaceId\n )\n )\n // If this terminal's token is ETH, send it in msg.value.\n try\n _split.allocator.allocate{value: token == JBTokens.ETH ? netPayoutAmount : 0}(_data)\n {} catch (bytes memory reason) {\n _reason = reason;\n _error = 1;\n }\n else _error = 2;\n\n if (_error != 0) {\n // Trigger any inhereted post-transfer cancelation logic.\n _cancelTransferTo(address(_split.allocator), netPayoutAmount);\n\n // Set the net payout amount to 0 to signal the reversion.\n netPayoutAmount = 0;\n\n // Add undistributed amount back to project's balance.\n IJBSingleTokenPaymentTerminalStore(store).recordAddedBalanceFor(_projectId, _amount);\n\n emit PayoutReverted(\n _projectId,\n _split,\n _amount,\n _error == 1 ? _reason : abi.encode('IERC165 fail'),\n msg.sender\n );\n }\n\n // Otherwise, if a project is specified, make a payment to it.\n } else if (_split.projectId != 0) {\n // Get a reference to the Juicebox terminal being used.\n IJBPaymentTerminal _terminal = directory.primaryTerminalOf(_split.projectId, token);\n\n // The project must have a terminal to send funds to.\n if (_terminal == IJBPaymentTerminal(address(0))) revert TERMINAL_IN_SPLIT_ZERO_ADDRESS();\n\n // If the terminal is set as feeless, this distribution is not eligible for a fee.\n if (\n _terminal == this ||\n _feeDiscount == JBConstants.MAX_FEE_DISCOUNT ||\n isFeelessAddress[address(_terminal)]\n )\n netPayoutAmount = _amount;\n // This distribution is eligible for a fee since the funds are leaving this contract and the terminal isn't listed as feeless.\n else {\n unchecked {\n netPayoutAmount = _amount - _feeAmount(_amount, fee, _feeDiscount);\n }\n }\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_terminal), netPayoutAmount);\n\n // Send the projectId in the metadata.\n bytes memory _projectMetadata = new bytes(32);\n _projectMetadata = bytes(abi.encodePacked(_projectId));\n\n // Add to balance if prefered.\n if (_split.preferAddToBalance)\n try\n _terminal.addToBalanceOf{value: token == JBTokens.ETH ? netPayoutAmount : 0}(\n _split.projectId,\n netPayoutAmount,\n token,\n '',\n _projectMetadata\n )\n {} catch (bytes memory reason) {\n // Trigger any inhereted post-transfer cancelation logic.\n _cancelTransferTo(address(_terminal), netPayoutAmount);\n\n // Set the net payout amount to 0 to signal the reversion.\n netPayoutAmount = 0;\n\n // Add undistributed amount back to project's balance.\n IJBSingleTokenPaymentTerminalStore(store).recordAddedBalanceFor(_projectId, _amount);\n\n emit PayoutReverted(_projectId, _split, _amount, reason, msg.sender);\n }\n else\n try\n _terminal.pay{value: token == JBTokens.ETH ? netPayoutAmount : 0}(\n _split.projectId,\n netPayoutAmount,\n token,\n _split.beneficiary != address(0) ? _split.beneficiary : msg.sender,\n 0,\n _split.preferClaimed,\n '',\n _projectMetadata\n )\n {} catch (bytes memory reason) {\n // Trigger any inhereted post-transfer cancelation logic.\n _cancelTransferTo(address(_terminal), netPayoutAmount);\n\n // Set the net payout amount to 0 to signal the reversion.\n netPayoutAmount = 0;\n\n // Add undistributed amount back to project's balance.\n IJBSingleTokenPaymentTerminalStore(store).recordAddedBalanceFor(_projectId, _amount);\n\n emit PayoutReverted(_projectId, _split, _amount, reason, msg.sender);\n }\n } else {\n // Keep a reference to the beneficiary.\n address payable _beneficiary = _split.beneficiary != address(0)\n ? _split.beneficiary\n : payable(msg.sender);\n\n // If there's a full discount, this distribution is not eligible for a fee.\n // Don't enforce feeless address for the beneficiary since the funds are leaving the ecosystem.\n if (_feeDiscount == JBConstants.MAX_FEE_DISCOUNT)\n netPayoutAmount = _amount;\n // This distribution is eligible for a fee since the funds are leaving this contract and the beneficiary isn't listed as feeless.\n else {\n unchecked {\n netPayoutAmount = _amount - _feeAmount(_amount, fee, _feeDiscount);\n }\n }\n\n // If there's a beneficiary, send the funds directly to the beneficiary. Otherwise send to the msg.sender.\n _transferFrom(address(this), _beneficiary, netPayoutAmount);\n }\n }\n\n /// @notice Takes a fee into the platform's project, which has an id of _FEE_BENEFICIARY_PROJECT_ID.\n /// @param _projectId The ID of the project having fees taken from.\n /// @param _fundingCycle The funding cycle during which the fee is being taken.\n /// @param _amount The amount of the fee to take, as a floating point number with 18 decimals.\n /// @param _beneficiary The address to mint the platforms tokens for.\n /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE.\n /// @return feeAmount The amount of the fee taken.\n function _takeFeeFrom(\n uint256 _projectId,\n JBFundingCycle memory _fundingCycle,\n uint256 _amount,\n address _beneficiary,\n uint256 _feeDiscount\n ) internal returns (uint256 feeAmount) {\n feeAmount = _feeAmount(_amount, fee, _feeDiscount);\n\n if (_fundingCycle.shouldHoldFees()) {\n // Store the held fee.\n _heldFeesOf[_projectId].push(JBFee(_amount, uint32(fee), uint32(_feeDiscount), _beneficiary));\n\n emit HoldFee(_projectId, _amount, fee, _feeDiscount, _beneficiary, msg.sender);\n } else {\n // Process the fee.\n _processFee(feeAmount, _beneficiary, _projectId); // Take the fee.\n\n emit ProcessFee(_projectId, feeAmount, false, _beneficiary, msg.sender);\n }\n }\n\n /// @notice Process a fee of the specified amount.\n /// @param _amount The fee amount, as a floating point number with 18 decimals.\n /// @param _beneficiary The address to mint the platform's tokens for.\n /// @param _from The project ID the fee is being paid from.\n function _processFee(uint256 _amount, address _beneficiary, uint256 _from) internal {\n // Get the terminal for the protocol project.\n IJBPaymentTerminal _terminal = directory.primaryTerminalOf(_FEE_BENEFICIARY_PROJECT_ID, token);\n\n // If this terminal's token is ETH, send it in msg.value.\n uint256 _payableValue = token == JBTokens.ETH ? _amount : 0;\n\n // Send the projectId in the metadata.\n bytes memory _projectMetadata = new bytes(32);\n _projectMetadata = bytes(abi.encodePacked(_from));\n\n // Trigger any inherited pre-transfer logic if funds will be transferred.\n if (address(_terminal) != address(this)) _beforeTransferTo(address(_terminal), _amount);\n\n try\n // Send the fee.\n _terminal.pay{value: _payableValue}(\n _FEE_BENEFICIARY_PROJECT_ID,\n _amount,\n token,\n _beneficiary,\n 0,\n false,\n '',\n _projectMetadata\n )\n {} catch (bytes memory reason) {\n // Trigger any inhereted post-transfer cancelation logic if the pre-transfer logic was triggered.\n if (address(_terminal) != address(this)) _cancelTransferTo(address(_terminal), _amount);\n\n // Add fee amount back to project's balance.\n IJBSingleTokenPaymentTerminalStore(store).recordAddedBalanceFor(_from, _amount);\n\n emit FeeReverted(_from, _FEE_BENEFICIARY_PROJECT_ID, _amount, reason, msg.sender);\n }\n }\n\n /// @notice Contribute tokens to a project.\n /// @param _amount The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place.\n /// @param _payer The address making the payment.\n /// @param _projectId The ID of the project being paid.\n /// @param _beneficiary The address to mint tokens for and pass along to the funding cycle's data source and delegate.\n /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\n /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return beneficiaryTokenCount The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals.\n function _pay(\n uint256 _amount,\n address _payer,\n uint256 _projectId,\n address _beneficiary,\n uint256 _minReturnedTokens,\n bool _preferClaimedTokens,\n string memory _memo,\n bytes memory _metadata\n ) internal returns (uint256 beneficiaryTokenCount) {\n // Cant send tokens to the zero address.\n if (_beneficiary == address(0)) revert PAY_TO_ZERO_ADDRESS();\n\n // Define variables that will be needed outside the scoped section below.\n // Keep a reference to the funding cycle during which the payment is being made.\n JBFundingCycle memory _fundingCycle;\n\n // Scoped section prevents stack too deep. `_delegateAllocations` and `_tokenCount` only used within scope.\n {\n JBPayDelegateAllocation[] memory _delegateAllocations;\n uint256 _tokenCount;\n\n // Bundle the amount info into a JBTokenAmount struct.\n JBTokenAmount memory _bundledAmount = JBTokenAmount(token, _amount, decimals, currency);\n\n // Record the payment.\n (\n _fundingCycle,\n _tokenCount,\n _delegateAllocations,\n _memo\n ) = IJBSingleTokenPaymentTerminalStore(store).recordPaymentFrom(\n _payer,\n _bundledAmount,\n _projectId,\n baseWeightCurrency,\n _beneficiary,\n _memo,\n _metadata\n );\n\n // Mint the tokens if needed.\n if (_tokenCount > 0)\n // Set token count to be the number of tokens minted for the beneficiary instead of the total amount.\n beneficiaryTokenCount = IJBController(directory.controllerOf(_projectId)).mintTokensOf(\n _projectId,\n _tokenCount,\n _beneficiary,\n '',\n _preferClaimedTokens,\n true\n );\n\n // The token count for the beneficiary must be greater than or equal to the minimum expected.\n if (beneficiaryTokenCount < _minReturnedTokens) revert INADEQUATE_TOKEN_COUNT();\n\n // If delegate allocations were specified by the data source, fulfill them.\n if (_delegateAllocations.length != 0) {\n // Keep a reference to the token amount being forwarded to the delegate.\n JBTokenAmount memory _forwardedAmount = JBTokenAmount(token, _amount, decimals, currency);\n\n JBDidPayData memory _data = JBDidPayData(\n _payer,\n _projectId,\n _fundingCycle.configuration,\n _bundledAmount,\n _forwardedAmount,\n beneficiaryTokenCount,\n _beneficiary,\n _preferClaimedTokens,\n _memo,\n _metadata\n );\n\n // Get a reference to the number of delegates to allocate to.\n uint256 _numDelegates = _delegateAllocations.length;\n\n for (uint256 _i; _i < _numDelegates; ) {\n // Get a reference to the delegate being iterated on.\n JBPayDelegateAllocation memory _delegateAllocation = _delegateAllocations[_i];\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_delegateAllocation.delegate), _delegateAllocation.amount);\n\n // Keep track of the msg.value to use in the delegate call\n uint256 _payableValue;\n\n // If this terminal's token is ETH, send it in msg.value.\n if (token == JBTokens.ETH) _payableValue = _delegateAllocation.amount;\n\n // Pass the correct token forwardedAmount to the delegate\n _data.forwardedAmount.value = _delegateAllocation.amount;\n\n _delegateAllocation.delegate.didPay{value: _payableValue}(_data);\n\n emit DelegateDidPay(\n _delegateAllocation.delegate,\n _data,\n _delegateAllocation.amount,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n }\n\n emit Pay(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _payer,\n _beneficiary,\n _amount,\n beneficiaryTokenCount,\n _memo,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Receives funds belonging to the specified project.\n /// @param _projectId The ID of the project to which the funds received belong.\n /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\n /// @param _shouldRefundHeldFees A flag indicating if held fees should be refunded based on the amount being added.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the emitted event.\n function _addToBalanceOf(\n uint256 _projectId,\n uint256 _amount,\n bool _shouldRefundHeldFees,\n string memory _memo,\n bytes memory _metadata\n ) internal {\n // Refund any held fees to make sure the project doesn't pay double for funds going in and out of the protocol.\n uint256 _refundedFees = _shouldRefundHeldFees ? _refundHeldFees(_projectId, _amount) : 0;\n\n // Record the added funds with any refunded fees.\n IJBSingleTokenPaymentTerminalStore(store).recordAddedBalanceFor(\n _projectId,\n _amount + _refundedFees\n );\n\n emit AddToBalance(_projectId, _amount, _refundedFees, _memo, _metadata, msg.sender);\n }\n\n /// @notice Refund fees based on the specified amount.\n /// @param _projectId The project for which fees are being refunded.\n /// @param _amount The amount to base the refund on, as a fixed point number with the same amount of decimals as this terminal.\n /// @return refundedFees How much fees were refunded, as a fixed point number with the same number of decimals as this terminal\n function _refundHeldFees(\n uint256 _projectId,\n uint256 _amount\n ) internal returns (uint256 refundedFees) {\n // Get a reference to the project's held fees.\n JBFee[] memory _heldFees = _heldFeesOf[_projectId];\n\n // Delete the current held fees.\n delete _heldFeesOf[_projectId];\n\n // Get a reference to the leftover amount once all fees have been settled.\n uint256 leftoverAmount = _amount;\n\n // Push length in stack\n uint256 _heldFeesLength = _heldFees.length;\n\n // Process each fee.\n for (uint256 _i; _i < _heldFeesLength; ) {\n if (leftoverAmount == 0) _heldFeesOf[_projectId].push(_heldFees[_i]);\n else if (leftoverAmount >= _heldFees[_i].amount) {\n unchecked {\n leftoverAmount = leftoverAmount - _heldFees[_i].amount;\n refundedFees += _feeAmount(\n _heldFees[_i].amount,\n _heldFees[_i].fee,\n _heldFees[_i].feeDiscount\n );\n }\n } else {\n unchecked {\n _heldFeesOf[_projectId].push(\n JBFee(\n _heldFees[_i].amount - leftoverAmount,\n _heldFees[_i].fee,\n _heldFees[_i].feeDiscount,\n _heldFees[_i].beneficiary\n )\n );\n refundedFees += _feeAmount(leftoverAmount, _heldFees[_i].fee, _heldFees[_i].feeDiscount);\n }\n leftoverAmount = 0;\n }\n\n unchecked {\n ++_i;\n }\n }\n\n emit RefundHeldFees(_projectId, _amount, refundedFees, leftoverAmount, msg.sender);\n }\n\n /// @notice Returns the fee amount based on the provided amount for the specified project.\n /// @param _amount The amount that the fee is based on, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _fee The percentage of the fee, out of MAX_FEE.\n /// @param _feeDiscount The percentage discount that should be applied out of the max amount, out of MAX_FEE_DISCOUNT.\n /// @return The amount of the fee, as a fixed point number with the same amount of decimals as this terminal.\n function _feeAmount(\n uint256 _amount,\n uint256 _fee,\n uint256 _feeDiscount\n ) internal pure returns (uint256) {\n // Calculate the discounted fee.\n uint256 _discountedFee = _fee -\n PRBMath.mulDiv(_fee, _feeDiscount, JBConstants.MAX_FEE_DISCOUNT);\n\n // The amount of tokens from the `_amount` to pay as a fee.\n return\n _amount - PRBMath.mulDiv(_amount, JBConstants.MAX_FEE, _discountedFee + JBConstants.MAX_FEE);\n }\n\n /// @notice Get the fee discount from the fee gauge for the specified project.\n /// @param _projectId The ID of the project to get a fee discount for.\n /// @return feeDiscount The fee discount, which should be interpreted as a percentage out MAX_FEE_DISCOUNT.\n function _currentFeeDiscount(uint256 _projectId) internal view returns (uint256) {\n // Can't take a fee if the protocol project doesn't have a terminal that accepts the token.\n if (\n directory.primaryTerminalOf(_FEE_BENEFICIARY_PROJECT_ID, token) ==\n IJBPaymentTerminal(address(0))\n ) return JBConstants.MAX_FEE_DISCOUNT;\n\n // Get the fee discount.\n if (feeGauge != address(0))\n // If the guage reverts, keep the discount at 0.\n try IJBFeeGauge(feeGauge).currentDiscountFor(_projectId) returns (uint256 discount) {\n // If the fee discount is greater than the max, we ignore the return value\n if (discount <= JBConstants.MAX_FEE_DISCOUNT) return discount;\n } catch {\n return 0;\n }\n\n return 0;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165Checker.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC165.sol\";\n\n/**\n * @dev Library used to query support of an interface declared via {IERC165}.\n *\n * Note that these functions return the actual result of the query: they do not\n * `revert` if an interface is not supported. It is up to the caller to decide\n * what to do in these cases.\n */\nlibrary ERC165Checker {\n // As per the EIP-165 spec, no interface should ever match 0xffffffff\n bytes4 private constant _INTERFACE_ID_INVALID = 0xffffffff;\n\n /**\n * @dev Returns true if `account` supports the {IERC165} interface,\n */\n function supportsERC165(address account) internal view returns (bool) {\n // Any contract that implements ERC165 must explicitly indicate support of\n // InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid\n return\n _supportsERC165Interface(account, type(IERC165).interfaceId) &&\n !_supportsERC165Interface(account, _INTERFACE_ID_INVALID);\n }\n\n /**\n * @dev Returns true if `account` supports the interface defined by\n * `interfaceId`. Support for {IERC165} itself is queried automatically.\n *\n * See {IERC165-supportsInterface}.\n */\n function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) {\n // query support of both ERC165 as per the spec and support of _interfaceId\n return supportsERC165(account) && _supportsERC165Interface(account, interfaceId);\n }\n\n /**\n * @dev Returns a boolean array where each value corresponds to the\n * interfaces passed in and whether they're supported or not. This allows\n * you to batch check interfaces for a contract where your expectation\n * is that some interfaces may not be supported.\n *\n * See {IERC165-supportsInterface}.\n *\n * _Available since v3.4._\n */\n function getSupportedInterfaces(address account, bytes4[] memory interfaceIds)\n internal\n view\n returns (bool[] memory)\n {\n // an array of booleans corresponding to interfaceIds and whether they're supported or not\n bool[] memory interfaceIdsSupported = new bool[](interfaceIds.length);\n\n // query support of ERC165 itself\n if (supportsERC165(account)) {\n // query support of each interface in interfaceIds\n for (uint256 i = 0; i < interfaceIds.length; i++) {\n interfaceIdsSupported[i] = _supportsERC165Interface(account, interfaceIds[i]);\n }\n }\n\n return interfaceIdsSupported;\n }\n\n /**\n * @dev Returns true if `account` supports all the interfaces defined in\n * `interfaceIds`. Support for {IERC165} itself is queried automatically.\n *\n * Batch-querying can lead to gas savings by skipping repeated checks for\n * {IERC165} support.\n *\n * See {IERC165-supportsInterface}.\n */\n function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) {\n // query support of ERC165 itself\n if (!supportsERC165(account)) {\n return false;\n }\n\n // query support of each interface in _interfaceIds\n for (uint256 i = 0; i < interfaceIds.length; i++) {\n if (!_supportsERC165Interface(account, interfaceIds[i])) {\n return false;\n }\n }\n\n // all interfaces supported\n return true;\n }\n\n /**\n * @notice Query if a contract implements an interface, does not check ERC165 support\n * @param account The address of the contract to query for support of an interface\n * @param interfaceId The interface identifier, as specified in ERC-165\n * @return true if the contract at account indicates support of the interface with\n * identifier interfaceId, false otherwise\n * @dev Assumes that account contains a contract that supports ERC165, otherwise\n * the behavior of this method is undefined. This precondition can be checked\n * with {supportsERC165}.\n * Interface identification is specified in ERC-165.\n */\n function _supportsERC165Interface(address account, bytes4 interfaceId) private view returns (bool) {\n bytes memory encodedParams = abi.encodeWithSelector(IERC165.supportsInterface.selector, interfaceId);\n (bool success, bytes memory result) = account.staticcall{gas: 30000}(encodedParams);\n if (result.length < 32) return false;\n return success && abi.decode(result, (bool));\n }\n}\n" + }, + "contracts/interfaces/IJBAllowanceTerminal3_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBAllowanceTerminal3_1 {\n function useAllowanceOf(\n uint256 projectId,\n uint256 amount,\n uint256 currency,\n address token,\n uint256 minReturnedTokens,\n address payable beneficiary,\n string calldata memo,\n bytes calldata metadata\n ) external returns (uint256 netDistributedAmount);\n}\n" + }, + "contracts/interfaces/IJBFeeGauge.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBFeeGauge {\n function currentDiscountFor(uint256 projectId) external view returns (uint256);\n}\n" + }, + "contracts/interfaces/IJBPayoutRedemptionPaymentTerminal3_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBFee} from './../structs/JBFee.sol';\nimport {IJBAllowanceTerminal3_1} from './IJBAllowanceTerminal3_1.sol';\nimport {IJBDirectory} from './IJBDirectory.sol';\nimport {IJBFeeHoldingTerminal} from './IJBFeeHoldingTerminal.sol';\nimport {IJBPayDelegate} from './IJBPayDelegate.sol';\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\nimport {IJBPayoutTerminal3_1} from './IJBPayoutTerminal3_1.sol';\nimport {IJBPrices} from './IJBPrices.sol';\nimport {IJBProjects} from './IJBProjects.sol';\nimport {IJBRedemptionDelegate} from './IJBRedemptionDelegate.sol';\nimport {IJBRedemptionTerminal} from './IJBRedemptionTerminal.sol';\nimport {IJBSplitsStore} from './IJBSplitsStore.sol';\nimport {JBDidPayData} from './../structs/JBDidPayData.sol';\nimport {JBDidRedeemData} from './../structs/JBDidRedeemData.sol';\nimport {JBSplit} from './../structs/JBSplit.sol';\n\ninterface IJBPayoutRedemptionPaymentTerminal3_1 is\n IJBPaymentTerminal,\n IJBPayoutTerminal3_1,\n IJBAllowanceTerminal3_1,\n IJBRedemptionTerminal,\n IJBFeeHoldingTerminal\n{\n event AddToBalance(\n uint256 indexed projectId,\n uint256 amount,\n uint256 refundedFees,\n string memo,\n bytes metadata,\n address caller\n );\n\n event Migrate(\n uint256 indexed projectId,\n IJBPaymentTerminal indexed to,\n uint256 amount,\n address caller\n );\n\n event DistributePayouts(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n address beneficiary,\n uint256 amount,\n uint256 distributedAmount,\n uint256 fee,\n uint256 beneficiaryDistributionAmount,\n bytes metadata,\n address caller\n );\n\n event UseAllowance(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n address beneficiary,\n uint256 amount,\n uint256 distributedAmount,\n uint256 netDistributedamount,\n string memo,\n bytes metadata,\n address caller\n );\n\n event HoldFee(\n uint256 indexed projectId,\n uint256 indexed amount,\n uint256 indexed fee,\n uint256 feeDiscount,\n address beneficiary,\n address caller\n );\n\n event ProcessFee(\n uint256 indexed projectId,\n uint256 indexed amount,\n bool indexed wasHeld,\n address beneficiary,\n address caller\n );\n\n event RefundHeldFees(\n uint256 indexed projectId,\n uint256 indexed amount,\n uint256 indexed refundedFees,\n uint256 leftoverAmount,\n address caller\n );\n\n event Pay(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n address payer,\n address beneficiary,\n uint256 amount,\n uint256 beneficiaryTokenCount,\n string memo,\n bytes metadata,\n address caller\n );\n\n event DelegateDidPay(\n IJBPayDelegate indexed delegate,\n JBDidPayData data,\n uint256 delegatedAmount,\n address caller\n );\n\n event RedeemTokens(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n address holder,\n address beneficiary,\n uint256 tokenCount,\n uint256 reclaimedAmount,\n string memo,\n bytes metadata,\n address caller\n );\n\n event DelegateDidRedeem(\n IJBRedemptionDelegate indexed delegate,\n JBDidRedeemData data,\n uint256 delegatedAmount,\n address caller\n );\n\n event DistributeToPayoutSplit(\n uint256 indexed projectId,\n uint256 indexed domain,\n uint256 indexed group,\n JBSplit split,\n uint256 amount,\n uint256 netAmount,\n address caller\n );\n\n event SetFee(uint256 fee, address caller);\n\n event SetFeeGauge(address indexed feeGauge, address caller);\n\n event SetFeelessAddress(address indexed addrs, bool indexed flag, address caller);\n\n event PayoutReverted(\n uint256 indexed projectId,\n JBSplit split,\n uint256 amount,\n bytes reason,\n address caller\n );\n\n event FeeReverted(\n uint256 indexed projectId,\n uint256 indexed feeProjectId,\n uint256 amount,\n bytes reason,\n address caller\n );\n\n function projects() external view returns (IJBProjects);\n\n function splitsStore() external view returns (IJBSplitsStore);\n\n function directory() external view returns (IJBDirectory);\n\n function prices() external view returns (IJBPrices);\n\n function store() external view returns (address);\n\n function baseWeightCurrency() external view returns (uint256);\n\n function payoutSplitsGroup() external view returns (uint256);\n\n function heldFeesOf(uint256 projectId) external view returns (JBFee[] memory);\n\n function fee() external view returns (uint256);\n\n function feeGauge() external view returns (address);\n\n function isFeelessAddress(address account) external view returns (bool);\n\n function migrate(uint256 projectId, IJBPaymentTerminal to) external returns (uint256 balance);\n\n function processFees(uint256 projectId) external;\n\n function setFee(uint256 fee) external;\n\n function setFeeGauge(address feeGauge) external;\n\n function setFeelessAddress(address account, bool flag) external;\n}\n" + }, + "contracts/interfaces/IJBPayoutTerminal3_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBPayoutTerminal3_1 {\n function distributePayoutsOf(\n uint256 projectId,\n uint256 amount,\n uint256 currency,\n address token,\n uint256 minReturnedTokens,\n bytes calldata metadata\n ) external returns (uint256 netLeftoverDistributionAmount);\n}\n" + }, + "contracts/abstract/JBSingleTokenPaymentTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {ERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol';\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\nimport {IJBSingleTokenPaymentTerminal} from './../interfaces/IJBSingleTokenPaymentTerminal.sol';\n\n/// @notice Generic terminal managing all inflows of funds into the protocol ecosystem for one token.\nabstract contract JBSingleTokenPaymentTerminal is ERC165, IJBSingleTokenPaymentTerminal {\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice The token that this terminal accepts.\n address public immutable override token;\n\n /// @notice The number of decimals the token fixed point amounts are expected to have.\n uint256 public immutable override decimals;\n\n /// @notice The currency to use when resolving price feeds for this terminal.\n uint256 public immutable override currency;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice A flag indicating if this terminal accepts the specified token.\n /// @param _token The token to check if this terminal accepts or not.\n /// @param _projectId The project ID to check for token acceptance.\n /// @return The flag.\n function acceptsToken(address _token, uint256 _projectId) external view override returns (bool) {\n _projectId; // Prevents unused var compiler and natspec complaints.\n\n return _token == token;\n }\n\n /// @notice The decimals that should be used in fixed number accounting for the specified token.\n /// @param _token The token to check for the decimals of.\n /// @return The number of decimals for the token.\n function decimalsForToken(address _token) external view override returns (uint256) {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return decimals;\n }\n\n /// @notice The currency that should be used for the specified token.\n /// @param _token The token to check for the currency of.\n /// @return The currency index.\n function currencyForToken(address _token) external view override returns (uint256) {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return currency;\n }\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if the provided interface ID is supported.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(ERC165, IERC165) returns (bool) {\n return\n _interfaceId == type(IJBPaymentTerminal).interfaceId ||\n _interfaceId == type(IJBSingleTokenPaymentTerminal).interfaceId ||\n super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _token The token that this terminal manages.\n /// @param _decimals The number of decimals the token fixed point amounts are expected to have.\n /// @param _currency The currency that this terminal's token adheres to for price feeds.\n constructor(address _token, uint256 _decimals, uint256 _currency) {\n token = _token;\n decimals = _decimals;\n currency = _currency;\n }\n}\n" + }, + "contracts/interfaces/IJBFeeHoldingTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBFeeHoldingTerminal {\n function addToBalanceOf(\n uint256 projectId,\n uint256 amount,\n address token,\n bool shouldRefundHeldFees,\n string calldata memo,\n bytes calldata metadata\n ) external payable;\n}\n" + }, + "contracts/JBETHPaymentTerminal3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Address} from '@openzeppelin/contracts/utils/Address.sol';\nimport {JBPayoutRedemptionPaymentTerminal3_1_1} from './abstract/JBPayoutRedemptionPaymentTerminal3_1_1.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\nimport {JBCurrencies} from './libraries/JBCurrencies.sol';\nimport {JBSplitsGroups} from './libraries/JBSplitsGroups.sol';\nimport {JBTokens} from './libraries/JBTokens.sol';\n\n/// @notice Manages all inflows and outflows of ETH funds into the protocol ecosystem.\ncontract JBETHPaymentTerminal3_1_1 is JBPayoutRedemptionPaymentTerminal3_1_1 {\n //*********************************************************************//\n // -------------------------- internal views ------------------------- //\n //*********************************************************************//\n\n /// @notice Checks the balance of tokens in this contract.\n /// @return The contract's balance, as a fixed point number with the same amount of decimals as this terminal.\n function _balance() internal view override returns (uint256) {\n return address(this).balance;\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _prices A contract that exposes price feeds.\n /// @param _store A contract that stores the terminal's data.\n /// @param _owner The address that will own this contract.\n constructor(\n uint256 _baseWeightCurrency,\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBSplitsStore _splitsStore,\n IJBPrices _prices,\n address _store,\n address _owner\n )\n JBPayoutRedemptionPaymentTerminal3_1_1(\n JBTokens.ETH,\n 18, // 18 decimals.\n JBCurrencies.ETH,\n _baseWeightCurrency,\n JBSplitsGroups.ETH_PAYOUT,\n _operatorStore,\n _projects,\n _directory,\n _splitsStore,\n _prices,\n _store,\n _owner\n )\n // solhint-disable-next-line no-empty-blocks\n {\n\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Transfers tokens.\n /// @param _from The address from which the transfer should originate.\n /// @param _to The address to which the transfer should go.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _transferFrom(address _from, address payable _to, uint256 _amount) internal override {\n _from; // Prevents unused var compiler and natspec complaints.\n\n Address.sendValue(_to, _amount);\n }\n}\n" + }, + "contracts/abstract/JBPayoutRedemptionPaymentTerminal3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {ERC165Checker} from '@openzeppelin/contracts/utils/introspection/ERC165Checker.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {JBFeeType} from './../enums/JBFeeType.sol';\nimport {IJBAllowanceTerminal3_1} from './../interfaces/IJBAllowanceTerminal3_1.sol';\nimport {IJBController} from './../interfaces/IJBController.sol';\nimport {IJBDirectory} from './../interfaces/IJBDirectory.sol';\nimport {IJBPayoutRedemptionPaymentTerminal3_1} from './../interfaces/IJBPayoutRedemptionPaymentTerminal3_1.sol';\nimport {IJBPayoutRedemptionPaymentTerminal3_1_1} from './../interfaces/IJBPayoutRedemptionPaymentTerminal3_1_1.sol';\nimport {IJBSplitsStore} from './../interfaces/IJBSplitsStore.sol';\nimport {IJBFeeGauge3_1} from './../interfaces/IJBFeeGauge3_1.sol';\nimport {IJBOperatable} from './../interfaces/IJBOperatable.sol';\nimport {IJBOperatorStore} from './../interfaces/IJBOperatorStore.sol';\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\nimport {IJBPayoutTerminal3_1} from './../interfaces/IJBPayoutTerminal3_1.sol';\nimport {IJBPrices} from './../interfaces/IJBPrices.sol';\nimport {IJBProjects} from './../interfaces/IJBProjects.sol';\nimport {IJBRedemptionTerminal} from './../interfaces/IJBRedemptionTerminal.sol';\nimport {IJBSingleTokenPaymentTerminalStore3_1_1} from './../interfaces/IJBSingleTokenPaymentTerminalStore3_1_1.sol';\nimport {IJBSplitAllocator} from './../interfaces/IJBSplitAllocator.sol';\nimport {JBConstants} from './../libraries/JBConstants.sol';\nimport {JBCurrencies} from './../libraries/JBCurrencies.sol';\nimport {JBFixedPointNumber} from './../libraries/JBFixedPointNumber.sol';\nimport {JBFundingCycleMetadataResolver} from './../libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBOperations} from './../libraries/JBOperations.sol';\nimport {JBTokens} from './../libraries/JBTokens.sol';\nimport {JBDidRedeemData3_1_1} from './../structs/JBDidRedeemData3_1_1.sol';\nimport {JBDidPayData3_1_1} from './../structs/JBDidPayData3_1_1.sol';\nimport {JBFee} from './../structs/JBFee.sol';\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\nimport {JBPayDelegateAllocation3_1_1} from './../structs/JBPayDelegateAllocation3_1_1.sol';\nimport {JBRedemptionDelegateAllocation3_1_1} from './../structs/JBRedemptionDelegateAllocation3_1_1.sol';\nimport {JBSplit} from './../structs/JBSplit.sol';\nimport {JBSplitAllocationData} from './../structs/JBSplitAllocationData.sol';\nimport {JBTokenAmount} from './../structs/JBTokenAmount.sol';\nimport {JBOperatable} from './JBOperatable.sol';\nimport {JBSingleTokenPaymentTerminal} from './JBSingleTokenPaymentTerminal.sol';\n\n/// @notice Generic terminal managing all inflows and outflows of funds into the protocol ecosystem.\nabstract contract JBPayoutRedemptionPaymentTerminal3_1_1 is\n JBSingleTokenPaymentTerminal,\n JBOperatable,\n Ownable,\n IJBPayoutRedemptionPaymentTerminal3_1,\n IJBPayoutRedemptionPaymentTerminal3_1_1\n{\n // A library that parses the packed funding cycle metadata into a friendlier format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error FEE_TOO_HIGH();\n error INADEQUATE_DISTRIBUTION_AMOUNT();\n error INADEQUATE_RECLAIM_AMOUNT();\n error INADEQUATE_TOKEN_COUNT();\n error NO_MSG_VALUE_ALLOWED();\n error PAY_TO_ZERO_ADDRESS();\n error PROJECT_TERMINAL_MISMATCH();\n error REDEEM_TO_ZERO_ADDRESS();\n error TERMINAL_TOKENS_INCOMPATIBLE();\n\n //*********************************************************************//\n // --------------------- internal stored constants ------------------- //\n //*********************************************************************//\n\n /// @notice Maximum fee that can be set for a funding cycle configuration.\n /// @dev Out of MAX_FEE (50_000_000 / 1_000_000_000).\n uint256 internal constant _FEE_CAP = 50_000_000;\n\n /// @notice The fee beneficiary project ID is 1, as it should be the first project launched during the deployment process.\n uint256 internal constant _FEE_BENEFICIARY_PROJECT_ID = 1;\n\n //*********************************************************************//\n // --------------------- internal stored properties ------------------ //\n //*********************************************************************//\n\n /// @notice Fees that are being held to be processed later.\n /// @custom:param _projectId The ID of the project for which fees are being held.\n mapping(uint256 => JBFee[]) internal _heldFeesOf;\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice Mints ERC-721's that represent project ownership and transfers.\n IJBProjects public immutable override projects;\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n /// @notice The contract that stores splits for each project.\n IJBSplitsStore public immutable override splitsStore;\n\n /// @notice The contract that exposes price feeds.\n IJBPrices public immutable override prices;\n\n /// @notice The contract that stores and manages the terminal's data.\n address public immutable override store;\n\n /// @notice The currency to base token issuance on.\n /// @dev If this differs from `currency`, there must be a price feed available to convert `currency` to `baseWeightCurrency`.\n uint256 public immutable override baseWeightCurrency;\n\n /// @notice The group that payout splits coming from this terminal are identified by.\n uint256 public immutable override payoutSplitsGroup;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The platform fee percent.\n /// @dev Out of MAX_FEE (25_000_000 / 1_000_000_000)\n uint256 public override fee = 25_000_000; // 2.5%\n\n /// @notice The data source that returns a discount to apply to a project's fee.\n address public override feeGauge;\n\n /// @notice Addresses that can be paid towards from this terminal without incurring a fee.\n /// @dev Only addresses that are considered to be contained within the ecosystem can be feeless. Funds sent outside the ecosystem may incur fees despite being stored as feeless.\n /// @custom:param _address The address that can be paid toward.\n mapping(address => bool) public override isFeelessAddress;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Gets the current overflowed amount in this terminal for a specified project, in terms of ETH.\n /// @dev The current overflow is represented as a fixed point number with 18 decimals.\n /// @param _projectId The ID of the project to get overflow for.\n /// @return The current amount of ETH overflow that project has in this terminal, as a fixed point number with 18 decimals.\n function currentEthOverflowOf(\n uint256 _projectId\n ) external view virtual override returns (uint256) {\n // Get this terminal's current overflow.\n uint256 _overflow = IJBSingleTokenPaymentTerminalStore3_1_1(store).currentOverflowOf(\n this,\n _projectId\n );\n\n // Adjust the decimals of the fixed point number if needed to have 18 decimals.\n uint256 _adjustedOverflow = (decimals == 18)\n ? _overflow\n : JBFixedPointNumber.adjustDecimals(_overflow, decimals, 18);\n\n // Return the amount converted to ETH.\n return\n (currency == JBCurrencies.ETH)\n ? _adjustedOverflow\n : PRBMath.mulDiv(\n _adjustedOverflow,\n 10 ** decimals,\n prices.priceFor(currency, JBCurrencies.ETH, decimals)\n );\n }\n\n /// @notice The fees that are currently being held to be processed later for each project.\n /// @param _projectId The ID of the project for which fees are being held.\n /// @return An array of fees that are being held.\n function heldFeesOf(uint256 _projectId) external view override returns (JBFee[] memory) {\n return _heldFeesOf[_projectId];\n }\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if the provided interface ID is supported.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(JBSingleTokenPaymentTerminal, IERC165) returns (bool) {\n return\n _interfaceId == type(IJBPayoutRedemptionPaymentTerminal3_1_1).interfaceId ||\n _interfaceId == type(IJBPayoutRedemptionPaymentTerminal3_1).interfaceId ||\n _interfaceId == type(IJBPayoutTerminal3_1).interfaceId ||\n _interfaceId == type(IJBAllowanceTerminal3_1).interfaceId ||\n _interfaceId == type(IJBRedemptionTerminal).interfaceId ||\n _interfaceId == type(IJBOperatable).interfaceId ||\n super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // -------------------------- internal views ------------------------- //\n //*********************************************************************//\n\n /// @notice Checks the balance of tokens in this contract.\n /// @return The contract's balance.\n function _balance() internal view virtual returns (uint256);\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _token The token that this terminal manages.\n /// @param _decimals The number of decimals the token fixed point amounts are expected to have.\n /// @param _currency The currency that this terminal's token adheres to for price feeds.\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _payoutSplitsGroup The group that denotes payout splits from this terminal in the splits store.\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _prices A contract that exposes price feeds.\n /// @param _store A contract that stores the terminal's data.\n /// @param _owner The address that will own this contract.\n constructor(\n // payable constructor save the gas used to check msg.value==0\n address _token,\n uint256 _decimals,\n uint256 _currency,\n uint256 _baseWeightCurrency,\n uint256 _payoutSplitsGroup,\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBSplitsStore _splitsStore,\n IJBPrices _prices,\n address _store,\n address _owner\n )\n payable\n JBSingleTokenPaymentTerminal(_token, _decimals, _currency)\n JBOperatable(_operatorStore)\n {\n baseWeightCurrency = _baseWeightCurrency;\n payoutSplitsGroup = _payoutSplitsGroup;\n projects = _projects;\n directory = _directory;\n splitsStore = _splitsStore;\n prices = _prices;\n store = _store;\n\n transferOwnership(_owner);\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Contribute tokens to a project.\n /// @param _projectId The ID of the project being paid.\n /// @param _amount The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place.\n /// @param _token The token being paid. This terminal ignores this property since it only manages one token.\n /// @param _beneficiary The address to mint tokens for and pass along to the funding cycle's data source and delegate.\n /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\n /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals.\n function pay(\n uint256 _projectId,\n uint256 _amount,\n address _token,\n address _beneficiary,\n uint256 _minReturnedTokens,\n bool _preferClaimedTokens,\n string calldata _memo,\n bytes calldata _metadata\n ) external payable virtual override returns (uint256) {\n _token; // Prevents unused var compiler and natspec complaints.\n\n // valid terminal check\n _isTerminalOf(_projectId);\n\n // ETH shouldn't be sent if this terminal's token isn't ETH.\n if (token != JBTokens.ETH) {\n if (msg.value != 0) revert NO_MSG_VALUE_ALLOWED();\n\n // Get a reference to the balance before receiving tokens.\n uint256 _balanceBefore = _balance();\n\n // Transfer tokens to this terminal from the msg sender.\n _transferFrom(msg.sender, payable(address(this)), _amount);\n\n // The amount should reflect the change in balance.\n _amount = _balance() - _balanceBefore;\n }\n // If this terminal's token is ETH, override _amount with msg.value.\n else _amount = msg.value;\n\n return\n _pay(\n _amount,\n msg.sender,\n _projectId,\n _beneficiary,\n _minReturnedTokens,\n _preferClaimedTokens,\n _memo,\n _metadata\n );\n }\n\n /// @notice Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source.\n /// @dev Only a token holder or a designated operator can redeem its tokens.\n /// @param _holder The account to redeem tokens for.\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\n /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals.\n /// @param _token The token being reclaimed. This terminal ignores this property since it only manages one token.\n /// @param _minReturnedTokens The minimum amount of terminal tokens expected in return, as a fixed point number with the same amount of decimals as the terminal.\n /// @param _beneficiary The address to send the terminal tokens to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return reclaimAmount The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals.\n function redeemTokensOf(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n address _token,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo,\n bytes memory _metadata\n )\n external\n virtual\n override\n requirePermission(_holder, _projectId, JBOperations.REDEEM)\n returns (uint256 reclaimAmount)\n {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return\n _redeemTokensOf(\n _holder,\n _projectId,\n _tokenCount,\n _minReturnedTokens,\n _beneficiary,\n _memo,\n _metadata\n );\n }\n\n /// @notice Distributes payouts for a project with the distribution limit of its current funding cycle.\n /// @dev Payouts are sent to the preprogrammed splits. Any leftover is sent to the project's owner.\n /// @dev 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.\n /// @dev All funds distributed outside of this contract or any feeless terminals incure the protocol fee.\n /// @param _projectId The ID of the project having its payouts distributed.\n /// @param _amount The amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency.\n /// @param _token The token being distributed. This terminal ignores this property since it only manages one token.\n /// @param _minReturnedTokens 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.\n /// @param _metadata Bytes to send along to the emitted event, if provided.\n /// @return netLeftoverDistributionAmount The amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal.\n function distributePayoutsOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n address _token,\n uint256 _minReturnedTokens,\n bytes calldata _metadata\n ) external virtual override returns (uint256 netLeftoverDistributionAmount) {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return _distributePayoutsOf(_projectId, _amount, _currency, _minReturnedTokens, _metadata);\n }\n\n /// @notice Allows a project to send funds from its overflow up to the preconfigured allowance.\n /// @dev Only a project's owner or a designated operator can use its allowance.\n /// @dev Incurs the protocol fee.\n /// @param _projectId The ID of the project to use the allowance of.\n /// @param _amount The amount of terminal tokens to use from this project's current allowance, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's overflow allowance currency.\n /// @param _token The token being distributed. This terminal ignores this property since it only manages one token.\n /// @param _minReturnedTokens The minimum number of tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with 18 decimals.\n /// @param _beneficiary The address to send the funds to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the emitted event, if provided.\n /// @return netDistributedAmount The amount of tokens that was distributed to the beneficiary, as a fixed point number with the same amount of decimals as the terminal.\n function useAllowanceOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n address _token,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo,\n bytes calldata _metadata\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.USE_ALLOWANCE)\n returns (uint256 netDistributedAmount)\n {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return\n _useAllowanceOf(\n _projectId,\n _amount,\n _currency,\n _minReturnedTokens,\n _beneficiary,\n _memo,\n _metadata\n );\n }\n\n /// @notice Allows a project owner to migrate its funds and operations to a new terminal that accepts the same token type.\n /// @dev Only a project's owner or a designated operator can migrate it.\n /// @param _projectId The ID of the project being migrated.\n /// @param _to The terminal contract that will gain the project's funds.\n /// @return balance The amount of funds that were migrated, as a fixed point number with the same amount of decimals as this terminal.\n function migrate(\n uint256 _projectId,\n IJBPaymentTerminal _to\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.MIGRATE_TERMINAL)\n returns (uint256 balance)\n {\n // The terminal being migrated to must accept the same token as this terminal.\n if (!_to.acceptsToken(token, _projectId)) revert TERMINAL_TOKENS_INCOMPATIBLE();\n\n // Record the migration in the store.\n balance = IJBSingleTokenPaymentTerminalStore3_1_1(store).recordMigration(_projectId);\n\n // Transfer the balance if needed.\n if (balance != 0) {\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_to), balance);\n\n // If this terminal's token is ETH, send it in msg.value.\n uint256 _payableValue = token == JBTokens.ETH ? balance : 0;\n\n // Withdraw the balance to transfer to the new terminal;\n _to.addToBalanceOf{value: _payableValue}(_projectId, balance, token, '', bytes(''));\n }\n\n emit Migrate(_projectId, _to, balance, msg.sender);\n }\n\n /// @notice Receives funds belonging to the specified project.\n /// @param _projectId The ID of the project to which the funds received belong.\n /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\n /// @param _token The token being paid. This terminal ignores this property since it only manages one currency.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the emitted event.\n function addToBalanceOf(\n uint256 _projectId,\n uint256 _amount,\n address _token,\n string calldata _memo,\n bytes calldata _metadata\n ) external payable virtual override {\n // valid terminal check\n _isTerminalOf(_projectId);\n\n // Do not refund held fees by default.\n addToBalanceOf(_projectId, _amount, _token, false, _memo, _metadata);\n }\n\n /// @notice Process any fees that are being held for the project.\n /// @dev Only a project owner, an operator, or the contract's owner can process held fees.\n /// @param _projectId The ID of the project whos held fees should be processed.\n function processFees(\n uint256 _projectId\n )\n external\n virtual\n override\n requirePermissionAllowingOverride(\n projects.ownerOf(_projectId),\n _projectId,\n JBOperations.PROCESS_FEES,\n msg.sender == owner()\n )\n {\n // Get a reference to the project's held fees.\n JBFee[] memory _heldFees = _heldFeesOf[_projectId];\n\n // Delete the held fees.\n delete _heldFeesOf[_projectId];\n\n // Push array length in stack\n uint256 _heldFeeLength = _heldFees.length;\n\n // Keep a reference to the amount.\n uint256 _amount;\n\n // Process each fee.\n for (uint256 _i; _i < _heldFeeLength; ) {\n // Get the fee amount.\n _amount = (\n _heldFees[_i].fee == 0 || _heldFees[_i].feeDiscount == JBConstants.MAX_FEE_DISCOUNT\n ? 0\n : _feeAmount(_heldFees[_i].amount, _heldFees[_i].fee, _heldFees[_i].feeDiscount)\n );\n\n // Process the fee.\n _processFee(_amount, _heldFees[_i].beneficiary, _projectId);\n\n emit ProcessFee(_projectId, _amount, true, _heldFees[_i].beneficiary, msg.sender);\n\n unchecked {\n ++_i;\n }\n }\n }\n\n /// @notice Allows the fee to be updated.\n /// @dev Only the owner of this contract can change the fee.\n /// @param _fee The new fee, out of MAX_FEE.\n function setFee(uint256 _fee) external virtual override onlyOwner {\n // The provided fee must be within the max.\n if (_fee > _FEE_CAP) revert FEE_TOO_HIGH();\n\n // Store the new fee.\n fee = _fee;\n\n emit SetFee(_fee, msg.sender);\n }\n\n /// @notice Allows the fee gauge to be updated.\n /// @dev Only the owner of this contract can change the fee gauge.\n /// @param _feeGauge The new fee gauge.\n function setFeeGauge(address _feeGauge) external virtual override onlyOwner {\n // Store the new fee gauge.\n feeGauge = _feeGauge;\n\n emit SetFeeGauge(_feeGauge, msg.sender);\n }\n\n /// @notice Sets whether projects operating on this terminal can pay towards the specified address without incurring a fee.\n /// @dev Only the owner of this contract can set addresses as feeless.\n /// @param _address The address that can be paid towards while still bypassing fees.\n /// @param _flag A flag indicating whether the terminal should be feeless or not.\n function setFeelessAddress(address _address, bool _flag) external virtual override onlyOwner {\n // Set the flag value.\n isFeelessAddress[_address] = _flag;\n\n emit SetFeelessAddress(_address, _flag, msg.sender);\n }\n\n //*********************************************************************//\n // ----------------------- public transactions ----------------------- //\n //*********************************************************************//\n\n /// @notice Receives funds belonging to the specified project.\n /// @param _projectId The ID of the project to which the funds received belong.\n /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\n /// @param _token The token being paid. This terminal ignores this property since it only manages one currency.\n /// @param _shouldRefundHeldFees A flag indicating if held fees should be refunded based on the amount being added.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the emitted event.\n function addToBalanceOf(\n uint256 _projectId,\n uint256 _amount,\n address _token,\n bool _shouldRefundHeldFees,\n string calldata _memo,\n bytes calldata _metadata\n ) public payable virtual override {\n // valid terminal check\n _isTerminalOf(_projectId);\n\n _token; // Prevents unused var compiler and natspec complaints.\n\n // If this terminal's token isn't ETH, make sure no msg.value was sent, then transfer the tokens in from msg.sender.\n if (token != JBTokens.ETH) {\n // Amount must be greater than 0.\n if (msg.value != 0) revert NO_MSG_VALUE_ALLOWED();\n\n // Get a reference to the balance before receiving tokens.\n uint256 _balanceBefore = _balance();\n\n // Transfer tokens to this terminal from the msg sender.\n _transferFrom(msg.sender, payable(address(this)), _amount);\n\n // The amount should reflect the change in balance.\n _amount = _balance() - _balanceBefore;\n }\n // If the terminal's token is ETH, override `_amount` with msg.value.\n else _amount = msg.value;\n\n // Add to balance.\n _addToBalanceOf(_projectId, _amount, _shouldRefundHeldFees, _memo, _metadata);\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Transfers tokens.\n /// @param _from The address from which the transfer should originate.\n /// @param _to The address to which the transfer should go.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _transferFrom(address _from, address payable _to, uint256 _amount) internal virtual {\n _from; // Prevents unused var compiler and natspec complaints.\n _to; // Prevents unused var compiler and natspec complaints.\n _amount; // Prevents unused var compiler and natspec complaints.\n }\n\n /// @notice Logic to be triggered before transferring tokens from this terminal.\n /// @param _to The address to which the transfer is going.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _beforeTransferTo(address _to, uint256 _amount) internal virtual {\n _to; // Prevents unused var compiler and natspec complaints.\n _amount; // Prevents unused var compiler and natspec complaints.\n }\n\n /// @notice Logic to be triggered if a transfer should be undone\n /// @param _to The address to which the transfer went.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _cancelTransferTo(address _to, uint256 _amount) internal virtual {\n _to; // Prevents unused var compiler and natspec complaints.\n _amount; // Prevents unused var compiler and natspec complaints.\n }\n\n /// @notice Verifies this terminal is a terminal of provided project ID.\n /// @param _projectId The ID of the project to check if this contract is a terminal of.\n function _isTerminalOf(uint256 _projectId) internal view {\n if (!directory.isTerminalOf(_projectId, this)) revert PROJECT_TERMINAL_MISMATCH();\n }\n\n /// @notice Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source.\n /// @dev Only a token holder or a designated operator can redeem its tokens.\n /// @param _holder The account to redeem tokens for.\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\n /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals.\n /// @param _minReturnedTokens The minimum amount of terminal tokens expected in return, as a fixed point number with the same amount of decimals as the terminal.\n /// @param _beneficiary The address to send the terminal tokens to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return reclaimAmount The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals.\n function _redeemTokensOf(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo,\n bytes memory _metadata\n ) internal returns (uint256 reclaimAmount) {\n // Can't send reclaimed funds to the zero address.\n if (_beneficiary == address(0)) revert REDEEM_TO_ZERO_ADDRESS();\n\n // Define variables that will be needed outside the scoped section below.\n // Keep a reference to the funding cycle during which the redemption is being made.\n JBFundingCycle memory _fundingCycle;\n\n // Scoped section prevents stack too deep. `_feeEligibleDistributionAmount`, `_feeDiscount` and `_feePercent` only used within scope.\n {\n // Keep a reference to the amount being reclaimed that should have fees withheld from.\n uint256 _feeEligibleDistributionAmount;\n\n // Keep a reference to the amount of discount to apply to the fee.\n uint256 _feeDiscount;\n\n // Keep a reference to the fee.\n uint256 _feePercent = fee;\n\n // Scoped section prevents stack too deep. `_delegateAllocations` only used within scope.\n {\n JBRedemptionDelegateAllocation3_1_1[] memory _delegateAllocations;\n\n // Record the redemption.\n (\n _fundingCycle,\n reclaimAmount,\n _delegateAllocations,\n _memo\n ) = IJBSingleTokenPaymentTerminalStore3_1_1(store).recordRedemptionFor(\n _holder,\n _projectId,\n _tokenCount,\n _memo,\n _metadata\n );\n\n // Set the reference to the fee discount to apply. No fee if the beneficiary is feeless or if the redemption rate is at its max.\n _feeDiscount = isFeelessAddress[_beneficiary] ||\n (_fundingCycle.redemptionRate() == JBConstants.MAX_REDEMPTION_RATE &&\n _fundingCycle.ballotRedemptionRate() == JBConstants.MAX_REDEMPTION_RATE) ||\n _feePercent == 0\n ? JBConstants.MAX_FEE_DISCOUNT\n : _currentFeeDiscount(_projectId, JBFeeType.REDEMPTION);\n\n // The amount being reclaimed must be at least as much as was expected.\n if (reclaimAmount < _minReturnedTokens) revert INADEQUATE_RECLAIM_AMOUNT();\n\n // Burn the project tokens.\n if (_tokenCount != 0)\n IJBController(directory.controllerOf(_projectId)).burnTokensOf(\n _holder,\n _projectId,\n _tokenCount,\n '',\n false\n );\n\n // If delegate allocations were specified by the data source, fulfill them.\n if (_delegateAllocations.length != 0) {\n JBDidRedeemData3_1_1 memory _data = JBDidRedeemData3_1_1(\n _holder,\n _projectId,\n _fundingCycle.configuration,\n _tokenCount,\n JBTokenAmount(token, reclaimAmount, decimals, currency),\n JBTokenAmount(token, 0, decimals, currency),\n _beneficiary,\n _memo,\n bytes(''),\n _metadata\n );\n\n // Keep a reference to the allocation.\n JBRedemptionDelegateAllocation3_1_1 memory _delegateAllocation;\n\n // Keep a reference to the fee.\n uint256 _delegatedAmountFee;\n\n // Keep a reference to the number of allocations.\n uint256 _numDelegates = _delegateAllocations.length;\n\n for (uint256 _i; _i < _numDelegates; ) {\n // Get a reference to the delegate being iterated on.\n _delegateAllocation = _delegateAllocations[_i];\n\n // Get the fee for the delegated amount.\n _delegatedAmountFee = _feePercent == 0\n ? 0\n : _feeAmount(_delegateAllocation.amount, _feePercent, _feeDiscount);\n\n // Add the delegated amount to the amount eligible for having a fee taken.\n if (_delegatedAmountFee != 0) {\n _feeEligibleDistributionAmount += _delegateAllocation.amount;\n _delegateAllocation.amount -= _delegatedAmountFee;\n }\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_delegateAllocation.delegate), _delegateAllocation.amount);\n\n // Pass the correct token forwardedAmount to the delegate\n _data.forwardedAmount.value = _delegateAllocation.amount;\n\n // Pass the correct metadata from the data source.\n _data.dataSourceMetadata = _delegateAllocation.metadata;\n\n _delegateAllocation.delegate.didRedeem{\n value: token == JBTokens.ETH ? _delegateAllocation.amount : 0\n }(_data);\n\n emit DelegateDidRedeem(\n _delegateAllocation.delegate,\n _data,\n _delegateAllocation.amount,\n _delegatedAmountFee,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n }\n\n // Send the reclaimed funds to the beneficiary.\n if (reclaimAmount != 0) {\n // Get the fee for the reclaimed amount.\n uint256 _reclaimAmountFee = _feeDiscount == JBConstants.MAX_FEE_DISCOUNT\n ? 0\n : _feeAmount(reclaimAmount, _feePercent, _feeDiscount);\n\n if (_reclaimAmountFee != 0) {\n _feeEligibleDistributionAmount += reclaimAmount;\n reclaimAmount -= _reclaimAmountFee;\n }\n\n // Subtract the fee from the reclaim amount.\n if (reclaimAmount != 0) _transferFrom(address(this), _beneficiary, reclaimAmount);\n }\n\n // Take the fee from all outbound reclaimations.\n _feeEligibleDistributionAmount != 0\n ? _takeFeeFrom(\n _projectId,\n false,\n _feeEligibleDistributionAmount,\n _feePercent,\n _beneficiary,\n _feeDiscount\n )\n : 0;\n }\n\n emit RedeemTokens(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _holder,\n _beneficiary,\n _tokenCount,\n reclaimAmount,\n _memo,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Distributes payouts for a project with the distribution limit of its current funding cycle.\n /// @dev Payouts are sent to the preprogrammed splits. Any leftover is sent to the project's owner.\n /// @dev 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.\n /// @dev All funds distributed outside of this contract or any feeless terminals incure the protocol fee.\n /// @param _projectId The ID of the project having its payouts distributed.\n /// @param _amount The amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency.\n /// @param _minReturnedTokens 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.\n /// @param _metadata Bytes to send along to the emitted event, if provided.\n /// @return netLeftoverDistributionAmount The amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal.\n function _distributePayoutsOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n uint256 _minReturnedTokens,\n bytes calldata _metadata\n ) internal returns (uint256 netLeftoverDistributionAmount) {\n // Record the distribution.\n (\n JBFundingCycle memory _fundingCycle,\n uint256 _distributedAmount\n ) = IJBSingleTokenPaymentTerminalStore3_1_1(store).recordDistributionFor(\n _projectId,\n _amount,\n _currency\n );\n\n // The amount being distributed must be at least as much as was expected.\n if (_distributedAmount < _minReturnedTokens) revert INADEQUATE_DISTRIBUTION_AMOUNT();\n\n // Get a reference to the project owner, which will receive tokens from paying the platform fee\n // and receive any extra distributable funds not allocated to payout splits.\n address payable _projectOwner = payable(projects.ownerOf(_projectId));\n\n // Define variables that will be needed outside the scoped section below.\n // Keep a reference to the fee amount that was paid.\n uint256 _feeTaken;\n\n // Scoped section prevents stack too deep. `_feePercent`, `_feeDiscount`, `_feeEligibleDistributionAmount`, and `_leftoverDistributionAmount` only used within scope.\n {\n // Keep a reference to the fee.\n uint256 _feePercent = fee;\n\n // Get the amount of discount that should be applied to any fees taken.\n // If the fee is zero, set the discount to 100% for convenience.\n uint256 _feeDiscount = _feePercent == 0\n ? JBConstants.MAX_FEE_DISCOUNT\n : _currentFeeDiscount(_projectId, JBFeeType.PAYOUT);\n\n // The amount distributed that is eligible for incurring fees.\n uint256 _feeEligibleDistributionAmount;\n\n // The amount leftover after distributing to the splits.\n uint256 _leftoverDistributionAmount;\n\n // Payout to splits and get a reference to the leftover transfer amount after all splits have been paid.\n // Also get a reference to the amount that was distributed to splits from which fees should be taken.\n (_leftoverDistributionAmount, _feeEligibleDistributionAmount) = _distributeToPayoutSplitsOf(\n _projectId,\n _fundingCycle.configuration,\n payoutSplitsGroup,\n _distributedAmount,\n _feePercent,\n _feeDiscount\n );\n\n if (_feeDiscount != JBConstants.MAX_FEE_DISCOUNT) {\n // Leftover distribution amount is also eligible for a fee since the funds are going out of the ecosystem to _beneficiary.\n unchecked {\n _feeEligibleDistributionAmount += _leftoverDistributionAmount;\n }\n }\n\n // Take the fee.\n _feeTaken = _feeEligibleDistributionAmount != 0\n ? _takeFeeFrom(\n _projectId,\n _fundingCycle.shouldHoldFees(),\n _feeEligibleDistributionAmount,\n _feePercent,\n _projectOwner,\n _feeDiscount\n )\n : 0;\n\n // Transfer any remaining balance to the project owner and update returned leftover accordingly.\n if (_leftoverDistributionAmount != 0) {\n // Subtract the fee from the net leftover amount.\n netLeftoverDistributionAmount =\n _leftoverDistributionAmount -\n (\n _feeDiscount == JBConstants.MAX_FEE_DISCOUNT\n ? 0\n : _feeAmount(_leftoverDistributionAmount, _feePercent, _feeDiscount)\n );\n\n // Transfer the amount to the project owner.\n _transferFrom(address(this), _projectOwner, netLeftoverDistributionAmount);\n }\n }\n\n emit DistributePayouts(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _projectOwner,\n _amount,\n _distributedAmount,\n _feeTaken,\n netLeftoverDistributionAmount,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Allows a project to send funds from its overflow up to the preconfigured allowance.\n /// @dev Only a project's owner or a designated operator can use its allowance.\n /// @dev Incurs the protocol fee.\n /// @param _projectId The ID of the project to use the allowance of.\n /// @param _amount The amount of terminal tokens to use from this project's current allowance, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's overflow allowance currency.\n /// @param _minReturnedTokens The minimum number of tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with 18 decimals.\n /// @param _beneficiary The address to send the funds to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the emitted event, if provided.\n /// @return netDistributedAmount The amount of tokens that was distributed to the beneficiary, as a fixed point number with the same amount of decimals as the terminal.\n function _useAllowanceOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo,\n bytes calldata _metadata\n ) internal returns (uint256 netDistributedAmount) {\n // Record the use of the allowance.\n (\n JBFundingCycle memory _fundingCycle,\n uint256 _distributedAmount\n ) = IJBSingleTokenPaymentTerminalStore3_1_1(store).recordUsedAllowanceOf(\n _projectId,\n _amount,\n _currency\n );\n\n // The amount being withdrawn must be at least as much as was expected.\n if (_distributedAmount < _minReturnedTokens) revert INADEQUATE_DISTRIBUTION_AMOUNT();\n\n // Scoped section prevents stack too deep. `_fee`, `_projectOwner`, `_feeDiscount`, and `_netAmount` only used within scope.\n {\n // Keep a reference to the fee amount that was paid.\n uint256 _feeTaken;\n\n // Keep a reference to the fee.\n uint256 _feePercent = fee;\n\n // Get a reference to the project owner, which will receive tokens from paying the platform fee.\n address _projectOwner = projects.ownerOf(_projectId);\n\n // Get the amount of discount that should be applied to any fees taken.\n // 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.\n uint256 _feeDiscount = _feePercent == 0 || isFeelessAddress[msg.sender]\n ? JBConstants.MAX_FEE_DISCOUNT\n : _currentFeeDiscount(_projectId, JBFeeType.ALLOWANCE);\n\n // Take a fee from the `_distributedAmount`, if needed.\n _feeTaken = _feeDiscount == JBConstants.MAX_FEE_DISCOUNT\n ? 0\n : _takeFeeFrom(\n _projectId,\n _fundingCycle.shouldHoldFees(),\n _distributedAmount,\n _feePercent,\n _projectOwner,\n _feeDiscount\n );\n\n unchecked {\n // The net amount is the withdrawn amount without the fee.\n netDistributedAmount = _distributedAmount - _feeTaken;\n }\n\n // Transfer any remaining balance to the beneficiary.\n if (netDistributedAmount != 0)\n _transferFrom(address(this), _beneficiary, netDistributedAmount);\n }\n\n emit UseAllowance(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _beneficiary,\n _amount,\n _distributedAmount,\n netDistributedAmount,\n _memo,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Pays out splits for a project's funding cycle configuration.\n /// @param _projectId The ID of the project for which payout splits are being distributed.\n /// @param _domain The domain of the splits to distribute the payout between.\n /// @param _group The group of the splits to distribute the payout between.\n /// @param _amount The total amount being distributed, as a fixed point number with the same number of decimals as this terminal.\n /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE.\n /// @param _feePercent The percent of fees to take, out of MAX_FEE.\n /// @return If the leftover amount if the splits don't add up to 100%.\n /// @return feeEligibleDistributionAmount The total amount of distributions that are eligible to have fees taken from.\n function _distributeToPayoutSplitsOf(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group,\n uint256 _amount,\n uint256 _feePercent,\n uint256 _feeDiscount\n ) internal returns (uint256, uint256 feeEligibleDistributionAmount) {\n // The total percentage available to split\n uint256 _leftoverPercentage = JBConstants.SPLITS_TOTAL_PERCENT;\n\n // Get a reference to the project's payout splits.\n JBSplit[] memory _splits = splitsStore.splitsOf(_projectId, _domain, _group);\n\n // Keep a reference to the split being iterated on.\n JBSplit memory _split;\n\n // Transfer between all splits.\n for (uint256 _i; _i < _splits.length; ) {\n // Get a reference to the split being iterated on.\n _split = _splits[_i];\n\n // The amount to send towards the split.\n uint256 _payoutAmount = PRBMath.mulDiv(_amount, _split.percent, _leftoverPercentage);\n\n // The payout amount substracting any applicable incurred fees.\n uint256 _netPayoutAmount = _distributeToPayoutSplit(\n _split,\n _projectId,\n _group,\n _payoutAmount,\n _feePercent,\n _feeDiscount\n );\n\n // If the split allocator is set as feeless, this distribution is not eligible for a fee.\n if (_netPayoutAmount != 0 && _netPayoutAmount != _payoutAmount)\n feeEligibleDistributionAmount += _payoutAmount;\n\n if (_payoutAmount != 0) {\n // Subtract from the amount to be sent to the beneficiary.\n unchecked {\n _amount -= _payoutAmount;\n }\n }\n\n unchecked {\n // Decrement the leftover percentage.\n _leftoverPercentage -= _split.percent;\n }\n\n emit DistributeToPayoutSplit(\n _projectId,\n _domain,\n _group,\n _split,\n _payoutAmount,\n _netPayoutAmount,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n\n return (_amount, feeEligibleDistributionAmount);\n }\n\n /// @notice Pays out a split for a project's funding cycle configuration.\n /// @param _split The split to distribute payouts to.\n /// @param _amount The total amount being distributed to the split, as a fixed point number with the same number of decimals as this terminal.\n /// @param _feePercent The percent of fees to take, out of MAX_FEE.\n /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE.\n /// @return netPayoutAmount The amount sent to the split after subtracting fees.\n function _distributeToPayoutSplit(\n JBSplit memory _split,\n uint256 _projectId,\n uint256 _group,\n uint256 _amount,\n uint256 _feePercent,\n uint256 _feeDiscount\n ) internal returns (uint256 netPayoutAmount) {\n // By default, the net payout amount is the full amount. This will be adjusted if fees are taken.\n netPayoutAmount = _amount;\n\n // If there's an allocator set, transfer to its `allocate` function.\n if (_split.allocator != IJBSplitAllocator(address(0))) {\n // This distribution is eligible for a fee since the funds are leaving this contract and the allocator isn't listed as feeless.\n if (\n _feeDiscount != JBConstants.MAX_FEE_DISCOUNT && !isFeelessAddress[address(_split.allocator)]\n ) {\n unchecked {\n netPayoutAmount -= _feeAmount(_amount, _feePercent, _feeDiscount);\n }\n }\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_split.allocator), netPayoutAmount);\n\n // Create the data to send to the allocator.\n JBSplitAllocationData memory _data = JBSplitAllocationData(\n token,\n netPayoutAmount,\n decimals,\n _projectId,\n _group,\n _split\n );\n\n // Trigger the allocator's `allocate` function.\n bytes memory _reason;\n\n if (\n ERC165Checker.supportsInterface(\n address(_split.allocator),\n type(IJBSplitAllocator).interfaceId\n )\n )\n // If this terminal's token is ETH, send it in msg.value.\n try\n _split.allocator.allocate{value: token == JBTokens.ETH ? netPayoutAmount : 0}(_data)\n {} catch (bytes memory __reason) {\n _reason = __reason.length == 0 ? abi.encode('Allocate fail') : __reason;\n }\n else {\n _reason = abi.encode('IERC165 fail');\n }\n\n if (_reason.length != 0) {\n // Revert the payout.\n _revertTransferFrom(_projectId, address(_split.allocator), netPayoutAmount, _amount);\n\n // Set the net payout amount to 0 to signal the reversion.\n netPayoutAmount = 0;\n\n emit PayoutReverted(_projectId, _split, _amount, _reason, msg.sender);\n }\n\n // Otherwise, if a project is specified, make a payment to it.\n } else if (_split.projectId != 0) {\n // Get a reference to the Juicebox terminal being used.\n IJBPaymentTerminal _terminal = directory.primaryTerminalOf(_split.projectId, token);\n\n // The project must have a terminal to send funds to.\n if (_terminal == IJBPaymentTerminal(address(0))) {\n // Set the net payout amount to 0 to signal the reversion.\n netPayoutAmount = 0;\n\n // Revert the payout.\n _revertTransferFrom(_projectId, address(0), 0, _amount);\n\n emit PayoutReverted(_projectId, _split, _amount, 'Terminal not found', msg.sender);\n } else {\n // This distribution is eligible for a fee since the funds are leaving this contract and the terminal isn't listed as feeless.\n if (\n _terminal != this &&\n _feeDiscount != JBConstants.MAX_FEE_DISCOUNT &&\n !isFeelessAddress[address(_terminal)]\n ) {\n unchecked {\n netPayoutAmount -= _feeAmount(_amount, _feePercent, _feeDiscount);\n }\n }\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_terminal), netPayoutAmount);\n\n // Add to balance if prefered.\n if (_split.preferAddToBalance)\n try\n _terminal.addToBalanceOf{value: token == JBTokens.ETH ? netPayoutAmount : 0}(\n _split.projectId,\n netPayoutAmount,\n token,\n '',\n // Send the projectId in the metadata as a referral.\n bytes(abi.encodePacked(_projectId))\n )\n {} catch (bytes memory _reason) {\n // Revert the payout.\n _revertTransferFrom(_projectId, address(_terminal), netPayoutAmount, _amount);\n\n // Set the net payout amount to 0 to signal the reversion.\n netPayoutAmount = 0;\n\n emit PayoutReverted(_projectId, _split, _amount, _reason, msg.sender);\n }\n else\n try\n _terminal.pay{value: token == JBTokens.ETH ? netPayoutAmount : 0}(\n _split.projectId,\n netPayoutAmount,\n token,\n _split.beneficiary != address(0) ? _split.beneficiary : msg.sender,\n 0,\n _split.preferClaimed,\n '',\n // Send the projectId in the metadata as a referral.\n bytes(abi.encodePacked(_projectId))\n )\n {} catch (bytes memory _reason) {\n // Revert the payout.\n _revertTransferFrom(_projectId, address(_terminal), netPayoutAmount, _amount);\n\n // Set the net payout amount to 0 to signal the reversion.\n netPayoutAmount = 0;\n\n emit PayoutReverted(_projectId, _split, _amount, _reason, msg.sender);\n }\n }\n } else {\n // This distribution is eligible for a fee since the funds are leaving this contract and the beneficiary isn't listed as feeless.\n // Don't enforce feeless address for the beneficiary since the funds are leaving the ecosystem.\n if (_feeDiscount != JBConstants.MAX_FEE_DISCOUNT) {\n unchecked {\n netPayoutAmount -= _feeAmount(_amount, _feePercent, _feeDiscount);\n }\n }\n\n // If there's a beneficiary, send the funds directly to the beneficiary. Otherwise send to the msg.sender.\n _transferFrom(\n address(this),\n _split.beneficiary != address(0) ? _split.beneficiary : payable(msg.sender),\n netPayoutAmount\n );\n }\n }\n\n /// @notice Takes a fee into the platform's project, which has an id of _FEE_BENEFICIARY_PROJECT_ID.\n /// @param _projectId The ID of the project having fees taken from.\n /// @param _shouldHoldFees If fees should be tracked and held back.\n /// @param _feePercent The percent of fees to take, out of MAX_FEE.\n /// @param _amount The amount of the fee to take, as a floating point number with 18 decimals.\n /// @param _beneficiary The address to mint the platforms tokens for.\n /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE.\n /// @return feeAmount The amount of the fee taken.\n function _takeFeeFrom(\n uint256 _projectId,\n bool _shouldHoldFees,\n uint256 _amount,\n uint256 _feePercent,\n address _beneficiary,\n uint256 _feeDiscount\n ) internal returns (uint256 feeAmount) {\n feeAmount = _feeAmount(_amount, _feePercent, _feeDiscount);\n\n if (_shouldHoldFees) {\n // Store the held fee.\n _heldFeesOf[_projectId].push(\n JBFee(_amount, uint32(_feePercent), uint32(_feeDiscount), _beneficiary)\n );\n\n emit HoldFee(_projectId, _amount, _feePercent, _feeDiscount, _beneficiary, msg.sender);\n } else {\n // Process the fee.\n _processFee(feeAmount, _beneficiary, _projectId); // Take the fee.\n\n emit ProcessFee(_projectId, feeAmount, false, _beneficiary, msg.sender);\n }\n }\n\n /// @notice Process a fee of the specified amount.\n /// @param _amount The fee amount, as a floating point number with 18 decimals.\n /// @param _beneficiary The address to mint the platform's tokens for.\n /// @param _from The project ID the fee is being paid from.\n function _processFee(uint256 _amount, address _beneficiary, uint256 _from) internal {\n // Get the terminal for the protocol project.\n IJBPaymentTerminal _terminal = directory.primaryTerminalOf(_FEE_BENEFICIARY_PROJECT_ID, token);\n\n // Trigger any inherited pre-transfer logic if funds will be transferred.\n if (address(_terminal) != address(this)) _beforeTransferTo(address(_terminal), _amount);\n\n try\n // Send the fee.\n // If this terminal's token is ETH, send it in msg.value.\n _terminal.pay{value: token == JBTokens.ETH ? _amount : 0}(\n _FEE_BENEFICIARY_PROJECT_ID,\n _amount,\n token,\n _beneficiary,\n 0,\n false,\n '',\n // Send the projectId in the metadata.\n bytes(abi.encodePacked(_from))\n )\n {} catch (bytes memory _reason) {\n _revertTransferFrom(\n _from,\n address(_terminal) != address(this) ? address(_terminal) : address(0),\n address(_terminal) != address(this) ? _amount : 0,\n _amount\n );\n emit FeeReverted(_from, _FEE_BENEFICIARY_PROJECT_ID, _amount, _reason, msg.sender);\n }\n }\n\n /// @notice Reverts an expected payout.\n /// @param _projectId The ID of the project having paying out.\n /// @param _expectedDestination The address the payout was expected to go to.\n /// @param _allowanceAmount The amount that the destination has been allowed to use.\n /// @param _depositAmount The amount of the payout as debited from the project's balance.\n function _revertTransferFrom(\n uint256 _projectId,\n address _expectedDestination,\n uint256 _allowanceAmount,\n uint256 _depositAmount\n ) internal {\n // Cancel allowance if needed.\n if (_allowanceAmount != 0) _cancelTransferTo(_expectedDestination, _allowanceAmount);\n\n // Add undistributed amount back to project's balance.\n IJBSingleTokenPaymentTerminalStore3_1_1(store).recordAddedBalanceFor(\n _projectId,\n _depositAmount\n );\n }\n\n /// @notice Contribute tokens to a project.\n /// @param _amount The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place.\n /// @param _payer The address making the payment.\n /// @param _projectId The ID of the project being paid.\n /// @param _beneficiary The address to mint tokens for and pass along to the funding cycle's data source and delegate.\n /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\n /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return beneficiaryTokenCount The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals.\n function _pay(\n uint256 _amount,\n address _payer,\n uint256 _projectId,\n address _beneficiary,\n uint256 _minReturnedTokens,\n bool _preferClaimedTokens,\n string memory _memo,\n bytes memory _metadata\n ) internal returns (uint256 beneficiaryTokenCount) {\n // Cant send tokens to the zero address.\n if (_beneficiary == address(0)) revert PAY_TO_ZERO_ADDRESS();\n\n // Define variables that will be needed outside the scoped section below.\n // Keep a reference to the funding cycle during which the payment is being made.\n JBFundingCycle memory _fundingCycle;\n\n // Scoped section prevents stack too deep. `_delegateAllocations` and `_tokenCount` only used within scope.\n {\n JBPayDelegateAllocation3_1_1[] memory _delegateAllocations;\n uint256 _tokenCount;\n\n // Bundle the amount info into a JBTokenAmount struct.\n JBTokenAmount memory _bundledAmount = JBTokenAmount(token, _amount, decimals, currency);\n\n // Record the payment.\n (\n _fundingCycle,\n _tokenCount,\n _delegateAllocations,\n _memo\n ) = IJBSingleTokenPaymentTerminalStore3_1_1(store).recordPaymentFrom(\n _payer,\n _bundledAmount,\n _projectId,\n baseWeightCurrency,\n _beneficiary,\n _memo,\n _metadata\n );\n\n // Mint the tokens if needed.\n if (_tokenCount != 0)\n // Set token count to be the number of tokens minted for the beneficiary instead of the total amount.\n beneficiaryTokenCount = IJBController(directory.controllerOf(_projectId)).mintTokensOf(\n _projectId,\n _tokenCount,\n _beneficiary,\n '',\n _preferClaimedTokens,\n true\n );\n\n // The token count for the beneficiary must be greater than or equal to the minimum expected.\n if (beneficiaryTokenCount < _minReturnedTokens) revert INADEQUATE_TOKEN_COUNT();\n\n // If delegate allocations were specified by the data source, fulfill them.\n if (_delegateAllocations.length != 0) {\n JBDidPayData3_1_1 memory _data = JBDidPayData3_1_1(\n _payer,\n _projectId,\n _fundingCycle.configuration,\n _bundledAmount,\n JBTokenAmount(token, 0, decimals, currency),\n beneficiaryTokenCount,\n _beneficiary,\n _preferClaimedTokens,\n _memo,\n bytes(''),\n _metadata\n );\n\n // Get a reference to the number of delegates to allocate to.\n uint256 _numDelegates = _delegateAllocations.length;\n\n // Keep a reference to the allocation.\n JBPayDelegateAllocation3_1_1 memory _delegateAllocation;\n\n for (uint256 _i; _i < _numDelegates; ) {\n // Get a reference to the delegate being iterated on.\n _delegateAllocation = _delegateAllocations[_i];\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_delegateAllocation.delegate), _delegateAllocation.amount);\n\n // Pass the correct token forwardedAmount to the delegate\n _data.forwardedAmount.value = _delegateAllocation.amount;\n\n // Pass the correct metadata from the data source.\n _data.dataSourceMetadata = _delegateAllocation.metadata;\n\n _delegateAllocation.delegate.didPay{\n value: token == JBTokens.ETH ? _delegateAllocation.amount : 0\n }(_data);\n\n emit DelegateDidPay(\n _delegateAllocation.delegate,\n _data,\n _delegateAllocation.amount,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n }\n\n emit Pay(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _payer,\n _beneficiary,\n _amount,\n beneficiaryTokenCount,\n _memo,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Receives funds belonging to the specified project.\n /// @param _projectId The ID of the project to which the funds received belong.\n /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\n /// @param _shouldRefundHeldFees A flag indicating if held fees should be refunded based on the amount being added.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the emitted event.\n function _addToBalanceOf(\n uint256 _projectId,\n uint256 _amount,\n bool _shouldRefundHeldFees,\n string memory _memo,\n bytes memory _metadata\n ) internal {\n // Refund any held fees to make sure the project doesn't pay double for funds going in and out of the protocol.\n uint256 _refundedFees = _shouldRefundHeldFees ? _refundHeldFees(_projectId, _amount) : 0;\n\n // Record the added funds with any refunded fees.\n IJBSingleTokenPaymentTerminalStore3_1_1(store).recordAddedBalanceFor(\n _projectId,\n _amount + _refundedFees\n );\n\n emit AddToBalance(_projectId, _amount, _refundedFees, _memo, _metadata, msg.sender);\n }\n\n /// @notice Refund fees based on the specified amount.\n /// @param _projectId The project for which fees are being refunded.\n /// @param _amount The amount to base the refund on, as a fixed point number with the same amount of decimals as this terminal.\n /// @return refundedFees How much fees were refunded, as a fixed point number with the same number of decimals as this terminal\n function _refundHeldFees(\n uint256 _projectId,\n uint256 _amount\n ) internal returns (uint256 refundedFees) {\n // Get a reference to the project's held fees.\n JBFee[] memory _heldFees = _heldFeesOf[_projectId];\n\n // Delete the current held fees.\n delete _heldFeesOf[_projectId];\n\n // Get a reference to the leftover amount once all fees have been settled.\n uint256 leftoverAmount = _amount;\n\n // Push length in stack\n uint256 _heldFeesLength = _heldFees.length;\n\n // Process each fee.\n for (uint256 _i; _i < _heldFeesLength; ) {\n if (leftoverAmount == 0) _heldFeesOf[_projectId].push(_heldFees[_i]);\n else if (leftoverAmount >= _heldFees[_i].amount) {\n unchecked {\n leftoverAmount = leftoverAmount - _heldFees[_i].amount;\n refundedFees += (\n _heldFees[_i].fee == 0 || _heldFees[_i].feeDiscount == JBConstants.MAX_FEE_DISCOUNT\n ? 0\n : _feeAmount(_heldFees[_i].amount, _heldFees[_i].fee, _heldFees[_i].feeDiscount)\n );\n }\n } else {\n unchecked {\n _heldFeesOf[_projectId].push(\n JBFee(\n _heldFees[_i].amount - leftoverAmount,\n _heldFees[_i].fee,\n _heldFees[_i].feeDiscount,\n _heldFees[_i].beneficiary\n )\n );\n refundedFees += (\n _heldFees[_i].fee == 0 || _heldFees[_i].feeDiscount == JBConstants.MAX_FEE_DISCOUNT\n ? 0\n : _feeAmount(leftoverAmount, _heldFees[_i].fee, _heldFees[_i].feeDiscount)\n );\n }\n leftoverAmount = 0;\n }\n\n unchecked {\n ++_i;\n }\n }\n\n emit RefundHeldFees(_projectId, _amount, refundedFees, leftoverAmount, msg.sender);\n }\n\n /// @notice Returns the fee amount based on the provided amount for the specified project.\n /// @param _amount The amount that the fee is based on, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _fee The percentage of the fee, out of MAX_FEE.\n /// @param _feeDiscount The percentage discount that should be applied out of the max amount, out of MAX_FEE_DISCOUNT.\n /// @return The amount of the fee, as a fixed point number with the same amount of decimals as this terminal.\n function _feeAmount(\n uint256 _amount,\n uint256 _fee,\n uint256 _feeDiscount\n ) internal pure returns (uint256) {\n // Calculate the discounted fee.\n uint256 _discountedFee = _fee -\n PRBMath.mulDiv(_fee, _feeDiscount, JBConstants.MAX_FEE_DISCOUNT);\n\n // The amount of tokens from the `_amount` to pay as a fee.\n return\n _amount - PRBMath.mulDiv(_amount, JBConstants.MAX_FEE, _discountedFee + JBConstants.MAX_FEE);\n }\n\n /// @notice Get the fee discount from the fee gauge for the specified project.\n /// @param _projectId The ID of the project to get a fee discount for.\n /// @param _feeType The type of fee the discount is being applied to.\n /// @return feeDiscount The fee discount, which should be interpreted as a percentage out MAX_FEE_DISCOUNT.\n function _currentFeeDiscount(\n uint256 _projectId,\n JBFeeType _feeType\n ) internal view returns (uint256) {\n // Can't take a fee if the protocol project doesn't have a terminal that accepts the token.\n if (\n directory.primaryTerminalOf(_FEE_BENEFICIARY_PROJECT_ID, token) ==\n IJBPaymentTerminal(address(0))\n ) return JBConstants.MAX_FEE_DISCOUNT;\n\n // Get the fee discount.\n if (feeGauge != address(0))\n // If the guage reverts, keep the discount at 0.\n try IJBFeeGauge3_1(feeGauge).currentDiscountFor(_projectId, _feeType) returns (\n uint256 discount\n ) {\n // If the fee discount is greater than the max, we ignore the return value\n if (discount <= JBConstants.MAX_FEE_DISCOUNT) return discount;\n } catch {\n return 0;\n }\n\n return 0;\n }\n}\n" + }, + "contracts/enums/JBFeeType.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nenum JBFeeType {\n PAYOUT,\n ALLOWANCE,\n REDEMPTION\n}\n" + }, + "contracts/interfaces/IJBPayoutRedemptionPaymentTerminal3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBFee} from './../structs/JBFee.sol';\nimport {JBDidRedeemData3_1_1} from './../structs/JBDidRedeemData3_1_1.sol';\nimport {JBDidPayData3_1_1} from './../structs/JBDidPayData3_1_1.sol';\nimport {IJBPayDelegate3_1_1} from './IJBPayDelegate3_1_1.sol';\nimport {IJBRedemptionDelegate3_1_1} from './IJBRedemptionDelegate3_1_1.sol';\n\ninterface IJBPayoutRedemptionPaymentTerminal3_1_1 {\n event DelegateDidRedeem(\n IJBRedemptionDelegate3_1_1 indexed delegate,\n JBDidRedeemData3_1_1 data,\n uint256 delegatedAmount,\n uint256 fee,\n address caller\n );\n\n event DelegateDidPay(\n IJBPayDelegate3_1_1 indexed delegate,\n JBDidPayData3_1_1 data,\n uint256 delegatedAmount,\n address caller\n );\n}\n" + }, + "contracts/interfaces/IJBFeeGauge3_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBFeeType} from './../enums/JBFeeType.sol';\n\ninterface IJBFeeGauge3_1 {\n function currentDiscountFor(uint256 projectId, JBFeeType feeType) external view returns (uint256);\n}\n" + }, + "contracts/JBETHPaymentTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Address} from '@openzeppelin/contracts/utils/Address.sol';\nimport {JBPayoutRedemptionPaymentTerminal} from './abstract/JBPayoutRedemptionPaymentTerminal.sol';\nimport {JBSplitsGroups} from './libraries/JBSplitsGroups.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {JBCurrencies} from './libraries/JBCurrencies.sol';\nimport {JBTokens} from './libraries/JBTokens.sol';\n\n/// @notice Manages all inflows and outflows of ETH funds into the protocol ecosystem.\ncontract JBETHPaymentTerminal is JBPayoutRedemptionPaymentTerminal {\n //*********************************************************************//\n // -------------------------- internal views ------------------------- //\n //*********************************************************************//\n\n /// @notice Checks the balance of tokens in this contract.\n /// @return The contract's balance, as a fixed point number with the same amount of decimals as this terminal.\n function _balance() internal view override returns (uint256) {\n return address(this).balance;\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _prices A contract that exposes price feeds.\n /// @param _store A contract that stores the terminal's data.\n /// @param _owner The address that will own this contract.\n constructor(\n uint256 _baseWeightCurrency,\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBSplitsStore _splitsStore,\n IJBPrices _prices,\n address _store,\n address _owner\n )\n JBPayoutRedemptionPaymentTerminal(\n JBTokens.ETH,\n 18, // 18 decimals.\n JBCurrencies.ETH,\n _baseWeightCurrency,\n JBSplitsGroups.ETH_PAYOUT,\n _operatorStore,\n _projects,\n _directory,\n _splitsStore,\n _prices,\n _store,\n _owner\n )\n // solhint-disable-next-line no-empty-blocks\n {\n\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Transfers tokens.\n /// @param _from The address from which the transfer should originate.\n /// @param _to The address to which the transfer should go.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _transferFrom(address _from, address payable _to, uint256 _amount) internal override {\n _from; // Prevents unused var compiler and natspec complaints.\n\n Address.sendValue(_to, _amount);\n }\n}\n" + }, + "contracts/abstract/JBPayoutRedemptionPaymentTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {IJBAllowanceTerminal} from './../interfaces/IJBAllowanceTerminal.sol';\nimport {IJBController} from './../interfaces/IJBController.sol';\nimport {IJBDirectory} from './../interfaces/IJBDirectory.sol';\nimport {IJBPayoutRedemptionPaymentTerminal} from './../interfaces/IJBPayoutRedemptionPaymentTerminal.sol';\nimport {IJBSplitAllocator} from './../interfaces/IJBSplitAllocator.sol';\nimport {IJBFeeGauge} from './../interfaces/IJBFeeGauge.sol';\nimport {IJBOperatable} from './../interfaces/IJBOperatable.sol';\nimport {IJBOperatorStore} from './../interfaces/IJBOperatorStore.sol';\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\nimport {IJBPayoutTerminal} from './../interfaces/IJBPayoutTerminal.sol';\nimport {IJBPrices} from './../interfaces/IJBPrices.sol';\nimport {IJBProjects} from './../interfaces/IJBProjects.sol';\nimport {IJBRedemptionTerminal} from './../interfaces/IJBRedemptionTerminal.sol';\nimport {IJBSingleTokenPaymentTerminalStore} from './../interfaces/IJBSingleTokenPaymentTerminalStore.sol';\nimport {IJBSplitsStore} from './../interfaces/IJBSplitsStore.sol';\nimport {JBConstants} from './../libraries/JBConstants.sol';\nimport {JBCurrencies} from './../libraries/JBCurrencies.sol';\nimport {JBFixedPointNumber} from './../libraries/JBFixedPointNumber.sol';\nimport {JBFundingCycleMetadataResolver} from './../libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBOperations} from './../libraries/JBOperations.sol';\nimport {JBTokens} from './../libraries/JBTokens.sol';\nimport {JBDidPayData} from './../structs/JBDidPayData.sol';\nimport {JBDidRedeemData} from './../structs/JBDidRedeemData.sol';\nimport {JBFee} from './../structs/JBFee.sol';\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\nimport {JBPayDelegateAllocation} from './../structs/JBPayDelegateAllocation.sol';\nimport {JBTokenAmount} from './../structs/JBTokenAmount.sol';\nimport {JBRedemptionDelegateAllocation} from './../structs/JBRedemptionDelegateAllocation.sol';\nimport {JBSplit} from './../structs/JBSplit.sol';\nimport {JBSplitAllocationData} from './../structs/JBSplitAllocationData.sol';\nimport {JBOperatable} from './JBOperatable.sol';\nimport {JBSingleTokenPaymentTerminal} from './JBSingleTokenPaymentTerminal.sol';\n\n/// @notice Generic terminal managing all inflows and outflows of funds into the protocol ecosystem.\n/// A project can transfer its funds, along with the power to reconfigure and mint/burn their tokens, from this contract to another allowed terminal of the same token type contract at any time.\nabstract contract JBPayoutRedemptionPaymentTerminal is\n JBSingleTokenPaymentTerminal,\n JBOperatable,\n Ownable,\n IJBPayoutRedemptionPaymentTerminal\n{\n // A library that parses the packed funding cycle metadata into a friendlier format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error FEE_TOO_HIGH();\n error INADEQUATE_DISTRIBUTION_AMOUNT();\n error INADEQUATE_RECLAIM_AMOUNT();\n error INADEQUATE_TOKEN_COUNT();\n error NO_MSG_VALUE_ALLOWED();\n error PAY_TO_ZERO_ADDRESS();\n error PROJECT_TERMINAL_MISMATCH();\n error REDEEM_TO_ZERO_ADDRESS();\n error TERMINAL_IN_SPLIT_ZERO_ADDRESS();\n error TERMINAL_TOKENS_INCOMPATIBLE();\n\n //*********************************************************************//\n // ---------------------------- modifiers ---------------------------- //\n //*********************************************************************//\n\n /// @notice A modifier that verifies this terminal is a terminal of provided project ID.\n modifier isTerminalOf(uint256 _projectId) {\n if (!directory.isTerminalOf(_projectId, this)) revert PROJECT_TERMINAL_MISMATCH();\n _;\n }\n\n //*********************************************************************//\n // --------------------- internal stored constants ------------------- //\n //*********************************************************************//\n\n /// @notice Maximum fee that can be set for a funding cycle configuration.\n /// @dev Out of MAX_FEE (50_000_000 / 1_000_000_000).\n uint256 internal constant _FEE_CAP = 50_000_000;\n\n /// @notice The fee beneficiary project ID is 1, as it should be the first project launched during the deployment process.\n uint256 internal constant _FEE_BENEFICIARY_PROJECT_ID = 1;\n\n //*********************************************************************//\n // --------------------- internal stored properties ------------------ //\n //*********************************************************************//\n\n /// @notice Fees that are being held to be processed later.\n /// @custom:param _projectId The ID of the project for which fees are being held.\n mapping(uint256 => JBFee[]) internal _heldFeesOf;\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice Mints ERC-721's that represent project ownership and transfers.\n IJBProjects public immutable override projects;\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n /// @notice The contract that stores splits for each project.\n IJBSplitsStore public immutable override splitsStore;\n\n /// @notice The contract that exposes price feeds.\n IJBPrices public immutable override prices;\n\n /// @notice The contract that stores and manages the terminal's data.\n address public immutable override store;\n\n /// @notice The currency to base token issuance on.\n /// @dev If this differs from `currency`, there must be a price feed available to convert `currency` to `baseWeightCurrency`.\n uint256 public immutable override baseWeightCurrency;\n\n /// @notice The group that payout splits coming from this terminal are identified by.\n uint256 public immutable override payoutSplitsGroup;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The platform fee percent.\n /// @dev Out of MAX_FEE (25_000_000 / 1_000_000_000)\n uint256 public override fee = 25_000_000; // 2.5%\n\n /// @notice The data source that returns a discount to apply to a project's fee.\n address public override feeGauge;\n\n /// @notice Addresses that can be paid towards from this terminal without incurring a fee.\n /// @dev Only addresses that are considered to be contained within the ecosystem can be feeless. Funds sent outside the ecosystem may incur fees despite being stored as feeless.\n /// @custom:param _address The address that can be paid toward.\n mapping(address => bool) public override isFeelessAddress;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Gets the current overflowed amount in this terminal for a specified project, in terms of ETH.\n /// @dev The current overflow is represented as a fixed point number with 18 decimals.\n /// @param _projectId The ID of the project to get overflow for.\n /// @return The current amount of ETH overflow that project has in this terminal, as a fixed point number with 18 decimals.\n function currentEthOverflowOf(\n uint256 _projectId\n ) external view virtual override returns (uint256) {\n // Get this terminal's current overflow.\n uint256 _overflow = IJBSingleTokenPaymentTerminalStore(store).currentOverflowOf(\n this,\n _projectId\n );\n\n // Adjust the decimals of the fixed point number if needed to have 18 decimals.\n uint256 _adjustedOverflow = (decimals == 18)\n ? _overflow\n : JBFixedPointNumber.adjustDecimals(_overflow, decimals, 18);\n\n // Return the amount converted to ETH.\n return\n (currency == JBCurrencies.ETH)\n ? _adjustedOverflow\n : PRBMath.mulDiv(\n _adjustedOverflow,\n 10 ** decimals,\n prices.priceFor(currency, JBCurrencies.ETH, decimals)\n );\n }\n\n /// @notice The fees that are currently being held to be processed later for each project.\n /// @param _projectId The ID of the project for which fees are being held.\n /// @return An array of fees that are being held.\n function heldFeesOf(uint256 _projectId) external view override returns (JBFee[] memory) {\n return _heldFeesOf[_projectId];\n }\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if the provided interface ID is supported.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(JBSingleTokenPaymentTerminal, IERC165) returns (bool) {\n return\n _interfaceId == type(IJBPayoutRedemptionPaymentTerminal).interfaceId ||\n _interfaceId == type(IJBPayoutTerminal).interfaceId ||\n _interfaceId == type(IJBAllowanceTerminal).interfaceId ||\n _interfaceId == type(IJBRedemptionTerminal).interfaceId ||\n _interfaceId == type(IJBOperatable).interfaceId ||\n super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // -------------------------- internal views ------------------------- //\n //*********************************************************************//\n\n /// @notice Checks the balance of tokens in this contract.\n /// @return The contract's balance.\n function _balance() internal view virtual returns (uint256);\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _token The token that this terminal manages.\n /// @param _decimals The number of decimals the token fixed point amounts are expected to have.\n /// @param _currency The currency that this terminal's token adheres to for price feeds.\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _payoutSplitsGroup The group that denotes payout splits from this terminal in the splits store.\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _prices A contract that exposes price feeds.\n /// @param _store A contract that stores the terminal's data.\n /// @param _owner The address that will own this contract.\n constructor(\n // payable constructor save the gas used to check msg.value==0\n address _token,\n uint256 _decimals,\n uint256 _currency,\n uint256 _baseWeightCurrency,\n uint256 _payoutSplitsGroup,\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBSplitsStore _splitsStore,\n IJBPrices _prices,\n address _store,\n address _owner\n )\n payable\n JBSingleTokenPaymentTerminal(_token, _decimals, _currency)\n JBOperatable(_operatorStore)\n {\n baseWeightCurrency = _baseWeightCurrency;\n payoutSplitsGroup = _payoutSplitsGroup;\n projects = _projects;\n directory = _directory;\n splitsStore = _splitsStore;\n prices = _prices;\n store = _store;\n\n transferOwnership(_owner);\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Contribute tokens to a project.\n /// @param _projectId The ID of the project being paid.\n /// @param _amount The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place.\n /// @param _token The token being paid. This terminal ignores this property since it only manages one token.\n /// @param _beneficiary The address to mint tokens for and pass along to the funding cycle's data source and delegate.\n /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\n /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals.\n function pay(\n uint256 _projectId,\n uint256 _amount,\n address _token,\n address _beneficiary,\n uint256 _minReturnedTokens,\n bool _preferClaimedTokens,\n string calldata _memo,\n bytes calldata _metadata\n ) external payable virtual override isTerminalOf(_projectId) returns (uint256) {\n _token; // Prevents unused var compiler and natspec complaints.\n\n // ETH shouldn't be sent if this terminal's token isn't ETH.\n if (token != JBTokens.ETH) {\n if (msg.value > 0) revert NO_MSG_VALUE_ALLOWED();\n\n // Get a reference to the balance before receiving tokens.\n uint256 _balanceBefore = _balance();\n\n // Transfer tokens to this terminal from the msg sender.\n _transferFrom(msg.sender, payable(address(this)), _amount);\n\n // The amount should reflect the change in balance.\n _amount = _balance() - _balanceBefore;\n }\n // If this terminal's token is ETH, override _amount with msg.value.\n else _amount = msg.value;\n\n return\n _pay(\n _amount,\n msg.sender,\n _projectId,\n _beneficiary,\n _minReturnedTokens,\n _preferClaimedTokens,\n _memo,\n _metadata\n );\n }\n\n /// @notice Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source.\n /// @dev Only a token holder or a designated operator can redeem its tokens.\n /// @param _holder The account to redeem tokens for.\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\n /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals.\n /// @param _token The token being reclaimed. This terminal ignores this property since it only manages one token.\n /// @param _minReturnedTokens The minimum amount of terminal tokens expected in return, as a fixed point number with the same amount of decimals as the terminal.\n /// @param _beneficiary The address to send the terminal tokens to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return reclaimAmount The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals.\n function redeemTokensOf(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n address _token,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo,\n bytes memory _metadata\n )\n external\n virtual\n override\n requirePermission(_holder, _projectId, JBOperations.REDEEM)\n returns (uint256 reclaimAmount)\n {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return\n _redeemTokensOf(\n _holder,\n _projectId,\n _tokenCount,\n _minReturnedTokens,\n _beneficiary,\n _memo,\n _metadata\n );\n }\n\n /// @notice Distributes payouts for a project with the distribution limit of its current funding cycle.\n /// @dev Payouts are sent to the preprogrammed splits. Any leftover is sent to the project's owner.\n /// @dev 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.\n /// @dev All funds distributed outside of this contract or any feeless terminals incure the protocol fee.\n /// @param _projectId The ID of the project having its payouts distributed.\n /// @param _amount The amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency.\n /// @param _token The token being distributed. This terminal ignores this property since it only manages one token.\n /// @param _minReturnedTokens 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.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return netLeftoverDistributionAmount The amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal.\n function distributePayoutsOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n address _token,\n uint256 _minReturnedTokens,\n string calldata _memo\n ) external virtual override returns (uint256 netLeftoverDistributionAmount) {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return _distributePayoutsOf(_projectId, _amount, _currency, _minReturnedTokens, _memo);\n }\n\n /// @notice Allows a project to send funds from its overflow up to the preconfigured allowance.\n /// @dev Only a project's owner or a designated operator can use its allowance.\n /// @dev Incurs the protocol fee.\n /// @param _projectId The ID of the project to use the allowance of.\n /// @param _amount The amount of terminal tokens to use from this project's current allowance, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's overflow allowance currency.\n /// @param _token The token being distributed. This terminal ignores this property since it only manages one token.\n /// @param _minReturnedTokens The minimum number of tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with 18 decimals.\n /// @param _beneficiary The address to send the funds to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return netDistributedAmount The amount of tokens that was distributed to the beneficiary, as a fixed point number with the same amount of decimals as the terminal.\n function useAllowanceOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n address _token,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.USE_ALLOWANCE)\n returns (uint256 netDistributedAmount)\n {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return _useAllowanceOf(_projectId, _amount, _currency, _minReturnedTokens, _beneficiary, _memo);\n }\n\n /// @notice Allows a project owner to migrate its funds and operations to a new terminal that accepts the same token type.\n /// @dev Only a project's owner or a designated operator can migrate it.\n /// @param _projectId The ID of the project being migrated.\n /// @param _to The terminal contract that will gain the project's funds.\n /// @return balance The amount of funds that were migrated, as a fixed point number with the same amount of decimals as this terminal.\n function migrate(\n uint256 _projectId,\n IJBPaymentTerminal _to\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.MIGRATE_TERMINAL)\n returns (uint256 balance)\n {\n // The terminal being migrated to must accept the same token as this terminal.\n if (!_to.acceptsToken(token, _projectId)) revert TERMINAL_TOKENS_INCOMPATIBLE();\n\n // Record the migration in the store.\n balance = IJBSingleTokenPaymentTerminalStore(store).recordMigration(_projectId);\n\n // Transfer the balance if needed.\n if (balance > 0) {\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_to), balance);\n\n // If this terminal's token is ETH, send it in msg.value.\n uint256 _payableValue = token == JBTokens.ETH ? balance : 0;\n\n // Withdraw the balance to transfer to the new terminal;\n _to.addToBalanceOf{value: _payableValue}(_projectId, balance, token, '', bytes(''));\n }\n\n emit Migrate(_projectId, _to, balance, msg.sender);\n }\n\n /// @notice Receives funds belonging to the specified project.\n /// @param _projectId The ID of the project to which the funds received belong.\n /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\n /// @param _token The token being paid. This terminal ignores this property since it only manages one currency.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the emitted event.\n function addToBalanceOf(\n uint256 _projectId,\n uint256 _amount,\n address _token,\n string calldata _memo,\n bytes calldata _metadata\n ) external payable virtual override isTerminalOf(_projectId) {\n _token; // Prevents unused var compiler and natspec complaints.\n\n // If this terminal's token isn't ETH, make sure no msg.value was sent, then transfer the tokens in from msg.sender.\n if (token != JBTokens.ETH) {\n // Amount must be greater than 0.\n if (msg.value > 0) revert NO_MSG_VALUE_ALLOWED();\n\n // Get a reference to the balance before receiving tokens.\n uint256 _balanceBefore = _balance();\n\n // Transfer tokens to this terminal from the msg sender.\n _transferFrom(msg.sender, payable(address(this)), _amount);\n\n // The amount should reflect the change in balance.\n _amount = _balance() - _balanceBefore;\n }\n // If the terminal's token is ETH, override `_amount` with msg.value.\n else _amount = msg.value;\n\n // Add to balance while only refunding held fees if the funds aren't originating from a feeless terminal.\n _addToBalanceOf(_projectId, _amount, !isFeelessAddress[msg.sender], _memo, _metadata);\n }\n\n /// @notice Process any fees that are being held for the project.\n /// @dev Only a project owner, an operator, or the contract's owner can process held fees.\n /// @param _projectId The ID of the project whos held fees should be processed.\n function processFees(\n uint256 _projectId\n )\n external\n virtual\n override\n requirePermissionAllowingOverride(\n projects.ownerOf(_projectId),\n _projectId,\n JBOperations.PROCESS_FEES,\n msg.sender == owner()\n )\n {\n // Get a reference to the project's held fees.\n JBFee[] memory _heldFees = _heldFeesOf[_projectId];\n\n // Delete the held fees.\n delete _heldFeesOf[_projectId];\n\n // Push array length in stack\n uint256 _heldFeeLength = _heldFees.length;\n\n // Process each fee.\n for (uint256 _i; _i < _heldFeeLength; ) {\n // Get the fee amount.\n uint256 _amount = _feeAmount(\n _heldFees[_i].amount,\n _heldFees[_i].fee,\n _heldFees[_i].feeDiscount\n );\n\n // Process the fee.\n _processFee(_amount, _heldFees[_i].beneficiary);\n\n emit ProcessFee(_projectId, _amount, true, _heldFees[_i].beneficiary, msg.sender);\n\n unchecked {\n ++_i;\n }\n }\n }\n\n /// @notice Allows the fee to be updated.\n /// @dev Only the owner of this contract can change the fee.\n /// @param _fee The new fee, out of MAX_FEE.\n function setFee(uint256 _fee) external virtual override onlyOwner {\n // The provided fee must be within the max.\n if (_fee > _FEE_CAP) revert FEE_TOO_HIGH();\n\n // Store the new fee.\n fee = _fee;\n\n emit SetFee(_fee, msg.sender);\n }\n\n /// @notice Allows the fee gauge to be updated.\n /// @dev Only the owner of this contract can change the fee gauge.\n /// @param _feeGauge The new fee gauge.\n function setFeeGauge(address _feeGauge) external virtual override onlyOwner {\n // Store the new fee gauge.\n feeGauge = _feeGauge;\n\n emit SetFeeGauge(_feeGauge, msg.sender);\n }\n\n /// @notice Sets whether projects operating on this terminal can pay towards the specified address without incurring a fee.\n /// @dev Only the owner of this contract can set addresses as feeless.\n /// @param _address The address that can be paid towards while still bypassing fees.\n /// @param _flag A flag indicating whether the terminal should be feeless or not.\n function setFeelessAddress(address _address, bool _flag) external virtual override onlyOwner {\n // Set the flag value.\n isFeelessAddress[_address] = _flag;\n\n emit SetFeelessAddress(_address, _flag, msg.sender);\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Transfers tokens.\n /// @param _from The address from which the transfer should originate.\n /// @param _to The address to which the transfer should go.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _transferFrom(address _from, address payable _to, uint256 _amount) internal virtual {\n _from; // Prevents unused var compiler and natspec complaints.\n _to; // Prevents unused var compiler and natspec complaints.\n _amount; // Prevents unused var compiler and natspec complaints.\n }\n\n /// @notice Logic to be triggered before transferring tokens from this terminal.\n /// @param _to The address to which the transfer is going.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _beforeTransferTo(address _to, uint256 _amount) internal virtual {\n _to; // Prevents unused var compiler and natspec complaints.\n _amount; // Prevents unused var compiler and natspec complaints.\n }\n\n /// @notice Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source.\n /// @dev Only a token holder or a designated operator can redeem its tokens.\n /// @param _holder The account to redeem tokens for.\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\n /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals.\n /// @param _minReturnedTokens The minimum amount of terminal tokens expected in return, as a fixed point number with the same amount of decimals as the terminal.\n /// @param _beneficiary The address to send the terminal tokens to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return reclaimAmount The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals.\n function _redeemTokensOf(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo,\n bytes memory _metadata\n ) internal returns (uint256 reclaimAmount) {\n // Can't send reclaimed funds to the zero address.\n if (_beneficiary == address(0)) revert REDEEM_TO_ZERO_ADDRESS();\n\n // Define variables that will be needed outside the scoped section below.\n // Keep a reference to the funding cycle during which the redemption is being made.\n JBFundingCycle memory _fundingCycle;\n\n // Scoped section prevents stack too deep. `_delegateAllocations` only used within scope.\n {\n JBRedemptionDelegateAllocation[] memory _delegateAllocations;\n\n // Record the redemption.\n (\n _fundingCycle,\n reclaimAmount,\n _delegateAllocations,\n _memo\n ) = IJBSingleTokenPaymentTerminalStore(store).recordRedemptionFor(\n _holder,\n _projectId,\n _tokenCount,\n _memo,\n _metadata\n );\n\n // The amount being reclaimed must be at least as much as was expected.\n if (reclaimAmount < _minReturnedTokens) revert INADEQUATE_RECLAIM_AMOUNT();\n\n // Burn the project tokens.\n if (_tokenCount > 0)\n IJBController(directory.controllerOf(_projectId)).burnTokensOf(\n _holder,\n _projectId,\n _tokenCount,\n '',\n false\n );\n\n // If delegate allocations were specified by the data source, fulfill them.\n if (_delegateAllocations.length != 0) {\n // Keep a reference to the token amount being forwarded to the delegate.\n JBTokenAmount memory _forwardedAmount = JBTokenAmount(token, 0, decimals, currency);\n\n JBDidRedeemData memory _data = JBDidRedeemData(\n _holder,\n _projectId,\n _fundingCycle.configuration,\n _tokenCount,\n JBTokenAmount(token, reclaimAmount, decimals, currency),\n _forwardedAmount,\n _beneficiary,\n _memo,\n _metadata\n );\n\n uint256 _numDelegates = _delegateAllocations.length;\n\n for (uint256 _i; _i < _numDelegates; ) {\n // Get a reference to the delegate being iterated on.\n JBRedemptionDelegateAllocation memory _delegateAllocation = _delegateAllocations[_i];\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_delegateAllocation.delegate), _delegateAllocation.amount);\n\n // Keep track of the msg.value to use in the delegate call\n uint256 _payableValue;\n\n // If this terminal's token is ETH, send it in msg.value.\n if (token == JBTokens.ETH) _payableValue = _delegateAllocation.amount;\n\n // Pass the correct token forwardedAmount to the delegate\n _data.forwardedAmount.value = _delegateAllocation.amount;\n\n _delegateAllocation.delegate.didRedeem{value: _payableValue}(_data);\n\n emit DelegateDidRedeem(\n _delegateAllocation.delegate,\n _data,\n _delegateAllocation.amount,\n msg.sender\n );\n unchecked {\n ++_i;\n }\n }\n }\n }\n\n // Send the reclaimed funds to the beneficiary.\n if (reclaimAmount > 0) _transferFrom(address(this), _beneficiary, reclaimAmount);\n\n emit RedeemTokens(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _holder,\n _beneficiary,\n _tokenCount,\n reclaimAmount,\n _memo,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Distributes payouts for a project with the distribution limit of its current funding cycle.\n /// @dev Payouts are sent to the preprogrammed splits. Any leftover is sent to the project's owner.\n /// @dev 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.\n /// @dev All funds distributed outside of this contract or any feeless terminals incure the protocol fee.\n /// @param _projectId The ID of the project having its payouts distributed.\n /// @param _amount The amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency.\n /// @param _minReturnedTokens 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.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return netLeftoverDistributionAmount The amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal.\n function _distributePayoutsOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n uint256 _minReturnedTokens,\n string calldata _memo\n ) internal returns (uint256 netLeftoverDistributionAmount) {\n // Record the distribution.\n (\n JBFundingCycle memory _fundingCycle,\n uint256 _distributedAmount\n ) = IJBSingleTokenPaymentTerminalStore(store).recordDistributionFor(\n _projectId,\n _amount,\n _currency\n );\n\n // The amount being distributed must be at least as much as was expected.\n if (_distributedAmount < _minReturnedTokens) revert INADEQUATE_DISTRIBUTION_AMOUNT();\n\n // Get a reference to the project owner, which will receive tokens from paying the platform fee\n // and receive any extra distributable funds not allocated to payout splits.\n address payable _projectOwner = payable(projects.ownerOf(_projectId));\n\n // Define variables that will be needed outside the scoped section below.\n // Keep a reference to the fee amount that was paid.\n uint256 _fee;\n\n // Scoped section prevents stack too deep. `_feeDiscount`, `_feeEligibleDistributionAmount`, and `_leftoverDistributionAmount` only used within scope.\n {\n // Get the amount of discount that should be applied to any fees taken.\n // If the fee is zero, set the discount to 100% for convenience.\n uint256 _feeDiscount = fee == 0\n ? JBConstants.MAX_FEE_DISCOUNT\n : _currentFeeDiscount(_projectId);\n\n // The amount distributed that is eligible for incurring fees.\n uint256 _feeEligibleDistributionAmount;\n\n // The amount leftover after distributing to the splits.\n uint256 _leftoverDistributionAmount;\n\n // Payout to splits and get a reference to the leftover transfer amount after all splits have been paid.\n // Also get a reference to the amount that was distributed to splits from which fees should be taken.\n (_leftoverDistributionAmount, _feeEligibleDistributionAmount) = _distributeToPayoutSplitsOf(\n _projectId,\n _fundingCycle.configuration,\n payoutSplitsGroup,\n _distributedAmount,\n _feeDiscount\n );\n\n if (_feeDiscount != JBConstants.MAX_FEE_DISCOUNT) {\n // Leftover distribution amount is also eligible for a fee since the funds are going out of the ecosystem to _beneficiary.\n unchecked {\n _feeEligibleDistributionAmount += _leftoverDistributionAmount;\n }\n }\n\n // Take the fee.\n _fee = _feeEligibleDistributionAmount != 0\n ? _takeFeeFrom(\n _projectId,\n _fundingCycle,\n _feeEligibleDistributionAmount,\n _projectOwner,\n _feeDiscount\n )\n : 0;\n\n // Transfer any remaining balance to the project owner and update returned leftover accordingly.\n if (_leftoverDistributionAmount != 0) {\n // Subtract the fee from the net leftover amount.\n netLeftoverDistributionAmount =\n _leftoverDistributionAmount -\n _feeAmount(_leftoverDistributionAmount, fee, _feeDiscount);\n\n // Transfer the amount to the project owner.\n _transferFrom(address(this), _projectOwner, netLeftoverDistributionAmount);\n }\n }\n\n emit DistributePayouts(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _projectOwner,\n _amount,\n _distributedAmount,\n _fee,\n netLeftoverDistributionAmount,\n _memo,\n msg.sender\n );\n }\n\n /// @notice Allows a project to send funds from its overflow up to the preconfigured allowance.\n /// @dev Only a project's owner or a designated operator can use its allowance.\n /// @dev Incurs the protocol fee.\n /// @param _projectId The ID of the project to use the allowance of.\n /// @param _amount The amount of terminal tokens to use from this project's current allowance, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's overflow allowance currency.\n /// @param _minReturnedTokens The minimum number of tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with 18 decimals.\n /// @param _beneficiary The address to send the funds to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return netDistributedAmount The amount of tokens that was distributed to the beneficiary, as a fixed point number with the same amount of decimals as the terminal.\n function _useAllowanceOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo\n ) internal returns (uint256 netDistributedAmount) {\n // Record the use of the allowance.\n (\n JBFundingCycle memory _fundingCycle,\n uint256 _distributedAmount\n ) = IJBSingleTokenPaymentTerminalStore(store).recordUsedAllowanceOf(\n _projectId,\n _amount,\n _currency\n );\n\n // The amount being withdrawn must be at least as much as was expected.\n if (_distributedAmount < _minReturnedTokens) revert INADEQUATE_DISTRIBUTION_AMOUNT();\n\n // Scoped section prevents stack too deep. `_fee`, `_projectOwner`, `_feeDiscount`, and `_netAmount` only used within scope.\n {\n // Keep a reference to the fee amount that was paid.\n uint256 _fee;\n\n // Get a reference to the project owner, which will receive tokens from paying the platform fee.\n address _projectOwner = projects.ownerOf(_projectId);\n\n // Get the amount of discount that should be applied to any fees taken.\n // 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.\n uint256 _feeDiscount = fee == 0 || isFeelessAddress[msg.sender]\n ? JBConstants.MAX_FEE_DISCOUNT\n : _currentFeeDiscount(_projectId);\n\n // Take a fee from the `_distributedAmount`, if needed.\n _fee = _feeDiscount == JBConstants.MAX_FEE_DISCOUNT\n ? 0\n : _takeFeeFrom(_projectId, _fundingCycle, _distributedAmount, _projectOwner, _feeDiscount);\n\n unchecked {\n // The net amount is the withdrawn amount without the fee.\n netDistributedAmount = _distributedAmount - _fee;\n }\n\n // Transfer any remaining balance to the beneficiary.\n if (netDistributedAmount > 0)\n _transferFrom(address(this), _beneficiary, netDistributedAmount);\n }\n\n emit UseAllowance(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _beneficiary,\n _amount,\n _distributedAmount,\n netDistributedAmount,\n _memo,\n msg.sender\n );\n }\n\n /// @notice Pays out splits for a project's funding cycle configuration.\n /// @param _projectId The ID of the project for which payout splits are being distributed.\n /// @param _domain The domain of the splits to distribute the payout between.\n /// @param _group The group of the splits to distribute the payout between.\n /// @param _amount The total amount being distributed, as a fixed point number with the same number of decimals as this terminal.\n /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE.\n /// @return leftoverAmount If the leftover amount if the splits don't add up to 100%.\n /// @return feeEligibleDistributionAmount The total amount of distributions that are eligible to have fees taken from.\n function _distributeToPayoutSplitsOf(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group,\n uint256 _amount,\n uint256 _feeDiscount\n ) internal returns (uint256 leftoverAmount, uint256 feeEligibleDistributionAmount) {\n // Set the leftover amount to the initial amount.\n leftoverAmount = _amount;\n // The total percentage available to split\n uint256 leftoverPercentage = JBConstants.SPLITS_TOTAL_PERCENT;\n\n // Get a reference to the project's payout splits.\n JBSplit[] memory _splits = splitsStore.splitsOf(_projectId, _domain, _group);\n\n // Transfer between all splits.\n for (uint256 _i; _i < _splits.length; ) {\n // Get a reference to the split being iterated on.\n JBSplit memory _split = _splits[_i];\n\n // The amount to send towards the split.\n uint256 _payoutAmount = _split.percent == leftoverPercentage\n ? leftoverAmount\n : PRBMath.mulDiv(_amount, _split.percent, JBConstants.SPLITS_TOTAL_PERCENT);\n\n // Decrement the leftover percentage.\n leftoverPercentage -= _split.percent;\n\n // The payout amount substracting any applicable incurred fees.\n uint256 _netPayoutAmount;\n\n if (_payoutAmount > 0) {\n // Transfer tokens to the split.\n // If there's an allocator set, transfer to its `allocate` function.\n if (_split.allocator != IJBSplitAllocator(address(0))) {\n // If the split allocator is set as feeless, this distribution is not eligible for a fee.\n if (\n _feeDiscount == JBConstants.MAX_FEE_DISCOUNT ||\n isFeelessAddress[address(_split.allocator)]\n )\n _netPayoutAmount = _payoutAmount;\n // This distribution is eligible for a fee since the funds are leaving this contract and the allocator isn't listed as feeless.\n else {\n unchecked {\n _netPayoutAmount = _payoutAmount - _feeAmount(_payoutAmount, fee, _feeDiscount);\n }\n\n // This distribution is eligible for a fee since the funds are leaving the ecosystem.\n feeEligibleDistributionAmount += _payoutAmount;\n }\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_split.allocator), _netPayoutAmount);\n\n // Create the data to send to the allocator.\n JBSplitAllocationData memory _data = JBSplitAllocationData(\n token,\n _netPayoutAmount,\n decimals,\n _projectId,\n _group,\n _split\n );\n\n // Trigger the allocator's `allocate` function.\n // If this terminal's token is ETH, send it in msg.value.\n _split.allocator.allocate{value: token == JBTokens.ETH ? _netPayoutAmount : 0}(_data);\n\n // Otherwise, if a project is specified, make a payment to it.\n } else if (_split.projectId != 0) {\n // Get a reference to the Juicebox terminal being used.\n IJBPaymentTerminal _terminal = directory.primaryTerminalOf(_split.projectId, token);\n\n // The project must have a terminal to send funds to.\n if (_terminal == IJBPaymentTerminal(address(0))) revert TERMINAL_IN_SPLIT_ZERO_ADDRESS();\n\n // Save gas if this contract is being used as the terminal.\n if (_terminal == this) {\n // This distribution does not incur a fee.\n _netPayoutAmount = _payoutAmount;\n\n // Send the projectId in the metadata.\n bytes memory _projectMetadata = new bytes(32);\n _projectMetadata = bytes(abi.encodePacked(_projectId));\n\n // Add to balance if prefered.\n if (_split.preferAddToBalance)\n _addToBalanceOf(_split.projectId, _netPayoutAmount, false, '', _projectMetadata);\n else\n _pay(\n _netPayoutAmount,\n address(this),\n _split.projectId,\n (_split.beneficiary != address(0)) ? _split.beneficiary : msg.sender,\n 0,\n _split.preferClaimed,\n '',\n _projectMetadata\n );\n } else {\n // If the terminal is set as feeless, this distribution is not eligible for a fee.\n if (\n _feeDiscount == JBConstants.MAX_FEE_DISCOUNT || isFeelessAddress[address(_terminal)]\n )\n _netPayoutAmount = _payoutAmount;\n // This distribution is eligible for a fee since the funds are leaving this contract and the terminal isn't listed as feeless.\n else {\n unchecked {\n _netPayoutAmount = _payoutAmount - _feeAmount(_payoutAmount, fee, _feeDiscount);\n }\n\n feeEligibleDistributionAmount += _payoutAmount;\n }\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_terminal), _netPayoutAmount);\n\n // If this terminal's token is ETH, send it in msg.value.\n uint256 _payableValue = token == JBTokens.ETH ? _netPayoutAmount : 0;\n\n // Send the projectId in the metadata.\n bytes memory _projectMetadata = new bytes(32);\n _projectMetadata = bytes(abi.encodePacked(_projectId));\n\n // Add to balance if prefered.\n if (_split.preferAddToBalance)\n _terminal.addToBalanceOf{value: _payableValue}(\n _split.projectId,\n _netPayoutAmount,\n token,\n '',\n _projectMetadata\n );\n else\n _terminal.pay{value: _payableValue}(\n _split.projectId,\n _netPayoutAmount,\n token,\n _split.beneficiary != address(0) ? _split.beneficiary : msg.sender,\n 0,\n _split.preferClaimed,\n '',\n _projectMetadata\n );\n }\n } else {\n // Keep a reference to the beneficiary.\n address payable _beneficiary = _split.beneficiary != address(0)\n ? _split.beneficiary\n : payable(msg.sender);\n\n // If there's a full discount, this distribution is not eligible for a fee.\n // Don't enforce feeless address for the beneficiary since the funds are leaving the ecosystem.\n if (_feeDiscount == JBConstants.MAX_FEE_DISCOUNT)\n _netPayoutAmount = _payoutAmount;\n // This distribution is eligible for a fee since the funds are leaving this contract and the beneficiary isn't listed as feeless.\n else {\n unchecked {\n _netPayoutAmount = _payoutAmount - _feeAmount(_payoutAmount, fee, _feeDiscount);\n }\n\n feeEligibleDistributionAmount += _payoutAmount;\n }\n\n // If there's a beneficiary, send the funds directly to the beneficiary. Otherwise send to the msg.sender.\n _transferFrom(address(this), _beneficiary, _netPayoutAmount);\n }\n\n // Subtract from the amount to be sent to the beneficiary.\n unchecked {\n leftoverAmount = leftoverAmount - _payoutAmount;\n }\n }\n\n emit DistributeToPayoutSplit(\n _projectId,\n _domain,\n _group,\n _split,\n _netPayoutAmount,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n\n /// @notice Takes a fee into the platform's project, which has an id of _FEE_BENEFICIARY_PROJECT_ID.\n /// @param _projectId The ID of the project having fees taken from.\n /// @param _fundingCycle The funding cycle during which the fee is being taken.\n /// @param _amount The amount of the fee to take, as a floating point number with 18 decimals.\n /// @param _beneficiary The address to mint the platforms tokens for.\n /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE.\n /// @return feeAmount The amount of the fee taken.\n function _takeFeeFrom(\n uint256 _projectId,\n JBFundingCycle memory _fundingCycle,\n uint256 _amount,\n address _beneficiary,\n uint256 _feeDiscount\n ) internal returns (uint256 feeAmount) {\n feeAmount = _feeAmount(_amount, fee, _feeDiscount);\n\n if (_fundingCycle.shouldHoldFees()) {\n // Store the held fee.\n _heldFeesOf[_projectId].push(JBFee(_amount, uint32(fee), uint32(_feeDiscount), _beneficiary));\n\n emit HoldFee(_projectId, _amount, fee, _feeDiscount, _beneficiary, msg.sender);\n } else {\n // Process the fee.\n _processFee(feeAmount, _beneficiary); // Take the fee.\n\n emit ProcessFee(_projectId, feeAmount, false, _beneficiary, msg.sender);\n }\n }\n\n /// @notice Process a fee of the specified amount.\n /// @param _amount The fee amount, as a floating point number with 18 decimals.\n /// @param _beneficiary The address to mint the platform's tokens for.\n function _processFee(uint256 _amount, address _beneficiary) internal {\n // Get the terminal for the protocol project.\n IJBPaymentTerminal _terminal = directory.primaryTerminalOf(_FEE_BENEFICIARY_PROJECT_ID, token);\n\n // When processing the admin fee, save gas if the admin is using this contract as its terminal.\n if (_terminal == this)\n _pay(\n _amount,\n address(this),\n _FEE_BENEFICIARY_PROJECT_ID,\n _beneficiary,\n 0,\n false,\n '',\n bytes('')\n ); // Use the local pay call.\n else {\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_terminal), _amount);\n\n // If this terminal's token is ETH, send it in msg.value.\n uint256 _payableValue = token == JBTokens.ETH ? _amount : 0;\n\n // Send the payment.\n _terminal.pay{value: _payableValue}(\n _FEE_BENEFICIARY_PROJECT_ID,\n _amount,\n token,\n _beneficiary,\n 0,\n false,\n '',\n bytes('')\n ); // Use the external pay call of the correct terminal.\n }\n }\n\n /// @notice Contribute tokens to a project.\n /// @param _amount The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place.\n /// @param _payer The address making the payment.\n /// @param _projectId The ID of the project being paid.\n /// @param _beneficiary The address to mint tokens for and pass along to the funding cycle's data source and delegate.\n /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\n /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return beneficiaryTokenCount The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals.\n function _pay(\n uint256 _amount,\n address _payer,\n uint256 _projectId,\n address _beneficiary,\n uint256 _minReturnedTokens,\n bool _preferClaimedTokens,\n string memory _memo,\n bytes memory _metadata\n ) internal returns (uint256 beneficiaryTokenCount) {\n // Cant send tokens to the zero address.\n if (_beneficiary == address(0)) revert PAY_TO_ZERO_ADDRESS();\n\n // Define variables that will be needed outside the scoped section below.\n // Keep a reference to the funding cycle during which the payment is being made.\n JBFundingCycle memory _fundingCycle;\n\n // Scoped section prevents stack too deep. `_delegateAllocations` and `_tokenCount` only used within scope.\n {\n JBPayDelegateAllocation[] memory _delegateAllocations;\n uint256 _tokenCount;\n\n // Bundle the amount info into a JBTokenAmount struct.\n JBTokenAmount memory _bundledAmount = JBTokenAmount(token, _amount, decimals, currency);\n\n // Record the payment.\n (\n _fundingCycle,\n _tokenCount,\n _delegateAllocations,\n _memo\n ) = IJBSingleTokenPaymentTerminalStore(store).recordPaymentFrom(\n _payer,\n _bundledAmount,\n _projectId,\n baseWeightCurrency,\n _beneficiary,\n _memo,\n _metadata\n );\n\n // Mint the tokens if needed.\n if (_tokenCount > 0)\n // Set token count to be the number of tokens minted for the beneficiary instead of the total amount.\n beneficiaryTokenCount = IJBController(directory.controllerOf(_projectId)).mintTokensOf(\n _projectId,\n _tokenCount,\n _beneficiary,\n '',\n _preferClaimedTokens,\n true\n );\n\n // The token count for the beneficiary must be greater than or equal to the minimum expected.\n if (beneficiaryTokenCount < _minReturnedTokens) revert INADEQUATE_TOKEN_COUNT();\n\n // If delegate allocations were specified by the data source, fulfill them.\n if (_delegateAllocations.length != 0) {\n // Keep a reference to the token amount being forwarded to the delegate.\n JBTokenAmount memory _forwardedAmount = JBTokenAmount(token, _amount, decimals, currency);\n\n JBDidPayData memory _data = JBDidPayData(\n _payer,\n _projectId,\n _fundingCycle.configuration,\n _bundledAmount,\n _forwardedAmount,\n beneficiaryTokenCount,\n _beneficiary,\n _preferClaimedTokens,\n _memo,\n _metadata\n );\n\n // Get a reference to the number of delegates to allocate to.\n uint256 _numDelegates = _delegateAllocations.length;\n\n for (uint256 _i; _i < _numDelegates; ) {\n // Get a reference to the delegate being iterated on.\n JBPayDelegateAllocation memory _delegateAllocation = _delegateAllocations[_i];\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_delegateAllocation.delegate), _delegateAllocation.amount);\n\n // Keep track of the msg.value to use in the delegate call\n uint256 _payableValue;\n\n // If this terminal's token is ETH, send it in msg.value.\n if (token == JBTokens.ETH) _payableValue = _delegateAllocation.amount;\n\n // Pass the correct token forwardedAmount to the delegate\n _data.forwardedAmount.value = _delegateAllocation.amount;\n\n _delegateAllocation.delegate.didPay{value: _payableValue}(_data);\n\n emit DelegateDidPay(\n _delegateAllocation.delegate,\n _data,\n _delegateAllocation.amount,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n }\n\n emit Pay(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _payer,\n _beneficiary,\n _amount,\n beneficiaryTokenCount,\n _memo,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Receives funds belonging to the specified project.\n /// @param _projectId The ID of the project to which the funds received belong.\n /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\n /// @param _shouldRefundHeldFees A flag indicating if held fees should be refunded based on the amount being added.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the emitted event.\n function _addToBalanceOf(\n uint256 _projectId,\n uint256 _amount,\n bool _shouldRefundHeldFees,\n string memory _memo,\n bytes memory _metadata\n ) internal {\n // Refund any held fees to make sure the project doesn't pay double for funds going in and out of the protocol.\n uint256 _refundedFees = _shouldRefundHeldFees ? _refundHeldFees(_projectId, _amount) : 0;\n\n // Record the added funds with any refunded fees.\n IJBSingleTokenPaymentTerminalStore(store).recordAddedBalanceFor(\n _projectId,\n _amount + _refundedFees\n );\n\n emit AddToBalance(_projectId, _amount, _refundedFees, _memo, _metadata, msg.sender);\n }\n\n /// @notice Refund fees based on the specified amount.\n /// @param _projectId The project for which fees are being refunded.\n /// @param _amount The amount to base the refund on, as a fixed point number with the same amount of decimals as this terminal.\n /// @return refundedFees How much fees were refunded, as a fixed point number with the same number of decimals as this terminal\n function _refundHeldFees(\n uint256 _projectId,\n uint256 _amount\n ) internal returns (uint256 refundedFees) {\n // Get a reference to the project's held fees.\n JBFee[] memory _heldFees = _heldFeesOf[_projectId];\n\n // Delete the current held fees.\n delete _heldFeesOf[_projectId];\n\n // Get a reference to the leftover amount once all fees have been settled.\n uint256 leftoverAmount = _amount;\n\n // Push length in stack\n uint256 _heldFeesLength = _heldFees.length;\n\n // Process each fee.\n for (uint256 _i; _i < _heldFeesLength; ) {\n if (leftoverAmount == 0) _heldFeesOf[_projectId].push(_heldFees[_i]);\n else if (leftoverAmount >= _heldFees[_i].amount) {\n unchecked {\n leftoverAmount = leftoverAmount - _heldFees[_i].amount;\n refundedFees += _feeAmount(\n _heldFees[_i].amount,\n _heldFees[_i].fee,\n _heldFees[_i].feeDiscount\n );\n }\n } else {\n unchecked {\n _heldFeesOf[_projectId].push(\n JBFee(\n _heldFees[_i].amount - leftoverAmount,\n _heldFees[_i].fee,\n _heldFees[_i].feeDiscount,\n _heldFees[_i].beneficiary\n )\n );\n refundedFees += _feeAmount(leftoverAmount, _heldFees[_i].fee, _heldFees[_i].feeDiscount);\n }\n leftoverAmount = 0;\n }\n\n unchecked {\n ++_i;\n }\n }\n\n emit RefundHeldFees(_projectId, _amount, refundedFees, leftoverAmount, msg.sender);\n }\n\n /// @notice Returns the fee amount based on the provided amount for the specified project.\n /// @param _amount The amount that the fee is based on, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _fee The percentage of the fee, out of MAX_FEE.\n /// @param _feeDiscount The percentage discount that should be applied out of the max amount, out of MAX_FEE_DISCOUNT.\n /// @return The amount of the fee, as a fixed point number with the same amount of decimals as this terminal.\n function _feeAmount(\n uint256 _amount,\n uint256 _fee,\n uint256 _feeDiscount\n ) internal pure returns (uint256) {\n // Calculate the discounted fee.\n uint256 _discountedFee = _fee -\n PRBMath.mulDiv(_fee, _feeDiscount, JBConstants.MAX_FEE_DISCOUNT);\n\n // The amount of tokens from the `_amount` to pay as a fee.\n return\n _amount - PRBMath.mulDiv(_amount, JBConstants.MAX_FEE, _discountedFee + JBConstants.MAX_FEE);\n }\n\n /// @notice Get the fee discount from the fee gauge for the specified project.\n /// @param _projectId The ID of the project to get a fee discount for.\n /// @return feeDiscount The fee discount, which should be interpreted as a percentage out MAX_FEE_DISCOUNT.\n function _currentFeeDiscount(uint256 _projectId) internal view returns (uint256) {\n // Can't take a fee if the protocol project doesn't have a terminal that accepts the token.\n if (\n directory.primaryTerminalOf(_FEE_BENEFICIARY_PROJECT_ID, token) ==\n IJBPaymentTerminal(address(0))\n ) return JBConstants.MAX_FEE_DISCOUNT;\n\n // Get the fee discount.\n if (feeGauge != address(0))\n // If the guage reverts, keep the discount at 0.\n try IJBFeeGauge(feeGauge).currentDiscountFor(_projectId) returns (uint256 discount) {\n // If the fee discount is greater than the max, we ignore the return value\n if (discount <= JBConstants.MAX_FEE_DISCOUNT) return discount;\n } catch {\n return 0;\n }\n\n return 0;\n }\n}\n" + }, + "contracts/JBERC20PaymentTerminal3_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';\nimport {IERC20Metadata} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol';\nimport {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';\nimport {JBPayoutRedemptionPaymentTerminal3_1} from './abstract/JBPayoutRedemptionPaymentTerminal3_1.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\n\n/// @notice Manages the inflows and outflows of an ERC-20 token.\ncontract JBERC20PaymentTerminal3_1 is JBPayoutRedemptionPaymentTerminal3_1 {\n using SafeERC20 for IERC20;\n\n //*********************************************************************//\n // -------------------------- internal views ------------------------- //\n //*********************************************************************//\n\n /// @notice Checks the balance of tokens in this contract.\n /// @return The contract's balance, as a fixed point number with the same amount of decimals as this terminal.\n function _balance() internal view override returns (uint256) {\n return IERC20(token).balanceOf(address(this));\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _token The token that this terminal manages.\n /// @param _currency The currency that this terminal's token adheres to for price feeds.\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _payoutSplitsGroup The group that denotes payout splits from this terminal in the splits store.\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _prices A contract that exposes price feeds.\n /// @param _store A contract that stores the terminal's data.\n /// @param _owner The address that will own this contract.\n constructor(\n IERC20Metadata _token,\n uint256 _currency,\n uint256 _baseWeightCurrency,\n uint256 _payoutSplitsGroup,\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBSplitsStore _splitsStore,\n IJBPrices _prices,\n address _store,\n address _owner\n )\n JBPayoutRedemptionPaymentTerminal3_1(\n address(_token),\n _token.decimals(),\n _currency,\n _baseWeightCurrency,\n _payoutSplitsGroup,\n _operatorStore,\n _projects,\n _directory,\n _splitsStore,\n _prices,\n _store,\n _owner\n )\n // solhint-disable-next-line no-empty-blocks\n {\n\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Transfers tokens.\n /// @param _from The address from which the transfer should originate.\n /// @param _to The address to which the transfer should go.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _transferFrom(address _from, address payable _to, uint256 _amount) internal override {\n _from == address(this)\n ? IERC20(token).safeTransfer(_to, _amount)\n : IERC20(token).safeTransferFrom(_from, _to, _amount);\n }\n\n /// @notice Logic to be triggered before transferring tokens from this terminal.\n /// @param _to The address to which the transfer is going.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _beforeTransferTo(address _to, uint256 _amount) internal override {\n IERC20(token).safeIncreaseAllowance(_to, _amount);\n }\n\n /// @notice Logic to be triggered if a transfer should be undone\n /// @param _to The address to which the transfer went.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _cancelTransferTo(address _to, uint256 _amount) internal override {\n IERC20(token).safeDecreaseAllowance(_to, _amount);\n }\n}\n" + }, + "contracts/JBPrices.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {IJBPriceFeed} from './interfaces/IJBPriceFeed.sol';\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\n\n/// @notice Manages and normalizes price feeds.\ncontract JBPrices is Ownable, IJBPrices {\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error PRICE_FEED_ALREADY_EXISTS();\n error PRICE_FEED_NOT_FOUND();\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The available price feeds.\n /// @dev The feed returns the number of `_currency` units that can be converted to 1 `_base` unit.\n /// @custom:param _currency The currency units the feed's resulting price is in terms of.\n /// @custom:param _base The base currency unit being priced by the feed.\n mapping(uint256 => mapping(uint256 => IJBPriceFeed)) public override feedFor;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Gets the number of `_currency` units that can be converted to 1 `_base` unit.\n /// @param _currency The currency units the resulting price is in terms of.\n /// @param _base The base currency unit being priced.\n /// @param _decimals The number of decimals the returned fixed point price should include.\n /// @return The price of the currency in terms of the base, as a fixed point number with the specified number of decimals.\n function priceFor(\n uint256 _currency,\n uint256 _base,\n uint256 _decimals\n ) external view override returns (uint256) {\n // If the currency is the base, return 1 since they are priced the same. Include the desired number of decimals.\n if (_currency == _base) return 10 ** _decimals;\n\n // Get a reference to the feed.\n IJBPriceFeed _feed = feedFor[_currency][_base];\n\n // If it exists, return the price.\n if (_feed != IJBPriceFeed(address(0))) return _feed.currentPrice(_decimals);\n\n // Get the inverse feed.\n _feed = feedFor[_base][_currency];\n\n // If it exists, return the inverse price.\n if (_feed != IJBPriceFeed(address(0)))\n return PRBMath.mulDiv(10 ** _decimals, 10 ** _decimals, _feed.currentPrice(_decimals));\n\n // No price feed available, revert.\n revert PRICE_FEED_NOT_FOUND();\n }\n\n //*********************************************************************//\n // ---------------------------- constructor -------------------------- //\n //*********************************************************************//\n\n /// @param _owner The address that will own the contract.\n constructor(address _owner) {\n // Transfer the ownership.\n transferOwnership(_owner);\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Add a price feed for a currency in terms of the provided base currency.\n /// @dev Current feeds can't be modified.\n /// @param _currency The currency units the feed's resulting price is in terms of.\n /// @param _base The base currency unit being priced by the feed.\n /// @param _feed The price feed being added.\n function addFeedFor(\n uint256 _currency,\n uint256 _base,\n IJBPriceFeed _feed\n ) external override onlyOwner {\n // There can't already be a feed for the specified currency.\n if (\n feedFor[_currency][_base] != IJBPriceFeed(address(0)) ||\n feedFor[_base][_currency] != IJBPriceFeed(address(0))\n ) revert PRICE_FEED_ALREADY_EXISTS();\n\n // Store the feed.\n feedFor[_currency][_base] = _feed;\n\n emit AddFeed(_currency, _base, _feed);\n }\n}\n" + }, + "contracts/JBChainlinkV3PriceFeed.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {AggregatorV3Interface} from '@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol';\nimport {IJBPriceFeed} from './interfaces/IJBPriceFeed.sol';\nimport {JBFixedPointNumber} from './libraries/JBFixedPointNumber.sol';\n\n/// @notice A generalized price feed for the Chainlink AggregatorV3Interface.\ncontract JBChainlinkV3PriceFeed is IJBPriceFeed {\n // A library that provides utility for fixed point numbers.\n using JBFixedPointNumber for uint256;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error STALE_PRICE();\n error INCOMPLETE_ROUND();\n error NEGATIVE_PRICE();\n\n //*********************************************************************//\n // ---------------- public stored immutable properties --------------- //\n //*********************************************************************//\n\n /// @notice The feed that prices are reported from.\n AggregatorV3Interface public immutable feed;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Gets the current price from the feed, normalized to the specified number of decimals.\n /// @param _decimals The number of decimals the returned fixed point price should include.\n /// @return The current price of the feed, as a fixed point number with the specified number of decimals.\n function currentPrice(uint256 _decimals) external view override returns (uint256) {\n // Get the latest round information.\n (uint80 roundId, int256 _price, , uint256 updatedAt, uint80 answeredInRound) = feed\n .latestRoundData();\n\n // Make sure the price isn't stale.\n if (answeredInRound < roundId) revert STALE_PRICE();\n\n // Make sure the round is finished.\n if (updatedAt == 0) revert INCOMPLETE_ROUND();\n\n // Make sure the price is positive.\n if (_price < 0) revert NEGATIVE_PRICE();\n\n // Get a reference to the number of decimals the feed uses.\n uint256 _feedDecimals = feed.decimals();\n\n // Return the price, adjusted to the target decimals.\n return uint256(_price).adjustDecimals(_feedDecimals, _decimals);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _feed The feed to report prices from.\n constructor(AggregatorV3Interface _feed) {\n feed = _feed;\n }\n}\n" + }, + "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface AggregatorV3Interface {\n\n function decimals()\n external\n view\n returns (\n uint8\n );\n\n function description()\n external\n view\n returns (\n string memory\n );\n\n function version()\n external\n view\n returns (\n uint256\n );\n\n // getRoundData and latestRoundData should both raise \"No data present\"\n // if they do not have data to report, instead of returning unset values\n // which could be misinterpreted as actual reported values.\n function getRoundData(\n uint80 _roundId\n )\n external\n view\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n );\n\n function latestRoundData()\n external\n view\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n );\n\n}\n" + }, + "contracts/JBERC20PaymentTerminal3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';\nimport {IERC20Metadata} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol';\nimport {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';\nimport {JBPayoutRedemptionPaymentTerminal3_1_1} from './abstract/JBPayoutRedemptionPaymentTerminal3_1_1.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\n\n/// @notice Manages the inflows and outflows of an ERC-20 token.\ncontract JBERC20PaymentTerminal3_1_1 is JBPayoutRedemptionPaymentTerminal3_1_1 {\n using SafeERC20 for IERC20;\n\n //*********************************************************************//\n // -------------------------- internal views ------------------------- //\n //*********************************************************************//\n\n /// @notice Checks the balance of tokens in this contract.\n /// @return The contract's balance, as a fixed point number with the same amount of decimals as this terminal.\n function _balance() internal view override returns (uint256) {\n return IERC20(token).balanceOf(address(this));\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _token The token that this terminal manages.\n /// @param _currency The currency that this terminal's token adheres to for price feeds.\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _payoutSplitsGroup The group that denotes payout splits from this terminal in the splits store.\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _prices A contract that exposes price feeds.\n /// @param _store A contract that stores the terminal's data.\n /// @param _owner The address that will own this contract.\n constructor(\n IERC20Metadata _token,\n uint256 _currency,\n uint256 _baseWeightCurrency,\n uint256 _payoutSplitsGroup,\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBSplitsStore _splitsStore,\n IJBPrices _prices,\n address _store,\n address _owner\n )\n JBPayoutRedemptionPaymentTerminal3_1_1(\n address(_token),\n _token.decimals(),\n _currency,\n _baseWeightCurrency,\n _payoutSplitsGroup,\n _operatorStore,\n _projects,\n _directory,\n _splitsStore,\n _prices,\n _store,\n _owner\n )\n // solhint-disable-next-line no-empty-blocks\n {\n\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Transfers tokens.\n /// @param _from The address from which the transfer should originate.\n /// @param _to The address to which the transfer should go.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _transferFrom(address _from, address payable _to, uint256 _amount) internal override {\n _from == address(this)\n ? IERC20(token).safeTransfer(_to, _amount)\n : IERC20(token).safeTransferFrom(_from, _to, _amount);\n }\n\n /// @notice Logic to be triggered before transferring tokens from this terminal.\n /// @param _to The address to which the transfer is going.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _beforeTransferTo(address _to, uint256 _amount) internal override {\n IERC20(token).safeIncreaseAllowance(_to, _amount);\n }\n\n /// @notice Logic to be triggered if a transfer should be undone\n /// @param _to The address to which the transfer went.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _cancelTransferTo(address _to, uint256 _amount) internal override {\n IERC20(token).safeDecreaseAllowance(_to, _amount);\n }\n}\n" + }, + "contracts/JBERC20PaymentTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';\nimport {IERC20Metadata} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol';\nimport {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';\nimport {JBPayoutRedemptionPaymentTerminal} from './abstract/JBPayoutRedemptionPaymentTerminal.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\n\n/// @notice Manages the inflows and outflows of an ERC-20 token.\ncontract JBERC20PaymentTerminal is JBPayoutRedemptionPaymentTerminal {\n using SafeERC20 for IERC20;\n\n //*********************************************************************//\n // -------------------------- internal views ------------------------- //\n //*********************************************************************//\n\n /// @notice Checks the balance of tokens in this contract.\n /// @return The contract's balance, as a fixed point number with the same amount of decimals as this terminal.\n function _balance() internal view override returns (uint256) {\n return IERC20(token).balanceOf(address(this));\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _token The token that this terminal manages.\n /// @param _currency The currency that this terminal's token adheres to for price feeds.\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _payoutSplitsGroup The group that denotes payout splits from this terminal in the splits store.\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _prices A contract that exposes price feeds.\n /// @param _store A contract that stores the terminal's data.\n /// @param _owner The address that will own this contract.\n constructor(\n IERC20Metadata _token,\n uint256 _currency,\n uint256 _baseWeightCurrency,\n uint256 _payoutSplitsGroup,\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBSplitsStore _splitsStore,\n IJBPrices _prices,\n address _store,\n address _owner\n )\n JBPayoutRedemptionPaymentTerminal(\n address(_token),\n _token.decimals(),\n _currency,\n _baseWeightCurrency,\n _payoutSplitsGroup,\n _operatorStore,\n _projects,\n _directory,\n _splitsStore,\n _prices,\n _store,\n _owner\n )\n // solhint-disable-next-line no-empty-blocks\n {\n\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Transfers tokens.\n /// @param _from The address from which the transfer should originate.\n /// @param _to The address to which the transfer should go.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _transferFrom(address _from, address payable _to, uint256 _amount) internal override {\n _from == address(this)\n ? IERC20(token).safeTransfer(_to, _amount)\n : IERC20(token).safeTransferFrom(_from, _to, _amount);\n }\n\n /// @notice Logic to be triggered before transferring tokens from this terminal.\n /// @param _to The address to which the transfer is going.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _beforeTransferTo(address _to, uint256 _amount) internal override {\n IERC20(token).safeApprove(_to, _amount);\n }\n}\n" + }, + "contracts/JBFundingCycleStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {JBControllerUtility} from './abstract/JBControllerUtility.sol';\nimport {JBBallotState} from './enums/JBBallotState.sol';\nimport {JBConstants} from './libraries/JBConstants.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBFundingCycleBallot} from './interfaces/IJBFundingCycleBallot.sol';\nimport {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\nimport {JBFundingCycleData} from './structs/JBFundingCycleData.sol';\n\n/// @notice Manages funding cycle configurations and scheduling.\ncontract JBFundingCycleStore is JBControllerUtility, IJBFundingCycleStore {\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error INVALID_BALLOT();\n error INVALID_DISCOUNT_RATE();\n error INVALID_DURATION();\n error INVALID_TIMEFRAME();\n error INVALID_WEIGHT();\n error NO_SAME_BLOCK_RECONFIGURATION();\n\n //*********************************************************************//\n // --------------------- private stored properties ------------------- //\n //*********************************************************************//\n\n /// @notice Stores the user defined properties of each funding cycle, packed into one storage slot.\n /// @custom:param _projectId The ID of the project to get properties of.\n /// @custom:param _configuration The funding cycle configuration to get properties of.\n mapping(uint256 => mapping(uint256 => uint256)) private _packedUserPropertiesOf;\n\n /// @notice Stores the properties added by the mechanism to manage and schedule each funding cycle, packed into one storage slot.\n /// @custom:param _projectId The ID of the project to get instrinsic properties of.\n /// @custom:param _configuration The funding cycle configuration to get properties of.\n mapping(uint256 => mapping(uint256 => uint256)) private _packedIntrinsicPropertiesOf;\n\n /// @notice Stores the metadata for each funding cycle configuration, packed into one storage slot.\n /// @custom:param _projectId The ID of the project to get metadata of.\n /// @custom:param _configuration The funding cycle configuration to get metadata of.\n mapping(uint256 => mapping(uint256 => uint256)) private _metadataOf;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The latest funding cycle configuration for each project.\n /// @custom:param _projectId The ID of the project to get the latest funding cycle configuration of.\n mapping(uint256 => uint256) public override latestConfigurationOf;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Get the funding cycle with the given configuration for the specified project.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @param _configuration The configuration of the funding cycle to get.\n /// @return fundingCycle The funding cycle.\n function get(\n uint256 _projectId,\n uint256 _configuration\n ) external view override returns (JBFundingCycle memory fundingCycle) {\n return _getStructFor(_projectId, _configuration);\n }\n\n /// @notice The latest funding cycle to be configured for the specified project, and its current ballot state.\n /// @param _projectId The ID of the project to get the latest configured funding cycle of.\n /// @return fundingCycle The project's queued funding cycle.\n /// @return ballotState The state of the ballot for the reconfiguration.\n function latestConfiguredOf(\n uint256 _projectId\n ) external view override returns (JBFundingCycle memory fundingCycle, JBBallotState ballotState) {\n // Get a reference to the latest funding cycle configuration.\n uint256 _fundingCycleConfiguration = latestConfigurationOf[_projectId];\n\n // Resolve the funding cycle for the latest configuration.\n fundingCycle = _getStructFor(_projectId, _fundingCycleConfiguration);\n\n // Resolve the ballot state.\n ballotState = _ballotStateOf(\n _projectId,\n fundingCycle.configuration,\n fundingCycle.start,\n fundingCycle.basedOn\n );\n }\n\n /// @notice The funding cycle that's next up for the specified project.\n /// @dev If a queued funding cycle of the project is not found, returns an empty funding cycle with all properties set to 0.\n /// @param _projectId The ID of the project to get the queued funding cycle of.\n /// @return fundingCycle The project's queued funding cycle.\n function queuedOf(\n uint256 _projectId\n ) external view override returns (JBFundingCycle memory fundingCycle) {\n // If the project does not have a funding cycle, return an empty struct.\n if (latestConfigurationOf[_projectId] == 0) return _getStructFor(0, 0);\n\n // Get a reference to the configuration of the standby funding cycle.\n uint256 _standbyFundingCycleConfiguration = _standbyOf(_projectId);\n\n // If it exists, return its funding cycle if it is approved.\n if (_standbyFundingCycleConfiguration > 0) {\n fundingCycle = _getStructFor(_projectId, _standbyFundingCycleConfiguration);\n\n if (_isApproved(_projectId, fundingCycle)) return fundingCycle;\n\n // Resolve the funding cycle for the latest configured funding cycle.\n fundingCycle = _getStructFor(_projectId, fundingCycle.basedOn);\n } else {\n // Resolve the funding cycle for the latest configured funding cycle.\n fundingCycle = _getStructFor(_projectId, latestConfigurationOf[_projectId]);\n\n // If the latest funding cycle starts in the future, it must start in the distant future\n // since its not in standby. In this case base the queued cycles on the base cycle.\n if (fundingCycle.start > block.timestamp)\n fundingCycle = _getStructFor(_projectId, fundingCycle.basedOn);\n }\n\n // There's no queued if the current has a duration of 0.\n if (fundingCycle.duration == 0) return _getStructFor(0, 0);\n\n // Check to see if this funding cycle's ballot is approved.\n // If so, return a funding cycle based on it.\n if (_isApproved(_projectId, fundingCycle)) return _mockFundingCycleBasedOn(fundingCycle, false);\n\n // Get the funding cycle of its base funding cycle, which carries the last approved configuration.\n fundingCycle = _getStructFor(_projectId, fundingCycle.basedOn);\n\n // There's no queued if the base, which must still be the current, has a duration of 0.\n if (fundingCycle.duration == 0) return _getStructFor(0, 0);\n\n // Return a mock of the next up funding cycle.\n return _mockFundingCycleBasedOn(fundingCycle, false);\n }\n\n /// @notice The funding cycle that is currently active for the specified project.\n /// @dev If a current funding cycle of the project is not found, returns an empty funding cycle with all properties set to 0.\n /// @param _projectId The ID of the project to get the current funding cycle of.\n /// @return fundingCycle The project's current funding cycle.\n function currentOf(\n uint256 _projectId\n ) external view override returns (JBFundingCycle memory fundingCycle) {\n // If the project does not have a funding cycle, return an empty struct.\n if (latestConfigurationOf[_projectId] == 0) return _getStructFor(0, 0);\n\n // Get a reference to the configuration of the eligible funding cycle.\n uint256 _fundingCycleConfiguration = _eligibleOf(_projectId);\n\n // Keep a reference to the eligible funding cycle.\n JBFundingCycle memory _fundingCycle;\n\n // If an eligible funding cycle exists...\n if (_fundingCycleConfiguration > 0) {\n // Resolve the funding cycle for the eligible configuration.\n _fundingCycle = _getStructFor(_projectId, _fundingCycleConfiguration);\n\n // Check to see if this funding cycle's ballot is approved.\n // If so, return it.\n if (_isApproved(_projectId, _fundingCycle)) return _fundingCycle;\n\n // If it hasn't been approved, set the funding cycle configuration to be the configuration of the funding cycle that it's based on,\n // which carries the last approved configuration.\n _fundingCycleConfiguration = _fundingCycle.basedOn;\n } else {\n // No upcoming funding cycle found that is eligible to become active,\n // so use the last configuration.\n _fundingCycleConfiguration = latestConfigurationOf[_projectId];\n\n // Get the funding cycle for the latest ID.\n _fundingCycle = _getStructFor(_projectId, _fundingCycleConfiguration);\n\n // If it's not approved or if it hasn't yet started, get a reference to the funding cycle that the latest is based on, which has the latest approved configuration.\n if (!_isApproved(_projectId, _fundingCycle) || block.timestamp < _fundingCycle.start)\n _fundingCycleConfiguration = _fundingCycle.basedOn;\n }\n\n // If there is not funding cycle to base the current one on, there can't be a current one.\n if (_fundingCycleConfiguration == 0) return _getStructFor(0, 0);\n\n // The funding cycle to base a current one on.\n _fundingCycle = _getStructFor(_projectId, _fundingCycleConfiguration);\n\n // If the base has no duration, it's still the current one.\n if (_fundingCycle.duration == 0) return _fundingCycle;\n\n // Return a mock of the current funding cycle.\n return _mockFundingCycleBasedOn(_fundingCycle, true);\n }\n\n /// @notice The current ballot state of the project.\n /// @param _projectId The ID of the project to check the ballot state of.\n /// @return The project's current ballot's state.\n function currentBallotStateOf(uint256 _projectId) external view override returns (JBBallotState) {\n // Get a reference to the latest funding cycle configuration.\n uint256 _fundingCycleConfiguration = latestConfigurationOf[_projectId];\n\n // Resolve the funding cycle for the latest configuration.\n JBFundingCycle memory _fundingCycle = _getStructFor(_projectId, _fundingCycleConfiguration);\n\n return\n _ballotStateOf(\n _projectId,\n _fundingCycle.configuration,\n _fundingCycle.start,\n _fundingCycle.basedOn\n );\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n // solhint-disable-next-line no-empty-blocks\n constructor(IJBDirectory _directory) JBControllerUtility(_directory) {}\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Configures the next eligible funding cycle for the specified project.\n /// @dev Only a project's current controller can configure its funding cycles.\n /// @param _projectId The ID of the project being configured.\n /// @param _data The funding cycle configuration data.\n /// @param _metadata Arbitrary extra data to associate with this funding cycle configuration that's not used within.\n /// @param _mustStartAtOrAfter The time before which the initialized funding cycle cannot start.\n /// @return The funding cycle that the configuration will take effect during.\n function configureFor(\n uint256 _projectId,\n JBFundingCycleData calldata _data,\n uint256 _metadata,\n uint256 _mustStartAtOrAfter\n ) external override onlyController(_projectId) returns (JBFundingCycle memory) {\n // Duration must fit in a uint32.\n if (_data.duration > type(uint32).max) revert INVALID_DURATION();\n\n // Discount rate must be less than or equal to 100%.\n if (_data.discountRate > JBConstants.MAX_DISCOUNT_RATE) revert INVALID_DISCOUNT_RATE();\n\n // Weight must fit into a uint88.\n if (_data.weight > type(uint88).max) revert INVALID_WEIGHT();\n\n // If the start date is in the past, set it to be the current timestamp.\n if (_mustStartAtOrAfter < block.timestamp) _mustStartAtOrAfter = block.timestamp;\n\n // Make sure the min start date fits in a uint56, and that the start date of an upcoming cycle also starts within the max.\n if (_mustStartAtOrAfter + _data.duration > type(uint56).max) revert INVALID_TIMEFRAME();\n\n // Ballot should be a valid contract, supporting the correct interface\n if (_data.ballot != IJBFundingCycleBallot(address(0))) {\n address _ballot = address(_data.ballot);\n\n // No contract at the address ?\n if (_ballot.code.length == 0) revert INVALID_BALLOT();\n\n // Make sure the ballot supports the expected interface.\n try _data.ballot.supportsInterface(type(IJBFundingCycleBallot).interfaceId) returns (\n bool _supports\n ) {\n if (!_supports) revert INVALID_BALLOT(); // Contract exists at the address but with the wrong interface\n } catch {\n revert INVALID_BALLOT(); // No ERC165 support\n }\n }\n\n // The configuration timestamp is now.\n uint256 _configuration = block.timestamp;\n\n // Set up a reconfiguration by configuring intrinsic properties.\n _configureIntrinsicPropertiesFor(_projectId, _configuration, _data.weight, _mustStartAtOrAfter);\n\n // Efficiently stores a funding cycles provided user defined properties.\n // If all user config properties are zero, no need to store anything as the default value will have the same outcome.\n if (\n _data.ballot != IJBFundingCycleBallot(address(0)) ||\n _data.duration > 0 ||\n _data.discountRate > 0\n ) {\n // ballot in bits 0-159 bytes.\n uint256 packed = uint160(address(_data.ballot));\n\n // duration in bits 160-191 bytes.\n packed |= _data.duration << 160;\n\n // discountRate in bits 192-223 bytes.\n packed |= _data.discountRate << 192;\n\n // Set in storage.\n _packedUserPropertiesOf[_projectId][_configuration] = packed;\n }\n\n // Set the metadata if needed.\n if (_metadata > 0) _metadataOf[_projectId][_configuration] = _metadata;\n\n emit Configure(_configuration, _projectId, _data, _metadata, _mustStartAtOrAfter, msg.sender);\n\n // Return the funding cycle for the new configuration.\n return _getStructFor(_projectId, _configuration);\n }\n\n //*********************************************************************//\n // --------------------- private helper functions -------------------- //\n //*********************************************************************//\n\n /// @notice Updates the configurable funding cycle for this project if it exists, otherwise creates one.\n /// @param _projectId The ID of the project to find a configurable funding cycle for.\n /// @param _configuration The time at which the funding cycle was configured.\n /// @param _weight The weight to store in the configured funding cycle.\n /// @param _mustStartAtOrAfter The time before which the initialized funding cycle can't start.\n function _configureIntrinsicPropertiesFor(\n uint256 _projectId,\n uint256 _configuration,\n uint256 _weight,\n uint256 _mustStartAtOrAfter\n ) private {\n // If there's not yet a funding cycle for the project, initialize one.\n if (latestConfigurationOf[_projectId] == 0)\n // Use an empty funding cycle as the base.\n return\n _initFor(_projectId, _getStructFor(0, 0), _configuration, _mustStartAtOrAfter, _weight);\n\n // Get the active funding cycle's configuration.\n uint256 _currentConfiguration = _eligibleOf(_projectId);\n\n // If an eligible funding cycle does not exist, get a reference to the latest funding cycle configuration for the project.\n if (_currentConfiguration == 0)\n // Get the latest funding cycle's configuration.\n _currentConfiguration = latestConfigurationOf[_projectId];\n\n // Get a reference to the funding cycle.\n JBFundingCycle memory _baseFundingCycle = _getStructFor(_projectId, _currentConfiguration);\n\n if (!_isApproved(_projectId, _baseFundingCycle) || block.timestamp < _baseFundingCycle.start)\n // If it hasn't been approved or hasn't yet started, set the ID to be the funding cycle it's based on,\n // which carries the latest approved configuration.\n _baseFundingCycle = _getStructFor(_projectId, _baseFundingCycle.basedOn);\n\n // The configuration can't be the same as the base configuration.\n if (_baseFundingCycle.configuration == _configuration) revert NO_SAME_BLOCK_RECONFIGURATION();\n\n // The time after the ballot of the provided funding cycle has expired.\n // If the provided funding cycle has no ballot, return the current timestamp.\n uint256 _timestampAfterBallot = _baseFundingCycle.ballot == IJBFundingCycleBallot(address(0))\n ? 0\n : _configuration + _baseFundingCycle.ballot.duration();\n\n _initFor(\n _projectId,\n _baseFundingCycle,\n _configuration,\n // Can only start after the ballot.\n _timestampAfterBallot > _mustStartAtOrAfter ? _timestampAfterBallot : _mustStartAtOrAfter,\n _weight\n );\n }\n\n /// @notice Initializes a funding cycle with the specified properties.\n /// @param _projectId The ID of the project to which the funding cycle being initialized belongs.\n /// @param _baseFundingCycle The funding cycle to base the initialized one on.\n /// @param _configuration The configuration of the funding cycle being initialized.\n /// @param _mustStartAtOrAfter The time before which the initialized funding cycle cannot start.\n /// @param _weight The weight to give the newly initialized funding cycle.\n function _initFor(\n uint256 _projectId,\n JBFundingCycle memory _baseFundingCycle,\n uint256 _configuration,\n uint256 _mustStartAtOrAfter,\n uint256 _weight\n ) private {\n // If there is no base, initialize a first cycle.\n if (_baseFundingCycle.number == 0) {\n // The first number is 1.\n uint256 _number = 1;\n\n // Set fresh intrinsic properties.\n _packAndStoreIntrinsicPropertiesOf(\n _configuration,\n _projectId,\n _number,\n _weight,\n _baseFundingCycle.configuration,\n _mustStartAtOrAfter\n );\n } else {\n // Derive the correct next start time from the base.\n uint256 _start = _deriveStartFrom(_baseFundingCycle, _mustStartAtOrAfter);\n\n // A weight of 1 is treated as a weight of 0.\n // This is to allow a weight of 0 (default) to represent inheriting the discounted weight of the previous funding cycle.\n _weight = _weight > 0\n ? (_weight == 1 ? 0 : _weight)\n : _deriveWeightFrom(_baseFundingCycle, _start);\n\n // Derive the correct number.\n uint256 _number = _deriveNumberFrom(_baseFundingCycle, _start);\n\n // Update the intrinsic properties.\n _packAndStoreIntrinsicPropertiesOf(\n _configuration,\n _projectId,\n _number,\n _weight,\n _baseFundingCycle.configuration,\n _start\n );\n }\n\n // Set the project's latest funding cycle configuration.\n latestConfigurationOf[_projectId] = _configuration;\n\n emit Init(_configuration, _projectId, _baseFundingCycle.configuration);\n }\n\n /// @notice Efficiently stores a funding cycle's provided intrinsic properties.\n /// @param _configuration The configuration of the funding cycle to pack and store.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @param _number The number of the funding cycle.\n /// @param _weight The weight of the funding cycle.\n /// @param _basedOn The configuration of the base funding cycle.\n /// @param _start The start time of this funding cycle.\n function _packAndStoreIntrinsicPropertiesOf(\n uint256 _configuration,\n uint256 _projectId,\n uint256 _number,\n uint256 _weight,\n uint256 _basedOn,\n uint256 _start\n ) private {\n // weight in bits 0-87.\n uint256 packed = _weight;\n\n // basedOn in bits 88-143.\n packed |= _basedOn << 88;\n\n // start in bits 144-199.\n packed |= _start << 144;\n\n // number in bits 200-255.\n packed |= _number << 200;\n\n // Store the packed value.\n _packedIntrinsicPropertiesOf[_projectId][_configuration] = packed;\n }\n\n /// @notice The project's stored funding cycle that hasn't yet started and should be used next, if one exists.\n /// @dev A value of 0 is returned if no funding cycle was found.\n /// @dev Assumes the project has a latest configuration.\n /// @param _projectId The ID of a project to look through for a standby cycle.\n /// @return configuration The configuration of the standby funding cycle if one exists, or 0 if one doesn't exist.\n function _standbyOf(uint256 _projectId) private view returns (uint256 configuration) {\n // Get a reference to the project's latest funding cycle.\n configuration = latestConfigurationOf[_projectId];\n\n // Get the necessary properties for the latest funding cycle.\n JBFundingCycle memory _fundingCycle = _getStructFor(_projectId, configuration);\n\n // There is no upcoming funding cycle if the latest funding cycle has already started.\n if (block.timestamp >= _fundingCycle.start) return 0;\n\n // If this is the first funding cycle, it is queued.\n if (_fundingCycle.number == 1) return configuration;\n\n // Get the necessary properties for the base funding cycle.\n JBFundingCycle memory _baseFundingCycle = _getStructFor(_projectId, _fundingCycle.basedOn);\n\n // If the latest configuration doesn't start until after another base cycle, return 0.\n if (\n _baseFundingCycle.duration > 0 &&\n block.timestamp < _fundingCycle.start - _baseFundingCycle.duration\n ) return 0;\n }\n\n /// @notice The project's stored funding cycle that has started and hasn't yet expired.\n /// @dev A value of 0 is returned if no funding cycle was found.\n /// @dev Assumes the project has a latest configuration.\n /// @param _projectId The ID of the project to look through.\n /// @return configuration The configuration of an eligible funding cycle if one exists, or 0 if one doesn't exist.\n function _eligibleOf(uint256 _projectId) private view returns (uint256 configuration) {\n // Get a reference to the project's latest funding cycle.\n configuration = latestConfigurationOf[_projectId];\n\n // Get the latest funding cycle.\n JBFundingCycle memory _fundingCycle = _getStructFor(_projectId, configuration);\n\n // If the latest is expired, return an empty funding cycle.\n // A duration of 0 cannot be expired.\n if (\n _fundingCycle.duration > 0 && block.timestamp >= _fundingCycle.start + _fundingCycle.duration\n ) return 0;\n\n // Return the funding cycle's configuration if it has started.\n if (block.timestamp >= _fundingCycle.start) return _fundingCycle.configuration;\n\n // Get a reference to the cycle's base configuration.\n JBFundingCycle memory _baseFundingCycle = _getStructFor(_projectId, _fundingCycle.basedOn);\n\n // If the base cycle isn't eligible, the project has no eligible cycle.\n // A duration of 0 is always eligible.\n if (\n _baseFundingCycle.duration > 0 &&\n block.timestamp >= _baseFundingCycle.start + _baseFundingCycle.duration\n ) return 0;\n\n // Return the configuration that the latest funding cycle is based on.\n configuration = _fundingCycle.basedOn;\n }\n\n /// @notice A view of the funding cycle that would be created based on the provided one if the project doesn't make a reconfiguration.\n /// @dev Returns an empty funding cycle if there can't be a mock funding cycle based on the provided one.\n /// @dev Assumes a funding cycle with a duration of 0 will never be asked to be the base of a mock.\n /// @param _baseFundingCycle The funding cycle that the resulting funding cycle should follow.\n /// @param _allowMidCycle A flag indicating if the mocked funding cycle is allowed to already be mid cycle.\n /// @return A mock of what the next funding cycle will be.\n function _mockFundingCycleBasedOn(\n JBFundingCycle memory _baseFundingCycle,\n bool _allowMidCycle\n ) private view returns (JBFundingCycle memory) {\n // Get the distance of the current time to the start of the next possible funding cycle.\n // If the returned mock cycle must not yet have started, the start time of the mock must be in the future.\n uint256 _mustStartAtOrAfter = !_allowMidCycle\n ? block.timestamp + 1\n : block.timestamp - _baseFundingCycle.duration + 1;\n\n // Derive what the start time should be.\n uint256 _start = _deriveStartFrom(_baseFundingCycle, _mustStartAtOrAfter);\n\n // Derive what the number should be.\n uint256 _number = _deriveNumberFrom(_baseFundingCycle, _start);\n\n return\n JBFundingCycle(\n _number,\n _baseFundingCycle.configuration,\n _baseFundingCycle.basedOn,\n _start,\n _baseFundingCycle.duration,\n _deriveWeightFrom(_baseFundingCycle, _start),\n _baseFundingCycle.discountRate,\n _baseFundingCycle.ballot,\n _baseFundingCycle.metadata\n );\n }\n\n /// @notice The date that is the nearest multiple of the specified funding cycle's duration from its end.\n /// @param _baseFundingCycle The funding cycle to base the calculation on.\n /// @param _mustStartAtOrAfter A date that the derived start must be on or come after.\n /// @return start The next start time.\n function _deriveStartFrom(\n JBFundingCycle memory _baseFundingCycle,\n uint256 _mustStartAtOrAfter\n ) private pure returns (uint256 start) {\n // A subsequent cycle to one with a duration of 0 should start as soon as possible.\n if (_baseFundingCycle.duration == 0) return _mustStartAtOrAfter;\n\n // The time when the funding cycle immediately after the specified funding cycle starts.\n uint256 _nextImmediateStart = _baseFundingCycle.start + _baseFundingCycle.duration;\n\n // If the next immediate start is now or in the future, return it.\n if (_nextImmediateStart >= _mustStartAtOrAfter) return _nextImmediateStart;\n\n // The amount of seconds since the `_mustStartAtOrAfter` time which results in a start time that might satisfy the specified constraints.\n uint256 _timeFromImmediateStartMultiple = (_mustStartAtOrAfter - _nextImmediateStart) %\n _baseFundingCycle.duration;\n\n // A reference to the first possible start timestamp.\n start = _mustStartAtOrAfter - _timeFromImmediateStartMultiple;\n\n // Add increments of duration as necessary to satisfy the threshold.\n while (_mustStartAtOrAfter > start) start = start + _baseFundingCycle.duration;\n }\n\n /// @notice The accumulated weight change since the specified funding cycle.\n /// @param _baseFundingCycle The funding cycle to base the calculation on.\n /// @param _start The start time of the funding cycle to derive a number for.\n /// @return weight The derived weight, as a fixed point number with 18 decimals.\n function _deriveWeightFrom(\n JBFundingCycle memory _baseFundingCycle,\n uint256 _start\n ) private pure returns (uint256 weight) {\n // A subsequent cycle to one with a duration of 0 should have the next possible weight.\n if (_baseFundingCycle.duration == 0)\n return\n PRBMath.mulDiv(\n _baseFundingCycle.weight,\n JBConstants.MAX_DISCOUNT_RATE - _baseFundingCycle.discountRate,\n JBConstants.MAX_DISCOUNT_RATE\n );\n\n // The weight should be based off the base funding cycle's weight.\n weight = _baseFundingCycle.weight;\n\n // If the discount is 0, the weight doesn't change.\n if (_baseFundingCycle.discountRate == 0) return weight;\n\n // The difference between the start of the base funding cycle and the proposed start.\n uint256 _startDistance = _start - _baseFundingCycle.start;\n\n // Apply the base funding cycle's discount rate for each cycle that has passed.\n uint256 _discountMultiple;\n unchecked {\n _discountMultiple = _startDistance / _baseFundingCycle.duration; // Non-null duration is excluded above\n }\n\n for (uint256 _i; _i < _discountMultiple; ) {\n // The number of times to apply the discount rate.\n // Base the new weight on the specified funding cycle's weight.\n weight = PRBMath.mulDiv(\n weight,\n JBConstants.MAX_DISCOUNT_RATE - _baseFundingCycle.discountRate,\n JBConstants.MAX_DISCOUNT_RATE\n );\n\n // The calculation doesn't need to continue if the weight is 0.\n if (weight == 0) break;\n\n unchecked {\n ++_i;\n }\n }\n }\n\n /// @notice The number of the next funding cycle given the specified funding cycle.\n /// @param _baseFundingCycle The funding cycle to base the calculation on.\n /// @param _start The start time of the funding cycle to derive a number for.\n /// @return The funding cycle number.\n function _deriveNumberFrom(\n JBFundingCycle memory _baseFundingCycle,\n uint256 _start\n ) private pure returns (uint256) {\n // A subsequent cycle to one with a duration of 0 should be the next number.\n if (_baseFundingCycle.duration == 0) return _baseFundingCycle.number + 1;\n\n // The difference between the start of the base funding cycle and the proposed start.\n uint256 _startDistance = _start - _baseFundingCycle.start;\n\n // Find the number of base cycles that fit in the start distance.\n return _baseFundingCycle.number + (_startDistance / _baseFundingCycle.duration);\n }\n\n /// @notice Checks to see if the provided funding cycle is approved according to the correct ballot.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @param _fundingCycle The funding cycle to get an approval flag for.\n /// @return The approval flag.\n function _isApproved(\n uint256 _projectId,\n JBFundingCycle memory _fundingCycle\n ) private view returns (bool) {\n return\n _ballotStateOf(\n _projectId,\n _fundingCycle.configuration,\n _fundingCycle.start,\n _fundingCycle.basedOn\n ) == JBBallotState.Approved;\n }\n\n /// @notice A project's latest funding cycle configuration approval status.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @param _configuration The funding cycle configuration to get the ballot state of.\n /// @param _start The start time of the funding cycle configuration to get the ballot state of.\n /// @param _ballotFundingCycleConfiguration The configuration of the funding cycle which is configured with the ballot that should be used.\n /// @return The ballot state of the project.\n function _ballotStateOf(\n uint256 _projectId,\n uint256 _configuration,\n uint256 _start,\n uint256 _ballotFundingCycleConfiguration\n ) private view returns (JBBallotState) {\n // If there is no ballot funding cycle, implicitly approve.\n if (_ballotFundingCycleConfiguration == 0) return JBBallotState.Approved;\n\n // Get the ballot funding cycle.\n JBFundingCycle memory _ballotFundingCycle = _getStructFor(\n _projectId,\n _ballotFundingCycleConfiguration\n );\n\n // If there is no ballot, the ID is auto approved.\n if (_ballotFundingCycle.ballot == IJBFundingCycleBallot(address(0)))\n return JBBallotState.Approved;\n\n // Return the ballot's state\n return _ballotFundingCycle.ballot.stateOf(_projectId, _configuration, _start);\n }\n\n /// @notice Unpack a funding cycle's packed stored values into an easy-to-work-with funding cycle struct.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @param _configuration The funding cycle configuration to get the full struct for.\n /// @return fundingCycle A funding cycle struct.\n function _getStructFor(\n uint256 _projectId,\n uint256 _configuration\n ) private view returns (JBFundingCycle memory fundingCycle) {\n // Return an empty funding cycle if the configuration specified is 0.\n if (_configuration == 0) return fundingCycle;\n\n fundingCycle.configuration = _configuration;\n\n uint256 _packedIntrinsicProperties = _packedIntrinsicPropertiesOf[_projectId][_configuration];\n\n // weight in bits 0-87 bits.\n fundingCycle.weight = uint256(uint88(_packedIntrinsicProperties));\n // basedOn in bits 88-143 bits.\n fundingCycle.basedOn = uint256(uint56(_packedIntrinsicProperties >> 88));\n // start in bits 144-199 bits.\n fundingCycle.start = uint256(uint56(_packedIntrinsicProperties >> 144));\n // number in bits 200-255 bits.\n fundingCycle.number = uint256(uint56(_packedIntrinsicProperties >> 200));\n\n uint256 _packedUserProperties = _packedUserPropertiesOf[_projectId][_configuration];\n\n // ballot in bits 0-159 bits.\n fundingCycle.ballot = IJBFundingCycleBallot(address(uint160(_packedUserProperties)));\n // duration in bits 160-191 bits.\n fundingCycle.duration = uint256(uint32(_packedUserProperties >> 160));\n // discountRate in bits 192-223 bits.\n fundingCycle.discountRate = uint256(uint32(_packedUserProperties >> 192));\n\n fundingCycle.metadata = _metadataOf[_projectId][_configuration];\n }\n}\n" + }, + "contracts/JBController.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {ERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {SafeCast} from '@openzeppelin/contracts/utils/math/SafeCast.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {JBOperatable} from './abstract/JBOperatable.sol';\nimport {JBBallotState} from './enums/JBBallotState.sol';\nimport {IJBController} from './interfaces/IJBController.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol';\nimport {IJBMigratable} from './interfaces/IJBMigratable.sol';\nimport {IJBOperatable} from './interfaces/IJBOperatable.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {IJBSplitAllocator} from './interfaces/IJBSplitAllocator.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {IJBTokenStore} from './interfaces/IJBTokenStore.sol';\nimport {JBConstants} from './libraries/JBConstants.sol';\nimport {JBFundingCycleMetadataResolver} from './libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBOperations} from './libraries/JBOperations.sol';\nimport {JBSplitsGroups} from './libraries/JBSplitsGroups.sol';\nimport {JBSplitAllocationData} from './structs/JBSplitAllocationData.sol';\nimport {JBFundAccessConstraints} from './structs/JBFundAccessConstraints.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\nimport {JBFundingCycleData} from './structs/JBFundingCycleData.sol';\nimport {JBFundingCycleMetadata} from './structs/JBFundingCycleMetadata.sol';\nimport {JBGroupedSplits} from './structs/JBGroupedSplits.sol';\nimport {JBProjectMetadata} from './structs/JBProjectMetadata.sol';\nimport {JBSplit} from './structs/JBSplit.sol';\n\n/// @notice Stitches together funding cycles and project tokens, making sure all activity is accounted for and correct.\ncontract JBController is JBOperatable, ERC165, IJBController, IJBMigratable {\n // A library that parses the packed funding cycle metadata into a more friendly format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error BURN_PAUSED_AND_SENDER_NOT_VALID_TERMINAL_DELEGATE();\n error CANT_MIGRATE_TO_CURRENT_CONTROLLER();\n error FUNDING_CYCLE_ALREADY_LAUNCHED();\n error INVALID_BALLOT_REDEMPTION_RATE();\n error INVALID_DISTRIBUTION_LIMIT();\n error INVALID_DISTRIBUTION_LIMIT_CURRENCY();\n error INVALID_OVERFLOW_ALLOWANCE();\n error INVALID_OVERFLOW_ALLOWANCE_CURRENCY();\n error INVALID_REDEMPTION_RATE();\n error INVALID_RESERVED_RATE();\n error MIGRATION_NOT_ALLOWED();\n error MINT_NOT_ALLOWED_AND_NOT_TERMINAL_DELEGATE();\n error NO_BURNABLE_TOKENS();\n error NOT_CURRENT_CONTROLLER();\n error ZERO_TOKENS_TO_MINT();\n\n //*********************************************************************//\n // --------------------- internal stored properties ------------------ //\n //*********************************************************************//\n\n /// @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.\n /// @custom:param _projectId The ID of the project to get the tracker of.\n mapping(uint256 => int256) internal _processedTokenTrackerOf;\n\n /// @notice Data regarding the distribution limit of a project during a configuration.\n /// @dev bits 0-231: The amount of token that a project can distribute per funding cycle.\n /// @dev bits 232-255: The currency of amount that a project can distribute.\n /// @custom:param _projectId The ID of the project to get the packed distribution limit data of.\n /// @custom:param _configuration The configuration during which the packed distribution limit data applies.\n /// @custom:param _terminal The terminal from which distributions are being limited.\n /// @custom:param _token The token for which distributions are being limited.\n mapping(uint256 => mapping(uint256 => mapping(IJBPaymentTerminal => mapping(address => uint256))))\n internal _packedDistributionLimitDataOf;\n\n /// @notice Data regarding the overflow allowance of a project during a configuration.\n /// @dev bits 0-231: The amount of overflow that a project is allowed to tap into on-demand throughout the configuration.\n /// @dev bits 232-255: The currency of the amount of overflow that a project is allowed to tap.\n /// @custom:param _projectId The ID of the project to get the packed overflow allowance data of.\n /// @custom:param _configuration The configuration during which the packed overflow allowance data applies.\n /// @custom:param _terminal The terminal managing the overflow.\n /// @custom:param _token The token for which overflow is being allowed.\n mapping(uint256 => mapping(uint256 => mapping(IJBPaymentTerminal => mapping(address => uint256))))\n internal _packedOverflowAllowanceDataOf;\n\n //*********************************************************************//\n // --------------- public immutable stored properties ---------------- //\n //*********************************************************************//\n\n /// @notice Mints ERC-721's that represent project ownership.\n IJBProjects public immutable override projects;\n\n /// @notice The contract storing all funding cycle configurations.\n IJBFundingCycleStore public immutable override fundingCycleStore;\n\n /// @notice The contract that manages token minting and burning.\n IJBTokenStore public immutable override tokenStore;\n\n /// @notice The contract that stores splits for each project.\n IJBSplitsStore public immutable override splitsStore;\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice The amount of token that a project can distribute per funding cycle, and the currency it's in terms of.\n /// @dev The number of decimals in the returned fixed point amount is the same as that of the specified terminal.\n /// @param _projectId The ID of the project to get the distribution limit of.\n /// @param _configuration The configuration during which the distribution limit applies.\n /// @param _terminal The terminal from which distributions are being limited.\n /// @param _token The token for which the distribution limit applies.\n /// @return The distribution limit, as a fixed point number with the same number of decimals as the provided terminal.\n /// @return The currency of the distribution limit.\n function distributionLimitOf(\n uint256 _projectId,\n uint256 _configuration,\n IJBPaymentTerminal _terminal,\n address _token\n ) external view override returns (uint256, uint256) {\n // Get a reference to the packed data.\n uint256 _data = _packedDistributionLimitDataOf[_projectId][_configuration][_terminal][_token];\n\n // The limit is in bits 0-231. The currency is in bits 232-255.\n return (uint256(uint232(_data)), _data >> 232);\n }\n\n /// @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.\n /// @dev The number of decimals in the returned fixed point amount is the same as that of the specified terminal.\n /// @param _projectId The ID of the project to get the overflow allowance of.\n /// @param _configuration The configuration of the during which the allowance applies.\n /// @param _terminal The terminal managing the overflow.\n /// @param _token The token for which the overflow allowance applies.\n /// @return The overflow allowance, as a fixed point number with the same number of decimals as the provided terminal.\n /// @return The currency of the overflow allowance.\n function overflowAllowanceOf(\n uint256 _projectId,\n uint256 _configuration,\n IJBPaymentTerminal _terminal,\n address _token\n ) external view override returns (uint256, uint256) {\n // Get a reference to the packed data.\n uint256 _data = _packedOverflowAllowanceDataOf[_projectId][_configuration][_terminal][_token];\n\n // The allowance is in bits 0-231. The currency is in bits 232-255.\n return (uint256(uint232(_data)), _data >> 232);\n }\n\n /// @notice Gets the amount of reserved tokens that a project has available to distribute.\n /// @param _projectId The ID of the project to get a reserved token balance of.\n /// @param _reservedRate The reserved rate to use when making the calculation.\n /// @return The current amount of reserved tokens.\n function reservedTokenBalanceOf(\n uint256 _projectId,\n uint256 _reservedRate\n ) external view override returns (uint256) {\n return\n _reservedTokenAmountFrom(\n _processedTokenTrackerOf[_projectId],\n _reservedRate,\n tokenStore.totalSupplyOf(_projectId)\n );\n }\n\n /// @notice Gets the current total amount of outstanding tokens for a project, given a reserved rate.\n /// @param _projectId The ID of the project to get total outstanding tokens of.\n /// @param _reservedRate The reserved rate to use when making the calculation.\n /// @return The current total amount of outstanding tokens for the project.\n function totalOutstandingTokensOf(\n uint256 _projectId,\n uint256 _reservedRate\n ) external view override returns (uint256) {\n // Get the total number of tokens in circulation.\n uint256 _totalSupply = tokenStore.totalSupplyOf(_projectId);\n\n // Get the number of reserved tokens the project has.\n uint256 _reservedTokenAmount = _reservedTokenAmountFrom(\n _processedTokenTrackerOf[_projectId],\n _reservedRate,\n _totalSupply\n );\n\n // Add the reserved tokens to the total supply.\n return _totalSupply + _reservedTokenAmount;\n }\n\n /// @notice A project's funding cycle for the specified configuration along with its metadata.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The funding cycle.\n /// @return metadata The funding cycle's metadata.\n function getFundingCycleOf(\n uint256 _projectId,\n uint256 _configuration\n )\n external\n view\n override\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata)\n {\n fundingCycle = fundingCycleStore.get(_projectId, _configuration);\n metadata = fundingCycle.expandMetadata();\n }\n\n /// @notice A project's latest configured funding cycle along with its metadata and the ballot state of the configuration.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The latest configured funding cycle.\n /// @return metadata The latest configured funding cycle's metadata.\n /// @return ballotState The state of the configuration.\n function latestConfiguredFundingCycleOf(\n uint256 _projectId\n )\n external\n view\n override\n returns (\n JBFundingCycle memory fundingCycle,\n JBFundingCycleMetadata memory metadata,\n JBBallotState ballotState\n )\n {\n (fundingCycle, ballotState) = fundingCycleStore.latestConfiguredOf(_projectId);\n metadata = fundingCycle.expandMetadata();\n }\n\n /// @notice A project's current funding cycle along with its metadata.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The current funding cycle.\n /// @return metadata The current funding cycle's metadata.\n function currentFundingCycleOf(\n uint256 _projectId\n )\n external\n view\n override\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata)\n {\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n metadata = fundingCycle.expandMetadata();\n }\n\n /// @notice A project's queued funding cycle along with its metadata.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The queued funding cycle.\n /// @return metadata The queued funding cycle's metadata.\n function queuedFundingCycleOf(\n uint256 _projectId\n )\n external\n view\n override\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata)\n {\n fundingCycle = fundingCycleStore.queuedOf(_projectId);\n metadata = fundingCycle.expandMetadata();\n }\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if the provided interface ID is supported.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(ERC165, IERC165) returns (bool) {\n return\n _interfaceId == type(IJBController).interfaceId ||\n _interfaceId == type(IJBMigratable).interfaceId ||\n _interfaceId == type(IJBOperatable).interfaceId ||\n super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // ---------------------------- constructor -------------------------- //\n //*********************************************************************//\n\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _fundingCycleStore A contract storing all funding cycle configurations.\n /// @param _tokenStore A contract that manages token minting and burning.\n /// @param _splitsStore A contract that stores splits for each project.\n constructor(\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBFundingCycleStore _fundingCycleStore,\n IJBTokenStore _tokenStore,\n IJBSplitsStore _splitsStore\n ) JBOperatable(_operatorStore) {\n projects = _projects;\n directory = _directory;\n fundingCycleStore = _fundingCycleStore;\n tokenStore = _tokenStore;\n splitsStore = _splitsStore;\n }\n\n //*********************************************************************//\n // --------------------- external transactions ----------------------- //\n //*********************************************************************//\n\n /// @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.\n /// @dev Each operation within this transaction can be done in sequence separately.\n /// @dev Anyone can deploy a project on an owner's behalf.\n /// @param _owner The address to set as the owner of the project. The project ERC-721 will be owned by this address.\n /// @param _projectMetadata Metadata to associate with the project within a particular domain. This can be updated any time by the owner of the project.\n /// @param _data Data that defines the project's first funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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`.\n /// @param _terminals Payment terminals to add for the project.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return projectId The ID of the project.\n function launchProjectFor(\n address _owner,\n JBProjectMetadata calldata _projectMetadata,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] calldata _groupedSplits,\n JBFundAccessConstraints[] calldata _fundAccessConstraints,\n IJBPaymentTerminal[] memory _terminals,\n string memory _memo\n ) external virtual override returns (uint256 projectId) {\n // Keep a reference to the directory.\n IJBDirectory _directory = directory;\n\n // Mint the project into the wallet of the owner.\n projectId = projects.createFor(_owner, _projectMetadata);\n\n // Set this contract as the project's controller in the directory.\n _directory.setControllerOf(projectId, address(this));\n\n // Configure the first funding cycle.\n uint256 _configuration = _configure(\n projectId,\n _data,\n _metadata,\n _mustStartAtOrAfter,\n _groupedSplits,\n _fundAccessConstraints\n );\n\n // Add the provided terminals to the list of terminals.\n if (_terminals.length > 0) _directory.setTerminalsOf(projectId, _terminals);\n\n emit LaunchProject(_configuration, projectId, _memo, msg.sender);\n }\n\n /// @notice Creates a funding cycle for an already existing project ERC-721.\n /// @dev Each operation within this transaction can be done in sequence separately.\n /// @dev Only a project owner or operator can launch its funding cycles.\n /// @param _projectId The ID of the project to launch funding cycles for.\n /// @param _data Data that defines the project's first funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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`.\n /// @param _terminals Payment terminals to add for the project.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return configuration The configuration of the funding cycle that was successfully created.\n function launchFundingCyclesFor(\n uint256 _projectId,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] calldata _groupedSplits,\n JBFundAccessConstraints[] memory _fundAccessConstraints,\n IJBPaymentTerminal[] memory _terminals,\n string memory _memo\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.RECONFIGURE)\n returns (uint256 configuration)\n {\n // If there is a previous configuration, reconfigureFundingCyclesOf should be called instead\n if (fundingCycleStore.latestConfigurationOf(_projectId) > 0)\n revert FUNDING_CYCLE_ALREADY_LAUNCHED();\n\n // Set this contract as the project's controller in the directory.\n directory.setControllerOf(_projectId, address(this));\n\n // Configure the first funding cycle.\n configuration = _configure(\n _projectId,\n _data,\n _metadata,\n _mustStartAtOrAfter,\n _groupedSplits,\n _fundAccessConstraints\n );\n\n // Add the provided terminals to the list of terminals.\n if (_terminals.length > 0) directory.setTerminalsOf(_projectId, _terminals);\n\n emit LaunchFundingCycles(configuration, _projectId, _memo, msg.sender);\n }\n\n /// @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.\n /// @dev Only a project's owner or a designated operator can configure its funding cycles.\n /// @param _projectId The ID of the project whose funding cycles are being reconfigured.\n /// @param _data Data that defines the funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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`.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return configuration The configuration of the funding cycle that was successfully reconfigured.\n function reconfigureFundingCyclesOf(\n uint256 _projectId,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] calldata _groupedSplits,\n JBFundAccessConstraints[] calldata _fundAccessConstraints,\n string calldata _memo\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.RECONFIGURE)\n returns (uint256 configuration)\n {\n // Configure the next funding cycle.\n configuration = _configure(\n _projectId,\n _data,\n _metadata,\n _mustStartAtOrAfter,\n _groupedSplits,\n _fundAccessConstraints\n );\n\n emit ReconfigureFundingCycles(configuration, _projectId, _memo, msg.sender);\n }\n\n /// @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.\n /// @dev Only a project's owner, a designated operator, one of its terminals, or the current data source can mint its tokens.\n /// @param _projectId The ID of the project to which the tokens being minted belong.\n /// @param _tokenCount The amount of tokens to mint in total, counting however many should be reserved.\n /// @param _beneficiary The account that the tokens are being minted for.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _preferClaimedTokens A flag indicating whether a project's attached token contract should be minted if they have been issued.\n /// @param _useReservedRate Whether to use the current funding cycle's reserved rate in the mint calculation.\n /// @return beneficiaryTokenCount The amount of tokens minted for the beneficiary.\n function mintTokensOf(\n uint256 _projectId,\n uint256 _tokenCount,\n address _beneficiary,\n string calldata _memo,\n bool _preferClaimedTokens,\n bool _useReservedRate\n ) external virtual override returns (uint256 beneficiaryTokenCount) {\n // There should be tokens to mint.\n if (_tokenCount == 0) revert ZERO_TOKENS_TO_MINT();\n\n // Define variables that will be needed outside scoped section below.\n // Keep a reference to the reserved rate to use\n uint256 _reservedRate;\n\n // Scoped section prevents stack too deep. `_fundingCycle` only used within scope.\n {\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Minting limited to: project owner, authorized callers, project terminal and current funding cycle data source\n _requirePermissionAllowingOverride(\n projects.ownerOf(_projectId),\n _projectId,\n JBOperations.MINT,\n directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender)) ||\n msg.sender == address(_fundingCycle.dataSource())\n );\n\n // If the message sender is not a terminal or a datasource, the current funding cycle must allow minting.\n if (\n !_fundingCycle.mintingAllowed() &&\n !directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender)) &&\n msg.sender != address(_fundingCycle.dataSource())\n ) revert MINT_NOT_ALLOWED_AND_NOT_TERMINAL_DELEGATE();\n\n // Determine the reserved rate to use.\n _reservedRate = _useReservedRate ? _fundingCycle.reservedRate() : 0;\n\n // Override the claimed token preference with the funding cycle value.\n _preferClaimedTokens = _preferClaimedTokens == true\n ? _preferClaimedTokens\n : _fundingCycle.preferClaimedTokenOverride();\n }\n\n if (_reservedRate == JBConstants.MAX_RESERVED_RATE)\n // Subtract the total weighted amount from the tracker so the full reserved token amount can be printed later.\n _processedTokenTrackerOf[_projectId] =\n _processedTokenTrackerOf[_projectId] -\n SafeCast.toInt256(_tokenCount);\n else {\n // The unreserved token count that will be minted for the beneficiary.\n beneficiaryTokenCount = PRBMath.mulDiv(\n _tokenCount,\n JBConstants.MAX_RESERVED_RATE - _reservedRate,\n JBConstants.MAX_RESERVED_RATE\n );\n\n if (_reservedRate == 0)\n // If there's no reserved rate, increment the tracker with the newly minted tokens.\n _processedTokenTrackerOf[_projectId] =\n _processedTokenTrackerOf[_projectId] +\n SafeCast.toInt256(beneficiaryTokenCount);\n\n // Mint the tokens.\n tokenStore.mintFor(_beneficiary, _projectId, beneficiaryTokenCount, _preferClaimedTokens);\n }\n\n emit MintTokens(\n _beneficiary,\n _projectId,\n _tokenCount,\n beneficiaryTokenCount,\n _memo,\n _reservedRate,\n msg.sender\n );\n }\n\n /// @notice Burns a token holder's supply.\n /// @dev Only a token's holder, a designated operator, or a project's terminal can burn it.\n /// @param _holder The account that is having its tokens burned.\n /// @param _projectId The ID of the project to which the tokens being burned belong.\n /// @param _tokenCount The number of tokens to burn.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _preferClaimedTokens A flag indicating whether a project's attached token contract should be burned first if they have been issued.\n function burnTokensOf(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n string calldata _memo,\n bool _preferClaimedTokens\n )\n external\n virtual\n override\n requirePermissionAllowingOverride(\n _holder,\n _projectId,\n JBOperations.BURN,\n directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender))\n )\n {\n // There should be tokens to burn\n if (_tokenCount == 0) revert NO_BURNABLE_TOKENS();\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // If the message sender is a terminal, the current funding cycle must not be paused.\n if (\n _fundingCycle.burnPaused() &&\n !directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender))\n ) revert BURN_PAUSED_AND_SENDER_NOT_VALID_TERMINAL_DELEGATE();\n\n // Update the token tracker so that reserved tokens will still be correctly mintable.\n _processedTokenTrackerOf[_projectId] =\n _processedTokenTrackerOf[_projectId] -\n SafeCast.toInt256(_tokenCount);\n\n // Burn the tokens.\n tokenStore.burnFrom(_holder, _projectId, _tokenCount, _preferClaimedTokens);\n\n emit BurnTokens(_holder, _projectId, _tokenCount, _memo, msg.sender);\n }\n\n /// @notice Distributes all outstanding reserved tokens for a project.\n /// @param _projectId The ID of the project to which the reserved tokens belong.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return The amount of minted reserved tokens.\n function distributeReservedTokensOf(\n uint256 _projectId,\n string calldata _memo\n ) external virtual override returns (uint256) {\n return _distributeReservedTokensOf(_projectId, _memo);\n }\n\n /// @notice Allows other controllers to signal to this one that a migration is expected for the specified project.\n /// @dev This controller should not yet be the project's controller.\n /// @param _projectId The ID of the project that will be migrated to this controller.\n /// @param _from The controller being migrated from.\n function prepForMigrationOf(uint256 _projectId, address _from) external virtual override {\n // This controller must not be the project's current controller.\n if (directory.controllerOf(_projectId) == address(this))\n revert CANT_MIGRATE_TO_CURRENT_CONTROLLER();\n\n // Set the tracker as the total supply.\n _processedTokenTrackerOf[_projectId] = SafeCast.toInt256(tokenStore.totalSupplyOf(_projectId));\n\n emit PrepMigration(_projectId, _from, msg.sender);\n }\n\n /// @notice Allows a project to migrate from this controller to another.\n /// @dev Only a project's owner or a designated operator can migrate it.\n /// @param _projectId The ID of the project that will be migrated from this controller.\n /// @param _to The controller to which the project is migrating.\n function migrate(\n uint256 _projectId,\n IJBMigratable _to\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.MIGRATE_CONTROLLER)\n {\n // Keep a reference to the directory.\n IJBDirectory _directory = directory;\n\n // This controller must be the project's current controller.\n if (_directory.controllerOf(_projectId) != address(this)) revert NOT_CURRENT_CONTROLLER();\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Migration must be allowed.\n if (!_fundingCycle.controllerMigrationAllowed()) revert MIGRATION_NOT_ALLOWED();\n\n // All reserved tokens must be minted before migrating.\n if (\n _processedTokenTrackerOf[_projectId] < 0 ||\n uint256(_processedTokenTrackerOf[_projectId]) != tokenStore.totalSupplyOf(_projectId)\n ) _distributeReservedTokensOf(_projectId, '');\n\n // Make sure the new controller is prepped for the migration.\n _to.prepForMigrationOf(_projectId, address(this));\n\n // Set the new controller.\n _directory.setControllerOf(_projectId, address(_to));\n\n emit Migrate(_projectId, _to, msg.sender);\n }\n\n //*********************************************************************//\n // ------------------------ internal functions ----------------------- //\n //*********************************************************************//\n\n /// @notice Distributes all outstanding reserved tokens for a project.\n /// @param _projectId The ID of the project to which the reserved tokens belong.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return tokenCount The amount of minted reserved tokens.\n function _distributeReservedTokensOf(\n uint256 _projectId,\n string memory _memo\n ) internal returns (uint256 tokenCount) {\n // Keep a reference to the token store.\n IJBTokenStore _tokenStore = tokenStore;\n\n // Get the current funding cycle to read the reserved rate from.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Get a reference to new total supply of tokens before minting reserved tokens.\n uint256 _totalTokens = _tokenStore.totalSupplyOf(_projectId);\n\n // Get a reference to the number of tokens that need to be minted.\n tokenCount = _reservedTokenAmountFrom(\n _processedTokenTrackerOf[_projectId],\n _fundingCycle.reservedRate(),\n _totalTokens\n );\n\n // Set the tracker to be the new total supply.\n _processedTokenTrackerOf[_projectId] = SafeCast.toInt256(_totalTokens + tokenCount);\n\n // Get a reference to the project owner.\n address _owner = projects.ownerOf(_projectId);\n\n // Distribute tokens to splits and get a reference to the leftover amount to mint after all splits have gotten their share.\n uint256 _leftoverTokenCount = tokenCount == 0\n ? 0\n : _distributeToReservedTokenSplitsOf(\n _projectId,\n _fundingCycle.configuration,\n JBSplitsGroups.RESERVED_TOKENS,\n tokenCount\n );\n\n // Mint any leftover tokens to the project owner.\n if (_leftoverTokenCount > 0)\n _tokenStore.mintFor(_owner, _projectId, _leftoverTokenCount, false);\n\n emit DistributeReservedTokens(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _owner,\n tokenCount,\n _leftoverTokenCount,\n _memo,\n msg.sender\n );\n }\n\n /// @notice Distribute tokens to the splits according to the specified funding cycle configuration.\n /// @param _projectId The ID of the project for which reserved token splits are being distributed.\n /// @param _domain The domain of the splits to distribute the reserved tokens between.\n /// @param _group The group of the splits to distribute the reserved tokens between.\n /// @param _amount The total amount of tokens to mint.\n /// @return leftoverAmount If the splits percents dont add up to 100%, the leftover amount is returned.\n function _distributeToReservedTokenSplitsOf(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group,\n uint256 _amount\n ) internal returns (uint256 leftoverAmount) {\n // Keep a reference to the token store.\n IJBTokenStore _tokenStore = tokenStore;\n\n // Set the leftover amount to the initial amount.\n leftoverAmount = _amount;\n\n // Get a reference to the project's reserved token splits.\n JBSplit[] memory _splits = splitsStore.splitsOf(_projectId, _domain, _group);\n\n //Transfer between all splits.\n for (uint256 _i; _i < _splits.length; ) {\n // Get a reference to the split being iterated on.\n JBSplit memory _split = _splits[_i];\n\n // The amount to send towards the split.\n uint256 _tokenCount = PRBMath.mulDiv(\n _amount,\n _split.percent,\n JBConstants.SPLITS_TOTAL_PERCENT\n );\n\n // Mints tokens for the split if needed.\n if (_tokenCount > 0) {\n _tokenStore.mintFor(\n // If an allocator is set in the splits, set it as the beneficiary.\n // Otherwise if a projectId is set in the split, set the project's owner as the beneficiary.\n // If the split has a beneficiary send to the split's beneficiary. Otherwise send to the msg.sender.\n _split.allocator != IJBSplitAllocator(address(0))\n ? address(_split.allocator)\n : _split.projectId != 0\n ? projects.ownerOf(_split.projectId)\n : _split.beneficiary != address(0)\n ? _split.beneficiary\n : msg.sender,\n _projectId,\n _tokenCount,\n _split.preferClaimed\n );\n\n // If there's an allocator set, trigger its `allocate` function.\n if (_split.allocator != IJBSplitAllocator(address(0)))\n _split.allocator.allocate(\n JBSplitAllocationData(\n address(_tokenStore.tokenOf(_projectId)),\n _tokenCount,\n 18,\n _projectId,\n _group,\n _split\n )\n );\n\n // Subtract from the amount to be sent to the beneficiary.\n leftoverAmount = leftoverAmount - _tokenCount;\n }\n\n emit DistributeToReservedTokenSplit(\n _projectId,\n _domain,\n _group,\n _split,\n _tokenCount,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n\n /// @notice Configures a funding cycle and stores information pertinent to the configuration.\n /// @param _projectId The ID of the project whose funding cycles are being reconfigured.\n /// @param _data Data that defines the funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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.\n /// @return configuration The configuration of the funding cycle that was successfully reconfigured.\n function _configure(\n uint256 _projectId,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] memory _groupedSplits,\n JBFundAccessConstraints[] memory _fundAccessConstraints\n ) internal returns (uint256) {\n // Make sure the provided reserved rate is valid.\n if (_metadata.reservedRate > JBConstants.MAX_RESERVED_RATE) revert INVALID_RESERVED_RATE();\n\n // Make sure the provided redemption rate is valid.\n if (_metadata.redemptionRate > JBConstants.MAX_REDEMPTION_RATE)\n revert INVALID_REDEMPTION_RATE();\n\n // Make sure the provided ballot redemption rate is valid.\n if (_metadata.ballotRedemptionRate > JBConstants.MAX_REDEMPTION_RATE)\n revert INVALID_BALLOT_REDEMPTION_RATE();\n\n // Configure the funding cycle's properties.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.configureFor(\n _projectId,\n _data,\n JBFundingCycleMetadataResolver.packFundingCycleMetadata(_metadata),\n _mustStartAtOrAfter\n );\n\n // Set splits for the group.\n splitsStore.set(_projectId, _fundingCycle.configuration, _groupedSplits);\n\n // Set distribution limits if there are any.\n for (uint256 _i; _i < _fundAccessConstraints.length; ) {\n JBFundAccessConstraints memory _constraints = _fundAccessConstraints[_i];\n\n // If distribution limit value is larger than 232 bits, revert.\n if (_constraints.distributionLimit > type(uint232).max) revert INVALID_DISTRIBUTION_LIMIT();\n\n // If distribution limit currency value is larger than 24 bits, revert.\n if (_constraints.distributionLimitCurrency > type(uint24).max)\n revert INVALID_DISTRIBUTION_LIMIT_CURRENCY();\n\n // If overflow allowance value is larger than 232 bits, revert.\n if (_constraints.overflowAllowance > type(uint232).max) revert INVALID_OVERFLOW_ALLOWANCE();\n\n // If overflow allowance currency value is larger than 24 bits, revert.\n if (_constraints.overflowAllowanceCurrency > type(uint24).max)\n revert INVALID_OVERFLOW_ALLOWANCE_CURRENCY();\n\n // Set the distribution limit if there is one.\n if (_constraints.distributionLimit > 0)\n _packedDistributionLimitDataOf[_projectId][_fundingCycle.configuration][\n _constraints.terminal\n ][_constraints.token] =\n _constraints.distributionLimit |\n (_constraints.distributionLimitCurrency << 232);\n\n // Set the overflow allowance if there is one.\n if (_constraints.overflowAllowance > 0)\n _packedOverflowAllowanceDataOf[_projectId][_fundingCycle.configuration][\n _constraints.terminal\n ][_constraints.token] =\n _constraints.overflowAllowance |\n (_constraints.overflowAllowanceCurrency << 232);\n\n emit SetFundAccessConstraints(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _constraints,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n\n return _fundingCycle.configuration;\n }\n\n /// @notice Gets the amount of reserved tokens currently tracked for a project given a reserved rate.\n /// @param _processedTokenTracker The tracker to make the calculation with.\n /// @param _reservedRate The reserved rate to use to make the calculation.\n /// @param _totalEligibleTokens The total amount to make the calculation with.\n /// @return amount reserved token amount.\n function _reservedTokenAmountFrom(\n int256 _processedTokenTracker,\n uint256 _reservedRate,\n uint256 _totalEligibleTokens\n ) internal pure returns (uint256) {\n // Get a reference to the amount of tokens that are unprocessed.\n uint256 _unprocessedTokenBalanceOf = _processedTokenTracker >= 0\n ? _totalEligibleTokens - uint256(_processedTokenTracker)\n : _totalEligibleTokens + uint256(-_processedTokenTracker);\n\n // If there are no unprocessed tokens, return.\n if (_unprocessedTokenBalanceOf == 0) return 0;\n\n // If all tokens are reserved, return the full unprocessed amount.\n if (_reservedRate == JBConstants.MAX_RESERVED_RATE) return _unprocessedTokenBalanceOf;\n\n return\n PRBMath.mulDiv(\n _unprocessedTokenBalanceOf,\n JBConstants.MAX_RESERVED_RATE,\n JBConstants.MAX_RESERVED_RATE - _reservedRate\n ) - _unprocessedTokenBalanceOf;\n }\n}\n" + }, + "contracts/JBReconfigurationBufferBallot.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {ERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBBallotState} from './enums/JBBallotState.sol';\nimport {IJBFundingCycleBallot} from './interfaces/IJBFundingCycleBallot.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\n\n/// @notice Manages approving funding cycle reconfigurations automatically after a buffer period.\ncontract JBReconfigurationBufferBallot is ERC165, IJBFundingCycleBallot {\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice The number of seconds that must pass for a funding cycle reconfiguration to become either `Approved` or `Failed`.\n uint256 public immutable override duration;\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice The approval state of a particular funding cycle.\n /// @param _projectId The ID of the project to which the funding cycle being checked belongs.\n /// @param _configured The configuration of the funding cycle to check the state of.\n /// @param _start The start timestamp of the funding cycle to check the state of.\n /// @return The state of the provided ballot.\n function stateOf(\n uint256 _projectId,\n uint256 _configured,\n uint256 _start\n ) public view override returns (JBBallotState) {\n _projectId; // Prevents unused var compiler and natspec complaints.\n\n // If the provided configured timestamp is after the start timestamp, the ballot is Failed.\n if (_configured > _start) return JBBallotState.Failed;\n\n unchecked {\n // If there was sufficient time between configuration and the start of the cycle, it is approved. Otherwise, it is failed.\n return (_start - _configured < duration) ? JBBallotState.Failed : JBBallotState.Approved;\n }\n }\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if this contract adheres to the specified interface.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(ERC165, IERC165) returns (bool) {\n return\n _interfaceId == type(IJBFundingCycleBallot).interfaceId ||\n super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _duration The number of seconds to wait until a reconfiguration can be either `Approved` or `Failed`.\n constructor(uint256 _duration) {\n duration = _duration;\n }\n}\n" + }, + "contracts/JBETHERC20ProjectPayerDeployer.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Clones} from '@openzeppelin/contracts/proxy/Clones.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBProjectPayer} from './interfaces/IJBProjectPayer.sol';\nimport {IJBETHERC20ProjectPayerDeployer} from './interfaces/IJBETHERC20ProjectPayerDeployer.sol';\nimport {JBETHERC20ProjectPayer} from './JBETHERC20ProjectPayer.sol';\n\n/// @notice Deploys project payer contracts.\ncontract JBETHERC20ProjectPayerDeployer is IJBETHERC20ProjectPayerDeployer {\n //*********************************************************************//\n // --------------- public immutable stored properties ---------------- //\n //*********************************************************************//\n\n /// @notice The implementation contract on which Clones will be based.\n address immutable implementation;\n\n /// @notice directory instance which keeps a track of which controller is linked to which project.\n IJBDirectory immutable directory;\n\n //*********************************************************************//\n // ---------------------------- constructor -------------------------- //\n //*********************************************************************//\n\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n constructor(IJBDirectory _directory) {\n implementation = address(new JBETHERC20ProjectPayer(_directory));\n directory = _directory;\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Allows anyone to deploy a new project payer contract.\n /// @param _defaultProjectId The ID of the project whose treasury should be forwarded the project payer contract's received payments.\n /// @param _defaultBeneficiary The address that'll receive the project's tokens when the project payer receives payments.\n /// @param _defaultPreferClaimedTokens A flag indicating whether issued tokens from the project payer's received payments should be automatically claimed into the beneficiary's wallet.\n /// @param _defaultMemo The memo that'll be forwarded with the project payer's received payments.\n /// @param _defaultMetadata The metadata that'll be forwarded with the project payer's received payments.\n /// @param _defaultPreferAddToBalance A flag indicating if received payments should call the `pay` function or the `addToBalance` function of a project.\n /// @param _owner The address that will own the project payer.\n /// @return projectPayer The project payer contract.\n function deployProjectPayer(\n uint256 _defaultProjectId,\n address payable _defaultBeneficiary,\n bool _defaultPreferClaimedTokens,\n string memory _defaultMemo,\n bytes memory _defaultMetadata,\n bool _defaultPreferAddToBalance,\n address _owner\n ) external override returns (IJBProjectPayer projectPayer) {\n // Deploy the project payer.\n projectPayer = IJBProjectPayer(payable(Clones.clone(implementation)));\n\n // Initialize the project payer.\n projectPayer.initialize(\n _defaultProjectId,\n _defaultBeneficiary,\n _defaultPreferClaimedTokens,\n _defaultMemo,\n _defaultMetadata,\n _defaultPreferAddToBalance,\n _owner\n );\n\n emit DeployProjectPayer(\n projectPayer,\n _defaultProjectId,\n _defaultBeneficiary,\n _defaultPreferClaimedTokens,\n _defaultMemo,\n _defaultMetadata,\n _defaultPreferAddToBalance,\n directory,\n _owner,\n msg.sender\n );\n }\n}\n" + }, + "contracts/interfaces/IJBETHERC20ProjectPayerDeployer.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBDirectory} from './IJBDirectory.sol';\nimport {IJBProjectPayer} from './IJBProjectPayer.sol';\n\ninterface IJBETHERC20ProjectPayerDeployer {\n event DeployProjectPayer(\n IJBProjectPayer indexed projectPayer,\n uint256 defaultProjectId,\n address defaultBeneficiary,\n bool defaultPreferClaimedTokens,\n string defaultMemo,\n bytes defaultMetadata,\n bool preferAddToBalance,\n IJBDirectory directory,\n address owner,\n address caller\n );\n\n function deployProjectPayer(\n uint256 defaultProjectId,\n address payable defaultBeneficiary,\n bool defaultPreferClaimedTokens,\n string memory defaultMemo,\n bytes memory defaultMetadata,\n bool preferAddToBalance,\n address owner\n ) external returns (IJBProjectPayer projectPayer);\n}\n" + }, + "contracts/JBOperatorStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {JBOperatorData} from './structs/JBOperatorData.sol';\n\n/// @notice Stores operator permissions for all addresses. Addresses can give permissions to any other address to take specific indexed actions on their behalf.\ncontract JBOperatorStore is IJBOperatorStore {\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error PERMISSION_INDEX_OUT_OF_BOUNDS();\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The permissions that an operator has been given to operate on a specific domain.\n /// @dev An account can give an operator permissions that only pertain to a specific domain namespace.\n /// @dev There is no domain with a value of 0 – accounts can use the 0 domain to give an operator permissions to all domains on their behalf.\n /// @dev Permissions are stored in a packed `uint256`. Each 256 bits represents the on/off state of a permission. Applications can specify the significance of each index.\n /// @custom:param _operator The address of the operator.\n /// @custom:param _account The address of the account being operated.\n /// @custom:param _domain The domain within which the permissions apply. Applications can use the domain namespace as they wish.\n mapping(address => mapping(address => mapping(uint256 => uint256))) public override permissionsOf;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Whether or not an operator has the permission to take a certain action pertaining to the specified domain.\n /// @param _operator The operator to check.\n /// @param _account The account that has given out permissions to the operator.\n /// @param _domain The domain that the operator has been given permissions to operate.\n /// @param _permissionIndex The permission index to check for.\n /// @return A flag indicating whether the operator has the specified permission.\n function hasPermission(\n address _operator,\n address _account,\n uint256 _domain,\n uint256 _permissionIndex\n ) external view override returns (bool) {\n if (_permissionIndex > 255) revert PERMISSION_INDEX_OUT_OF_BOUNDS();\n\n return (((permissionsOf[_operator][_account][_domain] >> _permissionIndex) & 1) == 1);\n }\n\n /// @notice Whether or not an operator has the permission to take certain actions pertaining to the specified domain.\n /// @param _operator The operator to check.\n /// @param _account The account that has given out permissions to the operator.\n /// @param _domain The domain that the operator has been given permissions to operate.\n /// @param _permissionIndexes An array of permission indexes to check for.\n /// @return A flag indicating whether the operator has all specified permissions.\n function hasPermissions(\n address _operator,\n address _account,\n uint256 _domain,\n uint256[] calldata _permissionIndexes\n ) external view override returns (bool) {\n for (uint256 _i; _i < _permissionIndexes.length; ) {\n uint256 _permissionIndex = _permissionIndexes[_i];\n\n if (_permissionIndex > 255) revert PERMISSION_INDEX_OUT_OF_BOUNDS();\n\n if (((permissionsOf[_operator][_account][_domain] >> _permissionIndex) & 1) == 0)\n return false;\n\n unchecked {\n ++_i;\n }\n }\n return true;\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Sets permissions for an operators.\n /// @dev Only an address can set its own operators.\n /// @param _operatorData The data that specifies the params for the operator being set.\n function setOperator(JBOperatorData calldata _operatorData) external override {\n // Pack the indexes into a uint256.\n uint256 _packed = _packedPermissions(_operatorData.permissionIndexes);\n\n // Store the new value.\n permissionsOf[_operatorData.operator][msg.sender][_operatorData.domain] = _packed;\n\n emit SetOperator(\n _operatorData.operator,\n msg.sender,\n _operatorData.domain,\n _operatorData.permissionIndexes,\n _packed\n );\n }\n\n /// @notice Sets permissions for many operators.\n /// @dev Only an address can set its own operators.\n /// @param _operatorData The data that specify the params for each operator being set.\n function setOperators(JBOperatorData[] calldata _operatorData) external override {\n for (uint256 _i; _i < _operatorData.length; ) {\n // Pack the indexes into a uint256.\n uint256 _packed = _packedPermissions(_operatorData[_i].permissionIndexes);\n\n // Store the new value.\n permissionsOf[_operatorData[_i].operator][msg.sender][_operatorData[_i].domain] = _packed;\n\n emit SetOperator(\n _operatorData[_i].operator,\n msg.sender,\n _operatorData[_i].domain,\n _operatorData[_i].permissionIndexes,\n _packed\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n\n //*********************************************************************//\n // --------------------- private helper functions -------------------- //\n //*********************************************************************//\n\n /// @notice Converts an array of permission indexes to a packed `uint256`.\n /// @param _indexes The indexes of the permissions to pack.\n /// @return packed The packed value.\n function _packedPermissions(uint256[] calldata _indexes) private pure returns (uint256 packed) {\n for (uint256 _i; _i < _indexes.length; ) {\n uint256 _index = _indexes[_i];\n\n if (_index > 255) revert PERMISSION_INDEX_OUT_OF_BOUNDS();\n\n // Turn the bit at the index on.\n packed |= 1 << _index;\n\n unchecked {\n ++_i;\n }\n }\n }\n}\n" + }, + "contracts/JBFundAccessConstraintsStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {ERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol';\nimport {JBControllerUtility} from './abstract/JBControllerUtility.sol';\nimport {IJBFundAccessConstraintsStore} from './interfaces/IJBFundAccessConstraintsStore.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\nimport {JBFundAccessConstraints} from './structs/JBFundAccessConstraints.sol';\n\n/// @notice Information pertaining to how much funds can be accessed by a project from each payment terminal.\ncontract JBFundAccessConstraintsStore is\n JBControllerUtility,\n ERC165,\n IJBFundAccessConstraintsStore\n{\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n\n error INVALID_DISTRIBUTION_LIMIT();\n error INVALID_DISTRIBUTION_LIMIT_CURRENCY();\n error INVALID_OVERFLOW_ALLOWANCE();\n error INVALID_OVERFLOW_ALLOWANCE_CURRENCY();\n\n //*********************************************************************//\n // --------------------- internal stored properties ------------------ //\n //*********************************************************************//\n\n /// @notice Data regarding the distribution limit of a project during a configuration.\n /// @dev bits 0-231: The amount of token that a project can distribute per funding cycle.\n /// @dev bits 232-255: The currency of amount that a project can distribute.\n /// @custom:param _projectId The ID of the project to get the packed distribution limit data of.\n /// @custom:param _configuration The configuration during which the packed distribution limit data applies.\n /// @custom:param _terminal The terminal from which distributions are being limited.\n /// @custom:param _token The token for which distributions are being limited.\n mapping(uint256 => mapping(uint256 => mapping(IJBPaymentTerminal => mapping(address => uint256))))\n internal _packedDistributionLimitDataOf;\n\n /// @notice Data regarding the overflow allowance of a project during a configuration.\n /// @dev bits 0-231: The amount of overflow that a project is allowed to tap into on-demand throughout the configuration.\n /// @dev bits 232-255: The currency of the amount of overflow that a project is allowed to tap.\n /// @custom:param _projectId The ID of the project to get the packed overflow allowance data of.\n /// @custom:param _configuration The configuration during which the packed overflow allowance data applies.\n /// @custom:param _terminal The terminal managing the overflow.\n /// @custom:param _token The token for which overflow is being allowed.\n mapping(uint256 => mapping(uint256 => mapping(IJBPaymentTerminal => mapping(address => uint256))))\n internal _packedOverflowAllowanceDataOf;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice The amount of token that a project can distribute per funding cycle, and the currency it's in terms of.\n /// @dev The number of decimals in the returned fixed point amount is the same as that of the specified terminal.\n /// @param _projectId The ID of the project to get the distribution limit of.\n /// @param _configuration The configuration during which the distribution limit applies.\n /// @param _terminal The terminal from which distributions are being limited.\n /// @param _token The token for which the distribution limit applies.\n /// @return The distribution limit, as a fixed point number with the same number of decimals as the provided terminal.\n /// @return The currency of the distribution limit.\n function distributionLimitOf(\n uint256 _projectId,\n uint256 _configuration,\n IJBPaymentTerminal _terminal,\n address _token\n ) external view override returns (uint256, uint256) {\n // Get a reference to the packed data.\n uint256 _data = _packedDistributionLimitDataOf[_projectId][_configuration][_terminal][_token];\n\n // The limit is in bits 0-231. The currency is in bits 232-255.\n return (uint256(uint232(_data)), _data >> 232);\n }\n\n /// @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.\n /// @dev The number of decimals in the returned fixed point amount is the same as that of the specified terminal.\n /// @param _projectId The ID of the project to get the overflow allowance of.\n /// @param _configuration The configuration of the during which the allowance applies.\n /// @param _terminal The terminal managing the overflow.\n /// @param _token The token for which the overflow allowance applies.\n /// @return The overflow allowance, as a fixed point number with the same number of decimals as the provided terminal.\n /// @return The currency of the overflow allowance.\n function overflowAllowanceOf(\n uint256 _projectId,\n uint256 _configuration,\n IJBPaymentTerminal _terminal,\n address _token\n ) external view override returns (uint256, uint256) {\n // Get a reference to the packed data.\n uint256 _data = _packedOverflowAllowanceDataOf[_projectId][_configuration][_terminal][_token];\n\n // The allowance is in bits 0-231. The currency is in bits 232-255.\n return (uint256(uint232(_data)), _data >> 232);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n // solhint-disable-next-line no-empty-blocks\n constructor(IJBDirectory _directory) JBControllerUtility(_directory) {}\n\n //*********************************************************************//\n // --------------------- external transactions ----------------------- //\n //*********************************************************************//\n\n /// @notice Sets a project's constraints for accessing treasury funds.\n /// @dev Only a project's current controller can set its fund access constraints.\n /// @param _projectId The ID of the project whose fund access constraints are being set.\n /// @param _configuration The funding cycle configuration the constraints apply within.\n /// @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`.\n function setFor(\n uint256 _projectId,\n uint256 _configuration,\n JBFundAccessConstraints[] calldata _fundAccessConstraints\n ) external override onlyController(_projectId) {\n // Save the number of constraints.\n uint256 _numberOfFundAccessConstraints = _fundAccessConstraints.length;\n\n // Set distribution limits if there are any.\n for (uint256 _i; _i < _numberOfFundAccessConstraints; ) {\n // If distribution limit value is larger than 232 bits, revert.\n if (_fundAccessConstraints[_i].distributionLimit > type(uint232).max)\n revert INVALID_DISTRIBUTION_LIMIT();\n\n // If distribution limit currency value is larger than 24 bits, revert.\n if (_fundAccessConstraints[_i].distributionLimitCurrency > type(uint24).max)\n revert INVALID_DISTRIBUTION_LIMIT_CURRENCY();\n\n // If overflow allowance value is larger than 232 bits, revert.\n if (_fundAccessConstraints[_i].overflowAllowance > type(uint232).max)\n revert INVALID_OVERFLOW_ALLOWANCE();\n\n // If overflow allowance currency value is larger than 24 bits, revert.\n if (_fundAccessConstraints[_i].overflowAllowanceCurrency > type(uint24).max)\n revert INVALID_OVERFLOW_ALLOWANCE_CURRENCY();\n\n // Set the distribution limit if there is one.\n if (_fundAccessConstraints[_i].distributionLimit > 0)\n _packedDistributionLimitDataOf[_projectId][_configuration][\n _fundAccessConstraints[_i].terminal\n ][_fundAccessConstraints[_i].token] =\n _fundAccessConstraints[_i].distributionLimit |\n (_fundAccessConstraints[_i].distributionLimitCurrency << 232);\n\n // Set the overflow allowance if there is one.\n if (_fundAccessConstraints[_i].overflowAllowance > 0)\n _packedOverflowAllowanceDataOf[_projectId][_configuration][\n _fundAccessConstraints[_i].terminal\n ][_fundAccessConstraints[_i].token] =\n _fundAccessConstraints[_i].overflowAllowance |\n (_fundAccessConstraints[_i].overflowAllowanceCurrency << 232);\n\n emit SetFundAccessConstraints(\n _configuration,\n _projectId,\n _fundAccessConstraints[_i],\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n}\n" + }, + "contracts/interfaces/IJBTerminalUtility.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBDirectory} from './IJBDirectory.sol';\n\ninterface IJBPaymentTerminalUtility {\n function directory() external view returns (IJBDirectory);\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": [ + "ast" + ] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} \ No newline at end of file diff --git a/deployments/sepolia/JBETHPaymentTerminal3_1_1.json b/deployments/sepolia/JBETHPaymentTerminal3_1_1.json new file mode 100644 index 000000000..3d2f45061 --- /dev/null +++ b/deployments/sepolia/JBETHPaymentTerminal3_1_1.json @@ -0,0 +1,2574 @@ +{ + "address": "0x82129d4109625F94582bDdF6101a8Cd1a27919f5", + "abi": [ + { + "inputs": [ + { + "internalType": "uint256", + "name": "_baseWeightCurrency", + "type": "uint256" + }, + { + "internalType": "contract IJBOperatorStore", + "name": "_operatorStore", + "type": "address" + }, + { + "internalType": "contract IJBProjects", + "name": "_projects", + "type": "address" + }, + { + "internalType": "contract IJBDirectory", + "name": "_directory", + "type": "address" + }, + { + "internalType": "contract IJBSplitsStore", + "name": "_splitsStore", + "type": "address" + }, + { + "internalType": "contract IJBPrices", + "name": "_prices", + "type": "address" + }, + { + "internalType": "address", + "name": "_store", + "type": "address" + }, + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "FEE_TOO_HIGH", + "type": "error" + }, + { + "inputs": [], + "name": "INADEQUATE_DISTRIBUTION_AMOUNT", + "type": "error" + }, + { + "inputs": [], + "name": "INADEQUATE_RECLAIM_AMOUNT", + "type": "error" + }, + { + "inputs": [], + "name": "INADEQUATE_TOKEN_COUNT", + "type": "error" + }, + { + "inputs": [], + "name": "NO_MSG_VALUE_ALLOWED", + "type": "error" + }, + { + "inputs": [], + "name": "PAY_TO_ZERO_ADDRESS", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "prod1", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "denominator", + "type": "uint256" + } + ], + "name": "PRBMath__MulDivOverflow", + "type": "error" + }, + { + "inputs": [], + "name": "PROJECT_TERMINAL_MISMATCH", + "type": "error" + }, + { + "inputs": [], + "name": "REDEEM_TO_ZERO_ADDRESS", + "type": "error" + }, + { + "inputs": [], + "name": "TERMINAL_TOKENS_INCOMPATIBLE", + "type": "error" + }, + { + "inputs": [], + "name": "UNAUTHORIZED", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "refundedFees", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "string", + "name": "memo", + "type": "string" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "metadata", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "AddToBalance", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract IJBPayDelegate3_1_1", + "name": "delegate", + "type": "address" + }, + { + "components": [ + { + "internalType": "address", + "name": "payer", + "type": "address" + }, + { + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "currentFundingCycleConfiguration", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "decimals", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "currency", + "type": "uint256" + } + ], + "internalType": "struct JBTokenAmount", + "name": "amount", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "decimals", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "currency", + "type": "uint256" + } + ], + "internalType": "struct JBTokenAmount", + "name": "forwardedAmount", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "projectTokenCount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "beneficiary", + "type": "address" + }, + { + "internalType": "bool", + "name": "preferClaimedTokens", + "type": "bool" + }, + { + "internalType": "string", + "name": "memo", + "type": "string" + }, + { + "internalType": "bytes", + "name": "dataSourceMetadata", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "payerMetadata", + "type": "bytes" + } + ], + "indexed": false, + "internalType": "struct JBDidPayData3_1_1", + "name": "data", + "type": "tuple" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "delegatedAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "DelegateDidPay", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract IJBPayDelegate", + "name": "delegate", + "type": "address" + }, + { + "components": [ + { + "internalType": "address", + "name": "payer", + "type": "address" + }, + { + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "currentFundingCycleConfiguration", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "decimals", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "currency", + "type": "uint256" + } + ], + "internalType": "struct JBTokenAmount", + "name": "amount", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "decimals", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "currency", + "type": "uint256" + } + ], + "internalType": "struct JBTokenAmount", + "name": "forwardedAmount", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "projectTokenCount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "beneficiary", + "type": "address" + }, + { + "internalType": "bool", + "name": "preferClaimedTokens", + "type": "bool" + }, + { + "internalType": "string", + "name": "memo", + "type": "string" + }, + { + "internalType": "bytes", + "name": "metadata", + "type": "bytes" + } + ], + "indexed": false, + "internalType": "struct JBDidPayData", + "name": "data", + "type": "tuple" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "delegatedAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "DelegateDidPay", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract IJBRedemptionDelegate3_1_1", + "name": "delegate", + "type": "address" + }, + { + "components": [ + { + "internalType": "address", + "name": "holder", + "type": "address" + }, + { + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "currentFundingCycleConfiguration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "projectTokenCount", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "decimals", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "currency", + "type": "uint256" + } + ], + "internalType": "struct JBTokenAmount", + "name": "reclaimedAmount", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "decimals", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "currency", + "type": "uint256" + } + ], + "internalType": "struct JBTokenAmount", + "name": "forwardedAmount", + "type": "tuple" + }, + { + "internalType": "address payable", + "name": "beneficiary", + "type": "address" + }, + { + "internalType": "string", + "name": "memo", + "type": "string" + }, + { + "internalType": "bytes", + "name": "dataSourceMetadata", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "redeemerMetadata", + "type": "bytes" + } + ], + "indexed": false, + "internalType": "struct JBDidRedeemData3_1_1", + "name": "data", + "type": "tuple" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "delegatedAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "fee", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "DelegateDidRedeem", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract IJBRedemptionDelegate", + "name": "delegate", + "type": "address" + }, + { + "components": [ + { + "internalType": "address", + "name": "holder", + "type": "address" + }, + { + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "currentFundingCycleConfiguration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "projectTokenCount", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "decimals", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "currency", + "type": "uint256" + } + ], + "internalType": "struct JBTokenAmount", + "name": "reclaimedAmount", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "decimals", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "currency", + "type": "uint256" + } + ], + "internalType": "struct JBTokenAmount", + "name": "forwardedAmount", + "type": "tuple" + }, + { + "internalType": "address payable", + "name": "beneficiary", + "type": "address" + }, + { + "internalType": "string", + "name": "memo", + "type": "string" + }, + { + "internalType": "bytes", + "name": "metadata", + "type": "bytes" + } + ], + "indexed": false, + "internalType": "struct JBDidRedeemData", + "name": "data", + "type": "tuple" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "delegatedAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "DelegateDidRedeem", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "fundingCycleConfiguration", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "fundingCycleNumber", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "beneficiary", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "distributedAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "fee", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "beneficiaryDistributionAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "metadata", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "DistributePayouts", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "domain", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "group", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "bool", + "name": "preferClaimed", + "type": "bool" + }, + { + "internalType": "bool", + "name": "preferAddToBalance", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "percent", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "internalType": "address payable", + "name": "beneficiary", + "type": "address" + }, + { + "internalType": "uint256", + "name": "lockedUntil", + "type": "uint256" + }, + { + "internalType": "contract IJBSplitAllocator", + "name": "allocator", + "type": "address" + } + ], + "indexed": false, + "internalType": "struct JBSplit", + "name": "split", + "type": "tuple" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "netAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "DistributeToPayoutSplit", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "feeProjectId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "reason", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "FeeReverted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "fee", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "feeDiscount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "beneficiary", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "HoldFee", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "contract IJBPaymentTerminal", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "Migrate", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "fundingCycleConfiguration", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "fundingCycleNumber", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "payer", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "beneficiary", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "beneficiaryTokenCount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "string", + "name": "memo", + "type": "string" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "metadata", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "Pay", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "bool", + "name": "preferClaimed", + "type": "bool" + }, + { + "internalType": "bool", + "name": "preferAddToBalance", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "percent", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "internalType": "address payable", + "name": "beneficiary", + "type": "address" + }, + { + "internalType": "uint256", + "name": "lockedUntil", + "type": "uint256" + }, + { + "internalType": "contract IJBSplitAllocator", + "name": "allocator", + "type": "address" + } + ], + "indexed": false, + "internalType": "struct JBSplit", + "name": "split", + "type": "tuple" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "reason", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "PayoutReverted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "bool", + "name": "wasHeld", + "type": "bool" + }, + { + "indexed": false, + "internalType": "address", + "name": "beneficiary", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "ProcessFee", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "fundingCycleConfiguration", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "fundingCycleNumber", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "holder", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "beneficiary", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "tokenCount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "reclaimedAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "string", + "name": "memo", + "type": "string" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "metadata", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "RedeemTokens", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "refundedFees", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "leftoverAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "RefundHeldFees", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "fee", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "SetFee", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "feeGauge", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "SetFeeGauge", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "addrs", + "type": "address" + }, + { + "indexed": true, + "internalType": "bool", + "name": "flag", + "type": "bool" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "SetFeelessAddress", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "fundingCycleConfiguration", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "fundingCycleNumber", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "projectId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "beneficiary", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "distributedAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "netDistributedamount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "string", + "name": "memo", + "type": "string" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "metadata", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "UseAllowance", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + } + ], + "name": "acceptsToken", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_token", + "type": "address" + }, + { + "internalType": "string", + "name": "_memo", + "type": "string" + }, + { + "internalType": "bytes", + "name": "_metadata", + "type": "bytes" + } + ], + "name": "addToBalanceOf", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_token", + "type": "address" + }, + { + "internalType": "bool", + "name": "_shouldRefundHeldFees", + "type": "bool" + }, + { + "internalType": "string", + "name": "_memo", + "type": "string" + }, + { + "internalType": "bytes", + "name": "_metadata", + "type": "bytes" + } + ], + "name": "addToBalanceOf", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "baseWeightCurrency", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "currency", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_token", + "type": "address" + } + ], + "name": "currencyForToken", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + } + ], + "name": "currentEthOverflowOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_token", + "type": "address" + } + ], + "name": "decimalsForToken", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "directory", + "outputs": [ + { + "internalType": "contract IJBDirectory", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_currency", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_minReturnedTokens", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "_metadata", + "type": "bytes" + } + ], + "name": "distributePayoutsOf", + "outputs": [ + { + "internalType": "uint256", + "name": "netLeftoverDistributionAmount", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "fee", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "feeGauge", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + } + ], + "name": "heldFeesOf", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint32", + "name": "fee", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "feeDiscount", + "type": "uint32" + }, + { + "internalType": "address", + "name": "beneficiary", + "type": "address" + } + ], + "internalType": "struct JBFee[]", + "name": "", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "isFeelessAddress", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + }, + { + "internalType": "contract IJBPaymentTerminal", + "name": "_to", + "type": "address" + } + ], + "name": "migrate", + "outputs": [ + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "operatorStore", + "outputs": [ + { + "internalType": "contract IJBOperatorStore", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_token", + "type": "address" + }, + { + "internalType": "address", + "name": "_beneficiary", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_minReturnedTokens", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "_preferClaimedTokens", + "type": "bool" + }, + { + "internalType": "string", + "name": "_memo", + "type": "string" + }, + { + "internalType": "bytes", + "name": "_metadata", + "type": "bytes" + } + ], + "name": "pay", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "payoutSplitsGroup", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "prices", + "outputs": [ + { + "internalType": "contract IJBPrices", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + } + ], + "name": "processFees", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "projects", + "outputs": [ + { + "internalType": "contract IJBProjects", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_holder", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_tokenCount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_minReturnedTokens", + "type": "uint256" + }, + { + "internalType": "address payable", + "name": "_beneficiary", + "type": "address" + }, + { + "internalType": "string", + "name": "_memo", + "type": "string" + }, + { + "internalType": "bytes", + "name": "_metadata", + "type": "bytes" + } + ], + "name": "redeemTokensOf", + "outputs": [ + { + "internalType": "uint256", + "name": "reclaimAmount", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_fee", + "type": "uint256" + } + ], + "name": "setFee", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_feeGauge", + "type": "address" + } + ], + "name": "setFeeGauge", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_address", + "type": "address" + }, + { + "internalType": "bool", + "name": "_flag", + "type": "bool" + } + ], + "name": "setFeelessAddress", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "splitsStore", + "outputs": [ + { + "internalType": "contract IJBSplitsStore", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "store", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "token", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_currency", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_minReturnedTokens", + "type": "uint256" + }, + { + "internalType": "address payable", + "name": "_beneficiary", + "type": "address" + }, + { + "internalType": "string", + "name": "_memo", + "type": "string" + }, + { + "internalType": "bytes", + "name": "_metadata", + "type": "bytes" + } + ], + "name": "useAllowanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "netDistributedAmount", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "transactionHash": "0x0ace87a8866f212233d06e4f7e8fa837923ad7198789dcc521ab35e396277611", + "receipt": { + "to": null, + "from": "0xc64533F8d8dEbC301cb4791e6ED941Cb38473DE6", + "contractAddress": "0x82129d4109625F94582bDdF6101a8Cd1a27919f5", + "transactionIndex": 13, + "gasUsed": "5083226", + "logsBloom": "0x00000000000000000000000000000000000000000000000000801000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000008020000000000000000000800000000000000000000000000200000400000000000000000000100000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000200020000000000000000000000000000000000008000000000000000040000000000000", + "blockHash": "0x296fce7f646d39eaa8a6af06a159f654dac37ba2d3a7186d2ac4ce6a4d050137", + "transactionHash": "0x0ace87a8866f212233d06e4f7e8fa837923ad7198789dcc521ab35e396277611", + "logs": [ + { + "transactionIndex": 13, + "blockNumber": 3798041, + "transactionHash": "0x0ace87a8866f212233d06e4f7e8fa837923ad7198789dcc521ab35e396277611", + "address": "0x82129d4109625F94582bDdF6101a8Cd1a27919f5", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000c64533f8d8debc301cb4791e6ed941cb38473de6" + ], + "data": "0x", + "logIndex": 14, + "blockHash": "0x296fce7f646d39eaa8a6af06a159f654dac37ba2d3a7186d2ac4ce6a4d050137" + }, + { + "transactionIndex": 13, + "blockNumber": 3798041, + "transactionHash": "0x0ace87a8866f212233d06e4f7e8fa837923ad7198789dcc521ab35e396277611", + "address": "0x82129d4109625F94582bDdF6101a8Cd1a27919f5", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x000000000000000000000000c64533f8d8debc301cb4791e6ed941cb38473de6", + "0x000000000000000000000000af28bcb48c40dbc86f52d459a6562f658fc94b1e" + ], + "data": "0x", + "logIndex": 15, + "blockHash": "0x296fce7f646d39eaa8a6af06a159f654dac37ba2d3a7186d2ac4ce6a4d050137" + } + ], + "blockNumber": 3798041, + "cumulativeGasUsed": "8187797", + "status": 1, + "byzantium": true + }, + "args": [ + "1", + "0x8f63c744c0280ef4b32af1f821c65e0fd4150ab3", + "0x43CB8FCe4F0d61579044342A5d5A027aB7aE4D63", + "0x3B3Bd16cc76cd53218e00b600bFCa27aA5057794", + "0xEdE89dB755855aF041b5f100B39db9324b5227Ac", + "0x6EF51C14045B386A0ae6374E48a9EeB928105ffb", + "0x981c8ECD009E3E84eE1fF99266BF1461a12e5c68", + "0xAF28bcB48C40dBC86f52D459A6562F658fc94B1e" + ], + "numDeployments": 2, + "solcInputHash": "11cb1f66a0f8213d7bf83deb0ae9d2f7", + "metadata": "{\"compiler\":{\"version\":\"0.8.16+commit.07a7930e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_baseWeightCurrency\",\"type\":\"uint256\"},{\"internalType\":\"contract IJBOperatorStore\",\"name\":\"_operatorStore\",\"type\":\"address\"},{\"internalType\":\"contract IJBProjects\",\"name\":\"_projects\",\"type\":\"address\"},{\"internalType\":\"contract IJBDirectory\",\"name\":\"_directory\",\"type\":\"address\"},{\"internalType\":\"contract IJBSplitsStore\",\"name\":\"_splitsStore\",\"type\":\"address\"},{\"internalType\":\"contract IJBPrices\",\"name\":\"_prices\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_store\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"FEE_TOO_HIGH\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"INADEQUATE_DISTRIBUTION_AMOUNT\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"INADEQUATE_RECLAIM_AMOUNT\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"INADEQUATE_TOKEN_COUNT\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NO_MSG_VALUE_ALLOWED\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PAY_TO_ZERO_ADDRESS\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"prod1\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"denominator\",\"type\":\"uint256\"}],\"name\":\"PRBMath__MulDivOverflow\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PROJECT_TERMINAL_MISMATCH\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"REDEEM_TO_ZERO_ADDRESS\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TERMINAL_TOKENS_INCOMPATIBLE\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UNAUTHORIZED\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"refundedFees\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"memo\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"metadata\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"AddToBalance\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"contract IJBPayDelegate3_1_1\",\"name\":\"delegate\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"payer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"currentFundingCycleConfiguration\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"decimals\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"currency\",\"type\":\"uint256\"}],\"internalType\":\"struct JBTokenAmount\",\"name\":\"amount\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"decimals\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"currency\",\"type\":\"uint256\"}],\"internalType\":\"struct JBTokenAmount\",\"name\":\"forwardedAmount\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"projectTokenCount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"beneficiary\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"preferClaimedTokens\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"memo\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"dataSourceMetadata\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"payerMetadata\",\"type\":\"bytes\"}],\"indexed\":false,\"internalType\":\"struct JBDidPayData3_1_1\",\"name\":\"data\",\"type\":\"tuple\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"delegatedAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"DelegateDidPay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"contract IJBPayDelegate\",\"name\":\"delegate\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"payer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"currentFundingCycleConfiguration\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"decimals\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"currency\",\"type\":\"uint256\"}],\"internalType\":\"struct JBTokenAmount\",\"name\":\"amount\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"decimals\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"currency\",\"type\":\"uint256\"}],\"internalType\":\"struct JBTokenAmount\",\"name\":\"forwardedAmount\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"projectTokenCount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"beneficiary\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"preferClaimedTokens\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"memo\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"metadata\",\"type\":\"bytes\"}],\"indexed\":false,\"internalType\":\"struct JBDidPayData\",\"name\":\"data\",\"type\":\"tuple\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"delegatedAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"DelegateDidPay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"contract IJBRedemptionDelegate3_1_1\",\"name\":\"delegate\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"holder\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"currentFundingCycleConfiguration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"projectTokenCount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"decimals\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"currency\",\"type\":\"uint256\"}],\"internalType\":\"struct JBTokenAmount\",\"name\":\"reclaimedAmount\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"decimals\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"currency\",\"type\":\"uint256\"}],\"internalType\":\"struct JBTokenAmount\",\"name\":\"forwardedAmount\",\"type\":\"tuple\"},{\"internalType\":\"address payable\",\"name\":\"beneficiary\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"memo\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"dataSourceMetadata\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"redeemerMetadata\",\"type\":\"bytes\"}],\"indexed\":false,\"internalType\":\"struct JBDidRedeemData3_1_1\",\"name\":\"data\",\"type\":\"tuple\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"delegatedAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fee\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"DelegateDidRedeem\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"contract IJBRedemptionDelegate\",\"name\":\"delegate\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"holder\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"currentFundingCycleConfiguration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"projectTokenCount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"decimals\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"currency\",\"type\":\"uint256\"}],\"internalType\":\"struct JBTokenAmount\",\"name\":\"reclaimedAmount\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"decimals\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"currency\",\"type\":\"uint256\"}],\"internalType\":\"struct JBTokenAmount\",\"name\":\"forwardedAmount\",\"type\":\"tuple\"},{\"internalType\":\"address payable\",\"name\":\"beneficiary\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"memo\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"metadata\",\"type\":\"bytes\"}],\"indexed\":false,\"internalType\":\"struct JBDidRedeemData\",\"name\":\"data\",\"type\":\"tuple\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"delegatedAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"DelegateDidRedeem\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"fundingCycleConfiguration\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"fundingCycleNumber\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"beneficiary\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"distributedAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fee\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"beneficiaryDistributionAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"metadata\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"DistributePayouts\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"domain\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"group\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"preferClaimed\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"preferAddToBalance\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"percent\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"internalType\":\"address payable\",\"name\":\"beneficiary\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"lockedUntil\",\"type\":\"uint256\"},{\"internalType\":\"contract IJBSplitAllocator\",\"name\":\"allocator\",\"type\":\"address\"}],\"indexed\":false,\"internalType\":\"struct JBSplit\",\"name\":\"split\",\"type\":\"tuple\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"netAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"DistributeToPayoutSplit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"feeProjectId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"reason\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"FeeReverted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"fee\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"feeDiscount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"beneficiary\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"HoldFee\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"contract IJBPaymentTerminal\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"Migrate\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"fundingCycleConfiguration\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"fundingCycleNumber\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"payer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"beneficiary\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"beneficiaryTokenCount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"memo\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"metadata\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"Pay\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"preferClaimed\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"preferAddToBalance\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"percent\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"internalType\":\"address payable\",\"name\":\"beneficiary\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"lockedUntil\",\"type\":\"uint256\"},{\"internalType\":\"contract IJBSplitAllocator\",\"name\":\"allocator\",\"type\":\"address\"}],\"indexed\":false,\"internalType\":\"struct JBSplit\",\"name\":\"split\",\"type\":\"tuple\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"reason\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"PayoutReverted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bool\",\"name\":\"wasHeld\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"beneficiary\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"ProcessFee\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"fundingCycleConfiguration\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"fundingCycleNumber\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"holder\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"beneficiary\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokenCount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"reclaimedAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"memo\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"metadata\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"RedeemTokens\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"refundedFees\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"leftoverAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"RefundHeldFees\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fee\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"SetFee\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"feeGauge\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"SetFeeGauge\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"addrs\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bool\",\"name\":\"flag\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"SetFeelessAddress\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"fundingCycleConfiguration\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"fundingCycleNumber\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"projectId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"beneficiary\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"distributedAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"netDistributedamount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"memo\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"metadata\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"UseAllowance\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"}],\"name\":\"acceptsToken\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"_memo\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"_metadata\",\"type\":\"bytes\"}],\"name\":\"addToBalanceOf\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"_shouldRefundHeldFees\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"_memo\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"_metadata\",\"type\":\"bytes\"}],\"name\":\"addToBalanceOf\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"baseWeightCurrency\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"currency\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"}],\"name\":\"currencyForToken\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"}],\"name\":\"currentEthOverflowOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"}],\"name\":\"decimalsForToken\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"directory\",\"outputs\":[{\"internalType\":\"contract IJBDirectory\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_currency\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_minReturnedTokens\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_metadata\",\"type\":\"bytes\"}],\"name\":\"distributePayoutsOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"netLeftoverDistributionAmount\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"feeGauge\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"}],\"name\":\"heldFeesOf\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"fee\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feeDiscount\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"beneficiary\",\"type\":\"address\"}],\"internalType\":\"struct JBFee[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"isFeelessAddress\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"},{\"internalType\":\"contract IJBPaymentTerminal\",\"name\":\"_to\",\"type\":\"address\"}],\"name\":\"migrate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"operatorStore\",\"outputs\":[{\"internalType\":\"contract IJBOperatorStore\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_beneficiary\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_minReturnedTokens\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"_preferClaimedTokens\",\"type\":\"bool\"},{\"internalType\":\"string\",\"name\":\"_memo\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"_metadata\",\"type\":\"bytes\"}],\"name\":\"pay\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"payoutSplitsGroup\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"prices\",\"outputs\":[{\"internalType\":\"contract IJBPrices\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"}],\"name\":\"processFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"projects\",\"outputs\":[{\"internalType\":\"contract IJBProjects\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_holder\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_tokenCount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_minReturnedTokens\",\"type\":\"uint256\"},{\"internalType\":\"address payable\",\"name\":\"_beneficiary\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"_memo\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"_metadata\",\"type\":\"bytes\"}],\"name\":\"redeemTokensOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"reclaimAmount\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_fee\",\"type\":\"uint256\"}],\"name\":\"setFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_feeGauge\",\"type\":\"address\"}],\"name\":\"setFeeGauge\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_address\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"_flag\",\"type\":\"bool\"}],\"name\":\"setFeelessAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"splitsStore\",\"outputs\":[{\"internalType\":\"contract IJBSplitsStore\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"store\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"_interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"token\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_currency\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_minReturnedTokens\",\"type\":\"uint256\"},{\"internalType\":\"address payable\",\"name\":\"_beneficiary\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"_memo\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"_metadata\",\"type\":\"bytes\"}],\"name\":\"useAllowanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"netDistributedAmount\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"acceptsToken(address,uint256)\":{\"params\":{\"_projectId\":\"The project ID to check for token acceptance.\",\"_token\":\"The token to check if this terminal accepts or not.\"},\"returns\":{\"_0\":\"The flag.\"}},\"addToBalanceOf(uint256,uint256,address,bool,string,bytes)\":{\"params\":{\"_amount\":\"The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\",\"_memo\":\"A memo to pass along to the emitted event.\",\"_metadata\":\"Extra data to pass along to the emitted event.\",\"_projectId\":\"The ID of the project to which the funds received belong.\",\"_shouldRefundHeldFees\":\"A flag indicating if held fees should be refunded based on the amount being added.\",\"_token\":\"The token being paid. This terminal ignores this property since it only manages one currency.\"}},\"addToBalanceOf(uint256,uint256,address,string,bytes)\":{\"params\":{\"_amount\":\"The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\",\"_memo\":\"A memo to pass along to the emitted event.\",\"_metadata\":\"Extra data to pass along to the emitted event.\",\"_projectId\":\"The ID of the project to which the funds received belong.\",\"_token\":\"The token being paid. This terminal ignores this property since it only manages one currency.\"}},\"constructor\":{\"params\":{\"_baseWeightCurrency\":\"The currency to base token issuance on.\",\"_directory\":\"A contract storing directories of terminals and controllers for each project.\",\"_operatorStore\":\"A contract storing operator assignments.\",\"_owner\":\"The address that will own this contract.\",\"_prices\":\"A contract that exposes price feeds.\",\"_projects\":\"A contract which mints ERC-721's that represent project ownership and transfers.\",\"_splitsStore\":\"A contract that stores splits for each project.\",\"_store\":\"A contract that stores the terminal's data.\"}},\"currencyForToken(address)\":{\"params\":{\"_token\":\"The token to check for the currency of.\"},\"returns\":{\"_0\":\"The currency index.\"}},\"currentEthOverflowOf(uint256)\":{\"details\":\"The current overflow is represented as a fixed point number with 18 decimals.\",\"params\":{\"_projectId\":\"The ID of the project to get overflow for.\"},\"returns\":{\"_0\":\"The current amount of ETH overflow that project has in this terminal, as a fixed point number with 18 decimals.\"}},\"decimalsForToken(address)\":{\"params\":{\"_token\":\"The token to check for the decimals of.\"},\"returns\":{\"_0\":\"The number of decimals for the token.\"}},\"distributePayoutsOf(uint256,uint256,uint256,address,uint256,bytes)\":{\"details\":\"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.\",\"params\":{\"_amount\":\"The amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal.\",\"_currency\":\"The expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency.\",\"_metadata\":\"Bytes to send along to the emitted event, if provided.\",\"_minReturnedTokens\":\"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.\",\"_projectId\":\"The ID of the project having its payouts distributed.\",\"_token\":\"The token being distributed. This terminal ignores this property since it only manages one token.\"},\"returns\":{\"netLeftoverDistributionAmount\":\"The amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal.\"}},\"heldFeesOf(uint256)\":{\"params\":{\"_projectId\":\"The ID of the project for which fees are being held.\"},\"returns\":{\"_0\":\"An array of fees that are being held.\"}},\"migrate(uint256,address)\":{\"details\":\"Only a project's owner or a designated operator can migrate it.\",\"params\":{\"_projectId\":\"The ID of the project being migrated.\",\"_to\":\"The terminal contract that will gain the project's funds.\"},\"returns\":{\"balance\":\"The amount of funds that were migrated, as a fixed point number with the same amount of decimals as this terminal.\"}},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"pay(uint256,uint256,address,address,uint256,bool,string,bytes)\":{\"params\":{\"_amount\":\"The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place.\",\"_beneficiary\":\"The address to mint tokens for and pass along to the funding cycle's data source and delegate.\",\"_memo\":\"A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\",\"_metadata\":\"Bytes to send along to the data source, delegate, and emitted event, if provided.\",\"_minReturnedTokens\":\"The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal.\",\"_preferClaimedTokens\":\"A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\",\"_projectId\":\"The ID of the project being paid.\",\"_token\":\"The token being paid. This terminal ignores this property since it only manages one token.\"},\"returns\":{\"_0\":\"The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals.\"}},\"processFees(uint256)\":{\"details\":\"Only a project owner, an operator, or the contract's owner can process held fees.\",\"params\":{\"_projectId\":\"The ID of the project whos held fees should be processed.\"}},\"redeemTokensOf(address,uint256,uint256,address,uint256,address,string,bytes)\":{\"details\":\"Only a token holder or a designated operator can redeem its tokens.\",\"params\":{\"_beneficiary\":\"The address to send the terminal tokens to.\",\"_holder\":\"The account to redeem tokens for.\",\"_memo\":\"A memo to pass along to the emitted event.\",\"_metadata\":\"Bytes to send along to the data source, delegate, and emitted event, if provided.\",\"_minReturnedTokens\":\"The minimum amount of terminal tokens expected in return, as a fixed point number with the same amount of decimals as the terminal.\",\"_projectId\":\"The ID of the project to which the tokens being redeemed belong.\",\"_token\":\"The token being reclaimed. This terminal ignores this property since it only manages one token.\",\"_tokenCount\":\"The number of project tokens to redeem, as a fixed point number with 18 decimals.\"},\"returns\":{\"reclaimAmount\":\"The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals.\"}},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"setFee(uint256)\":{\"details\":\"Only the owner of this contract can change the fee.\",\"params\":{\"_fee\":\"The new fee, out of MAX_FEE.\"}},\"setFeeGauge(address)\":{\"details\":\"Only the owner of this contract can change the fee gauge.\",\"params\":{\"_feeGauge\":\"The new fee gauge.\"}},\"setFeelessAddress(address,bool)\":{\"details\":\"Only the owner of this contract can set addresses as feeless.\",\"params\":{\"_address\":\"The address that can be paid towards while still bypassing fees.\",\"_flag\":\"A flag indicating whether the terminal should be feeless or not.\"}},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\",\"params\":{\"_interfaceId\":\"The ID of the interface to check for adherance to.\"},\"returns\":{\"_0\":\"A flag indicating if the provided interface ID is supported.\"}},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"},\"useAllowanceOf(uint256,uint256,uint256,address,uint256,address,string,bytes)\":{\"details\":\"Only a project's owner or a designated operator can use its allowance.Incurs the protocol fee.\",\"params\":{\"_amount\":\"The amount of terminal tokens to use from this project's current allowance, as a fixed point number with the same amount of decimals as this terminal.\",\"_beneficiary\":\"The address to send the funds to.\",\"_currency\":\"The expected currency of the amount being distributed. Must match the project's current funding cycle's overflow allowance currency.\",\"_memo\":\"A memo to pass along to the emitted event.\",\"_metadata\":\"Bytes to send along to the emitted event, if provided.\",\"_minReturnedTokens\":\"The minimum number of tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with 18 decimals.\",\"_projectId\":\"The ID of the project to use the allowance of.\",\"_token\":\"The token being distributed. This terminal ignores this property since it only manages one token.\"},\"returns\":{\"netDistributedAmount\":\"The amount of tokens that was distributed to the beneficiary, as a fixed point number with the same amount of decimals as the terminal.\"}}},\"version\":1},\"userdoc\":{\"errors\":{\"PRBMath__MulDivOverflow(uint256,uint256)\":[{\"notice\":\"Emitted when the result overflows uint256.\"}]},\"kind\":\"user\",\"methods\":{\"acceptsToken(address,uint256)\":{\"notice\":\"A flag indicating if this terminal accepts the specified token.\"},\"addToBalanceOf(uint256,uint256,address,bool,string,bytes)\":{\"notice\":\"Receives funds belonging to the specified project.\"},\"addToBalanceOf(uint256,uint256,address,string,bytes)\":{\"notice\":\"Receives funds belonging to the specified project.\"},\"baseWeightCurrency()\":{\"notice\":\"The currency to base token issuance on.\"},\"currency()\":{\"notice\":\"The currency to use when resolving price feeds for this terminal.\"},\"currencyForToken(address)\":{\"notice\":\"The currency that should be used for the specified token.\"},\"currentEthOverflowOf(uint256)\":{\"notice\":\"Gets the current overflowed amount in this terminal for a specified project, in terms of ETH.\"},\"decimals()\":{\"notice\":\"The number of decimals the token fixed point amounts are expected to have.\"},\"decimalsForToken(address)\":{\"notice\":\"The decimals that should be used in fixed number accounting for the specified token.\"},\"directory()\":{\"notice\":\"The directory of terminals and controllers for projects.\"},\"distributePayoutsOf(uint256,uint256,uint256,address,uint256,bytes)\":{\"notice\":\"Distributes payouts for a project with the distribution limit of its current funding cycle.\"},\"fee()\":{\"notice\":\"The platform fee percent.\"},\"feeGauge()\":{\"notice\":\"The data source that returns a discount to apply to a project's fee.\"},\"heldFeesOf(uint256)\":{\"notice\":\"The fees that are currently being held to be processed later for each project.\"},\"isFeelessAddress(address)\":{\"notice\":\"Addresses that can be paid towards from this terminal without incurring a fee.\"},\"migrate(uint256,address)\":{\"notice\":\"Allows a project owner to migrate its funds and operations to a new terminal that accepts the same token type.\"},\"operatorStore()\":{\"notice\":\"A contract storing operator assignments.\"},\"pay(uint256,uint256,address,address,uint256,bool,string,bytes)\":{\"notice\":\"Contribute tokens to a project.\"},\"payoutSplitsGroup()\":{\"notice\":\"The group that payout splits coming from this terminal are identified by.\"},\"prices()\":{\"notice\":\"The contract that exposes price feeds.\"},\"processFees(uint256)\":{\"notice\":\"Process any fees that are being held for the project.\"},\"projects()\":{\"notice\":\"Mints ERC-721's that represent project ownership and transfers.\"},\"redeemTokensOf(address,uint256,uint256,address,uint256,address,string,bytes)\":{\"notice\":\"Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source.\"},\"setFee(uint256)\":{\"notice\":\"Allows the fee to be updated.\"},\"setFeeGauge(address)\":{\"notice\":\"Allows the fee gauge to be updated.\"},\"setFeelessAddress(address,bool)\":{\"notice\":\"Sets whether projects operating on this terminal can pay towards the specified address without incurring a fee.\"},\"splitsStore()\":{\"notice\":\"The contract that stores splits for each project.\"},\"store()\":{\"notice\":\"The contract that stores and manages the terminal's data.\"},\"supportsInterface(bytes4)\":{\"notice\":\"Indicates if this contract adheres to the specified interface.\"},\"token()\":{\"notice\":\"The token that this terminal accepts.\"},\"useAllowanceOf(uint256,uint256,uint256,address,uint256,address,string,bytes)\":{\"notice\":\"Allows a project to send funds from its overflow up to the preconfigured allowance.\"}},\"notice\":\"Manages all inflows and outflows of ETH funds into the protocol ecosystem.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/JBETHPaymentTerminal3_1_1.sol\":\"JBETHPaymentTerminal3_1_1\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n _;\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0x24e0364e503a9bbde94c715d26573a76f14cd2a202d45f96f52134ab806b67b9\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC721/IERC721.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../../utils/introspection/IERC165.sol\\\";\\n\\n/**\\n * @dev Required interface of an ERC721 compliant contract.\\n */\\ninterface IERC721 is IERC165 {\\n /**\\n * @dev Emitted when `tokenId` token is transferred from `from` to `to`.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);\\n\\n /**\\n * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.\\n */\\n event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);\\n\\n /**\\n * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.\\n */\\n event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\\n\\n /**\\n * @dev Returns the number of tokens in ``owner``'s account.\\n */\\n function balanceOf(address owner) external view returns (uint256 balance);\\n\\n /**\\n * @dev Returns the owner of the `tokenId` token.\\n *\\n * Requirements:\\n *\\n * - `tokenId` must exist.\\n */\\n function ownerOf(uint256 tokenId) external view returns (address owner);\\n\\n /**\\n * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\\n * are aware of the ERC721 protocol to prevent tokens from being forever locked.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `tokenId` token must exist and be owned by `from`.\\n * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.\\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\\n *\\n * Emits a {Transfer} event.\\n */\\n function safeTransferFrom(\\n address from,\\n address to,\\n uint256 tokenId\\n ) external;\\n\\n /**\\n * @dev Transfers `tokenId` token from `from` to `to`.\\n *\\n * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `tokenId` token must be owned by `from`.\\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 tokenId\\n ) external;\\n\\n /**\\n * @dev Gives permission to `to` to transfer `tokenId` token to another account.\\n * The approval is cleared when the token is transferred.\\n *\\n * Only a single account can be approved at a time, so approving the zero address clears previous approvals.\\n *\\n * Requirements:\\n *\\n * - The caller must own the token or be an approved operator.\\n * - `tokenId` must exist.\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address to, uint256 tokenId) external;\\n\\n /**\\n * @dev Returns the account approved for `tokenId` token.\\n *\\n * Requirements:\\n *\\n * - `tokenId` must exist.\\n */\\n function getApproved(uint256 tokenId) external view returns (address operator);\\n\\n /**\\n * @dev Approve or remove `operator` as an operator for the caller.\\n * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.\\n *\\n * Requirements:\\n *\\n * - The `operator` cannot be the caller.\\n *\\n * Emits an {ApprovalForAll} event.\\n */\\n function setApprovalForAll(address operator, bool _approved) external;\\n\\n /**\\n * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.\\n *\\n * See {setApprovalForAll}\\n */\\n function isApprovedForAll(address owner, address operator) external view returns (bool);\\n\\n /**\\n * @dev Safely transfers `tokenId` token from `from` to `to`.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `tokenId` token must exist and be owned by `from`.\\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\\n *\\n * Emits a {Transfer} event.\\n */\\n function safeTransferFrom(\\n address from,\\n address to,\\n uint256 tokenId,\\n bytes calldata data\\n ) external;\\n}\\n\",\"keccak256\":\"0x516a22876c1fab47f49b1bc22b4614491cd05338af8bd2e7b382da090a079990\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x3777e696b62134e6177440dbe6e6601c0c156a443f57167194b67e75527439de\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/ERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC165.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC165} interface.\\n *\\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\\n * for the additional interface id that will be supported. For example:\\n *\\n * ```solidity\\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\\n * }\\n * ```\\n *\\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\\n */\\nabstract contract ERC165 is IERC165 {\\n /**\\n * @dev See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n return interfaceId == type(IERC165).interfaceId;\\n }\\n}\\n\",\"keccak256\":\"0xd10975de010d89fd1c78dc5e8a9a7e7f496198085c151648f20cba166b32582b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/ERC165Checker.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165Checker.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC165.sol\\\";\\n\\n/**\\n * @dev Library used to query support of an interface declared via {IERC165}.\\n *\\n * Note that these functions return the actual result of the query: they do not\\n * `revert` if an interface is not supported. It is up to the caller to decide\\n * what to do in these cases.\\n */\\nlibrary ERC165Checker {\\n // As per the EIP-165 spec, no interface should ever match 0xffffffff\\n bytes4 private constant _INTERFACE_ID_INVALID = 0xffffffff;\\n\\n /**\\n * @dev Returns true if `account` supports the {IERC165} interface,\\n */\\n function supportsERC165(address account) internal view returns (bool) {\\n // Any contract that implements ERC165 must explicitly indicate support of\\n // InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid\\n return\\n _supportsERC165Interface(account, type(IERC165).interfaceId) &&\\n !_supportsERC165Interface(account, _INTERFACE_ID_INVALID);\\n }\\n\\n /**\\n * @dev Returns true if `account` supports the interface defined by\\n * `interfaceId`. Support for {IERC165} itself is queried automatically.\\n *\\n * See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) {\\n // query support of both ERC165 as per the spec and support of _interfaceId\\n return supportsERC165(account) && _supportsERC165Interface(account, interfaceId);\\n }\\n\\n /**\\n * @dev Returns a boolean array where each value corresponds to the\\n * interfaces passed in and whether they're supported or not. This allows\\n * you to batch check interfaces for a contract where your expectation\\n * is that some interfaces may not be supported.\\n *\\n * See {IERC165-supportsInterface}.\\n *\\n * _Available since v3.4._\\n */\\n function getSupportedInterfaces(address account, bytes4[] memory interfaceIds)\\n internal\\n view\\n returns (bool[] memory)\\n {\\n // an array of booleans corresponding to interfaceIds and whether they're supported or not\\n bool[] memory interfaceIdsSupported = new bool[](interfaceIds.length);\\n\\n // query support of ERC165 itself\\n if (supportsERC165(account)) {\\n // query support of each interface in interfaceIds\\n for (uint256 i = 0; i < interfaceIds.length; i++) {\\n interfaceIdsSupported[i] = _supportsERC165Interface(account, interfaceIds[i]);\\n }\\n }\\n\\n return interfaceIdsSupported;\\n }\\n\\n /**\\n * @dev Returns true if `account` supports all the interfaces defined in\\n * `interfaceIds`. Support for {IERC165} itself is queried automatically.\\n *\\n * Batch-querying can lead to gas savings by skipping repeated checks for\\n * {IERC165} support.\\n *\\n * See {IERC165-supportsInterface}.\\n */\\n function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) {\\n // query support of ERC165 itself\\n if (!supportsERC165(account)) {\\n return false;\\n }\\n\\n // query support of each interface in _interfaceIds\\n for (uint256 i = 0; i < interfaceIds.length; i++) {\\n if (!_supportsERC165Interface(account, interfaceIds[i])) {\\n return false;\\n }\\n }\\n\\n // all interfaces supported\\n return true;\\n }\\n\\n /**\\n * @notice Query if a contract implements an interface, does not check ERC165 support\\n * @param account The address of the contract to query for support of an interface\\n * @param interfaceId The interface identifier, as specified in ERC-165\\n * @return true if the contract at account indicates support of the interface with\\n * identifier interfaceId, false otherwise\\n * @dev Assumes that account contains a contract that supports ERC165, otherwise\\n * the behavior of this method is undefined. This precondition can be checked\\n * with {supportsERC165}.\\n * Interface identification is specified in ERC-165.\\n */\\n function _supportsERC165Interface(address account, bytes4 interfaceId) private view returns (bool) {\\n bytes memory encodedParams = abi.encodeWithSelector(IERC165.supportsInterface.selector, interfaceId);\\n (bool success, bytes memory result) = account.staticcall{gas: 30000}(encodedParams);\\n if (result.length < 32) return false;\\n return success && abi.decode(result, (bool));\\n }\\n}\\n\",\"keccak256\":\"0xf7291d7213336b00ee7edbf7cd5034778dd7b0bda2a7489e664f1e5cacc6c24e\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/IERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC165 standard, as defined in the\\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\\n *\\n * Implementers can declare support of contract interfaces, which can then be\\n * queried by others ({ERC165Checker}).\\n *\\n * For an implementation, see {ERC165}.\\n */\\ninterface IERC165 {\\n /**\\n * @dev Returns true if this contract implements the interface defined by\\n * `interfaceId`. See the corresponding\\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\\n * to learn more about how these ids are created.\\n *\\n * This function call must use less than 30 000 gas.\\n */\\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\\n}\\n\",\"keccak256\":\"0x447a5f3ddc18419d41ff92b3773fb86471b1db25773e07f877f548918a185bf1\",\"license\":\"MIT\"},\"@paulrberg/contracts/math/PRBMath.sol\":{\"content\":\"// SPDX-License-Identifier: Unlicense\\npragma solidity >=0.8.4;\\n\\nimport \\\"prb-math/contracts/PRBMath.sol\\\";\\n\",\"keccak256\":\"0x42821345981bc0434a90ba2268a2f5278dfe9e38166981d72fc7f3b776a29495\",\"license\":\"Unlicense\"},\"contracts/JBETHPaymentTerminal3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.16;\\n\\nimport {Address} from '@openzeppelin/contracts/utils/Address.sol';\\nimport {JBPayoutRedemptionPaymentTerminal3_1_1} from './abstract/JBPayoutRedemptionPaymentTerminal3_1_1.sol';\\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\\nimport {JBCurrencies} from './libraries/JBCurrencies.sol';\\nimport {JBSplitsGroups} from './libraries/JBSplitsGroups.sol';\\nimport {JBTokens} from './libraries/JBTokens.sol';\\n\\n/// @notice Manages all inflows and outflows of ETH funds into the protocol ecosystem.\\ncontract JBETHPaymentTerminal3_1_1 is JBPayoutRedemptionPaymentTerminal3_1_1 {\\n //*********************************************************************//\\n // -------------------------- internal views ------------------------- //\\n //*********************************************************************//\\n\\n /// @notice Checks the balance of tokens in this contract.\\n /// @return The contract's balance, as a fixed point number with the same amount of decimals as this terminal.\\n function _balance() internal view override returns (uint256) {\\n return address(this).balance;\\n }\\n\\n //*********************************************************************//\\n // -------------------------- constructor ---------------------------- //\\n //*********************************************************************//\\n\\n /// @param _baseWeightCurrency The currency to base token issuance on.\\n /// @param _operatorStore A contract storing operator assignments.\\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\\n /// @param _directory A contract storing directories of terminals and controllers for each project.\\n /// @param _splitsStore A contract that stores splits for each project.\\n /// @param _prices A contract that exposes price feeds.\\n /// @param _store A contract that stores the terminal's data.\\n /// @param _owner The address that will own this contract.\\n constructor(\\n uint256 _baseWeightCurrency,\\n IJBOperatorStore _operatorStore,\\n IJBProjects _projects,\\n IJBDirectory _directory,\\n IJBSplitsStore _splitsStore,\\n IJBPrices _prices,\\n address _store,\\n address _owner\\n )\\n JBPayoutRedemptionPaymentTerminal3_1_1(\\n JBTokens.ETH,\\n 18, // 18 decimals.\\n JBCurrencies.ETH,\\n _baseWeightCurrency,\\n JBSplitsGroups.ETH_PAYOUT,\\n _operatorStore,\\n _projects,\\n _directory,\\n _splitsStore,\\n _prices,\\n _store,\\n _owner\\n )\\n // solhint-disable-next-line no-empty-blocks\\n {\\n\\n }\\n\\n //*********************************************************************//\\n // ---------------------- internal transactions ---------------------- //\\n //*********************************************************************//\\n\\n /// @notice Transfers tokens.\\n /// @param _from The address from which the transfer should originate.\\n /// @param _to The address to which the transfer should go.\\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\\n function _transferFrom(address _from, address payable _to, uint256 _amount) internal override {\\n _from; // Prevents unused var compiler and natspec complaints.\\n\\n Address.sendValue(_to, _amount);\\n }\\n}\\n\",\"keccak256\":\"0x2df0a5c2a17371ce249dae553a919521d9f3037ae397efb68aac726702097060\",\"license\":\"MIT\"},\"contracts/abstract/JBOperatable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.16;\\n\\nimport {IJBOperatable} from './../interfaces/IJBOperatable.sol';\\nimport {IJBOperatorStore} from './../interfaces/IJBOperatorStore.sol';\\n\\n/// @notice Modifiers to allow access to functions based on the message sender's operator status.\\nabstract contract JBOperatable is IJBOperatable {\\n //*********************************************************************//\\n // --------------------------- custom errors -------------------------- //\\n //*********************************************************************//\\n error UNAUTHORIZED();\\n\\n //*********************************************************************//\\n // ---------------------------- modifiers ---------------------------- //\\n //*********************************************************************//\\n\\n /// @notice Only allows the speficied account or an operator of the account to proceed.\\n /// @param _account The account to check for.\\n /// @param _domain The domain namespace to look for an operator within.\\n /// @param _permissionIndex The index of the permission to check for.\\n modifier requirePermission(\\n address _account,\\n uint256 _domain,\\n uint256 _permissionIndex\\n ) {\\n _requirePermission(_account, _domain, _permissionIndex);\\n _;\\n }\\n\\n /// @notice Only allows the speficied account, an operator of the account to proceed, or a truthy override flag.\\n /// @param _account The account to check for.\\n /// @param _domain The domain namespace to look for an operator within.\\n /// @param _permissionIndex The index of the permission to check for.\\n /// @param _override A condition to force allowance for.\\n modifier requirePermissionAllowingOverride(\\n address _account,\\n uint256 _domain,\\n uint256 _permissionIndex,\\n bool _override\\n ) {\\n _requirePermissionAllowingOverride(_account, _domain, _permissionIndex, _override);\\n _;\\n }\\n\\n //*********************************************************************//\\n // ---------------- public immutable stored properties --------------- //\\n //*********************************************************************//\\n\\n /// @notice A contract storing operator assignments.\\n IJBOperatorStore public immutable override operatorStore;\\n\\n //*********************************************************************//\\n // -------------------------- constructor ---------------------------- //\\n //*********************************************************************//\\n\\n /// @param _operatorStore A contract storing operator assignments.\\n constructor(IJBOperatorStore _operatorStore) {\\n operatorStore = _operatorStore;\\n }\\n\\n //*********************************************************************//\\n // -------------------------- internal views ------------------------- //\\n //*********************************************************************//\\n\\n /// @notice Require the message sender is either the account or has the specified permission.\\n /// @param _account The account to allow.\\n /// @param _domain The domain namespace within which the permission index will be checked.\\n /// @param _permissionIndex The permission index that an operator must have within the specified domain to be allowed.\\n function _requirePermission(\\n address _account,\\n uint256 _domain,\\n uint256 _permissionIndex\\n ) internal view {\\n if (\\n msg.sender != _account &&\\n !operatorStore.hasPermission(msg.sender, _account, _domain, _permissionIndex) &&\\n !operatorStore.hasPermission(msg.sender, _account, 0, _permissionIndex)\\n ) revert UNAUTHORIZED();\\n }\\n\\n /// @notice Require the message sender is either the account, has the specified permission, or the override condition is true.\\n /// @param _account The account to allow.\\n /// @param _domain The domain namespace within which the permission index will be checked.\\n /// @param _domain The permission index that an operator must have within the specified domain to be allowed.\\n /// @param _override The override condition to allow.\\n function _requirePermissionAllowingOverride(\\n address _account,\\n uint256 _domain,\\n uint256 _permissionIndex,\\n bool _override\\n ) internal view {\\n if (\\n !_override &&\\n msg.sender != _account &&\\n !operatorStore.hasPermission(msg.sender, _account, _domain, _permissionIndex) &&\\n !operatorStore.hasPermission(msg.sender, _account, 0, _permissionIndex)\\n ) revert UNAUTHORIZED();\\n }\\n}\\n\",\"keccak256\":\"0xed3071b63f3ac427ffcd357a53be2675d405e94e40a7b1bc0475054005807e91\",\"license\":\"MIT\"},\"contracts/abstract/JBPayoutRedemptionPaymentTerminal3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.16;\\n\\nimport {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\\nimport {ERC165Checker} from '@openzeppelin/contracts/utils/introspection/ERC165Checker.sol';\\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\\nimport {JBFeeType} from './../enums/JBFeeType.sol';\\nimport {IJBAllowanceTerminal3_1} from './../interfaces/IJBAllowanceTerminal3_1.sol';\\nimport {IJBController} from './../interfaces/IJBController.sol';\\nimport {IJBDirectory} from './../interfaces/IJBDirectory.sol';\\nimport {IJBPayoutRedemptionPaymentTerminal3_1} from './../interfaces/IJBPayoutRedemptionPaymentTerminal3_1.sol';\\nimport {IJBPayoutRedemptionPaymentTerminal3_1_1} from './../interfaces/IJBPayoutRedemptionPaymentTerminal3_1_1.sol';\\nimport {IJBSplitsStore} from './../interfaces/IJBSplitsStore.sol';\\nimport {IJBFeeGauge3_1} from './../interfaces/IJBFeeGauge3_1.sol';\\nimport {IJBOperatable} from './../interfaces/IJBOperatable.sol';\\nimport {IJBOperatorStore} from './../interfaces/IJBOperatorStore.sol';\\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\\nimport {IJBPayoutTerminal3_1} from './../interfaces/IJBPayoutTerminal3_1.sol';\\nimport {IJBPrices} from './../interfaces/IJBPrices.sol';\\nimport {IJBProjects} from './../interfaces/IJBProjects.sol';\\nimport {IJBRedemptionTerminal} from './../interfaces/IJBRedemptionTerminal.sol';\\nimport {IJBSingleTokenPaymentTerminalStore3_1_1} from './../interfaces/IJBSingleTokenPaymentTerminalStore3_1_1.sol';\\nimport {IJBSplitAllocator} from './../interfaces/IJBSplitAllocator.sol';\\nimport {JBConstants} from './../libraries/JBConstants.sol';\\nimport {JBCurrencies} from './../libraries/JBCurrencies.sol';\\nimport {JBFixedPointNumber} from './../libraries/JBFixedPointNumber.sol';\\nimport {JBFundingCycleMetadataResolver} from './../libraries/JBFundingCycleMetadataResolver.sol';\\nimport {JBOperations} from './../libraries/JBOperations.sol';\\nimport {JBTokens} from './../libraries/JBTokens.sol';\\nimport {JBDidRedeemData3_1_1} from './../structs/JBDidRedeemData3_1_1.sol';\\nimport {JBDidPayData3_1_1} from './../structs/JBDidPayData3_1_1.sol';\\nimport {JBFee} from './../structs/JBFee.sol';\\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\\nimport {JBPayDelegateAllocation3_1_1} from './../structs/JBPayDelegateAllocation3_1_1.sol';\\nimport {JBRedemptionDelegateAllocation3_1_1} from './../structs/JBRedemptionDelegateAllocation3_1_1.sol';\\nimport {JBSplit} from './../structs/JBSplit.sol';\\nimport {JBSplitAllocationData} from './../structs/JBSplitAllocationData.sol';\\nimport {JBTokenAmount} from './../structs/JBTokenAmount.sol';\\nimport {JBOperatable} from './JBOperatable.sol';\\nimport {JBSingleTokenPaymentTerminal} from './JBSingleTokenPaymentTerminal.sol';\\n\\n/// @notice Generic terminal managing all inflows and outflows of funds into the protocol ecosystem.\\nabstract contract JBPayoutRedemptionPaymentTerminal3_1_1 is\\n JBSingleTokenPaymentTerminal,\\n JBOperatable,\\n Ownable,\\n IJBPayoutRedemptionPaymentTerminal3_1,\\n IJBPayoutRedemptionPaymentTerminal3_1_1\\n{\\n // A library that parses the packed funding cycle metadata into a friendlier format.\\n using JBFundingCycleMetadataResolver for JBFundingCycle;\\n\\n //*********************************************************************//\\n // --------------------------- custom errors ------------------------- //\\n //*********************************************************************//\\n error FEE_TOO_HIGH();\\n error INADEQUATE_DISTRIBUTION_AMOUNT();\\n error INADEQUATE_RECLAIM_AMOUNT();\\n error INADEQUATE_TOKEN_COUNT();\\n error NO_MSG_VALUE_ALLOWED();\\n error PAY_TO_ZERO_ADDRESS();\\n error PROJECT_TERMINAL_MISMATCH();\\n error REDEEM_TO_ZERO_ADDRESS();\\n error TERMINAL_TOKENS_INCOMPATIBLE();\\n\\n //*********************************************************************//\\n // --------------------- internal stored constants ------------------- //\\n //*********************************************************************//\\n\\n /// @notice Maximum fee that can be set for a funding cycle configuration.\\n /// @dev Out of MAX_FEE (50_000_000 / 1_000_000_000).\\n uint256 internal constant _FEE_CAP = 50_000_000;\\n\\n /// @notice The fee beneficiary project ID is 1, as it should be the first project launched during the deployment process.\\n uint256 internal constant _FEE_BENEFICIARY_PROJECT_ID = 1;\\n\\n //*********************************************************************//\\n // --------------------- internal stored properties ------------------ //\\n //*********************************************************************//\\n\\n /// @notice Fees that are being held to be processed later.\\n /// @custom:param _projectId The ID of the project for which fees are being held.\\n mapping(uint256 => JBFee[]) internal _heldFeesOf;\\n\\n //*********************************************************************//\\n // ---------------- public immutable stored properties --------------- //\\n //*********************************************************************//\\n\\n /// @notice Mints ERC-721's that represent project ownership and transfers.\\n IJBProjects public immutable override projects;\\n\\n /// @notice The directory of terminals and controllers for projects.\\n IJBDirectory public immutable override directory;\\n\\n /// @notice The contract that stores splits for each project.\\n IJBSplitsStore public immutable override splitsStore;\\n\\n /// @notice The contract that exposes price feeds.\\n IJBPrices public immutable override prices;\\n\\n /// @notice The contract that stores and manages the terminal's data.\\n address public immutable override store;\\n\\n /// @notice The currency to base token issuance on.\\n /// @dev If this differs from `currency`, there must be a price feed available to convert `currency` to `baseWeightCurrency`.\\n uint256 public immutable override baseWeightCurrency;\\n\\n /// @notice The group that payout splits coming from this terminal are identified by.\\n uint256 public immutable override payoutSplitsGroup;\\n\\n //*********************************************************************//\\n // --------------------- public stored properties -------------------- //\\n //*********************************************************************//\\n\\n /// @notice The platform fee percent.\\n /// @dev Out of MAX_FEE (25_000_000 / 1_000_000_000)\\n uint256 public override fee = 25_000_000; // 2.5%\\n\\n /// @notice The data source that returns a discount to apply to a project's fee.\\n address public override feeGauge;\\n\\n /// @notice Addresses that can be paid towards from this terminal without incurring a fee.\\n /// @dev Only addresses that are considered to be contained within the ecosystem can be feeless. Funds sent outside the ecosystem may incur fees despite being stored as feeless.\\n /// @custom:param _address The address that can be paid toward.\\n mapping(address => bool) public override isFeelessAddress;\\n\\n //*********************************************************************//\\n // ------------------------- external views -------------------------- //\\n //*********************************************************************//\\n\\n /// @notice Gets the current overflowed amount in this terminal for a specified project, in terms of ETH.\\n /// @dev The current overflow is represented as a fixed point number with 18 decimals.\\n /// @param _projectId The ID of the project to get overflow for.\\n /// @return The current amount of ETH overflow that project has in this terminal, as a fixed point number with 18 decimals.\\n function currentEthOverflowOf(\\n uint256 _projectId\\n ) external view virtual override returns (uint256) {\\n // Get this terminal's current overflow.\\n uint256 _overflow = IJBSingleTokenPaymentTerminalStore3_1_1(store).currentOverflowOf(\\n this,\\n _projectId\\n );\\n\\n // Adjust the decimals of the fixed point number if needed to have 18 decimals.\\n uint256 _adjustedOverflow = (decimals == 18)\\n ? _overflow\\n : JBFixedPointNumber.adjustDecimals(_overflow, decimals, 18);\\n\\n // Return the amount converted to ETH.\\n return\\n (currency == JBCurrencies.ETH)\\n ? _adjustedOverflow\\n : PRBMath.mulDiv(\\n _adjustedOverflow,\\n 10 ** decimals,\\n prices.priceFor(currency, JBCurrencies.ETH, decimals)\\n );\\n }\\n\\n /// @notice The fees that are currently being held to be processed later for each project.\\n /// @param _projectId The ID of the project for which fees are being held.\\n /// @return An array of fees that are being held.\\n function heldFeesOf(uint256 _projectId) external view override returns (JBFee[] memory) {\\n return _heldFeesOf[_projectId];\\n }\\n\\n //*********************************************************************//\\n // -------------------------- public views --------------------------- //\\n //*********************************************************************//\\n\\n /// @notice Indicates if this contract adheres to the specified interface.\\n /// @dev See {IERC165-supportsInterface}.\\n /// @param _interfaceId The ID of the interface to check for adherance to.\\n /// @return A flag indicating if the provided interface ID is supported.\\n function supportsInterface(\\n bytes4 _interfaceId\\n ) public view virtual override(JBSingleTokenPaymentTerminal, IERC165) returns (bool) {\\n return\\n _interfaceId == type(IJBPayoutRedemptionPaymentTerminal3_1_1).interfaceId ||\\n _interfaceId == type(IJBPayoutRedemptionPaymentTerminal3_1).interfaceId ||\\n _interfaceId == type(IJBPayoutTerminal3_1).interfaceId ||\\n _interfaceId == type(IJBAllowanceTerminal3_1).interfaceId ||\\n _interfaceId == type(IJBRedemptionTerminal).interfaceId ||\\n _interfaceId == type(IJBOperatable).interfaceId ||\\n super.supportsInterface(_interfaceId);\\n }\\n\\n //*********************************************************************//\\n // -------------------------- internal views ------------------------- //\\n //*********************************************************************//\\n\\n /// @notice Checks the balance of tokens in this contract.\\n /// @return The contract's balance.\\n function _balance() internal view virtual returns (uint256);\\n\\n //*********************************************************************//\\n // -------------------------- constructor ---------------------------- //\\n //*********************************************************************//\\n\\n /// @param _token The token that this terminal manages.\\n /// @param _decimals The number of decimals the token fixed point amounts are expected to have.\\n /// @param _currency The currency that this terminal's token adheres to for price feeds.\\n /// @param _baseWeightCurrency The currency to base token issuance on.\\n /// @param _payoutSplitsGroup The group that denotes payout splits from this terminal in the splits store.\\n /// @param _operatorStore A contract storing operator assignments.\\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\\n /// @param _directory A contract storing directories of terminals and controllers for each project.\\n /// @param _splitsStore A contract that stores splits for each project.\\n /// @param _prices A contract that exposes price feeds.\\n /// @param _store A contract that stores the terminal's data.\\n /// @param _owner The address that will own this contract.\\n constructor(\\n // payable constructor save the gas used to check msg.value==0\\n address _token,\\n uint256 _decimals,\\n uint256 _currency,\\n uint256 _baseWeightCurrency,\\n uint256 _payoutSplitsGroup,\\n IJBOperatorStore _operatorStore,\\n IJBProjects _projects,\\n IJBDirectory _directory,\\n IJBSplitsStore _splitsStore,\\n IJBPrices _prices,\\n address _store,\\n address _owner\\n )\\n payable\\n JBSingleTokenPaymentTerminal(_token, _decimals, _currency)\\n JBOperatable(_operatorStore)\\n {\\n baseWeightCurrency = _baseWeightCurrency;\\n payoutSplitsGroup = _payoutSplitsGroup;\\n projects = _projects;\\n directory = _directory;\\n splitsStore = _splitsStore;\\n prices = _prices;\\n store = _store;\\n\\n transferOwnership(_owner);\\n }\\n\\n //*********************************************************************//\\n // ---------------------- external transactions ---------------------- //\\n //*********************************************************************//\\n\\n /// @notice Contribute tokens to a project.\\n /// @param _projectId The ID of the project being paid.\\n /// @param _amount The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place.\\n /// @param _token The token being paid. This terminal ignores this property since it only manages one token.\\n /// @param _beneficiary The address to mint tokens for and pass along to the funding cycle's data source and delegate.\\n /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal.\\n /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\\n /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\\n /// @return The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals.\\n function pay(\\n uint256 _projectId,\\n uint256 _amount,\\n address _token,\\n address _beneficiary,\\n uint256 _minReturnedTokens,\\n bool _preferClaimedTokens,\\n string calldata _memo,\\n bytes calldata _metadata\\n ) external payable virtual override returns (uint256) {\\n _token; // Prevents unused var compiler and natspec complaints.\\n\\n // valid terminal check\\n _isTerminalOf(_projectId);\\n\\n // ETH shouldn't be sent if this terminal's token isn't ETH.\\n if (token != JBTokens.ETH) {\\n if (msg.value != 0) revert NO_MSG_VALUE_ALLOWED();\\n\\n // Get a reference to the balance before receiving tokens.\\n uint256 _balanceBefore = _balance();\\n\\n // Transfer tokens to this terminal from the msg sender.\\n _transferFrom(msg.sender, payable(address(this)), _amount);\\n\\n // The amount should reflect the change in balance.\\n _amount = _balance() - _balanceBefore;\\n }\\n // If this terminal's token is ETH, override _amount with msg.value.\\n else _amount = msg.value;\\n\\n return\\n _pay(\\n _amount,\\n msg.sender,\\n _projectId,\\n _beneficiary,\\n _minReturnedTokens,\\n _preferClaimedTokens,\\n _memo,\\n _metadata\\n );\\n }\\n\\n /// @notice Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source.\\n /// @dev Only a token holder or a designated operator can redeem its tokens.\\n /// @param _holder The account to redeem tokens for.\\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\\n /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals.\\n /// @param _token The token being reclaimed. This terminal ignores this property since it only manages one token.\\n /// @param _minReturnedTokens The minimum amount of terminal tokens expected in return, as a fixed point number with the same amount of decimals as the terminal.\\n /// @param _beneficiary The address to send the terminal tokens to.\\n /// @param _memo A memo to pass along to the emitted event.\\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\\n /// @return reclaimAmount The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals.\\n function redeemTokensOf(\\n address _holder,\\n uint256 _projectId,\\n uint256 _tokenCount,\\n address _token,\\n uint256 _minReturnedTokens,\\n address payable _beneficiary,\\n string memory _memo,\\n bytes memory _metadata\\n )\\n external\\n virtual\\n override\\n requirePermission(_holder, _projectId, JBOperations.REDEEM)\\n returns (uint256 reclaimAmount)\\n {\\n _token; // Prevents unused var compiler and natspec complaints.\\n\\n return\\n _redeemTokensOf(\\n _holder,\\n _projectId,\\n _tokenCount,\\n _minReturnedTokens,\\n _beneficiary,\\n _memo,\\n _metadata\\n );\\n }\\n\\n /// @notice Distributes payouts for a project with the distribution limit of its current funding cycle.\\n /// @dev Payouts are sent to the preprogrammed splits. Any leftover is sent to the project's owner.\\n /// @dev 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.\\n /// @dev All funds distributed outside of this contract or any feeless terminals incure the protocol fee.\\n /// @param _projectId The ID of the project having its payouts distributed.\\n /// @param _amount The amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal.\\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency.\\n /// @param _token The token being distributed. This terminal ignores this property since it only manages one token.\\n /// @param _minReturnedTokens 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.\\n /// @param _metadata Bytes to send along to the emitted event, if provided.\\n /// @return netLeftoverDistributionAmount The amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal.\\n function distributePayoutsOf(\\n uint256 _projectId,\\n uint256 _amount,\\n uint256 _currency,\\n address _token,\\n uint256 _minReturnedTokens,\\n bytes calldata _metadata\\n ) external virtual override returns (uint256 netLeftoverDistributionAmount) {\\n _token; // Prevents unused var compiler and natspec complaints.\\n\\n return _distributePayoutsOf(_projectId, _amount, _currency, _minReturnedTokens, _metadata);\\n }\\n\\n /// @notice Allows a project to send funds from its overflow up to the preconfigured allowance.\\n /// @dev Only a project's owner or a designated operator can use its allowance.\\n /// @dev Incurs the protocol fee.\\n /// @param _projectId The ID of the project to use the allowance of.\\n /// @param _amount The amount of terminal tokens to use from this project's current allowance, as a fixed point number with the same amount of decimals as this terminal.\\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's overflow allowance currency.\\n /// @param _token The token being distributed. This terminal ignores this property since it only manages one token.\\n /// @param _minReturnedTokens The minimum number of tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with 18 decimals.\\n /// @param _beneficiary The address to send the funds to.\\n /// @param _memo A memo to pass along to the emitted event.\\n /// @param _metadata Bytes to send along to the emitted event, if provided.\\n /// @return netDistributedAmount The amount of tokens that was distributed to the beneficiary, as a fixed point number with the same amount of decimals as the terminal.\\n function useAllowanceOf(\\n uint256 _projectId,\\n uint256 _amount,\\n uint256 _currency,\\n address _token,\\n uint256 _minReturnedTokens,\\n address payable _beneficiary,\\n string memory _memo,\\n bytes calldata _metadata\\n )\\n external\\n virtual\\n override\\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.USE_ALLOWANCE)\\n returns (uint256 netDistributedAmount)\\n {\\n _token; // Prevents unused var compiler and natspec complaints.\\n\\n return\\n _useAllowanceOf(\\n _projectId,\\n _amount,\\n _currency,\\n _minReturnedTokens,\\n _beneficiary,\\n _memo,\\n _metadata\\n );\\n }\\n\\n /// @notice Allows a project owner to migrate its funds and operations to a new terminal that accepts the same token type.\\n /// @dev Only a project's owner or a designated operator can migrate it.\\n /// @param _projectId The ID of the project being migrated.\\n /// @param _to The terminal contract that will gain the project's funds.\\n /// @return balance The amount of funds that were migrated, as a fixed point number with the same amount of decimals as this terminal.\\n function migrate(\\n uint256 _projectId,\\n IJBPaymentTerminal _to\\n )\\n external\\n virtual\\n override\\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.MIGRATE_TERMINAL)\\n returns (uint256 balance)\\n {\\n // The terminal being migrated to must accept the same token as this terminal.\\n if (!_to.acceptsToken(token, _projectId)) revert TERMINAL_TOKENS_INCOMPATIBLE();\\n\\n // Record the migration in the store.\\n balance = IJBSingleTokenPaymentTerminalStore3_1_1(store).recordMigration(_projectId);\\n\\n // Transfer the balance if needed.\\n if (balance != 0) {\\n // Trigger any inherited pre-transfer logic.\\n _beforeTransferTo(address(_to), balance);\\n\\n // If this terminal's token is ETH, send it in msg.value.\\n uint256 _payableValue = token == JBTokens.ETH ? balance : 0;\\n\\n // Withdraw the balance to transfer to the new terminal;\\n _to.addToBalanceOf{value: _payableValue}(_projectId, balance, token, '', bytes(''));\\n }\\n\\n emit Migrate(_projectId, _to, balance, msg.sender);\\n }\\n\\n /// @notice Receives funds belonging to the specified project.\\n /// @param _projectId The ID of the project to which the funds received belong.\\n /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\\n /// @param _token The token being paid. This terminal ignores this property since it only manages one currency.\\n /// @param _memo A memo to pass along to the emitted event.\\n /// @param _metadata Extra data to pass along to the emitted event.\\n function addToBalanceOf(\\n uint256 _projectId,\\n uint256 _amount,\\n address _token,\\n string calldata _memo,\\n bytes calldata _metadata\\n ) external payable virtual override {\\n // valid terminal check\\n _isTerminalOf(_projectId);\\n\\n // Do not refund held fees by default.\\n addToBalanceOf(_projectId, _amount, _token, false, _memo, _metadata);\\n }\\n\\n /// @notice Process any fees that are being held for the project.\\n /// @dev Only a project owner, an operator, or the contract's owner can process held fees.\\n /// @param _projectId The ID of the project whos held fees should be processed.\\n function processFees(\\n uint256 _projectId\\n )\\n external\\n virtual\\n override\\n requirePermissionAllowingOverride(\\n projects.ownerOf(_projectId),\\n _projectId,\\n JBOperations.PROCESS_FEES,\\n msg.sender == owner()\\n )\\n {\\n // Get a reference to the project's held fees.\\n JBFee[] memory _heldFees = _heldFeesOf[_projectId];\\n\\n // Delete the held fees.\\n delete _heldFeesOf[_projectId];\\n\\n // Push array length in stack\\n uint256 _heldFeeLength = _heldFees.length;\\n\\n // Keep a reference to the amount.\\n uint256 _amount;\\n\\n // Process each fee.\\n for (uint256 _i; _i < _heldFeeLength; ) {\\n // Get the fee amount.\\n _amount = (\\n _heldFees[_i].fee == 0 || _heldFees[_i].feeDiscount == JBConstants.MAX_FEE_DISCOUNT\\n ? 0\\n : _feeAmount(_heldFees[_i].amount, _heldFees[_i].fee, _heldFees[_i].feeDiscount)\\n );\\n\\n // Process the fee.\\n _processFee(_amount, _heldFees[_i].beneficiary, _projectId);\\n\\n emit ProcessFee(_projectId, _amount, true, _heldFees[_i].beneficiary, msg.sender);\\n\\n unchecked {\\n ++_i;\\n }\\n }\\n }\\n\\n /// @notice Allows the fee to be updated.\\n /// @dev Only the owner of this contract can change the fee.\\n /// @param _fee The new fee, out of MAX_FEE.\\n function setFee(uint256 _fee) external virtual override onlyOwner {\\n // The provided fee must be within the max.\\n if (_fee > _FEE_CAP) revert FEE_TOO_HIGH();\\n\\n // Store the new fee.\\n fee = _fee;\\n\\n emit SetFee(_fee, msg.sender);\\n }\\n\\n /// @notice Allows the fee gauge to be updated.\\n /// @dev Only the owner of this contract can change the fee gauge.\\n /// @param _feeGauge The new fee gauge.\\n function setFeeGauge(address _feeGauge) external virtual override onlyOwner {\\n // Store the new fee gauge.\\n feeGauge = _feeGauge;\\n\\n emit SetFeeGauge(_feeGauge, msg.sender);\\n }\\n\\n /// @notice Sets whether projects operating on this terminal can pay towards the specified address without incurring a fee.\\n /// @dev Only the owner of this contract can set addresses as feeless.\\n /// @param _address The address that can be paid towards while still bypassing fees.\\n /// @param _flag A flag indicating whether the terminal should be feeless or not.\\n function setFeelessAddress(address _address, bool _flag) external virtual override onlyOwner {\\n // Set the flag value.\\n isFeelessAddress[_address] = _flag;\\n\\n emit SetFeelessAddress(_address, _flag, msg.sender);\\n }\\n\\n //*********************************************************************//\\n // ----------------------- public transactions ----------------------- //\\n //*********************************************************************//\\n\\n /// @notice Receives funds belonging to the specified project.\\n /// @param _projectId The ID of the project to which the funds received belong.\\n /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\\n /// @param _token The token being paid. This terminal ignores this property since it only manages one currency.\\n /// @param _shouldRefundHeldFees A flag indicating if held fees should be refunded based on the amount being added.\\n /// @param _memo A memo to pass along to the emitted event.\\n /// @param _metadata Extra data to pass along to the emitted event.\\n function addToBalanceOf(\\n uint256 _projectId,\\n uint256 _amount,\\n address _token,\\n bool _shouldRefundHeldFees,\\n string calldata _memo,\\n bytes calldata _metadata\\n ) public payable virtual override {\\n // valid terminal check\\n _isTerminalOf(_projectId);\\n\\n _token; // Prevents unused var compiler and natspec complaints.\\n\\n // If this terminal's token isn't ETH, make sure no msg.value was sent, then transfer the tokens in from msg.sender.\\n if (token != JBTokens.ETH) {\\n // Amount must be greater than 0.\\n if (msg.value != 0) revert NO_MSG_VALUE_ALLOWED();\\n\\n // Get a reference to the balance before receiving tokens.\\n uint256 _balanceBefore = _balance();\\n\\n // Transfer tokens to this terminal from the msg sender.\\n _transferFrom(msg.sender, payable(address(this)), _amount);\\n\\n // The amount should reflect the change in balance.\\n _amount = _balance() - _balanceBefore;\\n }\\n // If the terminal's token is ETH, override `_amount` with msg.value.\\n else _amount = msg.value;\\n\\n // Add to balance.\\n _addToBalanceOf(_projectId, _amount, _shouldRefundHeldFees, _memo, _metadata);\\n }\\n\\n //*********************************************************************//\\n // ---------------------- internal transactions ---------------------- //\\n //*********************************************************************//\\n\\n /// @notice Transfers tokens.\\n /// @param _from The address from which the transfer should originate.\\n /// @param _to The address to which the transfer should go.\\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\\n function _transferFrom(address _from, address payable _to, uint256 _amount) internal virtual {\\n _from; // Prevents unused var compiler and natspec complaints.\\n _to; // Prevents unused var compiler and natspec complaints.\\n _amount; // Prevents unused var compiler and natspec complaints.\\n }\\n\\n /// @notice Logic to be triggered before transferring tokens from this terminal.\\n /// @param _to The address to which the transfer is going.\\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\\n function _beforeTransferTo(address _to, uint256 _amount) internal virtual {\\n _to; // Prevents unused var compiler and natspec complaints.\\n _amount; // Prevents unused var compiler and natspec complaints.\\n }\\n\\n /// @notice Logic to be triggered if a transfer should be undone\\n /// @param _to The address to which the transfer went.\\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\\n function _cancelTransferTo(address _to, uint256 _amount) internal virtual {\\n _to; // Prevents unused var compiler and natspec complaints.\\n _amount; // Prevents unused var compiler and natspec complaints.\\n }\\n\\n /// @notice Verifies this terminal is a terminal of provided project ID.\\n /// @param _projectId The ID of the project to check if this contract is a terminal of.\\n function _isTerminalOf(uint256 _projectId) internal view {\\n if (!directory.isTerminalOf(_projectId, this)) revert PROJECT_TERMINAL_MISMATCH();\\n }\\n\\n /// @notice Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source.\\n /// @dev Only a token holder or a designated operator can redeem its tokens.\\n /// @param _holder The account to redeem tokens for.\\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\\n /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals.\\n /// @param _minReturnedTokens The minimum amount of terminal tokens expected in return, as a fixed point number with the same amount of decimals as the terminal.\\n /// @param _beneficiary The address to send the terminal tokens to.\\n /// @param _memo A memo to pass along to the emitted event.\\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\\n /// @return reclaimAmount The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals.\\n function _redeemTokensOf(\\n address _holder,\\n uint256 _projectId,\\n uint256 _tokenCount,\\n uint256 _minReturnedTokens,\\n address payable _beneficiary,\\n string memory _memo,\\n bytes memory _metadata\\n ) internal returns (uint256 reclaimAmount) {\\n // Can't send reclaimed funds to the zero address.\\n if (_beneficiary == address(0)) revert REDEEM_TO_ZERO_ADDRESS();\\n\\n // Define variables that will be needed outside the scoped section below.\\n // Keep a reference to the funding cycle during which the redemption is being made.\\n JBFundingCycle memory _fundingCycle;\\n\\n // Scoped section prevents stack too deep. `_feeEligibleDistributionAmount`, `_feeDiscount` and `_feePercent` only used within scope.\\n {\\n // Keep a reference to the amount being reclaimed that should have fees withheld from.\\n uint256 _feeEligibleDistributionAmount;\\n\\n // Keep a reference to the amount of discount to apply to the fee.\\n uint256 _feeDiscount;\\n\\n // Keep a reference to the fee.\\n uint256 _feePercent = fee;\\n\\n // Scoped section prevents stack too deep. `_delegateAllocations` only used within scope.\\n {\\n JBRedemptionDelegateAllocation3_1_1[] memory _delegateAllocations;\\n\\n // Record the redemption.\\n (\\n _fundingCycle,\\n reclaimAmount,\\n _delegateAllocations,\\n _memo\\n ) = IJBSingleTokenPaymentTerminalStore3_1_1(store).recordRedemptionFor(\\n _holder,\\n _projectId,\\n _tokenCount,\\n _memo,\\n _metadata\\n );\\n\\n // Set the reference to the fee discount to apply. No fee if the beneficiary is feeless or if the redemption rate is at its max.\\n _feeDiscount = isFeelessAddress[_beneficiary] ||\\n (_fundingCycle.redemptionRate() == JBConstants.MAX_REDEMPTION_RATE &&\\n _fundingCycle.ballotRedemptionRate() == JBConstants.MAX_REDEMPTION_RATE) ||\\n _feePercent == 0\\n ? JBConstants.MAX_FEE_DISCOUNT\\n : _currentFeeDiscount(_projectId, JBFeeType.REDEMPTION);\\n\\n // The amount being reclaimed must be at least as much as was expected.\\n if (reclaimAmount < _minReturnedTokens) revert INADEQUATE_RECLAIM_AMOUNT();\\n\\n // Burn the project tokens.\\n if (_tokenCount != 0)\\n IJBController(directory.controllerOf(_projectId)).burnTokensOf(\\n _holder,\\n _projectId,\\n _tokenCount,\\n '',\\n false\\n );\\n\\n // If delegate allocations were specified by the data source, fulfill them.\\n if (_delegateAllocations.length != 0) {\\n JBDidRedeemData3_1_1 memory _data = JBDidRedeemData3_1_1(\\n _holder,\\n _projectId,\\n _fundingCycle.configuration,\\n _tokenCount,\\n JBTokenAmount(token, reclaimAmount, decimals, currency),\\n JBTokenAmount(token, 0, decimals, currency),\\n _beneficiary,\\n _memo,\\n bytes(''),\\n _metadata\\n );\\n\\n // Keep a reference to the allocation.\\n JBRedemptionDelegateAllocation3_1_1 memory _delegateAllocation;\\n\\n // Keep a reference to the fee.\\n uint256 _delegatedAmountFee;\\n\\n // Keep a reference to the number of allocations.\\n uint256 _numDelegates = _delegateAllocations.length;\\n\\n for (uint256 _i; _i < _numDelegates; ) {\\n // Get a reference to the delegate being iterated on.\\n _delegateAllocation = _delegateAllocations[_i];\\n\\n // Get the fee for the delegated amount.\\n _delegatedAmountFee = _feePercent == 0\\n ? 0\\n : _feeAmount(_delegateAllocation.amount, _feePercent, _feeDiscount);\\n\\n // Add the delegated amount to the amount eligible for having a fee taken.\\n if (_delegatedAmountFee != 0) {\\n _feeEligibleDistributionAmount += _delegateAllocation.amount;\\n _delegateAllocation.amount -= _delegatedAmountFee;\\n }\\n\\n // Trigger any inherited pre-transfer logic.\\n _beforeTransferTo(address(_delegateAllocation.delegate), _delegateAllocation.amount);\\n\\n // Pass the correct token forwardedAmount to the delegate\\n _data.forwardedAmount.value = _delegateAllocation.amount;\\n\\n // Pass the correct metadata from the data source.\\n _data.dataSourceMetadata = _delegateAllocation.metadata;\\n\\n _delegateAllocation.delegate.didRedeem{\\n value: token == JBTokens.ETH ? _delegateAllocation.amount : 0\\n }(_data);\\n\\n emit DelegateDidRedeem(\\n _delegateAllocation.delegate,\\n _data,\\n _delegateAllocation.amount,\\n _delegatedAmountFee,\\n msg.sender\\n );\\n\\n unchecked {\\n ++_i;\\n }\\n }\\n }\\n }\\n\\n // Send the reclaimed funds to the beneficiary.\\n if (reclaimAmount != 0) {\\n // Get the fee for the reclaimed amount.\\n uint256 _reclaimAmountFee = _feeDiscount == JBConstants.MAX_FEE_DISCOUNT\\n ? 0\\n : _feeAmount(reclaimAmount, _feePercent, _feeDiscount);\\n\\n if (_reclaimAmountFee != 0) {\\n _feeEligibleDistributionAmount += reclaimAmount;\\n reclaimAmount -= _reclaimAmountFee;\\n }\\n\\n // Subtract the fee from the reclaim amount.\\n if (reclaimAmount != 0) _transferFrom(address(this), _beneficiary, reclaimAmount);\\n }\\n\\n // Take the fee from all outbound reclaimations.\\n _feeEligibleDistributionAmount != 0\\n ? _takeFeeFrom(\\n _projectId,\\n false,\\n _feeEligibleDistributionAmount,\\n _feePercent,\\n _beneficiary,\\n _feeDiscount\\n )\\n : 0;\\n }\\n\\n emit RedeemTokens(\\n _fundingCycle.configuration,\\n _fundingCycle.number,\\n _projectId,\\n _holder,\\n _beneficiary,\\n _tokenCount,\\n reclaimAmount,\\n _memo,\\n _metadata,\\n msg.sender\\n );\\n }\\n\\n /// @notice Distributes payouts for a project with the distribution limit of its current funding cycle.\\n /// @dev Payouts are sent to the preprogrammed splits. Any leftover is sent to the project's owner.\\n /// @dev 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.\\n /// @dev All funds distributed outside of this contract or any feeless terminals incure the protocol fee.\\n /// @param _projectId The ID of the project having its payouts distributed.\\n /// @param _amount The amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal.\\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency.\\n /// @param _minReturnedTokens 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.\\n /// @param _metadata Bytes to send along to the emitted event, if provided.\\n /// @return netLeftoverDistributionAmount The amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal.\\n function _distributePayoutsOf(\\n uint256 _projectId,\\n uint256 _amount,\\n uint256 _currency,\\n uint256 _minReturnedTokens,\\n bytes calldata _metadata\\n ) internal returns (uint256 netLeftoverDistributionAmount) {\\n // Record the distribution.\\n (\\n JBFundingCycle memory _fundingCycle,\\n uint256 _distributedAmount\\n ) = IJBSingleTokenPaymentTerminalStore3_1_1(store).recordDistributionFor(\\n _projectId,\\n _amount,\\n _currency\\n );\\n\\n // The amount being distributed must be at least as much as was expected.\\n if (_distributedAmount < _minReturnedTokens) revert INADEQUATE_DISTRIBUTION_AMOUNT();\\n\\n // Get a reference to the project owner, which will receive tokens from paying the platform fee\\n // and receive any extra distributable funds not allocated to payout splits.\\n address payable _projectOwner = payable(projects.ownerOf(_projectId));\\n\\n // Define variables that will be needed outside the scoped section below.\\n // Keep a reference to the fee amount that was paid.\\n uint256 _feeTaken;\\n\\n // Scoped section prevents stack too deep. `_feePercent`, `_feeDiscount`, `_feeEligibleDistributionAmount`, and `_leftoverDistributionAmount` only used within scope.\\n {\\n // Keep a reference to the fee.\\n uint256 _feePercent = fee;\\n\\n // Get the amount of discount that should be applied to any fees taken.\\n // If the fee is zero, set the discount to 100% for convenience.\\n uint256 _feeDiscount = _feePercent == 0\\n ? JBConstants.MAX_FEE_DISCOUNT\\n : _currentFeeDiscount(_projectId, JBFeeType.PAYOUT);\\n\\n // The amount distributed that is eligible for incurring fees.\\n uint256 _feeEligibleDistributionAmount;\\n\\n // The amount leftover after distributing to the splits.\\n uint256 _leftoverDistributionAmount;\\n\\n // Payout to splits and get a reference to the leftover transfer amount after all splits have been paid.\\n // Also get a reference to the amount that was distributed to splits from which fees should be taken.\\n (_leftoverDistributionAmount, _feeEligibleDistributionAmount) = _distributeToPayoutSplitsOf(\\n _projectId,\\n _fundingCycle.configuration,\\n payoutSplitsGroup,\\n _distributedAmount,\\n _feePercent,\\n _feeDiscount\\n );\\n\\n if (_feeDiscount != JBConstants.MAX_FEE_DISCOUNT) {\\n // Leftover distribution amount is also eligible for a fee since the funds are going out of the ecosystem to _beneficiary.\\n unchecked {\\n _feeEligibleDistributionAmount += _leftoverDistributionAmount;\\n }\\n }\\n\\n // Take the fee.\\n _feeTaken = _feeEligibleDistributionAmount != 0\\n ? _takeFeeFrom(\\n _projectId,\\n _fundingCycle.shouldHoldFees(),\\n _feeEligibleDistributionAmount,\\n _feePercent,\\n _projectOwner,\\n _feeDiscount\\n )\\n : 0;\\n\\n // Transfer any remaining balance to the project owner and update returned leftover accordingly.\\n if (_leftoverDistributionAmount != 0) {\\n // Subtract the fee from the net leftover amount.\\n netLeftoverDistributionAmount =\\n _leftoverDistributionAmount -\\n (\\n _feeDiscount == JBConstants.MAX_FEE_DISCOUNT\\n ? 0\\n : _feeAmount(_leftoverDistributionAmount, _feePercent, _feeDiscount)\\n );\\n\\n // Transfer the amount to the project owner.\\n _transferFrom(address(this), _projectOwner, netLeftoverDistributionAmount);\\n }\\n }\\n\\n emit DistributePayouts(\\n _fundingCycle.configuration,\\n _fundingCycle.number,\\n _projectId,\\n _projectOwner,\\n _amount,\\n _distributedAmount,\\n _feeTaken,\\n netLeftoverDistributionAmount,\\n _metadata,\\n msg.sender\\n );\\n }\\n\\n /// @notice Allows a project to send funds from its overflow up to the preconfigured allowance.\\n /// @dev Only a project's owner or a designated operator can use its allowance.\\n /// @dev Incurs the protocol fee.\\n /// @param _projectId The ID of the project to use the allowance of.\\n /// @param _amount The amount of terminal tokens to use from this project's current allowance, as a fixed point number with the same amount of decimals as this terminal.\\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's overflow allowance currency.\\n /// @param _minReturnedTokens The minimum number of tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with 18 decimals.\\n /// @param _beneficiary The address to send the funds to.\\n /// @param _memo A memo to pass along to the emitted event.\\n /// @param _metadata Bytes to send along to the emitted event, if provided.\\n /// @return netDistributedAmount The amount of tokens that was distributed to the beneficiary, as a fixed point number with the same amount of decimals as the terminal.\\n function _useAllowanceOf(\\n uint256 _projectId,\\n uint256 _amount,\\n uint256 _currency,\\n uint256 _minReturnedTokens,\\n address payable _beneficiary,\\n string memory _memo,\\n bytes calldata _metadata\\n ) internal returns (uint256 netDistributedAmount) {\\n // Record the use of the allowance.\\n (\\n JBFundingCycle memory _fundingCycle,\\n uint256 _distributedAmount\\n ) = IJBSingleTokenPaymentTerminalStore3_1_1(store).recordUsedAllowanceOf(\\n _projectId,\\n _amount,\\n _currency\\n );\\n\\n // The amount being withdrawn must be at least as much as was expected.\\n if (_distributedAmount < _minReturnedTokens) revert INADEQUATE_DISTRIBUTION_AMOUNT();\\n\\n // Scoped section prevents stack too deep. `_fee`, `_projectOwner`, `_feeDiscount`, and `_netAmount` only used within scope.\\n {\\n // Keep a reference to the fee amount that was paid.\\n uint256 _feeTaken;\\n\\n // Keep a reference to the fee.\\n uint256 _feePercent = fee;\\n\\n // Get a reference to the project owner, which will receive tokens from paying the platform fee.\\n address _projectOwner = projects.ownerOf(_projectId);\\n\\n // Get the amount of discount that should be applied to any fees taken.\\n // 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.\\n uint256 _feeDiscount = _feePercent == 0 || isFeelessAddress[msg.sender]\\n ? JBConstants.MAX_FEE_DISCOUNT\\n : _currentFeeDiscount(_projectId, JBFeeType.ALLOWANCE);\\n\\n // Take a fee from the `_distributedAmount`, if needed.\\n _feeTaken = _feeDiscount == JBConstants.MAX_FEE_DISCOUNT\\n ? 0\\n : _takeFeeFrom(\\n _projectId,\\n _fundingCycle.shouldHoldFees(),\\n _distributedAmount,\\n _feePercent,\\n _projectOwner,\\n _feeDiscount\\n );\\n\\n unchecked {\\n // The net amount is the withdrawn amount without the fee.\\n netDistributedAmount = _distributedAmount - _feeTaken;\\n }\\n\\n // Transfer any remaining balance to the beneficiary.\\n if (netDistributedAmount != 0)\\n _transferFrom(address(this), _beneficiary, netDistributedAmount);\\n }\\n\\n emit UseAllowance(\\n _fundingCycle.configuration,\\n _fundingCycle.number,\\n _projectId,\\n _beneficiary,\\n _amount,\\n _distributedAmount,\\n netDistributedAmount,\\n _memo,\\n _metadata,\\n msg.sender\\n );\\n }\\n\\n /// @notice Pays out splits for a project's funding cycle configuration.\\n /// @param _projectId The ID of the project for which payout splits are being distributed.\\n /// @param _domain The domain of the splits to distribute the payout between.\\n /// @param _group The group of the splits to distribute the payout between.\\n /// @param _amount The total amount being distributed, as a fixed point number with the same number of decimals as this terminal.\\n /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE.\\n /// @param _feePercent The percent of fees to take, out of MAX_FEE.\\n /// @return If the leftover amount if the splits don't add up to 100%.\\n /// @return feeEligibleDistributionAmount The total amount of distributions that are eligible to have fees taken from.\\n function _distributeToPayoutSplitsOf(\\n uint256 _projectId,\\n uint256 _domain,\\n uint256 _group,\\n uint256 _amount,\\n uint256 _feePercent,\\n uint256 _feeDiscount\\n ) internal returns (uint256, uint256 feeEligibleDistributionAmount) {\\n // The total percentage available to split\\n uint256 _leftoverPercentage = JBConstants.SPLITS_TOTAL_PERCENT;\\n\\n // Get a reference to the project's payout splits.\\n JBSplit[] memory _splits = splitsStore.splitsOf(_projectId, _domain, _group);\\n\\n // Keep a reference to the split being iterated on.\\n JBSplit memory _split;\\n\\n // Transfer between all splits.\\n for (uint256 _i; _i < _splits.length; ) {\\n // Get a reference to the split being iterated on.\\n _split = _splits[_i];\\n\\n // The amount to send towards the split.\\n uint256 _payoutAmount = PRBMath.mulDiv(_amount, _split.percent, _leftoverPercentage);\\n\\n // The payout amount substracting any applicable incurred fees.\\n uint256 _netPayoutAmount = _distributeToPayoutSplit(\\n _split,\\n _projectId,\\n _group,\\n _payoutAmount,\\n _feePercent,\\n _feeDiscount\\n );\\n\\n // If the split allocator is set as feeless, this distribution is not eligible for a fee.\\n if (_netPayoutAmount != 0 && _netPayoutAmount != _payoutAmount)\\n feeEligibleDistributionAmount += _payoutAmount;\\n\\n if (_payoutAmount != 0) {\\n // Subtract from the amount to be sent to the beneficiary.\\n unchecked {\\n _amount -= _payoutAmount;\\n }\\n }\\n\\n unchecked {\\n // Decrement the leftover percentage.\\n _leftoverPercentage -= _split.percent;\\n }\\n\\n emit DistributeToPayoutSplit(\\n _projectId,\\n _domain,\\n _group,\\n _split,\\n _payoutAmount,\\n _netPayoutAmount,\\n msg.sender\\n );\\n\\n unchecked {\\n ++_i;\\n }\\n }\\n\\n return (_amount, feeEligibleDistributionAmount);\\n }\\n\\n /// @notice Pays out a split for a project's funding cycle configuration.\\n /// @param _split The split to distribute payouts to.\\n /// @param _amount The total amount being distributed to the split, as a fixed point number with the same number of decimals as this terminal.\\n /// @param _feePercent The percent of fees to take, out of MAX_FEE.\\n /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE.\\n /// @return netPayoutAmount The amount sent to the split after subtracting fees.\\n function _distributeToPayoutSplit(\\n JBSplit memory _split,\\n uint256 _projectId,\\n uint256 _group,\\n uint256 _amount,\\n uint256 _feePercent,\\n uint256 _feeDiscount\\n ) internal returns (uint256 netPayoutAmount) {\\n // By default, the net payout amount is the full amount. This will be adjusted if fees are taken.\\n netPayoutAmount = _amount;\\n\\n // If there's an allocator set, transfer to its `allocate` function.\\n if (_split.allocator != IJBSplitAllocator(address(0))) {\\n // This distribution is eligible for a fee since the funds are leaving this contract and the allocator isn't listed as feeless.\\n if (\\n _feeDiscount != JBConstants.MAX_FEE_DISCOUNT && !isFeelessAddress[address(_split.allocator)]\\n ) {\\n unchecked {\\n netPayoutAmount -= _feeAmount(_amount, _feePercent, _feeDiscount);\\n }\\n }\\n\\n // Trigger any inherited pre-transfer logic.\\n _beforeTransferTo(address(_split.allocator), netPayoutAmount);\\n\\n // Create the data to send to the allocator.\\n JBSplitAllocationData memory _data = JBSplitAllocationData(\\n token,\\n netPayoutAmount,\\n decimals,\\n _projectId,\\n _group,\\n _split\\n );\\n\\n // Trigger the allocator's `allocate` function.\\n bytes memory _reason;\\n\\n if (\\n ERC165Checker.supportsInterface(\\n address(_split.allocator),\\n type(IJBSplitAllocator).interfaceId\\n )\\n )\\n // If this terminal's token is ETH, send it in msg.value.\\n try\\n _split.allocator.allocate{value: token == JBTokens.ETH ? netPayoutAmount : 0}(_data)\\n {} catch (bytes memory __reason) {\\n _reason = __reason.length == 0 ? abi.encode('Allocate fail') : __reason;\\n }\\n else {\\n _reason = abi.encode('IERC165 fail');\\n }\\n\\n if (_reason.length != 0) {\\n // Revert the payout.\\n _revertTransferFrom(_projectId, address(_split.allocator), netPayoutAmount, _amount);\\n\\n // Set the net payout amount to 0 to signal the reversion.\\n netPayoutAmount = 0;\\n\\n emit PayoutReverted(_projectId, _split, _amount, _reason, msg.sender);\\n }\\n\\n // Otherwise, if a project is specified, make a payment to it.\\n } else if (_split.projectId != 0) {\\n // Get a reference to the Juicebox terminal being used.\\n IJBPaymentTerminal _terminal = directory.primaryTerminalOf(_split.projectId, token);\\n\\n // The project must have a terminal to send funds to.\\n if (_terminal == IJBPaymentTerminal(address(0))) {\\n // Set the net payout amount to 0 to signal the reversion.\\n netPayoutAmount = 0;\\n\\n // Revert the payout.\\n _revertTransferFrom(_projectId, address(0), 0, _amount);\\n\\n emit PayoutReverted(_projectId, _split, _amount, 'Terminal not found', msg.sender);\\n } else {\\n // This distribution is eligible for a fee since the funds are leaving this contract and the terminal isn't listed as feeless.\\n if (\\n _terminal != this &&\\n _feeDiscount != JBConstants.MAX_FEE_DISCOUNT &&\\n !isFeelessAddress[address(_terminal)]\\n ) {\\n unchecked {\\n netPayoutAmount -= _feeAmount(_amount, _feePercent, _feeDiscount);\\n }\\n }\\n\\n // Trigger any inherited pre-transfer logic.\\n _beforeTransferTo(address(_terminal), netPayoutAmount);\\n\\n // Add to balance if prefered.\\n if (_split.preferAddToBalance)\\n try\\n _terminal.addToBalanceOf{value: token == JBTokens.ETH ? netPayoutAmount : 0}(\\n _split.projectId,\\n netPayoutAmount,\\n token,\\n '',\\n // Send the projectId in the metadata as a referral.\\n bytes(abi.encodePacked(_projectId))\\n )\\n {} catch (bytes memory _reason) {\\n // Revert the payout.\\n _revertTransferFrom(_projectId, address(_terminal), netPayoutAmount, _amount);\\n\\n // Set the net payout amount to 0 to signal the reversion.\\n netPayoutAmount = 0;\\n\\n emit PayoutReverted(_projectId, _split, _amount, _reason, msg.sender);\\n }\\n else\\n try\\n _terminal.pay{value: token == JBTokens.ETH ? netPayoutAmount : 0}(\\n _split.projectId,\\n netPayoutAmount,\\n token,\\n _split.beneficiary != address(0) ? _split.beneficiary : msg.sender,\\n 0,\\n _split.preferClaimed,\\n '',\\n // Send the projectId in the metadata as a referral.\\n bytes(abi.encodePacked(_projectId))\\n )\\n {} catch (bytes memory _reason) {\\n // Revert the payout.\\n _revertTransferFrom(_projectId, address(_terminal), netPayoutAmount, _amount);\\n\\n // Set the net payout amount to 0 to signal the reversion.\\n netPayoutAmount = 0;\\n\\n emit PayoutReverted(_projectId, _split, _amount, _reason, msg.sender);\\n }\\n }\\n } else {\\n // This distribution is eligible for a fee since the funds are leaving this contract and the beneficiary isn't listed as feeless.\\n // Don't enforce feeless address for the beneficiary since the funds are leaving the ecosystem.\\n if (_feeDiscount != JBConstants.MAX_FEE_DISCOUNT) {\\n unchecked {\\n netPayoutAmount -= _feeAmount(_amount, _feePercent, _feeDiscount);\\n }\\n }\\n\\n // If there's a beneficiary, send the funds directly to the beneficiary. Otherwise send to the msg.sender.\\n _transferFrom(\\n address(this),\\n _split.beneficiary != address(0) ? _split.beneficiary : payable(msg.sender),\\n netPayoutAmount\\n );\\n }\\n }\\n\\n /// @notice Takes a fee into the platform's project, which has an id of _FEE_BENEFICIARY_PROJECT_ID.\\n /// @param _projectId The ID of the project having fees taken from.\\n /// @param _shouldHoldFees If fees should be tracked and held back.\\n /// @param _feePercent The percent of fees to take, out of MAX_FEE.\\n /// @param _amount The amount of the fee to take, as a floating point number with 18 decimals.\\n /// @param _beneficiary The address to mint the platforms tokens for.\\n /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE.\\n /// @return feeAmount The amount of the fee taken.\\n function _takeFeeFrom(\\n uint256 _projectId,\\n bool _shouldHoldFees,\\n uint256 _amount,\\n uint256 _feePercent,\\n address _beneficiary,\\n uint256 _feeDiscount\\n ) internal returns (uint256 feeAmount) {\\n feeAmount = _feeAmount(_amount, _feePercent, _feeDiscount);\\n\\n if (_shouldHoldFees) {\\n // Store the held fee.\\n _heldFeesOf[_projectId].push(\\n JBFee(_amount, uint32(_feePercent), uint32(_feeDiscount), _beneficiary)\\n );\\n\\n emit HoldFee(_projectId, _amount, _feePercent, _feeDiscount, _beneficiary, msg.sender);\\n } else {\\n // Process the fee.\\n _processFee(feeAmount, _beneficiary, _projectId); // Take the fee.\\n\\n emit ProcessFee(_projectId, feeAmount, false, _beneficiary, msg.sender);\\n }\\n }\\n\\n /// @notice Process a fee of the specified amount.\\n /// @param _amount The fee amount, as a floating point number with 18 decimals.\\n /// @param _beneficiary The address to mint the platform's tokens for.\\n /// @param _from The project ID the fee is being paid from.\\n function _processFee(uint256 _amount, address _beneficiary, uint256 _from) internal {\\n // Get the terminal for the protocol project.\\n IJBPaymentTerminal _terminal = directory.primaryTerminalOf(_FEE_BENEFICIARY_PROJECT_ID, token);\\n\\n // Trigger any inherited pre-transfer logic if funds will be transferred.\\n if (address(_terminal) != address(this)) _beforeTransferTo(address(_terminal), _amount);\\n\\n try\\n // Send the fee.\\n // If this terminal's token is ETH, send it in msg.value.\\n _terminal.pay{value: token == JBTokens.ETH ? _amount : 0}(\\n _FEE_BENEFICIARY_PROJECT_ID,\\n _amount,\\n token,\\n _beneficiary,\\n 0,\\n false,\\n '',\\n // Send the projectId in the metadata.\\n bytes(abi.encodePacked(_from))\\n )\\n {} catch (bytes memory _reason) {\\n _revertTransferFrom(\\n _from,\\n address(_terminal) != address(this) ? address(_terminal) : address(0),\\n address(_terminal) != address(this) ? _amount : 0,\\n _amount\\n );\\n emit FeeReverted(_from, _FEE_BENEFICIARY_PROJECT_ID, _amount, _reason, msg.sender);\\n }\\n }\\n\\n /// @notice Reverts an expected payout.\\n /// @param _projectId The ID of the project having paying out.\\n /// @param _expectedDestination The address the payout was expected to go to.\\n /// @param _allowanceAmount The amount that the destination has been allowed to use.\\n /// @param _depositAmount The amount of the payout as debited from the project's balance.\\n function _revertTransferFrom(\\n uint256 _projectId,\\n address _expectedDestination,\\n uint256 _allowanceAmount,\\n uint256 _depositAmount\\n ) internal {\\n // Cancel allowance if needed.\\n if (_allowanceAmount != 0) _cancelTransferTo(_expectedDestination, _allowanceAmount);\\n\\n // Add undistributed amount back to project's balance.\\n IJBSingleTokenPaymentTerminalStore3_1_1(store).recordAddedBalanceFor(\\n _projectId,\\n _depositAmount\\n );\\n }\\n\\n /// @notice Contribute tokens to a project.\\n /// @param _amount The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place.\\n /// @param _payer The address making the payment.\\n /// @param _projectId The ID of the project being paid.\\n /// @param _beneficiary The address to mint tokens for and pass along to the funding cycle's data source and delegate.\\n /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal.\\n /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\\n /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\\n /// @return beneficiaryTokenCount The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals.\\n function _pay(\\n uint256 _amount,\\n address _payer,\\n uint256 _projectId,\\n address _beneficiary,\\n uint256 _minReturnedTokens,\\n bool _preferClaimedTokens,\\n string memory _memo,\\n bytes memory _metadata\\n ) internal returns (uint256 beneficiaryTokenCount) {\\n // Cant send tokens to the zero address.\\n if (_beneficiary == address(0)) revert PAY_TO_ZERO_ADDRESS();\\n\\n // Define variables that will be needed outside the scoped section below.\\n // Keep a reference to the funding cycle during which the payment is being made.\\n JBFundingCycle memory _fundingCycle;\\n\\n // Scoped section prevents stack too deep. `_delegateAllocations` and `_tokenCount` only used within scope.\\n {\\n JBPayDelegateAllocation3_1_1[] memory _delegateAllocations;\\n uint256 _tokenCount;\\n\\n // Bundle the amount info into a JBTokenAmount struct.\\n JBTokenAmount memory _bundledAmount = JBTokenAmount(token, _amount, decimals, currency);\\n\\n // Record the payment.\\n (\\n _fundingCycle,\\n _tokenCount,\\n _delegateAllocations,\\n _memo\\n ) = IJBSingleTokenPaymentTerminalStore3_1_1(store).recordPaymentFrom(\\n _payer,\\n _bundledAmount,\\n _projectId,\\n baseWeightCurrency,\\n _beneficiary,\\n _memo,\\n _metadata\\n );\\n\\n // Mint the tokens if needed.\\n if (_tokenCount != 0)\\n // Set token count to be the number of tokens minted for the beneficiary instead of the total amount.\\n beneficiaryTokenCount = IJBController(directory.controllerOf(_projectId)).mintTokensOf(\\n _projectId,\\n _tokenCount,\\n _beneficiary,\\n '',\\n _preferClaimedTokens,\\n true\\n );\\n\\n // The token count for the beneficiary must be greater than or equal to the minimum expected.\\n if (beneficiaryTokenCount < _minReturnedTokens) revert INADEQUATE_TOKEN_COUNT();\\n\\n // If delegate allocations were specified by the data source, fulfill them.\\n if (_delegateAllocations.length != 0) {\\n JBDidPayData3_1_1 memory _data = JBDidPayData3_1_1(\\n _payer,\\n _projectId,\\n _fundingCycle.configuration,\\n _bundledAmount,\\n JBTokenAmount(token, 0, decimals, currency),\\n beneficiaryTokenCount,\\n _beneficiary,\\n _preferClaimedTokens,\\n _memo,\\n bytes(''),\\n _metadata\\n );\\n\\n // Get a reference to the number of delegates to allocate to.\\n uint256 _numDelegates = _delegateAllocations.length;\\n\\n // Keep a reference to the allocation.\\n JBPayDelegateAllocation3_1_1 memory _delegateAllocation;\\n\\n for (uint256 _i; _i < _numDelegates; ) {\\n // Get a reference to the delegate being iterated on.\\n _delegateAllocation = _delegateAllocations[_i];\\n\\n // Trigger any inherited pre-transfer logic.\\n _beforeTransferTo(address(_delegateAllocation.delegate), _delegateAllocation.amount);\\n\\n // Pass the correct token forwardedAmount to the delegate\\n _data.forwardedAmount.value = _delegateAllocation.amount;\\n\\n // Pass the correct metadata from the data source.\\n _data.dataSourceMetadata = _delegateAllocation.metadata;\\n\\n _delegateAllocation.delegate.didPay{\\n value: token == JBTokens.ETH ? _delegateAllocation.amount : 0\\n }(_data);\\n\\n emit DelegateDidPay(\\n _delegateAllocation.delegate,\\n _data,\\n _delegateAllocation.amount,\\n msg.sender\\n );\\n\\n unchecked {\\n ++_i;\\n }\\n }\\n }\\n }\\n\\n emit Pay(\\n _fundingCycle.configuration,\\n _fundingCycle.number,\\n _projectId,\\n _payer,\\n _beneficiary,\\n _amount,\\n beneficiaryTokenCount,\\n _memo,\\n _metadata,\\n msg.sender\\n );\\n }\\n\\n /// @notice Receives funds belonging to the specified project.\\n /// @param _projectId The ID of the project to which the funds received belong.\\n /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\\n /// @param _shouldRefundHeldFees A flag indicating if held fees should be refunded based on the amount being added.\\n /// @param _memo A memo to pass along to the emitted event.\\n /// @param _metadata Extra data to pass along to the emitted event.\\n function _addToBalanceOf(\\n uint256 _projectId,\\n uint256 _amount,\\n bool _shouldRefundHeldFees,\\n string memory _memo,\\n bytes memory _metadata\\n ) internal {\\n // Refund any held fees to make sure the project doesn't pay double for funds going in and out of the protocol.\\n uint256 _refundedFees = _shouldRefundHeldFees ? _refundHeldFees(_projectId, _amount) : 0;\\n\\n // Record the added funds with any refunded fees.\\n IJBSingleTokenPaymentTerminalStore3_1_1(store).recordAddedBalanceFor(\\n _projectId,\\n _amount + _refundedFees\\n );\\n\\n emit AddToBalance(_projectId, _amount, _refundedFees, _memo, _metadata, msg.sender);\\n }\\n\\n /// @notice Refund fees based on the specified amount.\\n /// @param _projectId The project for which fees are being refunded.\\n /// @param _amount The amount to base the refund on, as a fixed point number with the same amount of decimals as this terminal.\\n /// @return refundedFees How much fees were refunded, as a fixed point number with the same number of decimals as this terminal\\n function _refundHeldFees(\\n uint256 _projectId,\\n uint256 _amount\\n ) internal returns (uint256 refundedFees) {\\n // Get a reference to the project's held fees.\\n JBFee[] memory _heldFees = _heldFeesOf[_projectId];\\n\\n // Delete the current held fees.\\n delete _heldFeesOf[_projectId];\\n\\n // Get a reference to the leftover amount once all fees have been settled.\\n uint256 leftoverAmount = _amount;\\n\\n // Push length in stack\\n uint256 _heldFeesLength = _heldFees.length;\\n\\n // Process each fee.\\n for (uint256 _i; _i < _heldFeesLength; ) {\\n if (leftoverAmount == 0) _heldFeesOf[_projectId].push(_heldFees[_i]);\\n else if (leftoverAmount >= _heldFees[_i].amount) {\\n unchecked {\\n leftoverAmount = leftoverAmount - _heldFees[_i].amount;\\n refundedFees += (\\n _heldFees[_i].fee == 0 || _heldFees[_i].feeDiscount == JBConstants.MAX_FEE_DISCOUNT\\n ? 0\\n : _feeAmount(_heldFees[_i].amount, _heldFees[_i].fee, _heldFees[_i].feeDiscount)\\n );\\n }\\n } else {\\n unchecked {\\n _heldFeesOf[_projectId].push(\\n JBFee(\\n _heldFees[_i].amount - leftoverAmount,\\n _heldFees[_i].fee,\\n _heldFees[_i].feeDiscount,\\n _heldFees[_i].beneficiary\\n )\\n );\\n refundedFees += (\\n _heldFees[_i].fee == 0 || _heldFees[_i].feeDiscount == JBConstants.MAX_FEE_DISCOUNT\\n ? 0\\n : _feeAmount(leftoverAmount, _heldFees[_i].fee, _heldFees[_i].feeDiscount)\\n );\\n }\\n leftoverAmount = 0;\\n }\\n\\n unchecked {\\n ++_i;\\n }\\n }\\n\\n emit RefundHeldFees(_projectId, _amount, refundedFees, leftoverAmount, msg.sender);\\n }\\n\\n /// @notice Returns the fee amount based on the provided amount for the specified project.\\n /// @param _amount The amount that the fee is based on, as a fixed point number with the same amount of decimals as this terminal.\\n /// @param _fee The percentage of the fee, out of MAX_FEE.\\n /// @param _feeDiscount The percentage discount that should be applied out of the max amount, out of MAX_FEE_DISCOUNT.\\n /// @return The amount of the fee, as a fixed point number with the same amount of decimals as this terminal.\\n function _feeAmount(\\n uint256 _amount,\\n uint256 _fee,\\n uint256 _feeDiscount\\n ) internal pure returns (uint256) {\\n // Calculate the discounted fee.\\n uint256 _discountedFee = _fee -\\n PRBMath.mulDiv(_fee, _feeDiscount, JBConstants.MAX_FEE_DISCOUNT);\\n\\n // The amount of tokens from the `_amount` to pay as a fee.\\n return\\n _amount - PRBMath.mulDiv(_amount, JBConstants.MAX_FEE, _discountedFee + JBConstants.MAX_FEE);\\n }\\n\\n /// @notice Get the fee discount from the fee gauge for the specified project.\\n /// @param _projectId The ID of the project to get a fee discount for.\\n /// @param _feeType The type of fee the discount is being applied to.\\n /// @return feeDiscount The fee discount, which should be interpreted as a percentage out MAX_FEE_DISCOUNT.\\n function _currentFeeDiscount(\\n uint256 _projectId,\\n JBFeeType _feeType\\n ) internal view returns (uint256) {\\n // Can't take a fee if the protocol project doesn't have a terminal that accepts the token.\\n if (\\n directory.primaryTerminalOf(_FEE_BENEFICIARY_PROJECT_ID, token) ==\\n IJBPaymentTerminal(address(0))\\n ) return JBConstants.MAX_FEE_DISCOUNT;\\n\\n // Get the fee discount.\\n if (feeGauge != address(0))\\n // If the guage reverts, keep the discount at 0.\\n try IJBFeeGauge3_1(feeGauge).currentDiscountFor(_projectId, _feeType) returns (\\n uint256 discount\\n ) {\\n // If the fee discount is greater than the max, we ignore the return value\\n if (discount <= JBConstants.MAX_FEE_DISCOUNT) return discount;\\n } catch {\\n return 0;\\n }\\n\\n return 0;\\n }\\n}\\n\",\"keccak256\":\"0xac6578a64c8c0544d26442921ae6b577f86e3f18e6338c7eda9ee2f5eb2c927d\",\"license\":\"MIT\"},\"contracts/abstract/JBSingleTokenPaymentTerminal.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.16;\\n\\nimport {ERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol';\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol';\\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\\nimport {IJBSingleTokenPaymentTerminal} from './../interfaces/IJBSingleTokenPaymentTerminal.sol';\\n\\n/// @notice Generic terminal managing all inflows of funds into the protocol ecosystem for one token.\\nabstract contract JBSingleTokenPaymentTerminal is ERC165, IJBSingleTokenPaymentTerminal {\\n //*********************************************************************//\\n // ---------------- public immutable stored properties --------------- //\\n //*********************************************************************//\\n\\n /// @notice The token that this terminal accepts.\\n address public immutable override token;\\n\\n /// @notice The number of decimals the token fixed point amounts are expected to have.\\n uint256 public immutable override decimals;\\n\\n /// @notice The currency to use when resolving price feeds for this terminal.\\n uint256 public immutable override currency;\\n\\n //*********************************************************************//\\n // ------------------------- external views -------------------------- //\\n //*********************************************************************//\\n\\n /// @notice A flag indicating if this terminal accepts the specified token.\\n /// @param _token The token to check if this terminal accepts or not.\\n /// @param _projectId The project ID to check for token acceptance.\\n /// @return The flag.\\n function acceptsToken(address _token, uint256 _projectId) external view override returns (bool) {\\n _projectId; // Prevents unused var compiler and natspec complaints.\\n\\n return _token == token;\\n }\\n\\n /// @notice The decimals that should be used in fixed number accounting for the specified token.\\n /// @param _token The token to check for the decimals of.\\n /// @return The number of decimals for the token.\\n function decimalsForToken(address _token) external view override returns (uint256) {\\n _token; // Prevents unused var compiler and natspec complaints.\\n\\n return decimals;\\n }\\n\\n /// @notice The currency that should be used for the specified token.\\n /// @param _token The token to check for the currency of.\\n /// @return The currency index.\\n function currencyForToken(address _token) external view override returns (uint256) {\\n _token; // Prevents unused var compiler and natspec complaints.\\n\\n return currency;\\n }\\n\\n //*********************************************************************//\\n // -------------------------- public views --------------------------- //\\n //*********************************************************************//\\n\\n /// @notice Indicates if this contract adheres to the specified interface.\\n /// @dev See {IERC165-supportsInterface}.\\n /// @param _interfaceId The ID of the interface to check for adherance to.\\n /// @return A flag indicating if the provided interface ID is supported.\\n function supportsInterface(\\n bytes4 _interfaceId\\n ) public view virtual override(ERC165, IERC165) returns (bool) {\\n return\\n _interfaceId == type(IJBPaymentTerminal).interfaceId ||\\n _interfaceId == type(IJBSingleTokenPaymentTerminal).interfaceId ||\\n super.supportsInterface(_interfaceId);\\n }\\n\\n //*********************************************************************//\\n // -------------------------- constructor ---------------------------- //\\n //*********************************************************************//\\n\\n /// @param _token The token that this terminal manages.\\n /// @param _decimals The number of decimals the token fixed point amounts are expected to have.\\n /// @param _currency The currency that this terminal's token adheres to for price feeds.\\n constructor(address _token, uint256 _decimals, uint256 _currency) {\\n token = _token;\\n decimals = _decimals;\\n currency = _currency;\\n }\\n}\\n\",\"keccak256\":\"0x27bd0b9e8170f16bc1318d6dee16aa3273e7d8f6cb8b80d7d905d0dce93e307c\",\"license\":\"MIT\"},\"contracts/enums/JBBallotState.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nenum JBBallotState {\\n Active,\\n Approved,\\n Failed\\n}\\n\",\"keccak256\":\"0x891fcac63470398b3a11239da7feba6b07d640809fcefd2404303b823d7378f8\",\"license\":\"MIT\"},\"contracts/enums/JBFeeType.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nenum JBFeeType {\\n PAYOUT,\\n ALLOWANCE,\\n REDEMPTION\\n}\\n\",\"keccak256\":\"0x02418e9bd3cce5ccf5a76822909558c61672719767bffe16490256268b05cb22\",\"license\":\"MIT\"},\"contracts/interfaces/IJBAllowanceTerminal3_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IJBAllowanceTerminal3_1 {\\n function useAllowanceOf(\\n uint256 projectId,\\n uint256 amount,\\n uint256 currency,\\n address token,\\n uint256 minReturnedTokens,\\n address payable beneficiary,\\n string calldata memo,\\n bytes calldata metadata\\n ) external returns (uint256 netDistributedAmount);\\n}\\n\",\"keccak256\":\"0x3d9f7edf01473dd1bf444c2c9c2cae93e5980e17134e77efd50ad1723fa66559\",\"license\":\"MIT\"},\"contracts/interfaces/IJBController.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\\nimport {JBBallotState} from './../enums/JBBallotState.sol';\\nimport {JBFundAccessConstraints} from './../structs/JBFundAccessConstraints.sol';\\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\\nimport {JBFundingCycleData} from './../structs/JBFundingCycleData.sol';\\nimport {JBFundingCycleMetadata} from './../structs/JBFundingCycleMetadata.sol';\\nimport {JBGroupedSplits} from './../structs/JBGroupedSplits.sol';\\nimport {JBProjectMetadata} from './../structs/JBProjectMetadata.sol';\\nimport {JBSplit} from './../structs/JBSplit.sol';\\nimport {IJBDirectory} from './IJBDirectory.sol';\\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\\nimport {IJBMigratable} from './IJBMigratable.sol';\\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\\nimport {IJBProjects} from './IJBProjects.sol';\\nimport {IJBSplitsStore} from './IJBSplitsStore.sol';\\nimport {IJBTokenStore} from './IJBTokenStore.sol';\\n\\ninterface IJBController is IERC165 {\\n event LaunchProject(uint256 configuration, uint256 projectId, string memo, address caller);\\n\\n event LaunchFundingCycles(uint256 configuration, uint256 projectId, string memo, address caller);\\n\\n event ReconfigureFundingCycles(\\n uint256 configuration,\\n uint256 projectId,\\n string memo,\\n address caller\\n );\\n\\n event SetFundAccessConstraints(\\n uint256 indexed fundingCycleConfiguration,\\n uint256 indexed fundingCycleNumber,\\n uint256 indexed projectId,\\n JBFundAccessConstraints constraints,\\n address caller\\n );\\n\\n event DistributeReservedTokens(\\n uint256 indexed fundingCycleConfiguration,\\n uint256 indexed fundingCycleNumber,\\n uint256 indexed projectId,\\n address beneficiary,\\n uint256 tokenCount,\\n uint256 beneficiaryTokenCount,\\n string memo,\\n address caller\\n );\\n\\n event DistributeToReservedTokenSplit(\\n uint256 indexed projectId,\\n uint256 indexed domain,\\n uint256 indexed group,\\n JBSplit split,\\n uint256 tokenCount,\\n address caller\\n );\\n\\n event MintTokens(\\n address indexed beneficiary,\\n uint256 indexed projectId,\\n uint256 tokenCount,\\n uint256 beneficiaryTokenCount,\\n string memo,\\n uint256 reservedRate,\\n address caller\\n );\\n\\n event BurnTokens(\\n address indexed holder,\\n uint256 indexed projectId,\\n uint256 tokenCount,\\n string memo,\\n address caller\\n );\\n\\n event Migrate(uint256 indexed projectId, IJBMigratable to, address caller);\\n\\n event PrepMigration(uint256 indexed projectId, address from, address caller);\\n\\n function projects() external view returns (IJBProjects);\\n\\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\\n\\n function tokenStore() external view returns (IJBTokenStore);\\n\\n function splitsStore() external view returns (IJBSplitsStore);\\n\\n function directory() external view returns (IJBDirectory);\\n\\n function reservedTokenBalanceOf(\\n uint256 projectId,\\n uint256 reservedRate\\n ) external view returns (uint256);\\n\\n function distributionLimitOf(\\n uint256 projectId,\\n uint256 configuration,\\n IJBPaymentTerminal terminal,\\n address token\\n ) external view returns (uint256 distributionLimit, uint256 distributionLimitCurrency);\\n\\n function overflowAllowanceOf(\\n uint256 projectId,\\n uint256 configuration,\\n IJBPaymentTerminal terminal,\\n address token\\n ) external view returns (uint256 overflowAllowance, uint256 overflowAllowanceCurrency);\\n\\n function totalOutstandingTokensOf(\\n uint256 projectId,\\n uint256 reservedRate\\n ) external view returns (uint256);\\n\\n function getFundingCycleOf(\\n uint256 projectId,\\n uint256 configuration\\n )\\n external\\n view\\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata);\\n\\n function latestConfiguredFundingCycleOf(\\n uint256 projectId\\n )\\n external\\n view\\n returns (JBFundingCycle memory, JBFundingCycleMetadata memory metadata, JBBallotState);\\n\\n function currentFundingCycleOf(\\n uint256 projectId\\n )\\n external\\n view\\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata);\\n\\n function queuedFundingCycleOf(\\n uint256 projectId\\n )\\n external\\n view\\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata);\\n\\n function launchProjectFor(\\n address owner,\\n JBProjectMetadata calldata projectMetadata,\\n JBFundingCycleData calldata data,\\n JBFundingCycleMetadata calldata metadata,\\n uint256 mustStartAtOrAfter,\\n JBGroupedSplits[] memory groupedSplits,\\n JBFundAccessConstraints[] memory fundAccessConstraints,\\n IJBPaymentTerminal[] memory terminals,\\n string calldata memo\\n ) external returns (uint256 projectId);\\n\\n function launchFundingCyclesFor(\\n uint256 projectId,\\n JBFundingCycleData calldata data,\\n JBFundingCycleMetadata calldata metadata,\\n uint256 mustStartAtOrAfter,\\n JBGroupedSplits[] memory groupedSplits,\\n JBFundAccessConstraints[] memory fundAccessConstraints,\\n IJBPaymentTerminal[] memory terminals,\\n string calldata memo\\n ) external returns (uint256 configuration);\\n\\n function reconfigureFundingCyclesOf(\\n uint256 projectId,\\n JBFundingCycleData calldata data,\\n JBFundingCycleMetadata calldata metadata,\\n uint256 mustStartAtOrAfter,\\n JBGroupedSplits[] memory groupedSplits,\\n JBFundAccessConstraints[] memory fundAccessConstraints,\\n string calldata memo\\n ) external returns (uint256);\\n\\n function mintTokensOf(\\n uint256 projectId,\\n uint256 tokenCount,\\n address beneficiary,\\n string calldata memo,\\n bool preferClaimedTokens,\\n bool useReservedRate\\n ) external returns (uint256 beneficiaryTokenCount);\\n\\n function burnTokensOf(\\n address holder,\\n uint256 projectId,\\n uint256 tokenCount,\\n string calldata memo,\\n bool preferClaimedTokens\\n ) external;\\n\\n function distributeReservedTokensOf(\\n uint256 projectId,\\n string memory memo\\n ) external returns (uint256);\\n\\n function migrate(uint256 projectId, IJBMigratable to) external;\\n}\\n\",\"keccak256\":\"0x6ebcb31173eff32f16f2f1fa6979a9dad0d7fac51e34441fafffa5e097ad507f\",\"license\":\"MIT\"},\"contracts/interfaces/IJBDirectory.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\\nimport {IJBProjects} from './IJBProjects.sol';\\n\\ninterface IJBDirectory {\\n event SetController(uint256 indexed projectId, address indexed controller, address caller);\\n\\n event AddTerminal(uint256 indexed projectId, IJBPaymentTerminal indexed terminal, address caller);\\n\\n event SetTerminals(uint256 indexed projectId, IJBPaymentTerminal[] terminals, address caller);\\n\\n event SetPrimaryTerminal(\\n uint256 indexed projectId,\\n address indexed token,\\n IJBPaymentTerminal indexed terminal,\\n address caller\\n );\\n\\n event SetIsAllowedToSetFirstController(address indexed addr, bool indexed flag, address caller);\\n\\n function projects() external view returns (IJBProjects);\\n\\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\\n\\n function controllerOf(uint256 projectId) external view returns (address);\\n\\n function isAllowedToSetFirstController(address account) external view returns (bool);\\n\\n function terminalsOf(uint256 projectId) external view returns (IJBPaymentTerminal[] memory);\\n\\n function isTerminalOf(\\n uint256 projectId,\\n IJBPaymentTerminal terminal\\n ) external view returns (bool);\\n\\n function primaryTerminalOf(\\n uint256 projectId,\\n address token\\n ) external view returns (IJBPaymentTerminal);\\n\\n function setControllerOf(uint256 projectId, address controller) external;\\n\\n function setTerminalsOf(uint256 projectId, IJBPaymentTerminal[] calldata terminals) external;\\n\\n function setPrimaryTerminalOf(\\n uint256 projectId,\\n address token,\\n IJBPaymentTerminal terminal\\n ) external;\\n\\n function setIsAllowedToSetFirstController(address account, bool flag) external;\\n}\\n\",\"keccak256\":\"0x490d5fe691ee7d9c9179fa19964de279882176513d92f3efc0aa98dc34799d1c\",\"license\":\"MIT\"},\"contracts/interfaces/IJBFeeGauge3_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBFeeType} from './../enums/JBFeeType.sol';\\n\\ninterface IJBFeeGauge3_1 {\\n function currentDiscountFor(uint256 projectId, JBFeeType feeType) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0xcf64e4b203422b50c968e890e3cf8621b63014e59dc8be25f13884c316f95266\",\"license\":\"MIT\"},\"contracts/interfaces/IJBFeeHoldingTerminal.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IJBFeeHoldingTerminal {\\n function addToBalanceOf(\\n uint256 projectId,\\n uint256 amount,\\n address token,\\n bool shouldRefundHeldFees,\\n string calldata memo,\\n bytes calldata metadata\\n ) external payable;\\n}\\n\",\"keccak256\":\"0xdda2332beec8a4f7f5ecd45a660b11796516933998b397c5d05ae639b5755454\",\"license\":\"MIT\"},\"contracts/interfaces/IJBFundingCycleBallot.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\\nimport {JBBallotState} from './../enums/JBBallotState.sol';\\n\\ninterface IJBFundingCycleBallot is IERC165 {\\n function duration() external view returns (uint256);\\n\\n function stateOf(\\n uint256 projectId,\\n uint256 configuration,\\n uint256 start\\n ) external view returns (JBBallotState);\\n}\\n\",\"keccak256\":\"0x729b4a700618f890e434d31ef9252e1cce9d0473fe7f8f070872df5b348bed23\",\"license\":\"MIT\"},\"contracts/interfaces/IJBFundingCycleStore.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBBallotState} from './../enums/JBBallotState.sol';\\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\\nimport {JBFundingCycleData} from './../structs/JBFundingCycleData.sol';\\n\\ninterface IJBFundingCycleStore {\\n event Configure(\\n uint256 indexed configuration,\\n uint256 indexed projectId,\\n JBFundingCycleData data,\\n uint256 metadata,\\n uint256 mustStartAtOrAfter,\\n address caller\\n );\\n\\n event Init(uint256 indexed configuration, uint256 indexed projectId, uint256 indexed basedOn);\\n\\n function latestConfigurationOf(uint256 projectId) external view returns (uint256);\\n\\n function get(\\n uint256 projectId,\\n uint256 configuration\\n ) external view returns (JBFundingCycle memory);\\n\\n function latestConfiguredOf(\\n uint256 projectId\\n ) external view returns (JBFundingCycle memory fundingCycle, JBBallotState ballotState);\\n\\n function queuedOf(uint256 projectId) external view returns (JBFundingCycle memory fundingCycle);\\n\\n function currentOf(uint256 projectId) external view returns (JBFundingCycle memory fundingCycle);\\n\\n function currentBallotStateOf(uint256 projectId) external view returns (JBBallotState);\\n\\n function configureFor(\\n uint256 projectId,\\n JBFundingCycleData calldata data,\\n uint256 metadata,\\n uint256 mustStartAtOrAfter\\n ) external returns (JBFundingCycle memory fundingCycle);\\n}\\n\",\"keccak256\":\"0x524350f6c6fcb45eaf927f4e6d13cd2f5029c2b858233bb9a338fe411ce34dab\",\"license\":\"MIT\"},\"contracts/interfaces/IJBMigratable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IJBMigratable {\\n function prepForMigrationOf(uint256 projectId, address from) external;\\n}\\n\",\"keccak256\":\"0xdee578477bbb7a66e9a1735e45a7795e95cfd374d85f55b61b3302476844c418\",\"license\":\"MIT\"},\"contracts/interfaces/IJBOperatable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBOperatorStore} from './IJBOperatorStore.sol';\\n\\ninterface IJBOperatable {\\n function operatorStore() external view returns (IJBOperatorStore);\\n}\\n\",\"keccak256\":\"0xe083d0c1b181e5c38cf3f03f97dd782f913710bf8cc54411eb4b6e7ec4c5a0c8\",\"license\":\"MIT\"},\"contracts/interfaces/IJBOperatorStore.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBOperatorData} from './../structs/JBOperatorData.sol';\\n\\ninterface IJBOperatorStore {\\n event SetOperator(\\n address indexed operator,\\n address indexed account,\\n uint256 indexed domain,\\n uint256[] permissionIndexes,\\n uint256 packed\\n );\\n\\n function permissionsOf(\\n address operator,\\n address account,\\n uint256 domain\\n ) external view returns (uint256);\\n\\n function hasPermission(\\n address operator,\\n address account,\\n uint256 domain,\\n uint256 permissionIndex\\n ) external view returns (bool);\\n\\n function hasPermissions(\\n address operator,\\n address account,\\n uint256 domain,\\n uint256[] calldata permissionIndexes\\n ) external view returns (bool);\\n\\n function setOperator(JBOperatorData calldata operatorData) external;\\n\\n function setOperators(JBOperatorData[] calldata operatorData) external;\\n}\\n\",\"keccak256\":\"0xb6ce539d040601d7e4b1cec567c64d93e5b14d5fa249e04dd67cf222c4431678\",\"license\":\"MIT\"},\"contracts/interfaces/IJBPayDelegate.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\\nimport {JBDidPayData} from './../structs/JBDidPayData.sol';\\n\\n/// @title Pay delegate\\n/// @notice Delegate called after JBTerminal.pay(..) logic completion (if passed by the funding cycle datasource)\\ninterface IJBPayDelegate is IERC165 {\\n /// @notice This function is called by JBPaymentTerminal.pay(..), after the execution of its logic\\n /// @dev Critical business logic should be protected by an appropriate access control\\n /// @param data the data passed by the terminal, as a JBDidPayData struct:\\n function didPay(JBDidPayData calldata data) external payable;\\n}\\n\",\"keccak256\":\"0x2321bc8e990c5e2cb4236e0ca68e7e556306b6aa3ba10fa19ff018039d6d1a02\",\"license\":\"MIT\"},\"contracts/interfaces/IJBPayDelegate3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\\nimport {JBDidPayData3_1_1} from './../structs/JBDidPayData3_1_1.sol';\\n\\n/// @title Pay delegate\\n/// @notice Delegate called after JBTerminal.pay(..) logic completion (if passed by the funding cycle datasource)\\ninterface IJBPayDelegate3_1_1 is IERC165 {\\n /// @notice This function is called by JBPaymentTerminal.pay(..), after the execution of its logic\\n /// @dev Critical business logic should be protected by an appropriate access control\\n /// @param data the data passed by the terminal, as a JBDidPayData3_1_1 struct:\\n function didPay(JBDidPayData3_1_1 calldata data) external payable;\\n}\\n\",\"keccak256\":\"0x9448d24cd9c559b44c468c6a76d850f6eaadf31446db903092a2f32503a67294\",\"license\":\"MIT\"},\"contracts/interfaces/IJBPaymentTerminal.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\\n\\ninterface IJBPaymentTerminal is IERC165 {\\n function acceptsToken(address token, uint256 projectId) external view returns (bool);\\n\\n function currencyForToken(address token) external view returns (uint256);\\n\\n function decimalsForToken(address token) external view returns (uint256);\\n\\n // Return value must be a fixed point number with 18 decimals.\\n function currentEthOverflowOf(uint256 projectId) external view returns (uint256);\\n\\n function pay(\\n uint256 projectId,\\n uint256 amount,\\n address token,\\n address beneficiary,\\n uint256 minReturnedTokens,\\n bool preferClaimedTokens,\\n string calldata memo,\\n bytes calldata metadata\\n ) external payable returns (uint256 beneficiaryTokenCount);\\n\\n function addToBalanceOf(\\n uint256 projectId,\\n uint256 amount,\\n address token,\\n string calldata memo,\\n bytes calldata metadata\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x273bc1fa373fac08e5635fce7d38fd92e9fabba353568b3f7a5be54c01fe4d27\",\"license\":\"MIT\"},\"contracts/interfaces/IJBPayoutRedemptionPaymentTerminal3_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBFee} from './../structs/JBFee.sol';\\nimport {IJBAllowanceTerminal3_1} from './IJBAllowanceTerminal3_1.sol';\\nimport {IJBDirectory} from './IJBDirectory.sol';\\nimport {IJBFeeHoldingTerminal} from './IJBFeeHoldingTerminal.sol';\\nimport {IJBPayDelegate} from './IJBPayDelegate.sol';\\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\\nimport {IJBPayoutTerminal3_1} from './IJBPayoutTerminal3_1.sol';\\nimport {IJBPrices} from './IJBPrices.sol';\\nimport {IJBProjects} from './IJBProjects.sol';\\nimport {IJBRedemptionDelegate} from './IJBRedemptionDelegate.sol';\\nimport {IJBRedemptionTerminal} from './IJBRedemptionTerminal.sol';\\nimport {IJBSplitsStore} from './IJBSplitsStore.sol';\\nimport {JBDidPayData} from './../structs/JBDidPayData.sol';\\nimport {JBDidRedeemData} from './../structs/JBDidRedeemData.sol';\\nimport {JBSplit} from './../structs/JBSplit.sol';\\n\\ninterface IJBPayoutRedemptionPaymentTerminal3_1 is\\n IJBPaymentTerminal,\\n IJBPayoutTerminal3_1,\\n IJBAllowanceTerminal3_1,\\n IJBRedemptionTerminal,\\n IJBFeeHoldingTerminal\\n{\\n event AddToBalance(\\n uint256 indexed projectId,\\n uint256 amount,\\n uint256 refundedFees,\\n string memo,\\n bytes metadata,\\n address caller\\n );\\n\\n event Migrate(\\n uint256 indexed projectId,\\n IJBPaymentTerminal indexed to,\\n uint256 amount,\\n address caller\\n );\\n\\n event DistributePayouts(\\n uint256 indexed fundingCycleConfiguration,\\n uint256 indexed fundingCycleNumber,\\n uint256 indexed projectId,\\n address beneficiary,\\n uint256 amount,\\n uint256 distributedAmount,\\n uint256 fee,\\n uint256 beneficiaryDistributionAmount,\\n bytes metadata,\\n address caller\\n );\\n\\n event UseAllowance(\\n uint256 indexed fundingCycleConfiguration,\\n uint256 indexed fundingCycleNumber,\\n uint256 indexed projectId,\\n address beneficiary,\\n uint256 amount,\\n uint256 distributedAmount,\\n uint256 netDistributedamount,\\n string memo,\\n bytes metadata,\\n address caller\\n );\\n\\n event HoldFee(\\n uint256 indexed projectId,\\n uint256 indexed amount,\\n uint256 indexed fee,\\n uint256 feeDiscount,\\n address beneficiary,\\n address caller\\n );\\n\\n event ProcessFee(\\n uint256 indexed projectId,\\n uint256 indexed amount,\\n bool indexed wasHeld,\\n address beneficiary,\\n address caller\\n );\\n\\n event RefundHeldFees(\\n uint256 indexed projectId,\\n uint256 indexed amount,\\n uint256 indexed refundedFees,\\n uint256 leftoverAmount,\\n address caller\\n );\\n\\n event Pay(\\n uint256 indexed fundingCycleConfiguration,\\n uint256 indexed fundingCycleNumber,\\n uint256 indexed projectId,\\n address payer,\\n address beneficiary,\\n uint256 amount,\\n uint256 beneficiaryTokenCount,\\n string memo,\\n bytes metadata,\\n address caller\\n );\\n\\n event DelegateDidPay(\\n IJBPayDelegate indexed delegate,\\n JBDidPayData data,\\n uint256 delegatedAmount,\\n address caller\\n );\\n\\n event RedeemTokens(\\n uint256 indexed fundingCycleConfiguration,\\n uint256 indexed fundingCycleNumber,\\n uint256 indexed projectId,\\n address holder,\\n address beneficiary,\\n uint256 tokenCount,\\n uint256 reclaimedAmount,\\n string memo,\\n bytes metadata,\\n address caller\\n );\\n\\n event DelegateDidRedeem(\\n IJBRedemptionDelegate indexed delegate,\\n JBDidRedeemData data,\\n uint256 delegatedAmount,\\n address caller\\n );\\n\\n event DistributeToPayoutSplit(\\n uint256 indexed projectId,\\n uint256 indexed domain,\\n uint256 indexed group,\\n JBSplit split,\\n uint256 amount,\\n uint256 netAmount,\\n address caller\\n );\\n\\n event SetFee(uint256 fee, address caller);\\n\\n event SetFeeGauge(address indexed feeGauge, address caller);\\n\\n event SetFeelessAddress(address indexed addrs, bool indexed flag, address caller);\\n\\n event PayoutReverted(\\n uint256 indexed projectId,\\n JBSplit split,\\n uint256 amount,\\n bytes reason,\\n address caller\\n );\\n\\n event FeeReverted(\\n uint256 indexed projectId,\\n uint256 indexed feeProjectId,\\n uint256 amount,\\n bytes reason,\\n address caller\\n );\\n\\n function projects() external view returns (IJBProjects);\\n\\n function splitsStore() external view returns (IJBSplitsStore);\\n\\n function directory() external view returns (IJBDirectory);\\n\\n function prices() external view returns (IJBPrices);\\n\\n function store() external view returns (address);\\n\\n function baseWeightCurrency() external view returns (uint256);\\n\\n function payoutSplitsGroup() external view returns (uint256);\\n\\n function heldFeesOf(uint256 projectId) external view returns (JBFee[] memory);\\n\\n function fee() external view returns (uint256);\\n\\n function feeGauge() external view returns (address);\\n\\n function isFeelessAddress(address account) external view returns (bool);\\n\\n function migrate(uint256 projectId, IJBPaymentTerminal to) external returns (uint256 balance);\\n\\n function processFees(uint256 projectId) external;\\n\\n function setFee(uint256 fee) external;\\n\\n function setFeeGauge(address feeGauge) external;\\n\\n function setFeelessAddress(address account, bool flag) external;\\n}\\n\",\"keccak256\":\"0xa96558c3623b7a9e71df7a6034af14b9e3bbd34cdc02c9b36136eb1b4b88da00\",\"license\":\"MIT\"},\"contracts/interfaces/IJBPayoutRedemptionPaymentTerminal3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBFee} from './../structs/JBFee.sol';\\nimport {JBDidRedeemData3_1_1} from './../structs/JBDidRedeemData3_1_1.sol';\\nimport {JBDidPayData3_1_1} from './../structs/JBDidPayData3_1_1.sol';\\nimport {IJBPayDelegate3_1_1} from './IJBPayDelegate3_1_1.sol';\\nimport {IJBRedemptionDelegate3_1_1} from './IJBRedemptionDelegate3_1_1.sol';\\n\\ninterface IJBPayoutRedemptionPaymentTerminal3_1_1 {\\n event DelegateDidRedeem(\\n IJBRedemptionDelegate3_1_1 indexed delegate,\\n JBDidRedeemData3_1_1 data,\\n uint256 delegatedAmount,\\n uint256 fee,\\n address caller\\n );\\n\\n event DelegateDidPay(\\n IJBPayDelegate3_1_1 indexed delegate,\\n JBDidPayData3_1_1 data,\\n uint256 delegatedAmount,\\n address caller\\n );\\n}\\n\",\"keccak256\":\"0x66908701a06aa3b692a75873567cb14f4c9999ed6c42519ae5564a643fd65f15\",\"license\":\"MIT\"},\"contracts/interfaces/IJBPayoutTerminal3_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IJBPayoutTerminal3_1 {\\n function distributePayoutsOf(\\n uint256 projectId,\\n uint256 amount,\\n uint256 currency,\\n address token,\\n uint256 minReturnedTokens,\\n bytes calldata metadata\\n ) external returns (uint256 netLeftoverDistributionAmount);\\n}\\n\",\"keccak256\":\"0x2e0b8c37a451f1723296af656bd4982d4e5339ce76061eb63bb5f57b235bdc44\",\"license\":\"MIT\"},\"contracts/interfaces/IJBPriceFeed.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IJBPriceFeed {\\n function currentPrice(uint256 targetDecimals) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0x9328b2b52bc112641f3a6167c8cf242831a52c85016ce1310626bdc3489bded7\",\"license\":\"MIT\"},\"contracts/interfaces/IJBPrices.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBPriceFeed} from './IJBPriceFeed.sol';\\n\\ninterface IJBPrices {\\n event AddFeed(uint256 indexed currency, uint256 indexed base, IJBPriceFeed feed);\\n\\n function feedFor(uint256 currency, uint256 base) external view returns (IJBPriceFeed);\\n\\n function priceFor(\\n uint256 currency,\\n uint256 base,\\n uint256 decimals\\n ) external view returns (uint256);\\n\\n function addFeedFor(uint256 currency, uint256 base, IJBPriceFeed priceFeed) external;\\n}\\n\",\"keccak256\":\"0xc1623499fa541b15891e27a59288e03360ce78c7933d28bf575b48b68ce4981c\",\"license\":\"MIT\"},\"contracts/interfaces/IJBProjects.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC721} from '@openzeppelin/contracts/token/ERC721/IERC721.sol';\\nimport {JBProjectMetadata} from './../structs/JBProjectMetadata.sol';\\nimport {IJBTokenUriResolver} from './IJBTokenUriResolver.sol';\\n\\ninterface IJBProjects is IERC721 {\\n event Create(\\n uint256 indexed projectId,\\n address indexed owner,\\n JBProjectMetadata metadata,\\n address caller\\n );\\n\\n event SetMetadata(uint256 indexed projectId, JBProjectMetadata metadata, address caller);\\n\\n event SetTokenUriResolver(IJBTokenUriResolver indexed resolver, address caller);\\n\\n function count() external view returns (uint256);\\n\\n function metadataContentOf(\\n uint256 projectId,\\n uint256 domain\\n ) external view returns (string memory);\\n\\n function tokenUriResolver() external view returns (IJBTokenUriResolver);\\n\\n function createFor(\\n address owner,\\n JBProjectMetadata calldata metadata\\n ) external returns (uint256 projectId);\\n\\n function setMetadataOf(uint256 projectId, JBProjectMetadata calldata metadata) external;\\n\\n function setTokenUriResolver(IJBTokenUriResolver newResolver) external;\\n}\\n\",\"keccak256\":\"0x00235f20975e6a9465ac921076c85125a3834e29893f93f93e287a89f9e6b915\",\"license\":\"MIT\"},\"contracts/interfaces/IJBRedemptionDelegate.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\\nimport {JBDidRedeemData} from './../structs/JBDidRedeemData.sol';\\n\\n/// @title Redemption delegate\\n/// @notice Delegate called after JBTerminal.redeemTokensOf(..) logic completion (if passed by the funding cycle datasource)\\ninterface IJBRedemptionDelegate is IERC165 {\\n /// @notice This function is called by JBPaymentTerminal.redeemTokensOf(..), after the execution of its logic\\n /// @dev Critical business logic should be protected by an appropriate access control\\n /// @param data the data passed by the terminal, as a JBDidRedeemData struct:\\n function didRedeem(JBDidRedeemData calldata data) external payable;\\n}\\n\",\"keccak256\":\"0xd70f498197187982962b9e6a5b7572bb6b2c524228a267b01758f7e50a827387\",\"license\":\"MIT\"},\"contracts/interfaces/IJBRedemptionDelegate3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\\nimport {JBDidRedeemData3_1_1} from './../structs/JBDidRedeemData3_1_1.sol';\\n\\n/// @title Redemption delegate\\n/// @notice Delegate called after JBTerminal.redeemTokensOf(..) logic completion (if passed by the funding cycle datasource)\\ninterface IJBRedemptionDelegate3_1_1 is IERC165 {\\n /// @notice This function is called by JBPaymentTerminal.redeemTokensOf(..), after the execution of its logic\\n /// @dev Critical business logic should be protected by an appropriate access control\\n /// @param data the data passed by the terminal, as a JBDidRedeemData struct:\\n function didRedeem(JBDidRedeemData3_1_1 calldata data) external payable;\\n}\\n\",\"keccak256\":\"0x6034773b78e98902625563bd176a97267e729cb5205d25b06e8a2262b131c0d8\",\"license\":\"MIT\"},\"contracts/interfaces/IJBRedemptionTerminal.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IJBRedemptionTerminal {\\n function redeemTokensOf(\\n address holder,\\n uint256 projectId,\\n uint256 tokenCount,\\n address token,\\n uint256 minReturnedTokens,\\n address payable beneficiary,\\n string calldata memo,\\n bytes calldata metadata\\n ) external returns (uint256 reclaimAmount);\\n}\\n\",\"keccak256\":\"0x5e6bbbfe81a6cc151ca7e7ce603e4adb861ba8eb0bd4a35a9f12e29795b161f5\",\"license\":\"MIT\"},\"contracts/interfaces/IJBSingleTokenPaymentTerminal.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\\n\\ninterface IJBSingleTokenPaymentTerminal is IJBPaymentTerminal {\\n function token() external view returns (address);\\n\\n function currency() external view returns (uint256);\\n\\n function decimals() external view returns (uint256);\\n}\\n\",\"keccak256\":\"0x8e00670c66dea368dc523615425c2a79fcee10ec3c3355bf94feb82638172b3f\",\"license\":\"MIT\"},\"contracts/interfaces/IJBSingleTokenPaymentTerminalStore3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\\nimport {JBPayDelegateAllocation3_1_1} from './../structs/JBPayDelegateAllocation3_1_1.sol';\\nimport {JBRedemptionDelegateAllocation3_1_1} from './../structs/JBRedemptionDelegateAllocation3_1_1.sol';\\nimport {JBTokenAmount} from './../structs/JBTokenAmount.sol';\\nimport {IJBDirectory} from './IJBDirectory.sol';\\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\\nimport {IJBPrices} from './IJBPrices.sol';\\nimport {IJBSingleTokenPaymentTerminal} from './IJBSingleTokenPaymentTerminal.sol';\\n\\ninterface IJBSingleTokenPaymentTerminalStore3_1_1 {\\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\\n\\n function directory() external view returns (IJBDirectory);\\n\\n function prices() external view returns (IJBPrices);\\n\\n function balanceOf(\\n IJBSingleTokenPaymentTerminal terminal,\\n uint256 projectId\\n ) external view returns (uint256);\\n\\n function usedDistributionLimitOf(\\n IJBSingleTokenPaymentTerminal terminal,\\n uint256 projectId,\\n uint256 fundingCycleNumber\\n ) external view returns (uint256);\\n\\n function usedOverflowAllowanceOf(\\n IJBSingleTokenPaymentTerminal terminal,\\n uint256 projectId,\\n uint256 fundingCycleConfiguration\\n ) external view returns (uint256);\\n\\n function currentOverflowOf(\\n IJBSingleTokenPaymentTerminal terminal,\\n uint256 projectId\\n ) external view returns (uint256);\\n\\n function currentTotalOverflowOf(\\n uint256 projectId,\\n uint256 decimals,\\n uint256 currency\\n ) external view returns (uint256);\\n\\n function currentReclaimableOverflowOf(\\n IJBSingleTokenPaymentTerminal terminal,\\n uint256 projectId,\\n uint256 tokenCount,\\n bool useTotalOverflow\\n ) external view returns (uint256);\\n\\n function currentReclaimableOverflowOf(\\n uint256 projectId,\\n uint256 tokenCount,\\n uint256 totalSupply,\\n uint256 overflow\\n ) external view returns (uint256);\\n\\n function recordPaymentFrom(\\n address payer,\\n JBTokenAmount memory amount,\\n uint256 projectId,\\n uint256 baseWeightCurrency,\\n address beneficiary,\\n string calldata inputMemo,\\n bytes calldata metadata\\n )\\n external\\n returns (\\n JBFundingCycle memory fundingCycle,\\n uint256 tokenCount,\\n JBPayDelegateAllocation3_1_1[] memory delegateAllocations,\\n string memory outputMemo\\n );\\n\\n function recordRedemptionFor(\\n address holder,\\n uint256 projectId,\\n uint256 tokenCount,\\n string calldata inputMemo,\\n bytes calldata metadata\\n )\\n external\\n returns (\\n JBFundingCycle memory fundingCycle,\\n uint256 reclaimAmount,\\n JBRedemptionDelegateAllocation3_1_1[] memory delegateAllocations,\\n string memory outputMemo\\n );\\n\\n function recordDistributionFor(\\n uint256 projectId,\\n uint256 amount,\\n uint256 currency\\n ) external returns (JBFundingCycle memory fundingCycle, uint256 distributedAmount);\\n\\n function recordUsedAllowanceOf(\\n uint256 projectId,\\n uint256 amount,\\n uint256 currency\\n ) external returns (JBFundingCycle memory fundingCycle, uint256 withdrawnAmount);\\n\\n function recordAddedBalanceFor(uint256 projectId, uint256 amount) external;\\n\\n function recordMigration(uint256 projectId) external returns (uint256 balance);\\n}\\n\",\"keccak256\":\"0xf009c9fb787cda2a18805b9a9e2105c7f1309ade1eac3af229816cfd27ba1d64\",\"license\":\"MIT\"},\"contracts/interfaces/IJBSplitAllocator.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\\nimport {JBSplitAllocationData} from '../structs/JBSplitAllocationData.sol';\\n\\n/// @title Split allocator\\n/// @notice Provide a way to process a single split with extra logic\\n/// @dev The contract address should be set as an allocator in the adequate split\\ninterface IJBSplitAllocator is IERC165 {\\n /// @notice This function is called by JBPaymentTerminal.distributePayoutOf(..), during the processing of the split including it\\n /// @dev Critical business logic should be protected by an appropriate access control. The token and/or eth are optimistically transfered to the allocator for its logic.\\n /// @param data the data passed by the terminal, as a JBSplitAllocationData struct:\\n function allocate(JBSplitAllocationData calldata data) external payable;\\n}\\n\",\"keccak256\":\"0x1643b444409d91858eb86f67abf3d757d2deb3ccd7265eb8e68d6ffdac083de6\",\"license\":\"MIT\"},\"contracts/interfaces/IJBSplitsStore.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBGroupedSplits} from './../structs/JBGroupedSplits.sol';\\nimport {JBSplit} from './../structs/JBSplit.sol';\\nimport {IJBDirectory} from './IJBDirectory.sol';\\nimport {IJBProjects} from './IJBProjects.sol';\\n\\ninterface IJBSplitsStore {\\n event SetSplit(\\n uint256 indexed projectId,\\n uint256 indexed domain,\\n uint256 indexed group,\\n JBSplit split,\\n address caller\\n );\\n\\n function projects() external view returns (IJBProjects);\\n\\n function directory() external view returns (IJBDirectory);\\n\\n function splitsOf(\\n uint256 projectId,\\n uint256 domain,\\n uint256 group\\n ) external view returns (JBSplit[] memory);\\n\\n function set(uint256 projectId, uint256 domain, JBGroupedSplits[] memory groupedSplits) external;\\n}\\n\",\"keccak256\":\"0x3ce0eb12f10282481a3bf86e62b368bcff254081088cfabb20353d60cfadbc7a\",\"license\":\"MIT\"},\"contracts/interfaces/IJBToken.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IJBToken {\\n function projectId() external view returns (uint256);\\n\\n function decimals() external view returns (uint8);\\n\\n function totalSupply(uint256 projectId) external view returns (uint256);\\n\\n function balanceOf(address account, uint256 projectId) external view returns (uint256);\\n\\n function mint(uint256 projectId, address account, uint256 amount) external;\\n\\n function burn(uint256 projectId, address account, uint256 amount) external;\\n\\n function approve(uint256, address spender, uint256 amount) external;\\n\\n function transfer(uint256 projectId, address to, uint256 amount) external;\\n\\n function transferFrom(uint256 projectId, address from, address to, uint256 amount) external;\\n}\\n\",\"keccak256\":\"0xeefe58d140e4e13f255d5c7c5cdf5ba66dd00835f04015c446ff224f8ad14c34\",\"license\":\"MIT\"},\"contracts/interfaces/IJBTokenStore.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\\nimport {IJBProjects} from './IJBProjects.sol';\\nimport {IJBToken} from './IJBToken.sol';\\n\\ninterface IJBTokenStore {\\n event Issue(\\n uint256 indexed projectId,\\n IJBToken indexed token,\\n string name,\\n string symbol,\\n address caller\\n );\\n\\n event Mint(\\n address indexed holder,\\n uint256 indexed projectId,\\n uint256 amount,\\n bool tokensWereClaimed,\\n bool preferClaimedTokens,\\n address caller\\n );\\n\\n event Burn(\\n address indexed holder,\\n uint256 indexed projectId,\\n uint256 amount,\\n uint256 initialUnclaimedBalance,\\n uint256 initialClaimedBalance,\\n bool preferClaimedTokens,\\n address caller\\n );\\n\\n event Claim(\\n address indexed holder,\\n uint256 indexed projectId,\\n uint256 initialUnclaimedBalance,\\n uint256 amount,\\n address caller\\n );\\n\\n event Set(uint256 indexed projectId, IJBToken indexed newToken, address caller);\\n\\n event Transfer(\\n address indexed holder,\\n uint256 indexed projectId,\\n address indexed recipient,\\n uint256 amount,\\n address caller\\n );\\n\\n function tokenOf(uint256 projectId) external view returns (IJBToken);\\n\\n function projects() external view returns (IJBProjects);\\n\\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\\n\\n function unclaimedBalanceOf(address holder, uint256 projectId) external view returns (uint256);\\n\\n function unclaimedTotalSupplyOf(uint256 projectId) external view returns (uint256);\\n\\n function totalSupplyOf(uint256 projectId) external view returns (uint256);\\n\\n function balanceOf(address holder, uint256 projectId) external view returns (uint256 result);\\n\\n function issueFor(\\n uint256 projectId,\\n string calldata name,\\n string calldata symbol\\n ) external returns (IJBToken token);\\n\\n function setFor(uint256 projectId, IJBToken token) external;\\n\\n function burnFrom(\\n address holder,\\n uint256 projectId,\\n uint256 amount,\\n bool preferClaimedTokens\\n ) external;\\n\\n function mintFor(\\n address holder,\\n uint256 projectId,\\n uint256 amount,\\n bool preferClaimedTokens\\n ) external;\\n\\n function claimFor(address holder, uint256 projectId, uint256 amount) external;\\n\\n function transferFrom(\\n address holder,\\n uint256 projectId,\\n address recipient,\\n uint256 amount\\n ) external;\\n}\\n\",\"keccak256\":\"0x4db7bb4fe824dc9bfbc997ea3e07f42be8900bcad4e0b991e726c23c2de84ba4\",\"license\":\"MIT\"},\"contracts/interfaces/IJBTokenUriResolver.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IJBTokenUriResolver {\\n function getUri(uint256 projectId) external view returns (string memory tokenUri);\\n}\\n\",\"keccak256\":\"0xc7c9537184a1a36bc30874e5ac29b0fbccf45a99d40806837cfe30d6d9a1c84a\",\"license\":\"MIT\"},\"contracts/libraries/JBConstants.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/// @notice Global constants used across Juicebox contracts.\\nlibrary JBConstants {\\n uint256 public constant MAX_RESERVED_RATE = 10_000;\\n uint256 public constant MAX_REDEMPTION_RATE = 10_000;\\n uint256 public constant MAX_DISCOUNT_RATE = 1_000_000_000;\\n uint256 public constant SPLITS_TOTAL_PERCENT = 1_000_000_000;\\n uint256 public constant MAX_FEE = 1_000_000_000;\\n uint256 public constant MAX_FEE_DISCOUNT = 1_000_000_000;\\n}\\n\",\"keccak256\":\"0x7f2741e86062c5019f51d7e1a7b192ec1880d7e15a9a1589362ae7424de3003b\",\"license\":\"MIT\"},\"contracts/libraries/JBCurrencies.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nlibrary JBCurrencies {\\n uint256 public constant ETH = 1;\\n uint256 public constant USD = 2;\\n}\\n\",\"keccak256\":\"0x7e417ff25c173608ee4fe6d9fc3dcd5e1458c78c889af12bac47b1189a436076\",\"license\":\"MIT\"},\"contracts/libraries/JBFixedPointNumber.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.16;\\n\\nlibrary JBFixedPointNumber {\\n function adjustDecimals(\\n uint256 _value,\\n uint256 _decimals,\\n uint256 _targetDecimals\\n ) internal pure returns (uint256) {\\n // If decimals need adjusting, multiply or divide the price by the decimal adjuster to get the normalized result.\\n if (_targetDecimals == _decimals) return _value;\\n else if (_targetDecimals > _decimals) return _value * 10**(_targetDecimals - _decimals);\\n else return _value / 10**(_decimals - _targetDecimals);\\n }\\n}\\n\",\"keccak256\":\"0x18efac48269f3a3bd7e9a1c770776f950e0afa86769e6f8b128002c3b8c6742c\",\"license\":\"MIT\"},\"contracts/libraries/JBFundingCycleMetadataResolver.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.16;\\n\\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\\nimport {JBFundingCycleMetadata} from './../structs/JBFundingCycleMetadata.sol';\\nimport {JBGlobalFundingCycleMetadata} from './../structs/JBGlobalFundingCycleMetadata.sol';\\nimport {JBConstants} from './JBConstants.sol';\\nimport {JBGlobalFundingCycleMetadataResolver} from './JBGlobalFundingCycleMetadataResolver.sol';\\n\\nlibrary JBFundingCycleMetadataResolver {\\n function global(JBFundingCycle memory _fundingCycle)\\n internal\\n pure\\n returns (JBGlobalFundingCycleMetadata memory)\\n {\\n return JBGlobalFundingCycleMetadataResolver.expandMetadata(uint8(_fundingCycle.metadata >> 8));\\n }\\n\\n function reservedRate(JBFundingCycle memory _fundingCycle) internal pure returns (uint256) {\\n return uint256(uint16(_fundingCycle.metadata >> 24));\\n }\\n\\n function redemptionRate(JBFundingCycle memory _fundingCycle) internal pure returns (uint256) {\\n // Redemption rate is a number 0-10000. It's inverse was stored so the most common case of 100% results in no storage needs.\\n return JBConstants.MAX_REDEMPTION_RATE - uint256(uint16(_fundingCycle.metadata >> 40));\\n }\\n\\n function ballotRedemptionRate(JBFundingCycle memory _fundingCycle)\\n internal\\n pure\\n returns (uint256)\\n {\\n // Redemption rate is a number 0-10000. It's inverse was stored so the most common case of 100% results in no storage needs.\\n return JBConstants.MAX_REDEMPTION_RATE - uint256(uint16(_fundingCycle.metadata >> 56));\\n }\\n\\n function payPaused(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\\n return ((_fundingCycle.metadata >> 72) & 1) == 1;\\n }\\n\\n function distributionsPaused(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\\n return ((_fundingCycle.metadata >> 73) & 1) == 1;\\n }\\n\\n function redeemPaused(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\\n return ((_fundingCycle.metadata >> 74) & 1) == 1;\\n }\\n\\n function burnPaused(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\\n return ((_fundingCycle.metadata >> 75) & 1) == 1;\\n }\\n\\n function mintingAllowed(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\\n return ((_fundingCycle.metadata >> 76) & 1) == 1;\\n }\\n\\n function terminalMigrationAllowed(JBFundingCycle memory _fundingCycle)\\n internal\\n pure\\n returns (bool)\\n {\\n return ((_fundingCycle.metadata >> 77) & 1) == 1;\\n }\\n\\n function controllerMigrationAllowed(JBFundingCycle memory _fundingCycle)\\n internal\\n pure\\n returns (bool)\\n {\\n return ((_fundingCycle.metadata >> 78) & 1) == 1;\\n }\\n\\n function shouldHoldFees(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\\n return ((_fundingCycle.metadata >> 79) & 1) == 1;\\n }\\n\\n function preferClaimedTokenOverride(JBFundingCycle memory _fundingCycle)\\n internal\\n pure\\n returns (bool)\\n {\\n return ((_fundingCycle.metadata >> 80) & 1) == 1;\\n }\\n\\n function useTotalOverflowForRedemptions(JBFundingCycle memory _fundingCycle)\\n internal\\n pure\\n returns (bool)\\n {\\n return ((_fundingCycle.metadata >> 81) & 1) == 1;\\n }\\n\\n function useDataSourceForPay(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\\n return (_fundingCycle.metadata >> 82) & 1 == 1;\\n }\\n\\n function useDataSourceForRedeem(JBFundingCycle memory _fundingCycle)\\n internal\\n pure\\n returns (bool)\\n {\\n return (_fundingCycle.metadata >> 83) & 1 == 1;\\n }\\n\\n function dataSource(JBFundingCycle memory _fundingCycle) internal pure returns (address) {\\n return address(uint160(_fundingCycle.metadata >> 84));\\n }\\n\\n function metadata(JBFundingCycle memory _fundingCycle) internal pure returns (uint256) {\\n return uint256(uint8(_fundingCycle.metadata >> 244));\\n }\\n\\n /// @notice Pack the funding cycle metadata.\\n /// @param _metadata The metadata to validate and pack.\\n /// @return packed The packed uint256 of all metadata params. The first 8 bits specify the version. \\n function packFundingCycleMetadata(JBFundingCycleMetadata memory _metadata)\\n internal\\n pure\\n returns (uint256 packed)\\n {\\n // version 1 in the bits 0-7 (8 bits).\\n packed = 1;\\n // global metadta in bits 8-23 (16 bits).\\n packed |=\\n JBGlobalFundingCycleMetadataResolver.packFundingCycleGlobalMetadata(_metadata.global) <<\\n 8;\\n // reserved rate in bits 24-39 (16 bits).\\n packed |= _metadata.reservedRate << 24;\\n // redemption rate in bits 40-55 (16 bits).\\n // redemption rate is a number 0-10000. Store the reverse so the most common case of 100% results in no storage needs.\\n packed |= (JBConstants.MAX_REDEMPTION_RATE - _metadata.redemptionRate) << 40;\\n // ballot redemption rate rate in bits 56-71 (16 bits).\\n // ballot redemption rate is a number 0-10000. Store the reverse so the most common case of 100% results in no storage needs.\\n packed |= (JBConstants.MAX_REDEMPTION_RATE - _metadata.ballotRedemptionRate) << 56;\\n // pause pay in bit 72.\\n if (_metadata.pausePay) packed |= 1 << 72;\\n // pause tap in bit 73.\\n if (_metadata.pauseDistributions) packed |= 1 << 73;\\n // pause redeem in bit 74.\\n if (_metadata.pauseRedeem) packed |= 1 << 74;\\n // pause burn in bit 75.\\n if (_metadata.pauseBurn) packed |= 1 << 75;\\n // allow minting in bit 76.\\n if (_metadata.allowMinting) packed |= 1 << 76;\\n // allow terminal migration in bit 77.\\n if (_metadata.allowTerminalMigration) packed |= 1 << 77;\\n // allow controller migration in bit 78.\\n if (_metadata.allowControllerMigration) packed |= 1 << 78;\\n // hold fees in bit 79.\\n if (_metadata.holdFees) packed |= 1 << 79;\\n // prefer claimed token override in bit 80.\\n if (_metadata.preferClaimedTokenOverride) packed |= 1 << 80;\\n // useTotalOverflowForRedemptions in bit 81.\\n if (_metadata.useTotalOverflowForRedemptions) packed |= 1 << 81;\\n // use pay data source in bit 82.\\n if (_metadata.useDataSourceForPay) packed |= 1 << 82;\\n // use redeem data source in bit 83.\\n if (_metadata.useDataSourceForRedeem) packed |= 1 << 83;\\n // data source address in bits 84-243.\\n packed |= uint256(uint160(address(_metadata.dataSource))) << 84;\\n // metadata in bits 244-252 (8 bits).\\n packed |= _metadata.metadata << 244;\\n }\\n\\n /// @notice Expand the funding cycle metadata.\\n /// @param _fundingCycle The funding cycle having its metadata expanded.\\n /// @return metadata The metadata object. \\n function expandMetadata(JBFundingCycle memory _fundingCycle)\\n internal\\n pure\\n returns (JBFundingCycleMetadata memory)\\n {\\n return\\n JBFundingCycleMetadata(\\n global(_fundingCycle),\\n reservedRate(_fundingCycle),\\n redemptionRate(_fundingCycle),\\n ballotRedemptionRate(_fundingCycle),\\n payPaused(_fundingCycle),\\n distributionsPaused(_fundingCycle),\\n redeemPaused(_fundingCycle),\\n burnPaused(_fundingCycle),\\n mintingAllowed(_fundingCycle),\\n terminalMigrationAllowed(_fundingCycle),\\n controllerMigrationAllowed(_fundingCycle),\\n shouldHoldFees(_fundingCycle),\\n preferClaimedTokenOverride(_fundingCycle),\\n useTotalOverflowForRedemptions(_fundingCycle),\\n useDataSourceForPay(_fundingCycle),\\n useDataSourceForRedeem(_fundingCycle),\\n dataSource(_fundingCycle),\\n metadata(_fundingCycle)\\n );\\n }\\n}\\n\",\"keccak256\":\"0xedb0b93d5578ca5a21ab55f65274e441513bce982b04ffc76f26e627abfbbe0c\",\"license\":\"MIT\"},\"contracts/libraries/JBGlobalFundingCycleMetadataResolver.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.16;\\n\\nimport {JBFundingCycleMetadata} from './../structs/JBFundingCycleMetadata.sol';\\nimport {JBGlobalFundingCycleMetadata} from './../structs/JBGlobalFundingCycleMetadata.sol';\\n\\nlibrary JBGlobalFundingCycleMetadataResolver {\\n function setTerminalsAllowed(uint8 _data) internal pure returns (bool) {\\n return (_data & 1) == 1;\\n }\\n\\n function setControllerAllowed(uint8 _data) internal pure returns (bool) {\\n return ((_data >> 1) & 1) == 1;\\n }\\n\\n function transfersPaused(uint8 _data) internal pure returns (bool) {\\n return ((_data >> 2) & 1) == 1;\\n }\\n\\n /// @notice Pack the global funding cycle metadata.\\n /// @param _metadata The metadata to validate and pack.\\n /// @return packed The packed uint256 of all global metadata params. The first 8 bits specify the version.\\n function packFundingCycleGlobalMetadata(\\n JBGlobalFundingCycleMetadata memory _metadata\\n ) internal pure returns (uint256 packed) {\\n // allow set terminals in bit 0.\\n if (_metadata.allowSetTerminals) packed |= 1;\\n // allow set controller in bit 1.\\n if (_metadata.allowSetController) packed |= 1 << 1;\\n // pause transfers in bit 2.\\n if (_metadata.pauseTransfers) packed |= 1 << 2;\\n }\\n\\n /// @notice Expand the global funding cycle metadata.\\n /// @param _packedMetadata The packed metadata to expand.\\n /// @return metadata The global metadata object.\\n function expandMetadata(\\n uint8 _packedMetadata\\n ) internal pure returns (JBGlobalFundingCycleMetadata memory metadata) {\\n return\\n JBGlobalFundingCycleMetadata(\\n setTerminalsAllowed(_packedMetadata),\\n setControllerAllowed(_packedMetadata),\\n transfersPaused(_packedMetadata)\\n );\\n }\\n}\\n\",\"keccak256\":\"0x8a016001787db05e3bbd442db7eaa3f49f1d3a3210d2b5c6e52254a241f3b161\",\"license\":\"MIT\"},\"contracts/libraries/JBOperations.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nlibrary JBOperations {\\n uint256 public constant RECONFIGURE = 1;\\n uint256 public constant REDEEM = 2;\\n uint256 public constant MIGRATE_CONTROLLER = 3;\\n uint256 public constant MIGRATE_TERMINAL = 4;\\n uint256 public constant PROCESS_FEES = 5;\\n uint256 public constant SET_METADATA = 6;\\n uint256 public constant ISSUE = 7;\\n uint256 public constant SET_TOKEN = 8;\\n uint256 public constant MINT = 9;\\n uint256 public constant BURN = 10;\\n uint256 public constant CLAIM = 11;\\n uint256 public constant TRANSFER = 12;\\n uint256 public constant REQUIRE_CLAIM = 13; // unused in v3\\n uint256 public constant SET_CONTROLLER = 14;\\n uint256 public constant SET_TERMINALS = 15;\\n uint256 public constant SET_PRIMARY_TERMINAL = 16;\\n uint256 public constant USE_ALLOWANCE = 17;\\n uint256 public constant SET_SPLITS = 18;\\n}\\n\",\"keccak256\":\"0x7f8e501e6890297f4015b1c27cebdb44fadbf21204bea1f3162f5388c060f690\",\"license\":\"MIT\"},\"contracts/libraries/JBSplitsGroups.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nlibrary JBSplitsGroups {\\n uint256 public constant ETH_PAYOUT = 1;\\n uint256 public constant RESERVED_TOKENS = 2;\\n}\\n\",\"keccak256\":\"0x4183db6087bd8db645fc3a0d3d8afb0d6356e003650793f63c301ebbbae47269\",\"license\":\"MIT\"},\"contracts/libraries/JBTokens.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nlibrary JBTokens {\\n /// @notice The ETH token address in Juicebox is represented by 0x000000000000000000000000000000000000EEEe.\\n address public constant ETH = address(0x000000000000000000000000000000000000EEEe);\\n}\\n\",\"keccak256\":\"0x9e724a7e65c6d6e01e7f0c1419d750307ed6ce8bc29bbd959e029bcdd4b4e479\",\"license\":\"MIT\"},\"contracts/structs/JBDidPayData.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBTokenAmount} from './JBTokenAmount.sol';\\n\\n/// @custom:member payer The address from which the payment originated.\\n/// @custom:member projectId The ID of the project for which the payment was made.\\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the payment is being made.\\n/// @custom:member amount The amount of the payment. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\\n/// @custom:member forwardedAmount The amount of the payment that is being sent to the delegate. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\\n/// @custom:member projectTokenCount The number of project tokens minted for the beneficiary.\\n/// @custom:member beneficiary The address to which the tokens were minted.\\n/// @custom:member preferClaimedTokens A flag indicating whether the request prefered to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract.\\n/// @custom:member memo The memo that is being emitted alongside the payment.\\n/// @custom:member metadata Extra data to send to the delegate.\\nstruct JBDidPayData {\\n address payer;\\n uint256 projectId;\\n uint256 currentFundingCycleConfiguration;\\n JBTokenAmount amount;\\n JBTokenAmount forwardedAmount;\\n uint256 projectTokenCount;\\n address beneficiary;\\n bool preferClaimedTokens;\\n string memo;\\n bytes metadata;\\n}\\n\",\"keccak256\":\"0x235e117009bfb825d14c5433fa46f777fa512400df74e76290e869d4c3d8b26e\",\"license\":\"MIT\"},\"contracts/structs/JBDidPayData3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBTokenAmount} from './JBTokenAmount.sol';\\n\\n/// @custom:member payer The address from which the payment originated.\\n/// @custom:member projectId The ID of the project for which the payment was made.\\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the payment is being made.\\n/// @custom:member amount The amount of the payment. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\\n/// @custom:member forwardedAmount The amount of the payment that is being sent to the delegate. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\\n/// @custom:member projectTokenCount The number of project tokens minted for the beneficiary.\\n/// @custom:member beneficiary The address to which the tokens were minted.\\n/// @custom:member preferClaimedTokens A flag indicating whether the request prefered to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract.\\n/// @custom:member memo The memo that is being emitted alongside the payment.\\n/// @custom:member dataSourceMetadata Extra data to send to the delegate sent by the data source.\\n/// @custom:member payerMetadata Extra data to send to the delegate sent by the payer.\\nstruct JBDidPayData3_1_1 {\\n address payer;\\n uint256 projectId;\\n uint256 currentFundingCycleConfiguration;\\n JBTokenAmount amount;\\n JBTokenAmount forwardedAmount;\\n uint256 projectTokenCount;\\n address beneficiary;\\n bool preferClaimedTokens;\\n string memo;\\n bytes dataSourceMetadata;\\n bytes payerMetadata;\\n}\\n\",\"keccak256\":\"0x2e659555149ff14c045b749b1d1a3156b8296ab08375ac2abec92afc43bf3acf\",\"license\":\"MIT\"},\"contracts/structs/JBDidRedeemData.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBTokenAmount} from './JBTokenAmount.sol';\\n\\n/// @custom:member holder The holder of the tokens being redeemed.\\n/// @custom:member projectId The ID of the project with which the redeemed tokens are associated.\\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the redemption is being made.\\n/// @custom:member projectTokenCount The number of project tokens being redeemed.\\n/// @custom:member reclaimedAmount The amount reclaimed from the treasury. Includes the token being reclaimed, the value, the number of decimals included, and the currency of the amount.\\n/// @custom:member forwardedAmount The amount of the payment that is being sent to the delegate. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\\n/// @custom:member beneficiary The address to which the reclaimed amount will be sent.\\n/// @custom:member memo The memo that is being emitted alongside the redemption.\\n/// @custom:member metadata Extra data to send to the delegate.\\nstruct JBDidRedeemData {\\n address holder;\\n uint256 projectId;\\n uint256 currentFundingCycleConfiguration;\\n uint256 projectTokenCount;\\n JBTokenAmount reclaimedAmount;\\n JBTokenAmount forwardedAmount;\\n address payable beneficiary;\\n string memo;\\n bytes metadata;\\n}\\n\",\"keccak256\":\"0xee0c3728a39069f5a2a9b25c120739da5cae4c4e6fd0cae371a961a9d1367549\",\"license\":\"MIT\"},\"contracts/structs/JBDidRedeemData3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBTokenAmount} from './JBTokenAmount.sol';\\n\\n/// @custom:member holder The holder of the tokens being redeemed.\\n/// @custom:member projectId The ID of the project with which the redeemed tokens are associated.\\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the redemption is being made.\\n/// @custom:member projectTokenCount The number of project tokens being redeemed.\\n/// @custom:member reclaimedAmount The amount reclaimed from the treasury. Includes the token being reclaimed, the value, the number of decimals included, and the currency of the amount.\\n/// @custom:member forwardedAmount The amount of the payment that is being sent to the delegate. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\\n/// @custom:member beneficiary The address to which the reclaimed amount will be sent.\\n/// @custom:member memo The memo that is being emitted alongside the redemption.\\n/// @custom:member dataSourceMetadata Extra data to send to the delegate sent by the data source.\\n/// @custom:member redeemerMetadata Extra data to send to the delegate sent by the redeemer.\\nstruct JBDidRedeemData3_1_1 {\\n address holder;\\n uint256 projectId;\\n uint256 currentFundingCycleConfiguration;\\n uint256 projectTokenCount;\\n JBTokenAmount reclaimedAmount;\\n JBTokenAmount forwardedAmount;\\n address payable beneficiary;\\n string memo;\\n bytes dataSourceMetadata;\\n bytes redeemerMetadata;\\n}\\n\",\"keccak256\":\"0x23848d41aa179d16e9b7033befd3a855d43f6a009e24030c2ba1bb5b06cb3924\",\"license\":\"MIT\"},\"contracts/structs/JBFee.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/// @custom:member amount The total amount the fee was taken from, as a fixed point number with the same number of decimals as the terminal in which this struct was created.\\n/// @custom:member fee The percent of the fee, out of MAX_FEE.\\n/// @custom:member feeDiscount The discount of the fee.\\n/// @custom:member beneficiary The address that will receive the tokens that are minted as a result of the fee payment.\\nstruct JBFee {\\n uint256 amount;\\n uint32 fee;\\n uint32 feeDiscount;\\n address beneficiary;\\n}\\n\",\"keccak256\":\"0xd105627d21718704db798df0b958e6223fb2d79854e72cda2bfa9eca0630c1f6\",\"license\":\"MIT\"},\"contracts/structs/JBFundAccessConstraints.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\\n\\n/// @custom:member terminal The terminal within which the distribution limit and the overflow allowance applies.\\n/// @custom:member token The token for which the fund access constraints apply.\\n/// @custom:member distributionLimit The amount of the distribution limit, as a fixed point number with the same number of decimals as the terminal within which the limit applies.\\n/// @custom:member distributionLimitCurrency The currency of the distribution limit.\\n/// @custom:member overflowAllowance The amount of the allowance, as a fixed point number with the same number of decimals as the terminal within which the allowance applies.\\n/// @custom:member overflowAllowanceCurrency The currency of the overflow allowance.\\nstruct JBFundAccessConstraints {\\n IJBPaymentTerminal terminal;\\n address token;\\n uint256 distributionLimit;\\n uint256 distributionLimitCurrency;\\n uint256 overflowAllowance;\\n uint256 overflowAllowanceCurrency;\\n}\\n\",\"keccak256\":\"0xbef975eb73e58c00eaaa7abbd449db545056b049907bb2034aefcdde10bcf11f\",\"license\":\"MIT\"},\"contracts/structs/JBFundingCycle.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBFundingCycleBallot} from './../interfaces/IJBFundingCycleBallot.sol';\\n\\n/// @custom:member number The funding cycle number for the cycle's project. Each funding cycle has a number that is an increment of the cycle that directly preceded it. Each project's first funding cycle has a number of 1.\\n/// @custom:member configuration The timestamp when the parameters for this funding cycle were configured. This value will stay the same for subsequent funding cycles that roll over from an originally configured cycle.\\n/// @custom:member basedOn The `configuration` of the funding cycle that was active when this cycle was created.\\n/// @custom:member start The timestamp marking the moment from which the funding cycle is considered active. It is a unix timestamp measured in seconds.\\n/// @custom:member duration The number of seconds the funding cycle lasts for, after which a new funding cycle will start. A duration of 0 means that the funding cycle will stay active until the project owner explicitly issues a reconfiguration, at which point a new funding cycle will immediately start with the updated properties. If the duration is greater than 0, a project owner cannot make changes to a funding cycle's parameters while it is active \\u2013 any proposed changes will apply to the subsequent cycle. If no changes are proposed, a funding cycle rolls over to another one with the same properties but new `start` timestamp and a discounted `weight`.\\n/// @custom:member weight A fixed point number with 18 decimals that contracts can use to base arbitrary calculations on. For example, payment terminals can use this to determine how many tokens should be minted when a payment is received.\\n/// @custom:member discountRate A percent by how much the `weight` of the subsequent funding cycle should be reduced, if the project owner hasn't configured the subsequent funding cycle with an explicit `weight`. If it's 0, each funding cycle will have equal weight. If the number is 90%, the next funding cycle will have a 10% smaller weight. This weight is out of `JBConstants.MAX_DISCOUNT_RATE`.\\n/// @custom:member ballot An address of a contract that says whether a proposed reconfiguration should be accepted or rejected. It can be used to create rules around how a project owner can change funding cycle parameters over time.\\n/// @custom:member metadata Extra data that can be associated with a funding cycle.\\nstruct JBFundingCycle {\\n uint256 number;\\n uint256 configuration;\\n uint256 basedOn;\\n uint256 start;\\n uint256 duration;\\n uint256 weight;\\n uint256 discountRate;\\n IJBFundingCycleBallot ballot;\\n uint256 metadata;\\n}\\n\",\"keccak256\":\"0x01d2ee9ae017694097985a08a36421b6801d96badd16e38c6085f3a5ac796ed1\",\"license\":\"MIT\"},\"contracts/structs/JBFundingCycleData.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBFundingCycleBallot} from './../interfaces/IJBFundingCycleBallot.sol';\\n\\n/// @custom:member duration The number of seconds the funding cycle lasts for, after which a new funding cycle will start. A duration of 0 means that the funding cycle will stay active until the project owner explicitly issues a reconfiguration, at which point a new funding cycle will immediately start with the updated properties. If the duration is greater than 0, a project owner cannot make changes to a funding cycle's parameters while it is active \\u2013 any proposed changes will apply to the subsequent cycle. If no changes are proposed, a funding cycle rolls over to another one with the same properties but new `start` timestamp and a discounted `weight`.\\n/// @custom:member weight A fixed point number with 18 decimals that contracts can use to base arbitrary calculations on. For example, payment terminals can use this to determine how many tokens should be minted when a payment is received.\\n/// @custom:member discountRate A percent by how much the `weight` of the subsequent funding cycle should be reduced, if the project owner hasn't configured the subsequent funding cycle with an explicit `weight`. If it's 0, each funding cycle will have equal weight. If the number is 90%, the next funding cycle will have a 10% smaller weight. This weight is out of `JBConstants.MAX_DISCOUNT_RATE`.\\n/// @custom:member ballot An address of a contract that says whether a proposed reconfiguration should be accepted or rejected. It can be used to create rules around how a project owner can change funding cycle parameters over time.\\nstruct JBFundingCycleData {\\n uint256 duration;\\n uint256 weight;\\n uint256 discountRate;\\n IJBFundingCycleBallot ballot;\\n}\\n\",\"keccak256\":\"0x3cd9257969fdd54bee497b01be2c623e33c941306662002b3b88fa0ab8a27db5\",\"license\":\"MIT\"},\"contracts/structs/JBFundingCycleMetadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBGlobalFundingCycleMetadata} from './JBGlobalFundingCycleMetadata.sol';\\n\\n/// @custom:member global Data used globally in non-migratable ecosystem contracts.\\n/// @custom:member reservedRate The reserved rate of the funding cycle. This number is a percentage calculated out of `JBConstants.MAX_RESERVED_RATE`.\\n/// @custom:member redemptionRate The redemption rate of the funding cycle. This number is a percentage calculated out of `JBConstants.MAX_REDEMPTION_RATE`.\\n/// @custom:member ballotRedemptionRate The redemption rate to use during an active ballot of the funding cycle. This number is a percentage calculated out of `JBConstants.MAX_REDEMPTION_RATE`.\\n/// @custom:member pausePay A flag indicating if the pay functionality should be paused during the funding cycle.\\n/// @custom:member pauseDistributions A flag indicating if the distribute functionality should be paused during the funding cycle.\\n/// @custom:member pauseRedeem A flag indicating if the redeem functionality should be paused during the funding cycle.\\n/// @custom:member pauseBurn A flag indicating if the burn functionality should be paused during the funding cycle.\\n/// @custom:member allowMinting A flag indicating if minting tokens should be allowed during this funding cycle.\\n/// @custom:member allowTerminalMigration A flag indicating if migrating terminals should be allowed during this funding cycle.\\n/// @custom:member allowControllerMigration A flag indicating if migrating controllers should be allowed during this funding cycle.\\n/// @custom:member holdFees A flag indicating if fees should be held during this funding cycle.\\n/// @custom:member preferClaimedTokenOverride A flag indicating if claimed tokens should always be prefered to unclaimed tokens when minting.\\n/// @custom:member useTotalOverflowForRedemptions A flag indicating if redemptions should use the project's balance held in all terminals instead of the project's local terminal balance from which the redemption is being fulfilled.\\n/// @custom:member useDataSourceForPay A flag indicating if the data source should be used for pay transactions during this funding cycle.\\n/// @custom:member useDataSourceForRedeem A flag indicating if the data source should be used for redeem transactions during this funding cycle.\\n/// @custom:member dataSource The data source to use during this funding cycle.\\n/// @custom:member metadata Metadata of the metadata, up to uint8 in size.\\nstruct JBFundingCycleMetadata {\\n JBGlobalFundingCycleMetadata global;\\n uint256 reservedRate;\\n uint256 redemptionRate;\\n uint256 ballotRedemptionRate;\\n bool pausePay;\\n bool pauseDistributions;\\n bool pauseRedeem;\\n bool pauseBurn;\\n bool allowMinting;\\n bool allowTerminalMigration;\\n bool allowControllerMigration;\\n bool holdFees;\\n bool preferClaimedTokenOverride;\\n bool useTotalOverflowForRedemptions;\\n bool useDataSourceForPay;\\n bool useDataSourceForRedeem;\\n address dataSource;\\n uint256 metadata;\\n}\\n\",\"keccak256\":\"0x477bbd36c94da3f56fac6c8c60b2e2e3c5b8fc557a880b5359980bc556ccd300\",\"license\":\"MIT\"},\"contracts/structs/JBGlobalFundingCycleMetadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/// @custom:member allowSetTerminals A flag indicating if setting terminals should be allowed during this funding cycle.\\n/// @custom:member allowSetController A flag indicating if setting a new controller should be allowed during this funding cycle.\\n/// @custom:member pauseTransfers A flag indicating if the project token transfer functionality should be paused during the funding cycle.\\nstruct JBGlobalFundingCycleMetadata {\\n bool allowSetTerminals;\\n bool allowSetController;\\n bool pauseTransfers;\\n}\\n\",\"keccak256\":\"0x5f95bce22550c69bb7b1ee17279d51415ae8bae10c5b759c8b88f0b0aba854ed\",\"license\":\"MIT\"},\"contracts/structs/JBGroupedSplits.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBSplit} from './JBSplit.sol';\\n\\n/// @custom:member group The group indentifier.\\n/// @custom:member splits The splits to associate with the group.\\nstruct JBGroupedSplits {\\n uint256 group;\\n JBSplit[] splits;\\n}\\n\",\"keccak256\":\"0x71fcdbff5cd055cee8d06b73568c44cedda8f5a2351e7d8ce9dd71d8a1f914a8\",\"license\":\"MIT\"},\"contracts/structs/JBOperatorData.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/// @custom:member operator The address of the operator.\\n/// @custom:member domain The domain within which the operator is being given permissions. A domain of 0 is a wildcard domain, which gives an operator access to all domains.\\n/// @custom:member permissionIndexes The indexes of the permissions the operator is being given.\\nstruct JBOperatorData {\\n address operator;\\n uint256 domain;\\n uint256[] permissionIndexes;\\n}\\n\",\"keccak256\":\"0x77fba183d08748c7b75a12425f987b1b48f6bbfec0284517ffaf261429b45a7c\",\"license\":\"MIT\"},\"contracts/structs/JBPayDelegateAllocation3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBPayDelegate3_1_1} from '../interfaces/IJBPayDelegate3_1_1.sol';\\n\\n/// @custom:member delegate A delegate contract to use for subsequent calls.\\n/// @custom:member amount The amount to send to the delegate.\\n/// @custom:member metadata Metadata to pass the delegate.\\nstruct JBPayDelegateAllocation3_1_1 {\\n IJBPayDelegate3_1_1 delegate;\\n uint256 amount;\\n bytes metadata;\\n}\\n\",\"keccak256\":\"0x8d87206a7015af9ec9e5fc059e39bfcea44aa007f8812213c6fd489d0a9c2e17\",\"license\":\"MIT\"},\"contracts/structs/JBProjectMetadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/// @custom:member content The metadata content.\\n/// @custom:member domain The domain within which the metadata applies.\\nstruct JBProjectMetadata {\\n string content;\\n uint256 domain;\\n}\\n\",\"keccak256\":\"0x9545ea42927f3451c9d901a2f7ab7c1aeef3242e5ed2b75521a90225a5a0f891\",\"license\":\"MIT\"},\"contracts/structs/JBRedemptionDelegateAllocation3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBRedemptionDelegate3_1_1} from '../interfaces/IJBRedemptionDelegate3_1_1.sol';\\n\\n/// @custom:member delegate A delegate contract to use for subsequent calls.\\n/// @custom:member amount The amount to send to the delegate.\\n/// @custom:member metadata Metadata to pass the delegate.\\nstruct JBRedemptionDelegateAllocation3_1_1 {\\n IJBRedemptionDelegate3_1_1 delegate;\\n uint256 amount;\\n bytes metadata;\\n}\\n\",\"keccak256\":\"0x16d2b586f4591b0d18324f233b4d4a13c6dc687b5f2c5becadbedbbdc373cdc4\",\"license\":\"MIT\"},\"contracts/structs/JBSplit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBSplitAllocator} from './../interfaces/IJBSplitAllocator.sol';\\n\\n/// @custom:member preferClaimed A flag that only has effect if a projectId is also specified, and the project has a token contract attached. If so, this flag indicates if the tokens that result from making a payment to the project should be delivered claimed into the beneficiary's wallet, or unclaimed to save gas.\\n/// @custom:member preferAddToBalance A flag indicating if a distribution to a project should prefer triggering it's addToBalance function instead of its pay function.\\n/// @custom:member percent The percent of the whole group that this split occupies. This number is out of `JBConstants.SPLITS_TOTAL_PERCENT`.\\n/// @custom:member projectId The ID of a project. If an allocator is not set but a projectId is set, funds will be sent to the protocol treasury belonging to the project who's ID is specified. Resulting tokens will be routed to the beneficiary with the claimed token preference respected.\\n/// @custom:member beneficiary An address. The role the of the beneficary depends on whether or not projectId is specified, and whether or not an allocator is specified. If allocator is set, the beneficiary will be forwarded to the allocator for it to use. If allocator is not set but projectId is set, the beneficiary is the address to which the project's tokens will be sent that result from a payment to it. If neither allocator or projectId are set, the beneficiary is where the funds from the split will be sent.\\n/// @custom:member lockedUntil Specifies if the split should be unchangeable until the specified time, with the exception of extending the locked period.\\n/// @custom:member allocator If an allocator is specified, funds will be sent to the allocator contract along with all properties of this split.\\nstruct JBSplit {\\n bool preferClaimed;\\n bool preferAddToBalance;\\n uint256 percent;\\n uint256 projectId;\\n address payable beneficiary;\\n uint256 lockedUntil;\\n IJBSplitAllocator allocator;\\n}\\n\",\"keccak256\":\"0x7bf3f79f95cf6211dcdcf5af68ddc963f2304379ea50a5feaf27c645879fe3fe\",\"license\":\"MIT\"},\"contracts/structs/JBSplitAllocationData.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBSplit} from './JBSplit.sol';\\n\\n/// @custom:member token The token being sent to the split allocator.\\n/// @custom:member amount The amount being sent to the split allocator, as a fixed point number.\\n/// @custom:member decimals The number of decimals in the amount.\\n/// @custom:member projectId The project to which the split belongs.\\n/// @custom:member group The group to which the split belongs.\\n/// @custom:member split The split that caused the allocation.\\nstruct JBSplitAllocationData {\\n address token;\\n uint256 amount;\\n uint256 decimals;\\n uint256 projectId;\\n uint256 group;\\n JBSplit split;\\n}\\n\",\"keccak256\":\"0x85dcbcad02f315a1a3cc44140ffc77fdfbcafed7089eab55ffb66f1bebc2b40b\",\"license\":\"MIT\"},\"contracts/structs/JBTokenAmount.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/// @custom:member token The token the payment was made in.\\n/// @custom:member value The amount of tokens that was paid, as a fixed point number.\\n/// @custom:member decimals The number of decimals included in the value fixed point number.\\n/// @custom:member currency The expected currency of the value.\\nstruct JBTokenAmount {\\n address token;\\n uint256 value;\\n uint256 decimals;\\n uint256 currency;\\n}\\n\",\"keccak256\":\"0x9317f1f47aef544de592a48a4b20fa3d54586d988c8bb7420b40076920ea200d\",\"license\":\"MIT\"},\"prb-math/contracts/PRBMath.sol\":{\"content\":\"// SPDX-License-Identifier: Unlicense\\npragma solidity >=0.8.4;\\n\\n/// @notice Emitted when the result overflows uint256.\\nerror PRBMath__MulDivFixedPointOverflow(uint256 prod1);\\n\\n/// @notice Emitted when the result overflows uint256.\\nerror PRBMath__MulDivOverflow(uint256 prod1, uint256 denominator);\\n\\n/// @notice Emitted when one of the inputs is type(int256).min.\\nerror PRBMath__MulDivSignedInputTooSmall();\\n\\n/// @notice Emitted when the intermediary absolute result overflows int256.\\nerror PRBMath__MulDivSignedOverflow(uint256 rAbs);\\n\\n/// @notice Emitted when the input is MIN_SD59x18.\\nerror PRBMathSD59x18__AbsInputTooSmall();\\n\\n/// @notice Emitted when ceiling a number overflows SD59x18.\\nerror PRBMathSD59x18__CeilOverflow(int256 x);\\n\\n/// @notice Emitted when one of the inputs is MIN_SD59x18.\\nerror PRBMathSD59x18__DivInputTooSmall();\\n\\n/// @notice Emitted when one of the intermediary unsigned results overflows SD59x18.\\nerror PRBMathSD59x18__DivOverflow(uint256 rAbs);\\n\\n/// @notice Emitted when the input is greater than 133.084258667509499441.\\nerror PRBMathSD59x18__ExpInputTooBig(int256 x);\\n\\n/// @notice Emitted when the input is greater than 192.\\nerror PRBMathSD59x18__Exp2InputTooBig(int256 x);\\n\\n/// @notice Emitted when flooring a number underflows SD59x18.\\nerror PRBMathSD59x18__FloorUnderflow(int256 x);\\n\\n/// @notice Emitted when converting a basic integer to the fixed-point format overflows SD59x18.\\nerror PRBMathSD59x18__FromIntOverflow(int256 x);\\n\\n/// @notice Emitted when converting a basic integer to the fixed-point format underflows SD59x18.\\nerror PRBMathSD59x18__FromIntUnderflow(int256 x);\\n\\n/// @notice Emitted when the product of the inputs is negative.\\nerror PRBMathSD59x18__GmNegativeProduct(int256 x, int256 y);\\n\\n/// @notice Emitted when multiplying the inputs overflows SD59x18.\\nerror PRBMathSD59x18__GmOverflow(int256 x, int256 y);\\n\\n/// @notice Emitted when the input is less than or equal to zero.\\nerror PRBMathSD59x18__LogInputTooSmall(int256 x);\\n\\n/// @notice Emitted when one of the inputs is MIN_SD59x18.\\nerror PRBMathSD59x18__MulInputTooSmall();\\n\\n/// @notice Emitted when the intermediary absolute result overflows SD59x18.\\nerror PRBMathSD59x18__MulOverflow(uint256 rAbs);\\n\\n/// @notice Emitted when the intermediary absolute result overflows SD59x18.\\nerror PRBMathSD59x18__PowuOverflow(uint256 rAbs);\\n\\n/// @notice Emitted when the input is negative.\\nerror PRBMathSD59x18__SqrtNegativeInput(int256 x);\\n\\n/// @notice Emitted when the calculating the square root overflows SD59x18.\\nerror PRBMathSD59x18__SqrtOverflow(int256 x);\\n\\n/// @notice Emitted when addition overflows UD60x18.\\nerror PRBMathUD60x18__AddOverflow(uint256 x, uint256 y);\\n\\n/// @notice Emitted when ceiling a number overflows UD60x18.\\nerror PRBMathUD60x18__CeilOverflow(uint256 x);\\n\\n/// @notice Emitted when the input is greater than 133.084258667509499441.\\nerror PRBMathUD60x18__ExpInputTooBig(uint256 x);\\n\\n/// @notice Emitted when the input is greater than 192.\\nerror PRBMathUD60x18__Exp2InputTooBig(uint256 x);\\n\\n/// @notice Emitted when converting a basic integer to the fixed-point format format overflows UD60x18.\\nerror PRBMathUD60x18__FromUintOverflow(uint256 x);\\n\\n/// @notice Emitted when multiplying the inputs overflows UD60x18.\\nerror PRBMathUD60x18__GmOverflow(uint256 x, uint256 y);\\n\\n/// @notice Emitted when the input is less than 1.\\nerror PRBMathUD60x18__LogInputTooSmall(uint256 x);\\n\\n/// @notice Emitted when the calculating the square root overflows UD60x18.\\nerror PRBMathUD60x18__SqrtOverflow(uint256 x);\\n\\n/// @notice Emitted when subtraction underflows UD60x18.\\nerror PRBMathUD60x18__SubUnderflow(uint256 x, uint256 y);\\n\\n/// @dev Common mathematical functions used in both PRBMathSD59x18 and PRBMathUD60x18. Note that this shared library\\n/// does not always assume the signed 59.18-decimal fixed-point or the unsigned 60.18-decimal fixed-point\\n/// representation. When it does not, it is explicitly mentioned in the NatSpec documentation.\\nlibrary PRBMath {\\n /// STRUCTS ///\\n\\n struct SD59x18 {\\n int256 value;\\n }\\n\\n struct UD60x18 {\\n uint256 value;\\n }\\n\\n /// STORAGE ///\\n\\n /// @dev How many trailing decimals can be represented.\\n uint256 internal constant SCALE = 1e18;\\n\\n /// @dev Largest power of two divisor of SCALE.\\n uint256 internal constant SCALE_LPOTD = 262144;\\n\\n /// @dev SCALE inverted mod 2^256.\\n uint256 internal constant SCALE_INVERSE =\\n 78156646155174841979727994598816262306175212592076161876661_508869554232690281;\\n\\n /// FUNCTIONS ///\\n\\n /// @notice Calculates the binary exponent of x using the binary fraction method.\\n /// @dev Has to use 192.64-bit fixed-point numbers.\\n /// See https://ethereum.stackexchange.com/a/96594/24693.\\n /// @param x The exponent as an unsigned 192.64-bit fixed-point number.\\n /// @return result The result as an unsigned 60.18-decimal fixed-point number.\\n function exp2(uint256 x) internal pure returns (uint256 result) {\\n unchecked {\\n // Start from 0.5 in the 192.64-bit fixed-point format.\\n result = 0x800000000000000000000000000000000000000000000000;\\n\\n // Multiply the result by root(2, 2^-i) when the bit at position i is 1. None of the intermediary results overflows\\n // because the initial result is 2^191 and all magic factors are less than 2^65.\\n if (x & 0x8000000000000000 > 0) {\\n result = (result * 0x16A09E667F3BCC909) >> 64;\\n }\\n if (x & 0x4000000000000000 > 0) {\\n result = (result * 0x1306FE0A31B7152DF) >> 64;\\n }\\n if (x & 0x2000000000000000 > 0) {\\n result = (result * 0x1172B83C7D517ADCE) >> 64;\\n }\\n if (x & 0x1000000000000000 > 0) {\\n result = (result * 0x10B5586CF9890F62A) >> 64;\\n }\\n if (x & 0x800000000000000 > 0) {\\n result = (result * 0x1059B0D31585743AE) >> 64;\\n }\\n if (x & 0x400000000000000 > 0) {\\n result = (result * 0x102C9A3E778060EE7) >> 64;\\n }\\n if (x & 0x200000000000000 > 0) {\\n result = (result * 0x10163DA9FB33356D8) >> 64;\\n }\\n if (x & 0x100000000000000 > 0) {\\n result = (result * 0x100B1AFA5ABCBED61) >> 64;\\n }\\n if (x & 0x80000000000000 > 0) {\\n result = (result * 0x10058C86DA1C09EA2) >> 64;\\n }\\n if (x & 0x40000000000000 > 0) {\\n result = (result * 0x1002C605E2E8CEC50) >> 64;\\n }\\n if (x & 0x20000000000000 > 0) {\\n result = (result * 0x100162F3904051FA1) >> 64;\\n }\\n if (x & 0x10000000000000 > 0) {\\n result = (result * 0x1000B175EFFDC76BA) >> 64;\\n }\\n if (x & 0x8000000000000 > 0) {\\n result = (result * 0x100058BA01FB9F96D) >> 64;\\n }\\n if (x & 0x4000000000000 > 0) {\\n result = (result * 0x10002C5CC37DA9492) >> 64;\\n }\\n if (x & 0x2000000000000 > 0) {\\n result = (result * 0x1000162E525EE0547) >> 64;\\n }\\n if (x & 0x1000000000000 > 0) {\\n result = (result * 0x10000B17255775C04) >> 64;\\n }\\n if (x & 0x800000000000 > 0) {\\n result = (result * 0x1000058B91B5BC9AE) >> 64;\\n }\\n if (x & 0x400000000000 > 0) {\\n result = (result * 0x100002C5C89D5EC6D) >> 64;\\n }\\n if (x & 0x200000000000 > 0) {\\n result = (result * 0x10000162E43F4F831) >> 64;\\n }\\n if (x & 0x100000000000 > 0) {\\n result = (result * 0x100000B1721BCFC9A) >> 64;\\n }\\n if (x & 0x80000000000 > 0) {\\n result = (result * 0x10000058B90CF1E6E) >> 64;\\n }\\n if (x & 0x40000000000 > 0) {\\n result = (result * 0x1000002C5C863B73F) >> 64;\\n }\\n if (x & 0x20000000000 > 0) {\\n result = (result * 0x100000162E430E5A2) >> 64;\\n }\\n if (x & 0x10000000000 > 0) {\\n result = (result * 0x1000000B172183551) >> 64;\\n }\\n if (x & 0x8000000000 > 0) {\\n result = (result * 0x100000058B90C0B49) >> 64;\\n }\\n if (x & 0x4000000000 > 0) {\\n result = (result * 0x10000002C5C8601CC) >> 64;\\n }\\n if (x & 0x2000000000 > 0) {\\n result = (result * 0x1000000162E42FFF0) >> 64;\\n }\\n if (x & 0x1000000000 > 0) {\\n result = (result * 0x10000000B17217FBB) >> 64;\\n }\\n if (x & 0x800000000 > 0) {\\n result = (result * 0x1000000058B90BFCE) >> 64;\\n }\\n if (x & 0x400000000 > 0) {\\n result = (result * 0x100000002C5C85FE3) >> 64;\\n }\\n if (x & 0x200000000 > 0) {\\n result = (result * 0x10000000162E42FF1) >> 64;\\n }\\n if (x & 0x100000000 > 0) {\\n result = (result * 0x100000000B17217F8) >> 64;\\n }\\n if (x & 0x80000000 > 0) {\\n result = (result * 0x10000000058B90BFC) >> 64;\\n }\\n if (x & 0x40000000 > 0) {\\n result = (result * 0x1000000002C5C85FE) >> 64;\\n }\\n if (x & 0x20000000 > 0) {\\n result = (result * 0x100000000162E42FF) >> 64;\\n }\\n if (x & 0x10000000 > 0) {\\n result = (result * 0x1000000000B17217F) >> 64;\\n }\\n if (x & 0x8000000 > 0) {\\n result = (result * 0x100000000058B90C0) >> 64;\\n }\\n if (x & 0x4000000 > 0) {\\n result = (result * 0x10000000002C5C860) >> 64;\\n }\\n if (x & 0x2000000 > 0) {\\n result = (result * 0x1000000000162E430) >> 64;\\n }\\n if (x & 0x1000000 > 0) {\\n result = (result * 0x10000000000B17218) >> 64;\\n }\\n if (x & 0x800000 > 0) {\\n result = (result * 0x1000000000058B90C) >> 64;\\n }\\n if (x & 0x400000 > 0) {\\n result = (result * 0x100000000002C5C86) >> 64;\\n }\\n if (x & 0x200000 > 0) {\\n result = (result * 0x10000000000162E43) >> 64;\\n }\\n if (x & 0x100000 > 0) {\\n result = (result * 0x100000000000B1721) >> 64;\\n }\\n if (x & 0x80000 > 0) {\\n result = (result * 0x10000000000058B91) >> 64;\\n }\\n if (x & 0x40000 > 0) {\\n result = (result * 0x1000000000002C5C8) >> 64;\\n }\\n if (x & 0x20000 > 0) {\\n result = (result * 0x100000000000162E4) >> 64;\\n }\\n if (x & 0x10000 > 0) {\\n result = (result * 0x1000000000000B172) >> 64;\\n }\\n if (x & 0x8000 > 0) {\\n result = (result * 0x100000000000058B9) >> 64;\\n }\\n if (x & 0x4000 > 0) {\\n result = (result * 0x10000000000002C5D) >> 64;\\n }\\n if (x & 0x2000 > 0) {\\n result = (result * 0x1000000000000162E) >> 64;\\n }\\n if (x & 0x1000 > 0) {\\n result = (result * 0x10000000000000B17) >> 64;\\n }\\n if (x & 0x800 > 0) {\\n result = (result * 0x1000000000000058C) >> 64;\\n }\\n if (x & 0x400 > 0) {\\n result = (result * 0x100000000000002C6) >> 64;\\n }\\n if (x & 0x200 > 0) {\\n result = (result * 0x10000000000000163) >> 64;\\n }\\n if (x & 0x100 > 0) {\\n result = (result * 0x100000000000000B1) >> 64;\\n }\\n if (x & 0x80 > 0) {\\n result = (result * 0x10000000000000059) >> 64;\\n }\\n if (x & 0x40 > 0) {\\n result = (result * 0x1000000000000002C) >> 64;\\n }\\n if (x & 0x20 > 0) {\\n result = (result * 0x10000000000000016) >> 64;\\n }\\n if (x & 0x10 > 0) {\\n result = (result * 0x1000000000000000B) >> 64;\\n }\\n if (x & 0x8 > 0) {\\n result = (result * 0x10000000000000006) >> 64;\\n }\\n if (x & 0x4 > 0) {\\n result = (result * 0x10000000000000003) >> 64;\\n }\\n if (x & 0x2 > 0) {\\n result = (result * 0x10000000000000001) >> 64;\\n }\\n if (x & 0x1 > 0) {\\n result = (result * 0x10000000000000001) >> 64;\\n }\\n\\n // We're doing two things at the same time:\\n //\\n // 1. Multiply the result by 2^n + 1, where \\\"2^n\\\" is the integer part and the one is added to account for\\n // the fact that we initially set the result to 0.5. This is accomplished by subtracting from 191\\n // rather than 192.\\n // 2. Convert the result to the unsigned 60.18-decimal fixed-point format.\\n //\\n // This works because 2^(191-ip) = 2^ip / 2^191, where \\\"ip\\\" is the integer part \\\"2^n\\\".\\n result *= SCALE;\\n result >>= (191 - (x >> 64));\\n }\\n }\\n\\n /// @notice Finds the zero-based index of the first one in the binary representation of x.\\n /// @dev See the note on msb in the \\\"Find First Set\\\" Wikipedia article https://en.wikipedia.org/wiki/Find_first_set\\n /// @param x The uint256 number for which to find the index of the most significant bit.\\n /// @return msb The index of the most significant bit as an uint256.\\n function mostSignificantBit(uint256 x) internal pure returns (uint256 msb) {\\n if (x >= 2**128) {\\n x >>= 128;\\n msb += 128;\\n }\\n if (x >= 2**64) {\\n x >>= 64;\\n msb += 64;\\n }\\n if (x >= 2**32) {\\n x >>= 32;\\n msb += 32;\\n }\\n if (x >= 2**16) {\\n x >>= 16;\\n msb += 16;\\n }\\n if (x >= 2**8) {\\n x >>= 8;\\n msb += 8;\\n }\\n if (x >= 2**4) {\\n x >>= 4;\\n msb += 4;\\n }\\n if (x >= 2**2) {\\n x >>= 2;\\n msb += 2;\\n }\\n if (x >= 2**1) {\\n // No need to shift x any more.\\n msb += 1;\\n }\\n }\\n\\n /// @notice Calculates floor(x*y\\u00f7denominator) with full precision.\\n ///\\n /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv.\\n ///\\n /// Requirements:\\n /// - The denominator cannot be zero.\\n /// - The result must fit within uint256.\\n ///\\n /// Caveats:\\n /// - This function does not work with fixed-point numbers.\\n ///\\n /// @param x The multiplicand as an uint256.\\n /// @param y The multiplier as an uint256.\\n /// @param denominator The divisor as an uint256.\\n /// @return result The result as an uint256.\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator\\n ) internal pure returns (uint256 result) {\\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\\n // variables such that product = prod1 * 2^256 + prod0.\\n uint256 prod0; // Least significant 256 bits of the product\\n uint256 prod1; // Most significant 256 bits of the product\\n assembly {\\n let mm := mulmod(x, y, not(0))\\n prod0 := mul(x, y)\\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\\n }\\n\\n // Handle non-overflow cases, 256 by 256 division.\\n if (prod1 == 0) {\\n unchecked {\\n result = prod0 / denominator;\\n }\\n return result;\\n }\\n\\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\\n if (prod1 >= denominator) {\\n revert PRBMath__MulDivOverflow(prod1, denominator);\\n }\\n\\n ///////////////////////////////////////////////\\n // 512 by 256 division.\\n ///////////////////////////////////////////////\\n\\n // Make division exact by subtracting the remainder from [prod1 prod0].\\n uint256 remainder;\\n assembly {\\n // Compute remainder using mulmod.\\n remainder := mulmod(x, y, denominator)\\n\\n // Subtract 256 bit number from 512 bit number.\\n prod1 := sub(prod1, gt(remainder, prod0))\\n prod0 := sub(prod0, remainder)\\n }\\n\\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\\n // See https://cs.stackexchange.com/q/138556/92363.\\n unchecked {\\n // Does not overflow because the denominator cannot be zero at this stage in the function.\\n uint256 lpotdod = denominator & (~denominator + 1);\\n assembly {\\n // Divide denominator by lpotdod.\\n denominator := div(denominator, lpotdod)\\n\\n // Divide [prod1 prod0] by lpotdod.\\n prod0 := div(prod0, lpotdod)\\n\\n // Flip lpotdod such that it is 2^256 / lpotdod. If lpotdod is zero, then it becomes one.\\n lpotdod := add(div(sub(0, lpotdod), lpotdod), 1)\\n }\\n\\n // Shift in bits from prod1 into prod0.\\n prod0 |= prod1 * lpotdod;\\n\\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\\n // four bits. That is, denominator * inv = 1 mod 2^4.\\n uint256 inverse = (3 * denominator) ^ 2;\\n\\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\\n // in modular arithmetic, doubling the correct bits in each step.\\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\\n\\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\\n // is no longer required.\\n result = prod0 * inverse;\\n return result;\\n }\\n }\\n\\n /// @notice Calculates floor(x*y\\u00f71e18) with full precision.\\n ///\\n /// @dev Variant of \\\"mulDiv\\\" with constant folding, i.e. in which the denominator is always 1e18. Before returning the\\n /// final result, we add 1 if (x * y) % SCALE >= HALF_SCALE. Without this, 6.6e-19 would be truncated to 0 instead of\\n /// being rounded to 1e-18. See \\\"Listing 6\\\" and text above it at https://accu.org/index.php/journals/1717.\\n ///\\n /// Requirements:\\n /// - The result must fit within uint256.\\n ///\\n /// Caveats:\\n /// - The body is purposely left uncommented; see the NatSpec comments in \\\"PRBMath.mulDiv\\\" to understand how this works.\\n /// - It is assumed that the result can never be type(uint256).max when x and y solve the following two equations:\\n /// 1. x * y = type(uint256).max * SCALE\\n /// 2. (x * y) % SCALE >= SCALE / 2\\n ///\\n /// @param x The multiplicand as an unsigned 60.18-decimal fixed-point number.\\n /// @param y The multiplier as an unsigned 60.18-decimal fixed-point number.\\n /// @return result The result as an unsigned 60.18-decimal fixed-point number.\\n function mulDivFixedPoint(uint256 x, uint256 y) internal pure returns (uint256 result) {\\n uint256 prod0;\\n uint256 prod1;\\n assembly {\\n let mm := mulmod(x, y, not(0))\\n prod0 := mul(x, y)\\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\\n }\\n\\n if (prod1 >= SCALE) {\\n revert PRBMath__MulDivFixedPointOverflow(prod1);\\n }\\n\\n uint256 remainder;\\n uint256 roundUpUnit;\\n assembly {\\n remainder := mulmod(x, y, SCALE)\\n roundUpUnit := gt(remainder, 499999999999999999)\\n }\\n\\n if (prod1 == 0) {\\n unchecked {\\n result = (prod0 / SCALE) + roundUpUnit;\\n return result;\\n }\\n }\\n\\n assembly {\\n result := add(\\n mul(\\n or(\\n div(sub(prod0, remainder), SCALE_LPOTD),\\n mul(sub(prod1, gt(remainder, prod0)), add(div(sub(0, SCALE_LPOTD), SCALE_LPOTD), 1))\\n ),\\n SCALE_INVERSE\\n ),\\n roundUpUnit\\n )\\n }\\n }\\n\\n /// @notice Calculates floor(x*y\\u00f7denominator) with full precision.\\n ///\\n /// @dev An extension of \\\"mulDiv\\\" for signed numbers. Works by computing the signs and the absolute values separately.\\n ///\\n /// Requirements:\\n /// - None of the inputs can be type(int256).min.\\n /// - The result must fit within int256.\\n ///\\n /// @param x The multiplicand as an int256.\\n /// @param y The multiplier as an int256.\\n /// @param denominator The divisor as an int256.\\n /// @return result The result as an int256.\\n function mulDivSigned(\\n int256 x,\\n int256 y,\\n int256 denominator\\n ) internal pure returns (int256 result) {\\n if (x == type(int256).min || y == type(int256).min || denominator == type(int256).min) {\\n revert PRBMath__MulDivSignedInputTooSmall();\\n }\\n\\n // Get hold of the absolute values of x, y and the denominator.\\n uint256 ax;\\n uint256 ay;\\n uint256 ad;\\n unchecked {\\n ax = x < 0 ? uint256(-x) : uint256(x);\\n ay = y < 0 ? uint256(-y) : uint256(y);\\n ad = denominator < 0 ? uint256(-denominator) : uint256(denominator);\\n }\\n\\n // Compute the absolute value of (x*y)\\u00f7denominator. The result must fit within int256.\\n uint256 rAbs = mulDiv(ax, ay, ad);\\n if (rAbs > uint256(type(int256).max)) {\\n revert PRBMath__MulDivSignedOverflow(rAbs);\\n }\\n\\n // Get the signs of x, y and the denominator.\\n uint256 sx;\\n uint256 sy;\\n uint256 sd;\\n assembly {\\n sx := sgt(x, sub(0, 1))\\n sy := sgt(y, sub(0, 1))\\n sd := sgt(denominator, sub(0, 1))\\n }\\n\\n // XOR over sx, sy and sd. This is checking whether there are one or three negative signs in the inputs.\\n // If yes, the result should be negative.\\n result = sx ^ sy ^ sd == 0 ? -int256(rAbs) : int256(rAbs);\\n }\\n\\n /// @notice Calculates the square root of x, rounding down.\\n /// @dev Uses the Babylonian method https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method.\\n ///\\n /// Caveats:\\n /// - This function does not work with fixed-point numbers.\\n ///\\n /// @param x The uint256 number for which to calculate the square root.\\n /// @return result The result as an uint256.\\n function sqrt(uint256 x) internal pure returns (uint256 result) {\\n if (x == 0) {\\n return 0;\\n }\\n\\n // Set the initial guess to the closest power of two that is higher than x.\\n uint256 xAux = uint256(x);\\n result = 1;\\n if (xAux >= 0x100000000000000000000000000000000) {\\n xAux >>= 128;\\n result <<= 64;\\n }\\n if (xAux >= 0x10000000000000000) {\\n xAux >>= 64;\\n result <<= 32;\\n }\\n if (xAux >= 0x100000000) {\\n xAux >>= 32;\\n result <<= 16;\\n }\\n if (xAux >= 0x10000) {\\n xAux >>= 16;\\n result <<= 8;\\n }\\n if (xAux >= 0x100) {\\n xAux >>= 8;\\n result <<= 4;\\n }\\n if (xAux >= 0x10) {\\n xAux >>= 4;\\n result <<= 2;\\n }\\n if (xAux >= 0x8) {\\n result <<= 1;\\n }\\n\\n // The operations can never overflow because the result is max 2^127 when it enters this block.\\n unchecked {\\n result = (result + x / result) >> 1;\\n result = (result + x / result) >> 1;\\n result = (result + x / result) >> 1;\\n result = (result + x / result) >> 1;\\n result = (result + x / result) >> 1;\\n result = (result + x / result) >> 1;\\n result = (result + x / result) >> 1; // Seven iterations should be enough\\n uint256 roundedDownResult = x / result;\\n return result >= roundedDownResult ? roundedDownResult : result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x62cbabae4910e168e99b9c2c3e3b5c9c7ad5e7abd961dcc63b7ea3d83d8ea87e\",\"license\":\"Unlicense\"}},\"version\":1}", + "bytecode": "0x6101e060405263017d78406002553480156200001a57600080fd5b5060405162005f4a38038062005f4a8339810160408190526200003d916200020a565b61eeee6080819052601260a0819052600160c08190526001600160a01b038a1660e0528a818b8b8b8b8b8b8b6200007433620000cf565b6101a08990526101c08890526001600160a01b0380871661010052858116610120528481166101405283811661016052821661018052620000b5816200011f565b5050505050505050505050505050505050505050620002bf565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000546001600160a01b031633146200017f5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064015b60405180910390fd5b6001600160a01b038116620001e65760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840162000176565b620001f181620000cf565b50565b6001600160a01b0381168114620001f157600080fd5b600080600080600080600080610100898b0312156200022857600080fd5b8851975060208901516200023c81620001f4565b60408a01519097506200024f81620001f4565b60608a01519096506200026281620001f4565b60808a01519095506200027581620001f4565b60a08a01519094506200028881620001f4565b60c08a01519093506200029b81620001f4565b60e08a0151909250620002ae81620001f4565b809150509295985092959890939650565b60805160a05160c05160e05161010051610120516101405161016051610180516101a0516101c051615a2f6200051b600039600081816103cf015261206e01526000818161030701526118d00152600081816104f701528181610ad5015281816112fc0152818161189e01528181611f19015281816126250152818161298701528181612a9401526136d101526000818161065601526114810152600081816102bb01526133a801526000818161060f0152818161173b01528181611981015281816123ce01528181612bdf0152818161324e0152613ea80152600081816104a50152818161099001528181610e7d0152818161123101528181611fc501526126df01526000818161056b01528181611dad01528181611e4901528181612200015261229c0152600081816102660152818161070e015281816113cc0152818161142e0152818161187801528181611b5401528181612d750152612e0501526000818161033b015281816105db0152818161136d01528181611399015281816113f90152818161145b0152818161185201528181611b2e01528181612d4f01528181612ddf0152613c5c0152600081816106cc015281816107620152818161087e01528181610a2801528181610b5601528181610bc9015281816115130152818161181d01528181611af801528181611c46015281816123a30152818161245a0152818161249501528181612d1a01528181612da901528181612f320152818161322101528181613c2701528181613ccf01528181613ed5015281816140300152818161406e015281816141a301526141e70152615a2f6000f3fe6080604052600436106101f95760003560e01c80638da5cb5b1161010d578063c715967a116100a0578063df21a7dd1161006f578063df21a7dd146106ae578063e5a6b10f146106fc578063f2fde38b14610730578063fc0c546a14610750578063fe663f0f1461078457600080fd5b8063c715967a14610631578063d3419bf314610644578063d6dacc5314610678578063ddca3f431461069857600080fd5b8063ad007d63116100dc578063ad007d6314610559578063b631b5001461058d578063b7bad1b1146105bd578063c41c2f24146105fd57600080fd5b80638da5cb5b146104c7578063975057e7146104e5578063a02f801c14610519578063a32e1e961461053957600080fd5b80634a4305c011610190578063715018a61161015f578063715018a6146104115780637258002c1461042657806389701db5146104465780638af56094146104665780638b79543c1461049357600080fd5b80634a4305c01461037d578063637913ac1461039d57806366248b86146103bd57806369fe0e2d146103f157600080fd5b80632bdfe004116101cc5780632bdfe004146102a95780632d1a5903146102f5578063313ce56714610329578063405b84fa1461035d57600080fd5b806301ffc9a7146101fe5780630cf8e858146102335780631982d679146102485780631ebc263f14610296575b600080fd5b34801561020a57600080fd5b5061021e6102193660046144ec565b6107a4565b60405190151581526020015b60405180910390f35b610246610241366004614573565b61084e565b005b34801561025457600080fd5b50610288610263366004614608565b507f000000000000000000000000000000000000000000000000000000000000000090565b60405190815260200161022a565b6102886102a4366004614633565b610871565b3480156102b557600080fd5b506102dd7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200161022a565b34801561030157600080fd5b506102887f000000000000000000000000000000000000000000000000000000000000000081565b34801561033557600080fd5b506102887f000000000000000000000000000000000000000000000000000000000000000081565b34801561036957600080fd5b506102886103783660046146fa565b610977565b34801561038957600080fd5b5061028861039836600461472a565b610c73565b3480156103a957600080fd5b506102466103b8366004614608565b610c8f565b3480156103c957600080fd5b506102887f000000000000000000000000000000000000000000000000000000000000000081565b3480156103fd57600080fd5b5061024661040c366004614793565b610d16565b34801561041d57600080fd5b50610246610da5565b34801561043257600080fd5b506102466104413660046147ac565b610ddb565b34801561045257600080fd5b50610246610461366004614793565b610e67565b34801561047257600080fd5b50610486610481366004614793565b61116b565b60405161022a91906147da565b34801561049f57600080fd5b506102dd7f000000000000000000000000000000000000000000000000000000000000000081565b3480156104d357600080fd5b506000546001600160a01b03166102dd565b3480156104f157600080fd5b506102dd7f000000000000000000000000000000000000000000000000000000000000000081565b34801561052557600080fd5b50610288610534366004614980565b611218565b34801561054557600080fd5b50610288610554366004614793565b6112d3565b34801561056557600080fd5b506102dd7f000000000000000000000000000000000000000000000000000000000000000081565b34801561059957600080fd5b5061021e6105a8366004614608565b60046020526000908152604090205460ff1681565b3480156105c957600080fd5b506102886105d8366004614608565b507f000000000000000000000000000000000000000000000000000000000000000090565b34801561060957600080fd5b506102dd7f000000000000000000000000000000000000000000000000000000000000000081565b61024661063f366004614a38565b611508565b34801561065057600080fd5b506102dd7f000000000000000000000000000000000000000000000000000000000000000081565b34801561068457600080fd5b506003546102dd906001600160a01b031681565b3480156106a457600080fd5b5061028860025481565b3480156106ba57600080fd5b5061021e6106c9366004614adf565b507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b34801561070857600080fd5b506102887f000000000000000000000000000000000000000000000000000000000000000081565b34801561073c57600080fd5b5061024661074b366004614608565b611604565b34801561075c57600080fd5b506102dd7f000000000000000000000000000000000000000000000000000000000000000081565b34801561079057600080fd5b5061028861079f366004614b0b565b61169f565b60006001600160e01b0319821615806107cd57506001600160e01b0319821663edb527eb60e01b145b806107e857506001600160e01b031982166301290c1760e61b145b8061080357506001600160e01b0319821663280be00760e21b145b8061081e57506001600160e01b0319821663fe663f0f60e01b145b8061083957506001600160e01b0319821663ad007d6360e01b145b806108485750610848826116cf565b92915050565b6108578761171f565b610868878787600088888888611508565b50505050505050565b600061087c8b61171f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031661eeee146108eb5734156108cd57604051635e7e9adf60e11b815260040160405180910390fd5b476108d933308d6117cb565b6108e38147614bd9565b9a50506108ef565b3499505b6109688a338d8b8b8b8b8b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8f018190048102820181019092528d815292508d91508c90819084018382808284376000920191909152506117da92505050565b9b9a5050505050505050505050565b6040516331a9108f60e11b8152600481018390526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636352211e90602401602060405180830381865afa1580156109df573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a039190614bec565b836004610a11838383611d82565b60405163df21a7dd60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301526024820188905286169063df21a7dd90604401602060405180830381865afa158015610a7e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aa29190614c09565b610abf5760405163581010ed60e01b815260040160405180910390fd5b604051636bb6a5ad60e01b8152600481018790527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636bb6a5ad906024016020604051808303816000875af1158015610b26573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b4a9190614c26565b93508315610c255760007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031661eeee14610b8d576000610b8f565b845b6040805160208101825260008152905163019f1d0b60e31b81529192506001600160a01b03881691630cf8e858918491610bf1918c918b917f000000000000000000000000000000000000000000000000000000000000000091600401614c8f565b6000604051808303818588803b158015610c0a57600080fd5b505af1158015610c1e573d6000803e3d6000fd5b5050505050505b604080518581523360208201526001600160a01b0387169188917fa7519e5f94697b7f53e97c5eb46a0c730a296ab686ab8fd333835c5f735784eb910160405180910390a350505092915050565b6000610c83888888878787611ee6565b98975050505050505050565b6000546001600160a01b03163314610cc25760405162461bcd60e51b8152600401610cb990614cca565b60405180910390fd5b600380546001600160a01b0319166001600160a01b0383169081179091556040513381527f0a9a80fe9716605b3e52abb3d792d6a4e7816d6afc02a5a4ef023081feaf9f609060200160405180910390a250565b6000546001600160a01b03163314610d405760405162461bcd60e51b8152600401610cb990614cca565b6302faf080811115610d65576040516345fbd9c160e01b815260040160405180910390fd5b6002819055604080518281523360208201527fd7414e590e1cb532989ab2a34c8f4c2c17f7ab6f006efeeaef2e87cd5008c202910160405180910390a150565b6000546001600160a01b03163314610dcf5760405162461bcd60e51b8152600401610cb990614cca565b610dd9600061217b565b565b6000546001600160a01b03163314610e055760405162461bcd60e51b8152600401610cb990614cca565b6001600160a01b038216600081815260046020908152604091829020805460ff191685151590811790915591513381529192917fa2653e25a502c023a5830d0de847ef6f458387865b1f4f575d7594f9f2c0d71e910160405180910390a35050565b6040516331a9108f60e11b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636352211e90602401602060405180830381865afa158015610ecc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ef09190614bec565b816005610f056000546001600160a01b031690565b6001600160a01b0316336001600160a01b031614610f25848484846121cb565b600085815260016020908152604080832080548251818502810185019093528083529192909190849084015b82821015610fbe57600084815260209081902060408051608081018252600286029092018054835260019081015463ffffffff8082168587015264010000000082041692840192909252600160401b9091046001600160a01b031660608301529083529092019101610f51565b5050506000888152600160205260408120929350610fdd92915061444b565b80516000805b8281101561116057838181518110610ffd57610ffd614cff565b60200260200101516020015163ffffffff16600014806110435750633b9aca0084828151811061102f5761102f614cff565b60200260200101516040015163ffffffff16145b6110ba576110b584828151811061105c5761105c614cff565b60200260200101516000015185838151811061107a5761107a614cff565b60200260200101516020015163ffffffff1686848151811061109e5761109e614cff565b60200260200101516040015163ffffffff1661233f565b6110bd565b60005b91506110e7828583815181106110d5576110d5614cff565b6020026020010151606001518b612385565b60011515828a7fcf0c92a2c6d7c42f488326b0cb900104b99984b6b218db81cd29371364a3525187858151811061112057611120614cff565b602002602001015160600151336040516111509291906001600160a01b0392831681529116602082015260400190565b60405180910390a4600101610fe3565b505050505050505050565b606060016000838152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b8282101561120d57600084815260209081902060408051608081018252600286029092018054835260019081015463ffffffff8082168587015264010000000082041692840192909252600160401b9091046001600160a01b0316606083015290835290920191016111a0565b505050509050919050565b6040516331a9108f60e11b8152600481018a90526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636352211e90602401602060405180830381865afa158015611280573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112a49190614bec565b8a60116112b2838383611d82565b6112c28d8d8d8c8c8c8c8c6125f2565b9d9c50505050505050505050505050565b60405163035240c760e61b81523060048201526024810182905260009081906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063d49031c090604401602060405180830381865afa158015611343573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113679190614c26565b905060007f00000000000000000000000000000000000000000000000000000000000000006012146113c4576113bf827f00000000000000000000000000000000000000000000000000000000000000006012612839565b6113c6565b815b905060017f0000000000000000000000000000000000000000000000000000000000000000146114fe576114f98161141f7f0000000000000000000000000000000000000000000000000000000000000000600a614df9565b604051635268657960e11b81527f00000000000000000000000000000000000000000000000000000000000000006004820152600160248201527f000000000000000000000000000000000000000000000000000000000000000060448201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a4d0caf290606401602060405180830381865afa1580156114d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114f49190614c26565b612896565b611500565b805b949350505050565b6115118861171f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031661eeee1461158057341561156257604051635e7e9adf60e11b815260040160405180910390fd5b4761156e33308a6117cb565b6115788147614bd9565b975050611584565b3496505b6115fa88888787878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8b01819004810282018101909252898152925089915088908190840183828082843760009201919091525061296392505050565b5050505050505050565b6000546001600160a01b0316331461162e5760405162461bcd60e51b8152600401610cb990614cca565b6001600160a01b0381166116935760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610cb9565b61169c8161217b565b50565b6000888860026116b0838383611d82565b6116bf8c8c8c8b8b8b8b612a55565b9c9b505050505050505050505050565b60006001600160e01b0319821663301cdc3960e21b148061170057506001600160e01b0319821663144b000160e11b145b8061084857506301ffc9a760e01b6001600160e01b0319831614610848565b604051636e49181f60e01b8152600481018290523060248201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636e49181f90604401602060405180830381865afa15801561178a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117ae9190614c09565b61169c57604051631b1d5a5960e31b815260040160405180910390fd5b6117d582826130ea565b505050565b60006001600160a01b0386166118035760405163a762251360e01b815260040160405180910390fd5b61180b61446c565b606060008060405180608001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020018e81526020017f000000000000000000000000000000000000000000000000000000000000000081526020017f000000000000000000000000000000000000000000000000000000000000000081525090507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632fa1b3918d838e7f00000000000000000000000000000000000000000000000000000000000000008f8d8d6040518863ffffffff1660e01b81526004016119149796959493929190614e31565b6000604051808303816000875af1158015611933573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261195b9190810190614f95565b995091955090935091508115611a9057604051632eec7b5560e11b8152600481018c90527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635dd8f6aa90602401602060405180830381865afa1580156119d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119f49190614bec565b604051638ae9c07b60e01b8152600481018d9052602481018490526001600160a01b038c8116604483015260c06064830152600060c48301528a15156084830152600160a48301529190911690638ae9c07b9060e4016020604051808303816000875af1158015611a69573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a8d9190614c26565b94505b88851015611ab157604051633dca309360e11b815260040160405180910390fd5b825115611d245760006040518061016001604052808e6001600160a01b031681526020018d81526020018660200151815260200183815260200160405180608001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602001600081526020017f000000000000000000000000000000000000000000000000000000000000000081526020017f000000000000000000000000000000000000000000000000000000000000000081525081526020018781526020018c6001600160a01b031681526020018a15158152602001898152602001604051806020016040528060008152508152602001888152509050600084519050611bec604051806060016040528060006001600160a01b0316815260200160008152602001606081525090565b60005b82811015611d1f57868181518110611c0957611c09614cff565b60209081029190910101519150602080830151608086015190910152604082015161012085015281516001600160a01b0390811690636b204943907f00000000000000000000000000000000000000000000000000000000000000001661eeee14611c75576000611c7b565b83602001515b866040518363ffffffff1660e01b8152600401611c9891906151b0565b6000604051808303818588803b158015611cb157600080fd5b505af1158015611cc5573d6000803e3d6000fd5b505050505081600001516001600160a01b03167f232bbbe420e7bac6f941dc82678daec2b4c712378d91e864b69aab6e26cdd42485846020015133604051611d0f939291906151c3565b60405180910390a2600101611bef565b505050505b50505087816000015182602001517f133161f1c9161488f777ab9a26aae91d47c0d9a3fafb398960f138db02c737978c8b8f888b8b33604051611d6d97969594939291906151f6565b60405180910390a45098975050505050505050565b336001600160a01b03841614801590611e2b575060405163c161c93f60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063c161c93f90611de8903390879087908790600401615256565b602060405180830381865afa158015611e05573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e299190614c09565b155b8015611ec8575060405163c161c93f60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063c161c93f90611e8590339087906000908790600401615256565b602060405180830381865afa158015611ea2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ec69190614c09565b155b156117d55760405163075fd2b160e01b815260040160405180910390fd5b60405163c664459760e01b8152600481018790526024810186905260448101859052600090819081906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063c664459790606401610140604051808303816000875af1158015611f63573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f87919061527f565b9150915085811015611fac5760405163b01493c160e01b815260040160405180910390fd5b6040516331a9108f60e11b8152600481018a90526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636352211e90602401602060405180830381865afa158015612014573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120389190614bec565b600254909150600090818115612058576120538d6000613203565b61205e565b633b9aca005b90506000806120958f89602001517f00000000000000000000000000000000000000000000000000000000000000008a8888613377565b92509050633b9aca0083146120a957908101905b816000036120b85760006120dc565b6120dc8f6120d38a61010001516001604f9190911c81161490565b84878a88613537565b9450801561211957633b9aca0083146120ff576120fa81858561233f565b612102565b60005b61210c9082614bd9565b985061211930878b6117cb565b505050508a846000015185602001517fc41a8d26c70cfcf1b9ea10f82482ac947b8be5bea2750bc729af844bbfde1e28858e88878c8f8f336040516121659897969594939291906152d7565b60405180910390a4505050509695505050505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b801580156121e25750336001600160a01b03851614155b801561227e575060405163c161c93f60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063c161c93f9061223b903390889088908890600401615256565b602060405180830381865afa158015612258573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061227c9190614c09565b155b801561231b575060405163c161c93f60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063c161c93f906122d890339088906000908890600401615256565b602060405180830381865afa1580156122f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123199190614c09565b155b156123395760405163075fd2b160e01b815260040160405180910390fd5b50505050565b6000806123518484633b9aca00612896565b61235b9085614bd9565b905061237085633b9aca006114f4818561532a565b61237a9086614bd9565b9150505b9392505050565b604051630862026560e41b8152600160048201526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660248301526000917f000000000000000000000000000000000000000000000000000000000000000090911690638620265090604401602060405180830381865afa158015612417573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061243b9190614bec565b9050806001600160a01b0316631ebc263f61eeee6001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03161461248e576000612490565b855b6001877f0000000000000000000000000000000000000000000000000000000000000000886000808a6040516020016124cb91815260200190565b6040516020818303038152906040526040518963ffffffff1660e01b81526004016124fc979695949392919061533d565b60206040518083038185885af193505050508015612537575060408051601f3d908101601f1916820190925261253491810190614c26565b60015b6125eb573d808015612565576040519150601f19603f3d011682016040523d82523d6000602084013e61256a565b606091505b506125a783306001600160a01b03851603612586576000612588565b835b306001600160a01b0386160361259f5760006125a1565b875b886136b4565b6001837f80a889d08f0d59eb962335b57fb1d5b29e86e3d23f15087b5541fddf15422bbe8784336040516125dd93929190615395565b60405180910390a350612339565b5050505050565b604051632538671560e01b8152600481018990526024810188905260448101879052600090819081906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690632538671590606401610140604051808303816000875af115801561266f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612693919061527f565b91509150878110156126b85760405163b01493c160e01b815260040160405180910390fd5b6002546040516331a9108f60e11b8152600481018d90526000919082906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690636352211e90602401602060405180830381865afa158015612726573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061274a9190614bec565b9050600082158061276a57503360009081526004602052604090205460ff165b61277e576127798f6001613203565b612784565b633b9aca005b9050633b9aca0081146127ba576127b58f6127ac8861010001516001604f9190911c81161490565b87868686613537565b6127bd565b60005b93508385039650866000146127d7576127d7308c896117cb565b505050508a826000015183602001517f2eeee47c6d8d31c3523c3aa07b4c3e3795db36be4c04546ef3e30a5102f568e18a8e86898d8d8d336040516128239897969594939291906153c6565b60405180910390a4505098975050505050505050565b600082820361284957508261237e565b828211156128775761285b8383614bd9565b61286690600a614df9565b6128709085615426565b905061237e565b6128818284614bd9565b61288c90600a614df9565b612870908561545b565b60008080600019858709858702925082811083820303915050806000036128d0578382816128c6576128c6615445565b049250505061237e565b8381106128fa57604051631dcf306360e21b81526004810182905260248101859052604401610cb9565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60008361297157600061297b565b61297b8686613731565b90506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663e7c8e3e3876129b7848961532a565b6040516001600160e01b031960e085901b16815260048101929092526024820152604401600060405180830381600087803b1580156129f557600080fd5b505af1158015612a09573d6000803e3d6000fd5b50505050857f9ecaf7fc3dfffd6867c175d6e684b1f1e3aef019398ba8db2c1ffab4a09db2538683868633604051612a4595949392919061547d565b60405180910390a2505050505050565b60006001600160a01b038416612a7e57604051637ba50db360e11b815260040160405180910390fd5b612a8661446c565b6000806000600254905060607f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a2df1f958e8e8e8c8c6040518663ffffffff1660e01b8152600401612ae69594939291906154c9565b6000604051808303816000875af1158015612b05573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612b2d9190810190615508565b6001600160a01b038d16600090815260046020526040902054909b5091985091965090915060ff1680612b7d5750612710612b6786613b85565b148015612b7d5750612710612b7b86613ba2565b145b80612b86575081155b612b9a57612b958c6002613203565b612ba0565b633b9aca005b925089861015612bc35760405163f896960b60e01b815260040160405180910390fd5b8a15612cd357604051632eec7b5560e11b8152600481018d90527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635dd8f6aa90602401602060405180830381865afa158015612c2e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c529190614bec565b604051631665bc0f60e01b81526001600160a01b038f81166004830152602482018f9052604482018e905260a06064830152600060a4830181905260848301529190911690631665bc0f9060c401600060405180830381600087803b158015612cba57600080fd5b505af1158015612cce573d6000803e3d6000fd5b505050505b8051156130135760006040518061014001604052808f6001600160a01b031681526020018e8152602001876020015181526020018d815260200160405180608001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020018a81526020017f000000000000000000000000000000000000000000000000000000000000000081526020017f0000000000000000000000000000000000000000000000000000000000000000815250815260200160405180608001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602001600081526020017f000000000000000000000000000000000000000000000000000000000000000081526020017f000000000000000000000000000000000000000000000000000000000000000081525081526020018b6001600160a01b031681526020018a8152602001604051806020016040528060008152508152602001898152509050612e89604051806060016040528060006001600160a01b0316815260200160008152602001606081525090565b8251600090815b8181101561300d57858181518110612eaa57612eaa614cff565b6020026020010151935086600014612ed057612ecb8460200151888a61233f565b612ed3565b60005b92508215612f02576020840151612eea908a61532a565b98508284602001818151612efe9190614bd9565b9052505b60208085015160a087015190910152604084015161010086015283516001600160a01b0390811690630bf46e59907f00000000000000000000000000000000000000000000000000000000000000001661eeee14612f61576000612f67565b85602001515b876040518363ffffffff1660e01b8152600401612f8491906156da565b6000604051808303818588803b158015612f9d57600080fd5b505af1158015612fb1573d6000803e3d6000fd5b505050505083600001516001600160a01b03167f6596068545b2541b0aff5579d91f991d0fe5957df8e2082483ef361953e1f9978686602001518633604051612ffd94939291906156ed565b60405180910390a2600101612e90565b50505050505b50841561306e576000633b9aca0083146130375761303286838561233f565b61303a565b60005b9050801561305b5761304c868561532a565b93506130588187614bd9565b95505b851561306c5761306c308a886117cb565b505b8260000361307d57600061308c565b61308c8b600085848c87613537565b5050505087816000015182602001517f2be10f2a0203c77d0fcaa9fd6484a8a1d6904de31cd820587f60c1c8c338c8148c898c888b8b336040516130d697969594939291906151f6565b60405180910390a450979650505050505050565b8047101561313a5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e63650000006044820152606401610cb9565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114613187576040519150601f19603f3d011682016040523d82523d6000602084013e61318c565b606091505b50509050806117d55760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d617920686176652072657665727465640000000000006064820152608401610cb9565b604051630862026560e41b8152600160048201526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116602483015260009182917f00000000000000000000000000000000000000000000000000000000000000001690638620265090604401602060405180830381865afa158015613295573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132b99190614bec565b6001600160a01b0316036132d25750633b9aca00610848565b6003546001600160a01b03161561336e5760035460405163192dd60960e01b81526001600160a01b039091169063192dd609906133159086908690600401615725565b602060405180830381865afa92505050801561334e575060408051601f3d908101601f1916820190925261334b91810190614c26565b60015b61335a57506000610848565b633b9aca00811161336c579050610848565b505b50600092915050565b6040516369e11cc560e01b81526004810187905260248101869052604481018590526000908190633b9aca009082907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906369e11cc590606401600060405180830381865afa1580156133f7573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261341f9190810190615757565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081018290529192505b82518110156135255782818151811061347657613476614cff565b6020026020010151915060006134918a846040015187612896565b905060006134a3848f8e858e8e613bbf565b905080158015906134b45750818114155b156134c6576134c3828861532a565b96505b81156134d257818b039a505b8360400151860395508b8d8f7f0d31ab573f6daa4b1edba8d31973b4ba9f98fbfecc47010c1533eeefd2a1225a8786863360405161351394939291906158b4565b60405180910390a4505060010161345b565b50879450505050965096945050505050565b600061354485858461233f565b9050851561365657600087815260016020818152604080842081516080810183528a815263ffffffff808b168286019081528982168386019081526001600160a01b03808d16606086019081528654808b018855968b5297909920935160029095029093019384555192909501805491519451909616600160401b02600160401b600160e01b03199486166401000000000267ffffffffffffffff199092169290951691909117179190911691909117909155518490869089907f77813be0661650ddc1a5193ff2837df4162b251cb432651e2c060c3fc39756be90613649908790899033909283526001600160a01b03918216602084015216604082015260600190565b60405180910390a46136aa565b613661818489612385565b604080516001600160a01b038516815233602082015260009183918a917fcf0c92a2c6d7c42f488326b0cb900104b99984b6b218db81cd29371364a35251910160405180910390a45b9695505050505050565b60405163e7c8e3e360e01b815260048101859052602481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063e7c8e3e390604401600060405180830381600087803b15801561371d57600080fd5b505af11580156115fa573d6000803e3d6000fd5b600082815260016020908152604080832080548251818502810185019093528083528493849084015b828210156137c757600084815260209081902060408051608081018252600286029092018054835260019081015463ffffffff8082168587015264010000000082041692840192909252600160401b9091046001600160a01b03166060830152908352909201910161375a565b50505060008681526001602052604081209293506137e692915061444b565b8051839060005b81811015613b3d57826000036138ac576000878152600160205260409020845185908390811061381f5761381f614cff565b60209081029190910181015182546001818101855560009485529383902082516002909202019081559181015191909201805460408401516060909401516001600160a01b0316600160401b02600160401b600160e01b031963ffffffff9586166401000000000267ffffffffffffffff1990931695909416949094171791909116919091179055613b35565b8381815181106138be576138be614cff565b6020026020010151600001518310613974578381815181106138e2576138e2614cff565b6020026020010151600001518303925083818151811061390457613904614cff565b60200260200101516020015163ffffffff166000148061394a5750633b9aca0084828151811061393657613936614cff565b60200260200101516040015163ffffffff16145b6139685761396384828151811061105c5761105c614cff565b61396b565b60005b85019450613b35565b600160008881526020019081526020016000206040518060800160405280858785815181106139a5576139a5614cff565b6020026020010151600001510381526020018684815181106139c9576139c9614cff565b60200260200101516020015163ffffffff1681526020018684815181106139f2576139f2614cff565b60200260200101516040015163ffffffff168152602001868481518110613a1b57613a1b614cff565b6020908102919091018101516060908101516001600160a01b0390811690935284546001818101875560009687529583902085516002909202019081559184015191909401805460408501519490950151909216600160401b02600160401b600160e01b031963ffffffff9485166401000000000267ffffffffffffffff19909616949092169390931793909317929092161790558351849082908110613ac457613ac4614cff565b60200260200101516020015163ffffffff1660001480613b0a5750633b9aca00848281518110613af657613af6614cff565b60200260200101516040015163ffffffff16145b613b2957613b248385838151811061107a5761107a614cff565b613b2c565b60005b85019450600092505b6001016137ed565b50604080518381523360208201528591879189917f59860d79d97c1fce2be7f987915c631471f4b08f671200463cc40a3380194ffb910160405180910390a450505092915050565b60006028826101000151901c61ffff166127106108489190614bd9565b60006038826101000151901c61ffff166127106108489190614bd9565b60c086015183906001600160a01b031615613e7f57633b9aca008214158015613c05575060c08701516001600160a01b031660009081526004602052604090205460ff16155b15613c1857613c1584848461233f565b90035b60006040518060c001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020018381526020017f000000000000000000000000000000000000000000000000000000000000000081526020018881526020018781526020018981525090506060613ca98960c00151634eba05fd60e11b61431d565b15613ddc578860c001516001600160a01b0316639d740bfa61eeee6001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614613d03576000613d05565b845b846040518363ffffffff1660e01b8152600401613d2291906158e9565b6000604051808303818588803b158015613d3b57600080fd5b505af193505050508015613d4d575060015b613dd7573d808015613d7b576040519150601f19603f3d011682016040523d82523d6000602084013e613d80565b606091505b50805115613d8e5780613dcf565b604051602001613dbf906020808252600d908201526c105b1b1bd8d85d194819985a5b609a1b604082015260600190565b6040516020818303038152906040525b915050613e1e565b613e1e565b604051602001613e0c906020808252600c908201526b12515490cc4d8d4819985a5b60a21b604082015260600190565b60405160208183030381529060405290505b805115613e7857613e35888a60c0015185896136b4565b60009250877f290b5df59e172593762964e4f8ed2b4a9192d3197bfd2be4bae123908f8007968a888433604051613e6f949392919061593d565b60405180910390a25b50506136aa565b6060870151156142da576060870151604051630862026560e41b81526000916001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691638620265091613f0f917f0000000000000000000000000000000000000000000000000000000000000000906004019182526001600160a01b0316602082015260400190565b602060405180830381865afa158015613f2c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f509190614bec565b90506001600160a01b038116613fb25760009150613f7187600080886136b4565b867f290b5df59e172593762964e4f8ed2b4a9192d3197bfd2be4bae123908f800796898733604051613fa593929190615980565b60405180910390a26142d4565b6001600160a01b0381163014801590613fcf5750633b9aca008314155b8015613ff457506001600160a01b03811660009081526004602052604090205460ff16155b156140095761400485858561233f565b820391505b87602001511561418657806001600160a01b0316630cf8e85861eeee6001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614614064576000614066565b835b8a60600151857f00000000000000000000000000000000000000000000000000000000000000008c6040516020016140a091815260200190565b6040516020818303038152906040526040518663ffffffff1660e01b81526004016140ce9493929190614c8f565b6000604051808303818588803b1580156140e757600080fd5b505af1935050505080156140f9575060015b614181573d808015614127576040519150601f19603f3d011682016040523d82523d6000602084013e61412c565b606091505b50614139888385896136b4565b60009250877f290b5df59e172593762964e4f8ed2b4a9192d3197bfd2be4bae123908f8007968a888433604051614173949392919061593d565b60405180910390a2506142d4565b6142d4565b806001600160a01b0316631ebc263f61eeee6001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316146141d75760006141d9565b835b60608b015160808c015186907f0000000000000000000000000000000000000000000000000000000000000000906001600160a01b031661421a5733614220565b8d608001515b60008f600001518f60405160200161423a91815260200190565b6040516020818303038152906040526040518963ffffffff1660e01b815260040161426b979695949392919061533d565b60206040518083038185885af1935050505080156142a6575060408051601f3d908101601f191682019092526142a391810190614c26565b60015b613e78573d808015614127576040519150601f19603f3d011682016040523d82523d6000602084013e61412c565b506136aa565b633b9aca0082146142f3576142f084848461233f565b90035b60808701516136aa9030906001600160a01b03166143115733614317565b88608001515b836117cb565b600061432883614339565b801561237e575061237e838361436c565b600061434c826301ffc9a760e01b61436c565b80156108485750614365826001600160e01b031961436c565b1592915050565b604080516001600160e01b0319831660248083019190915282518083039091018152604490910182526020810180516001600160e01b03166301ffc9a760e01b179052905160009190829081906001600160a01b03871690617530906143d39086906159dd565b6000604051808303818686fa925050503d806000811461440f576040519150601f19603f3d011682016040523d82523d6000602084013e614414565b606091505b509150915060208151101561442f5760009350505050610848565b8180156136aa5750808060200190518101906136aa9190614c09565b508054600082556002029060005260206000209081019061169c91906144c1565b6040518061012001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b03168152602001600081525090565b5b808211156144e857600081556001810180546001600160e01b03191690556002016144c2565b5090565b6000602082840312156144fe57600080fd5b81356001600160e01b03198116811461237e57600080fd5b6001600160a01b038116811461169c57600080fd5b60008083601f84011261453d57600080fd5b5081356001600160401b0381111561455457600080fd5b60208301915083602082850101111561456c57600080fd5b9250929050565b600080600080600080600060a0888a03121561458e57600080fd5b873596506020880135955060408801356145a781614516565b945060608801356001600160401b03808211156145c357600080fd5b6145cf8b838c0161452b565b909650945060808a01359150808211156145e857600080fd5b506145f58a828b0161452b565b989b979a50959850939692959293505050565b60006020828403121561461a57600080fd5b813561237e81614516565b801515811461169c57600080fd5b6000806000806000806000806000806101008b8d03121561465357600080fd5b8a35995060208b0135985060408b013561466c81614516565b975060608b013561467c81614516565b965060808b0135955060a08b013561469381614625565b945060c08b01356001600160401b03808211156146af57600080fd5b6146bb8e838f0161452b565b909650945060e08d01359150808211156146d457600080fd5b506146e18d828e0161452b565b915080935050809150509295989b9194979a5092959850565b6000806040838503121561470d57600080fd5b82359150602083013561471f81614516565b809150509250929050565b600080600080600080600060c0888a03121561474557600080fd5b873596506020880135955060408801359450606088013561476581614516565b93506080880135925060a08801356001600160401b0381111561478757600080fd5b6145f58a828b0161452b565b6000602082840312156147a557600080fd5b5035919050565b600080604083850312156147bf57600080fd5b82356147ca81614516565b9150602083013561471f81614625565b602080825282518282018190526000919060409081850190868401855b82811015614843578151805185528681015163ffffffff908116888701528682015116868601526060908101516001600160a01b031690850152608090930192908501906001016147f7565b5091979650505050505050565b634e487b7160e01b600052604160045260246000fd5b60405161012081016001600160401b038111828210171561488957614889614850565b60405290565b604051606081016001600160401b038111828210171561488957614889614850565b60405160e081016001600160401b038111828210171561488957614889614850565b604051601f8201601f191681016001600160401b03811182821017156148fb576148fb614850565b604052919050565b60006001600160401b0382111561491c5761491c614850565b50601f01601f191660200190565b600082601f83011261493b57600080fd5b813561494e61494982614903565b6148d3565b81815284602083860101111561496357600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060008060006101008a8c03121561499f57600080fd5b8935985060208a0135975060408a0135965060608a01356149bf81614516565b955060808a0135945060a08a01356149d681614516565b935060c08a01356001600160401b03808211156149f257600080fd5b6149fe8d838e0161492a565b945060e08c0135915080821115614a1457600080fd5b50614a218c828d0161452b565b915080935050809150509295985092959850929598565b60008060008060008060008060c0898b031215614a5457600080fd5b88359750602089013596506040890135614a6d81614516565b95506060890135614a7d81614625565b945060808901356001600160401b0380821115614a9957600080fd5b614aa58c838d0161452b565b909650945060a08b0135915080821115614abe57600080fd5b50614acb8b828c0161452b565b999c989b5096995094979396929594505050565b60008060408385031215614af257600080fd5b8235614afd81614516565b946020939093013593505050565b600080600080600080600080610100898b031215614b2857600080fd5b8835614b3381614516565b975060208901359650604089013595506060890135614b5181614516565b94506080890135935060a0890135614b6881614516565b925060c08901356001600160401b0380821115614b8457600080fd5b614b908c838d0161492a565b935060e08b0135915080821115614ba657600080fd5b50614bb38b828c0161492a565b9150509295985092959890939650565b634e487b7160e01b600052601160045260246000fd5b8181038181111561084857610848614bc3565b600060208284031215614bfe57600080fd5b815161237e81614516565b600060208284031215614c1b57600080fd5b815161237e81614625565b600060208284031215614c3857600080fd5b5051919050565b60005b83811015614c5a578181015183820152602001614c42565b50506000910152565b60008151808452614c7b816020860160208601614c3f565b601f01601f19169290920160200192915050565b84815283602082015260018060a01b038316604082015260a06060820152600060a082015260c0608082015260006136aa60c0830184614c63565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b634e487b7160e01b600052603260045260246000fd5b600181815b80851115614d50578160001904821115614d3657614d36614bc3565b80851615614d4357918102915b93841c9390800290614d1a565b509250929050565b600082614d6757506001610848565b81614d7457506000610848565b8160018114614d8a5760028114614d9457614db0565b6001915050610848565b60ff841115614da557614da5614bc3565b50506001821b610848565b5060208310610133831016604e8410600b8410161715614dd3575081810a610848565b614ddd8383614d15565b8060001904821115614df157614df1614bc3565b029392505050565b600061237e8383614d58565b80516001600160a01b031682526020808201519083015260408082015190830152606090810151910152565b6001600160a01b03888116825260009061014090614e52602085018b614e05565b8860a08501528760c085015280871660e08501525080610100840152614e7a81840186614c63565b9050828103610120840152614e8f8185614c63565b9a9950505050505050505050565b8051614ea881614516565b919050565b60006101208284031215614ec057600080fd5b614ec8614866565b9050815181526020820151602082015260408201516040820152606082015160608201526080820151608082015260a082015160a082015260c082015160c0820152614f1660e08301614e9d565b60e082015261010080830151818301525092915050565b60006001600160401b03821115614f4657614f46614850565b5060051b60200190565b600082601f830112614f6157600080fd5b8151614f6f61494982614903565b818152846020838601011115614f8457600080fd5b611500826020830160208701614c3f565b6000806000806101808587031215614fac57600080fd5b614fb68686614ead565b935061012085015192506101408501516001600160401b0380821115614fdb57600080fd5b818701915087601f830112614fef57600080fd5b8151614ffd61494982614f2d565b8082825260208201915060208360051b86010192508a83111561501f57600080fd5b602085015b838110156150a95780518581111561503b57600080fd5b86016060818e03601f1901121561505157600080fd5b61505961488f565b602082015161506781614516565b81526040820151602082015260608201518781111561508557600080fd5b6150948f602083860101614f50565b60408301525084525060209283019201615024565b506101608a015190965093505050808211156150c457600080fd5b506150d187828801614f50565b91505092959194509250565b80516001600160a01b031682526000610220602083015160208501526040830151604085015260608301516151156060860182614e05565b50608083015161512860e0860182614e05565b5060a083015161016085015260c08301516001600160a01b031661018085015260e083015115156101a08501526101008301516101c0850182905261516f82860182614c63565b9150506101208301518482036101e086015261518b8282614c63565b9150506101408301518482036102008601526151a78282614c63565b95945050505050565b60208152600061237e60208301846150dd565b6060815260006151d660608301866150dd565b6020830194909452506001600160a01b0391909116604090910152919050565b600060018060a01b03808a168352808916602084015287604084015286606084015260e0608084015261522c60e0840187614c63565b83810360a085015261523e8187614c63565b92505080841660c08401525098975050505050505050565b6001600160a01b0394851681529290931660208301526040820152606081019190915260800190565b600080610140838503121561529357600080fd5b61529d8484614ead565b915061012083015190509250929050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b600060018060a01b03808b16835289602084015288604084015287606084015286608084015260e060a084015261531260e0840186886152ae565b915080841660c0840152509998505050505050505050565b8082018082111561084857610848614bc3565b878152602081018790526001600160a01b038681166040830152851660608201526080810184905282151560a082015261010060c08201819052600090820181905261012060e08301819052614e8f81840185614c63565b8381526060602082015260006153ae6060830185614c63565b905060018060a01b0383166040830152949350505050565b600060018060a01b03808b16835289602084015288604084015287606084015260e060808401526153fa60e0840188614c63565b83810360a085015261540d8187896152ae565b92505080841660c0840152509998505050505050505050565b600081600019048311821515161561544057615440614bc3565b500290565b634e487b7160e01b600052601260045260246000fd5b60008261547857634e487b7160e01b600052601260045260246000fd5b500490565b85815284602082015260a06040820152600061549c60a0830186614c63565b82810360608401526154ae8186614c63565b91505060018060a01b03831660808301529695505050505050565b60018060a01b038616815284602082015283604082015260a0606082015260006154f660a0830185614c63565b8281036080840152610c838185614c63565b600080600080610180858703121561551f57600080fd5b6155298686614ead565b935061012085015192506101408501516001600160401b038082111561554e57600080fd5b818701915087601f83011261556257600080fd5b815161557061494982614f2d565b8082825260208201915060208360051b86010192508a83111561559257600080fd5b602085015b838110156150a9578051858111156155ae57600080fd5b86016060818e03601f190112156155c457600080fd5b6155cc61488f565b60208201516155da81614516565b8152604082015160208201526060820151878111156155f857600080fd5b6156078f602083860101614f50565b60408301525084525060209283019201615597565b80516001600160a01b031682526000610200602083015160208501526040830151604085015260608301516060850152608083015161565e6080860182614e05565b5060a083015161010061567381870183614e05565b60c08501516001600160a01b031661018087015260e08501516101a0870184905291506156a283870183614c63565b9250808501519150508482036101c08601526156be8282614c63565b9150506101208301518482036101e08601526151a78282614c63565b60208152600061237e602083018461561c565b608081526000615700608083018761561c565b60208301959095525060408101929092526001600160a01b0316606090910152919050565b828152604081016003831061574a57634e487b7160e01b600052602160045260246000fd5b8260208301529392505050565b6000602080838503121561576a57600080fd5b82516001600160401b0381111561578057600080fd5b8301601f8101851361579157600080fd5b805161579f61494982614f2d565b81815260e091820283018401918482019190888411156157be57600080fd5b938501935b838510156158545780858a0312156157db5760008081fd5b6157e36148b1565b85516157ee81614625565b8152858701516157fd81614625565b81880152604086810151908201526060808701519082015260808087015161582481614516565b9082015260a0868101519082015260c08087015161584181614516565b90820152835293840193918501916157c3565b50979650505050505050565b80511515825260208082015115159083015260408082015190830152606080820151908301526080808201516001600160a01b039081169184019190915260a0808301519084015260c09182015116910152565b61014081016158c38287615860565b60e08201949094526101008101929092526001600160a01b031661012090910152919050565b81516001600160a01b031681526020808301519082015260408083015190820152606080830151908201526080808301519082015260a08281015161018083019161593690840182615860565b5092915050565b600061014061594c8388615860565b8560e08401528061010084015261596581840186614c63565b91505060018060a01b03831661012083015295945050505050565b600061014061598f8387615860565b60e08301949094525061010081018390526012928101929092527115195c9b5a5b985b081b9bdd08199bdd5b9960721b6101608301526001600160a01b031661012082015261018001919050565b600082516159ef818460208701614c3f565b919091019291505056fea2646970667358221220558248dbc04ea10c612e57468002e5730c490a4a5abc710d603914a962691a5464736f6c63430008100033", + "deployedBytecode": "0x6080604052600436106101f95760003560e01c80638da5cb5b1161010d578063c715967a116100a0578063df21a7dd1161006f578063df21a7dd146106ae578063e5a6b10f146106fc578063f2fde38b14610730578063fc0c546a14610750578063fe663f0f1461078457600080fd5b8063c715967a14610631578063d3419bf314610644578063d6dacc5314610678578063ddca3f431461069857600080fd5b8063ad007d63116100dc578063ad007d6314610559578063b631b5001461058d578063b7bad1b1146105bd578063c41c2f24146105fd57600080fd5b80638da5cb5b146104c7578063975057e7146104e5578063a02f801c14610519578063a32e1e961461053957600080fd5b80634a4305c011610190578063715018a61161015f578063715018a6146104115780637258002c1461042657806389701db5146104465780638af56094146104665780638b79543c1461049357600080fd5b80634a4305c01461037d578063637913ac1461039d57806366248b86146103bd57806369fe0e2d146103f157600080fd5b80632bdfe004116101cc5780632bdfe004146102a95780632d1a5903146102f5578063313ce56714610329578063405b84fa1461035d57600080fd5b806301ffc9a7146101fe5780630cf8e858146102335780631982d679146102485780631ebc263f14610296575b600080fd5b34801561020a57600080fd5b5061021e6102193660046144ec565b6107a4565b60405190151581526020015b60405180910390f35b610246610241366004614573565b61084e565b005b34801561025457600080fd5b50610288610263366004614608565b507f000000000000000000000000000000000000000000000000000000000000000090565b60405190815260200161022a565b6102886102a4366004614633565b610871565b3480156102b557600080fd5b506102dd7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200161022a565b34801561030157600080fd5b506102887f000000000000000000000000000000000000000000000000000000000000000081565b34801561033557600080fd5b506102887f000000000000000000000000000000000000000000000000000000000000000081565b34801561036957600080fd5b506102886103783660046146fa565b610977565b34801561038957600080fd5b5061028861039836600461472a565b610c73565b3480156103a957600080fd5b506102466103b8366004614608565b610c8f565b3480156103c957600080fd5b506102887f000000000000000000000000000000000000000000000000000000000000000081565b3480156103fd57600080fd5b5061024661040c366004614793565b610d16565b34801561041d57600080fd5b50610246610da5565b34801561043257600080fd5b506102466104413660046147ac565b610ddb565b34801561045257600080fd5b50610246610461366004614793565b610e67565b34801561047257600080fd5b50610486610481366004614793565b61116b565b60405161022a91906147da565b34801561049f57600080fd5b506102dd7f000000000000000000000000000000000000000000000000000000000000000081565b3480156104d357600080fd5b506000546001600160a01b03166102dd565b3480156104f157600080fd5b506102dd7f000000000000000000000000000000000000000000000000000000000000000081565b34801561052557600080fd5b50610288610534366004614980565b611218565b34801561054557600080fd5b50610288610554366004614793565b6112d3565b34801561056557600080fd5b506102dd7f000000000000000000000000000000000000000000000000000000000000000081565b34801561059957600080fd5b5061021e6105a8366004614608565b60046020526000908152604090205460ff1681565b3480156105c957600080fd5b506102886105d8366004614608565b507f000000000000000000000000000000000000000000000000000000000000000090565b34801561060957600080fd5b506102dd7f000000000000000000000000000000000000000000000000000000000000000081565b61024661063f366004614a38565b611508565b34801561065057600080fd5b506102dd7f000000000000000000000000000000000000000000000000000000000000000081565b34801561068457600080fd5b506003546102dd906001600160a01b031681565b3480156106a457600080fd5b5061028860025481565b3480156106ba57600080fd5b5061021e6106c9366004614adf565b507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b34801561070857600080fd5b506102887f000000000000000000000000000000000000000000000000000000000000000081565b34801561073c57600080fd5b5061024661074b366004614608565b611604565b34801561075c57600080fd5b506102dd7f000000000000000000000000000000000000000000000000000000000000000081565b34801561079057600080fd5b5061028861079f366004614b0b565b61169f565b60006001600160e01b0319821615806107cd57506001600160e01b0319821663edb527eb60e01b145b806107e857506001600160e01b031982166301290c1760e61b145b8061080357506001600160e01b0319821663280be00760e21b145b8061081e57506001600160e01b0319821663fe663f0f60e01b145b8061083957506001600160e01b0319821663ad007d6360e01b145b806108485750610848826116cf565b92915050565b6108578761171f565b610868878787600088888888611508565b50505050505050565b600061087c8b61171f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031661eeee146108eb5734156108cd57604051635e7e9adf60e11b815260040160405180910390fd5b476108d933308d6117cb565b6108e38147614bd9565b9a50506108ef565b3499505b6109688a338d8b8b8b8b8b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8f018190048102820181019092528d815292508d91508c90819084018382808284376000920191909152506117da92505050565b9b9a5050505050505050505050565b6040516331a9108f60e11b8152600481018390526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636352211e90602401602060405180830381865afa1580156109df573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a039190614bec565b836004610a11838383611d82565b60405163df21a7dd60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301526024820188905286169063df21a7dd90604401602060405180830381865afa158015610a7e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aa29190614c09565b610abf5760405163581010ed60e01b815260040160405180910390fd5b604051636bb6a5ad60e01b8152600481018790527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636bb6a5ad906024016020604051808303816000875af1158015610b26573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b4a9190614c26565b93508315610c255760007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031661eeee14610b8d576000610b8f565b845b6040805160208101825260008152905163019f1d0b60e31b81529192506001600160a01b03881691630cf8e858918491610bf1918c918b917f000000000000000000000000000000000000000000000000000000000000000091600401614c8f565b6000604051808303818588803b158015610c0a57600080fd5b505af1158015610c1e573d6000803e3d6000fd5b5050505050505b604080518581523360208201526001600160a01b0387169188917fa7519e5f94697b7f53e97c5eb46a0c730a296ab686ab8fd333835c5f735784eb910160405180910390a350505092915050565b6000610c83888888878787611ee6565b98975050505050505050565b6000546001600160a01b03163314610cc25760405162461bcd60e51b8152600401610cb990614cca565b60405180910390fd5b600380546001600160a01b0319166001600160a01b0383169081179091556040513381527f0a9a80fe9716605b3e52abb3d792d6a4e7816d6afc02a5a4ef023081feaf9f609060200160405180910390a250565b6000546001600160a01b03163314610d405760405162461bcd60e51b8152600401610cb990614cca565b6302faf080811115610d65576040516345fbd9c160e01b815260040160405180910390fd5b6002819055604080518281523360208201527fd7414e590e1cb532989ab2a34c8f4c2c17f7ab6f006efeeaef2e87cd5008c202910160405180910390a150565b6000546001600160a01b03163314610dcf5760405162461bcd60e51b8152600401610cb990614cca565b610dd9600061217b565b565b6000546001600160a01b03163314610e055760405162461bcd60e51b8152600401610cb990614cca565b6001600160a01b038216600081815260046020908152604091829020805460ff191685151590811790915591513381529192917fa2653e25a502c023a5830d0de847ef6f458387865b1f4f575d7594f9f2c0d71e910160405180910390a35050565b6040516331a9108f60e11b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636352211e90602401602060405180830381865afa158015610ecc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ef09190614bec565b816005610f056000546001600160a01b031690565b6001600160a01b0316336001600160a01b031614610f25848484846121cb565b600085815260016020908152604080832080548251818502810185019093528083529192909190849084015b82821015610fbe57600084815260209081902060408051608081018252600286029092018054835260019081015463ffffffff8082168587015264010000000082041692840192909252600160401b9091046001600160a01b031660608301529083529092019101610f51565b5050506000888152600160205260408120929350610fdd92915061444b565b80516000805b8281101561116057838181518110610ffd57610ffd614cff565b60200260200101516020015163ffffffff16600014806110435750633b9aca0084828151811061102f5761102f614cff565b60200260200101516040015163ffffffff16145b6110ba576110b584828151811061105c5761105c614cff565b60200260200101516000015185838151811061107a5761107a614cff565b60200260200101516020015163ffffffff1686848151811061109e5761109e614cff565b60200260200101516040015163ffffffff1661233f565b6110bd565b60005b91506110e7828583815181106110d5576110d5614cff565b6020026020010151606001518b612385565b60011515828a7fcf0c92a2c6d7c42f488326b0cb900104b99984b6b218db81cd29371364a3525187858151811061112057611120614cff565b602002602001015160600151336040516111509291906001600160a01b0392831681529116602082015260400190565b60405180910390a4600101610fe3565b505050505050505050565b606060016000838152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b8282101561120d57600084815260209081902060408051608081018252600286029092018054835260019081015463ffffffff8082168587015264010000000082041692840192909252600160401b9091046001600160a01b0316606083015290835290920191016111a0565b505050509050919050565b6040516331a9108f60e11b8152600481018a90526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636352211e90602401602060405180830381865afa158015611280573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112a49190614bec565b8a60116112b2838383611d82565b6112c28d8d8d8c8c8c8c8c6125f2565b9d9c50505050505050505050505050565b60405163035240c760e61b81523060048201526024810182905260009081906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063d49031c090604401602060405180830381865afa158015611343573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113679190614c26565b905060007f00000000000000000000000000000000000000000000000000000000000000006012146113c4576113bf827f00000000000000000000000000000000000000000000000000000000000000006012612839565b6113c6565b815b905060017f0000000000000000000000000000000000000000000000000000000000000000146114fe576114f98161141f7f0000000000000000000000000000000000000000000000000000000000000000600a614df9565b604051635268657960e11b81527f00000000000000000000000000000000000000000000000000000000000000006004820152600160248201527f000000000000000000000000000000000000000000000000000000000000000060448201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a4d0caf290606401602060405180830381865afa1580156114d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114f49190614c26565b612896565b611500565b805b949350505050565b6115118861171f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031661eeee1461158057341561156257604051635e7e9adf60e11b815260040160405180910390fd5b4761156e33308a6117cb565b6115788147614bd9565b975050611584565b3496505b6115fa88888787878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8b01819004810282018101909252898152925089915088908190840183828082843760009201919091525061296392505050565b5050505050505050565b6000546001600160a01b0316331461162e5760405162461bcd60e51b8152600401610cb990614cca565b6001600160a01b0381166116935760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610cb9565b61169c8161217b565b50565b6000888860026116b0838383611d82565b6116bf8c8c8c8b8b8b8b612a55565b9c9b505050505050505050505050565b60006001600160e01b0319821663301cdc3960e21b148061170057506001600160e01b0319821663144b000160e11b145b8061084857506301ffc9a760e01b6001600160e01b0319831614610848565b604051636e49181f60e01b8152600481018290523060248201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636e49181f90604401602060405180830381865afa15801561178a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117ae9190614c09565b61169c57604051631b1d5a5960e31b815260040160405180910390fd5b6117d582826130ea565b505050565b60006001600160a01b0386166118035760405163a762251360e01b815260040160405180910390fd5b61180b61446c565b606060008060405180608001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020018e81526020017f000000000000000000000000000000000000000000000000000000000000000081526020017f000000000000000000000000000000000000000000000000000000000000000081525090507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632fa1b3918d838e7f00000000000000000000000000000000000000000000000000000000000000008f8d8d6040518863ffffffff1660e01b81526004016119149796959493929190614e31565b6000604051808303816000875af1158015611933573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261195b9190810190614f95565b995091955090935091508115611a9057604051632eec7b5560e11b8152600481018c90527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635dd8f6aa90602401602060405180830381865afa1580156119d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119f49190614bec565b604051638ae9c07b60e01b8152600481018d9052602481018490526001600160a01b038c8116604483015260c06064830152600060c48301528a15156084830152600160a48301529190911690638ae9c07b9060e4016020604051808303816000875af1158015611a69573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a8d9190614c26565b94505b88851015611ab157604051633dca309360e11b815260040160405180910390fd5b825115611d245760006040518061016001604052808e6001600160a01b031681526020018d81526020018660200151815260200183815260200160405180608001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602001600081526020017f000000000000000000000000000000000000000000000000000000000000000081526020017f000000000000000000000000000000000000000000000000000000000000000081525081526020018781526020018c6001600160a01b031681526020018a15158152602001898152602001604051806020016040528060008152508152602001888152509050600084519050611bec604051806060016040528060006001600160a01b0316815260200160008152602001606081525090565b60005b82811015611d1f57868181518110611c0957611c09614cff565b60209081029190910101519150602080830151608086015190910152604082015161012085015281516001600160a01b0390811690636b204943907f00000000000000000000000000000000000000000000000000000000000000001661eeee14611c75576000611c7b565b83602001515b866040518363ffffffff1660e01b8152600401611c9891906151b0565b6000604051808303818588803b158015611cb157600080fd5b505af1158015611cc5573d6000803e3d6000fd5b505050505081600001516001600160a01b03167f232bbbe420e7bac6f941dc82678daec2b4c712378d91e864b69aab6e26cdd42485846020015133604051611d0f939291906151c3565b60405180910390a2600101611bef565b505050505b50505087816000015182602001517f133161f1c9161488f777ab9a26aae91d47c0d9a3fafb398960f138db02c737978c8b8f888b8b33604051611d6d97969594939291906151f6565b60405180910390a45098975050505050505050565b336001600160a01b03841614801590611e2b575060405163c161c93f60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063c161c93f90611de8903390879087908790600401615256565b602060405180830381865afa158015611e05573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e299190614c09565b155b8015611ec8575060405163c161c93f60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063c161c93f90611e8590339087906000908790600401615256565b602060405180830381865afa158015611ea2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ec69190614c09565b155b156117d55760405163075fd2b160e01b815260040160405180910390fd5b60405163c664459760e01b8152600481018790526024810186905260448101859052600090819081906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063c664459790606401610140604051808303816000875af1158015611f63573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f87919061527f565b9150915085811015611fac5760405163b01493c160e01b815260040160405180910390fd5b6040516331a9108f60e11b8152600481018a90526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636352211e90602401602060405180830381865afa158015612014573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120389190614bec565b600254909150600090818115612058576120538d6000613203565b61205e565b633b9aca005b90506000806120958f89602001517f00000000000000000000000000000000000000000000000000000000000000008a8888613377565b92509050633b9aca0083146120a957908101905b816000036120b85760006120dc565b6120dc8f6120d38a61010001516001604f9190911c81161490565b84878a88613537565b9450801561211957633b9aca0083146120ff576120fa81858561233f565b612102565b60005b61210c9082614bd9565b985061211930878b6117cb565b505050508a846000015185602001517fc41a8d26c70cfcf1b9ea10f82482ac947b8be5bea2750bc729af844bbfde1e28858e88878c8f8f336040516121659897969594939291906152d7565b60405180910390a4505050509695505050505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b801580156121e25750336001600160a01b03851614155b801561227e575060405163c161c93f60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063c161c93f9061223b903390889088908890600401615256565b602060405180830381865afa158015612258573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061227c9190614c09565b155b801561231b575060405163c161c93f60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063c161c93f906122d890339088906000908890600401615256565b602060405180830381865afa1580156122f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123199190614c09565b155b156123395760405163075fd2b160e01b815260040160405180910390fd5b50505050565b6000806123518484633b9aca00612896565b61235b9085614bd9565b905061237085633b9aca006114f4818561532a565b61237a9086614bd9565b9150505b9392505050565b604051630862026560e41b8152600160048201526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660248301526000917f000000000000000000000000000000000000000000000000000000000000000090911690638620265090604401602060405180830381865afa158015612417573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061243b9190614bec565b9050806001600160a01b0316631ebc263f61eeee6001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03161461248e576000612490565b855b6001877f0000000000000000000000000000000000000000000000000000000000000000886000808a6040516020016124cb91815260200190565b6040516020818303038152906040526040518963ffffffff1660e01b81526004016124fc979695949392919061533d565b60206040518083038185885af193505050508015612537575060408051601f3d908101601f1916820190925261253491810190614c26565b60015b6125eb573d808015612565576040519150601f19603f3d011682016040523d82523d6000602084013e61256a565b606091505b506125a783306001600160a01b03851603612586576000612588565b835b306001600160a01b0386160361259f5760006125a1565b875b886136b4565b6001837f80a889d08f0d59eb962335b57fb1d5b29e86e3d23f15087b5541fddf15422bbe8784336040516125dd93929190615395565b60405180910390a350612339565b5050505050565b604051632538671560e01b8152600481018990526024810188905260448101879052600090819081906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690632538671590606401610140604051808303816000875af115801561266f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612693919061527f565b91509150878110156126b85760405163b01493c160e01b815260040160405180910390fd5b6002546040516331a9108f60e11b8152600481018d90526000919082906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690636352211e90602401602060405180830381865afa158015612726573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061274a9190614bec565b9050600082158061276a57503360009081526004602052604090205460ff165b61277e576127798f6001613203565b612784565b633b9aca005b9050633b9aca0081146127ba576127b58f6127ac8861010001516001604f9190911c81161490565b87868686613537565b6127bd565b60005b93508385039650866000146127d7576127d7308c896117cb565b505050508a826000015183602001517f2eeee47c6d8d31c3523c3aa07b4c3e3795db36be4c04546ef3e30a5102f568e18a8e86898d8d8d336040516128239897969594939291906153c6565b60405180910390a4505098975050505050505050565b600082820361284957508261237e565b828211156128775761285b8383614bd9565b61286690600a614df9565b6128709085615426565b905061237e565b6128818284614bd9565b61288c90600a614df9565b612870908561545b565b60008080600019858709858702925082811083820303915050806000036128d0578382816128c6576128c6615445565b049250505061237e565b8381106128fa57604051631dcf306360e21b81526004810182905260248101859052604401610cb9565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60008361297157600061297b565b61297b8686613731565b90506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663e7c8e3e3876129b7848961532a565b6040516001600160e01b031960e085901b16815260048101929092526024820152604401600060405180830381600087803b1580156129f557600080fd5b505af1158015612a09573d6000803e3d6000fd5b50505050857f9ecaf7fc3dfffd6867c175d6e684b1f1e3aef019398ba8db2c1ffab4a09db2538683868633604051612a4595949392919061547d565b60405180910390a2505050505050565b60006001600160a01b038416612a7e57604051637ba50db360e11b815260040160405180910390fd5b612a8661446c565b6000806000600254905060607f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a2df1f958e8e8e8c8c6040518663ffffffff1660e01b8152600401612ae69594939291906154c9565b6000604051808303816000875af1158015612b05573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612b2d9190810190615508565b6001600160a01b038d16600090815260046020526040902054909b5091985091965090915060ff1680612b7d5750612710612b6786613b85565b148015612b7d5750612710612b7b86613ba2565b145b80612b86575081155b612b9a57612b958c6002613203565b612ba0565b633b9aca005b925089861015612bc35760405163f896960b60e01b815260040160405180910390fd5b8a15612cd357604051632eec7b5560e11b8152600481018d90527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635dd8f6aa90602401602060405180830381865afa158015612c2e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c529190614bec565b604051631665bc0f60e01b81526001600160a01b038f81166004830152602482018f9052604482018e905260a06064830152600060a4830181905260848301529190911690631665bc0f9060c401600060405180830381600087803b158015612cba57600080fd5b505af1158015612cce573d6000803e3d6000fd5b505050505b8051156130135760006040518061014001604052808f6001600160a01b031681526020018e8152602001876020015181526020018d815260200160405180608001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020018a81526020017f000000000000000000000000000000000000000000000000000000000000000081526020017f0000000000000000000000000000000000000000000000000000000000000000815250815260200160405180608001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602001600081526020017f000000000000000000000000000000000000000000000000000000000000000081526020017f000000000000000000000000000000000000000000000000000000000000000081525081526020018b6001600160a01b031681526020018a8152602001604051806020016040528060008152508152602001898152509050612e89604051806060016040528060006001600160a01b0316815260200160008152602001606081525090565b8251600090815b8181101561300d57858181518110612eaa57612eaa614cff565b6020026020010151935086600014612ed057612ecb8460200151888a61233f565b612ed3565b60005b92508215612f02576020840151612eea908a61532a565b98508284602001818151612efe9190614bd9565b9052505b60208085015160a087015190910152604084015161010086015283516001600160a01b0390811690630bf46e59907f00000000000000000000000000000000000000000000000000000000000000001661eeee14612f61576000612f67565b85602001515b876040518363ffffffff1660e01b8152600401612f8491906156da565b6000604051808303818588803b158015612f9d57600080fd5b505af1158015612fb1573d6000803e3d6000fd5b505050505083600001516001600160a01b03167f6596068545b2541b0aff5579d91f991d0fe5957df8e2082483ef361953e1f9978686602001518633604051612ffd94939291906156ed565b60405180910390a2600101612e90565b50505050505b50841561306e576000633b9aca0083146130375761303286838561233f565b61303a565b60005b9050801561305b5761304c868561532a565b93506130588187614bd9565b95505b851561306c5761306c308a886117cb565b505b8260000361307d57600061308c565b61308c8b600085848c87613537565b5050505087816000015182602001517f2be10f2a0203c77d0fcaa9fd6484a8a1d6904de31cd820587f60c1c8c338c8148c898c888b8b336040516130d697969594939291906151f6565b60405180910390a450979650505050505050565b8047101561313a5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e63650000006044820152606401610cb9565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114613187576040519150601f19603f3d011682016040523d82523d6000602084013e61318c565b606091505b50509050806117d55760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d617920686176652072657665727465640000000000006064820152608401610cb9565b604051630862026560e41b8152600160048201526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116602483015260009182917f00000000000000000000000000000000000000000000000000000000000000001690638620265090604401602060405180830381865afa158015613295573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132b99190614bec565b6001600160a01b0316036132d25750633b9aca00610848565b6003546001600160a01b03161561336e5760035460405163192dd60960e01b81526001600160a01b039091169063192dd609906133159086908690600401615725565b602060405180830381865afa92505050801561334e575060408051601f3d908101601f1916820190925261334b91810190614c26565b60015b61335a57506000610848565b633b9aca00811161336c579050610848565b505b50600092915050565b6040516369e11cc560e01b81526004810187905260248101869052604481018590526000908190633b9aca009082907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906369e11cc590606401600060405180830381865afa1580156133f7573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261341f9190810190615757565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081018290529192505b82518110156135255782818151811061347657613476614cff565b6020026020010151915060006134918a846040015187612896565b905060006134a3848f8e858e8e613bbf565b905080158015906134b45750818114155b156134c6576134c3828861532a565b96505b81156134d257818b039a505b8360400151860395508b8d8f7f0d31ab573f6daa4b1edba8d31973b4ba9f98fbfecc47010c1533eeefd2a1225a8786863360405161351394939291906158b4565b60405180910390a4505060010161345b565b50879450505050965096945050505050565b600061354485858461233f565b9050851561365657600087815260016020818152604080842081516080810183528a815263ffffffff808b168286019081528982168386019081526001600160a01b03808d16606086019081528654808b018855968b5297909920935160029095029093019384555192909501805491519451909616600160401b02600160401b600160e01b03199486166401000000000267ffffffffffffffff199092169290951691909117179190911691909117909155518490869089907f77813be0661650ddc1a5193ff2837df4162b251cb432651e2c060c3fc39756be90613649908790899033909283526001600160a01b03918216602084015216604082015260600190565b60405180910390a46136aa565b613661818489612385565b604080516001600160a01b038516815233602082015260009183918a917fcf0c92a2c6d7c42f488326b0cb900104b99984b6b218db81cd29371364a35251910160405180910390a45b9695505050505050565b60405163e7c8e3e360e01b815260048101859052602481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063e7c8e3e390604401600060405180830381600087803b15801561371d57600080fd5b505af11580156115fa573d6000803e3d6000fd5b600082815260016020908152604080832080548251818502810185019093528083528493849084015b828210156137c757600084815260209081902060408051608081018252600286029092018054835260019081015463ffffffff8082168587015264010000000082041692840192909252600160401b9091046001600160a01b03166060830152908352909201910161375a565b50505060008681526001602052604081209293506137e692915061444b565b8051839060005b81811015613b3d57826000036138ac576000878152600160205260409020845185908390811061381f5761381f614cff565b60209081029190910181015182546001818101855560009485529383902082516002909202019081559181015191909201805460408401516060909401516001600160a01b0316600160401b02600160401b600160e01b031963ffffffff9586166401000000000267ffffffffffffffff1990931695909416949094171791909116919091179055613b35565b8381815181106138be576138be614cff565b6020026020010151600001518310613974578381815181106138e2576138e2614cff565b6020026020010151600001518303925083818151811061390457613904614cff565b60200260200101516020015163ffffffff166000148061394a5750633b9aca0084828151811061393657613936614cff565b60200260200101516040015163ffffffff16145b6139685761396384828151811061105c5761105c614cff565b61396b565b60005b85019450613b35565b600160008881526020019081526020016000206040518060800160405280858785815181106139a5576139a5614cff565b6020026020010151600001510381526020018684815181106139c9576139c9614cff565b60200260200101516020015163ffffffff1681526020018684815181106139f2576139f2614cff565b60200260200101516040015163ffffffff168152602001868481518110613a1b57613a1b614cff565b6020908102919091018101516060908101516001600160a01b0390811690935284546001818101875560009687529583902085516002909202019081559184015191909401805460408501519490950151909216600160401b02600160401b600160e01b031963ffffffff9485166401000000000267ffffffffffffffff19909616949092169390931793909317929092161790558351849082908110613ac457613ac4614cff565b60200260200101516020015163ffffffff1660001480613b0a5750633b9aca00848281518110613af657613af6614cff565b60200260200101516040015163ffffffff16145b613b2957613b248385838151811061107a5761107a614cff565b613b2c565b60005b85019450600092505b6001016137ed565b50604080518381523360208201528591879189917f59860d79d97c1fce2be7f987915c631471f4b08f671200463cc40a3380194ffb910160405180910390a450505092915050565b60006028826101000151901c61ffff166127106108489190614bd9565b60006038826101000151901c61ffff166127106108489190614bd9565b60c086015183906001600160a01b031615613e7f57633b9aca008214158015613c05575060c08701516001600160a01b031660009081526004602052604090205460ff16155b15613c1857613c1584848461233f565b90035b60006040518060c001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020018381526020017f000000000000000000000000000000000000000000000000000000000000000081526020018881526020018781526020018981525090506060613ca98960c00151634eba05fd60e11b61431d565b15613ddc578860c001516001600160a01b0316639d740bfa61eeee6001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614613d03576000613d05565b845b846040518363ffffffff1660e01b8152600401613d2291906158e9565b6000604051808303818588803b158015613d3b57600080fd5b505af193505050508015613d4d575060015b613dd7573d808015613d7b576040519150601f19603f3d011682016040523d82523d6000602084013e613d80565b606091505b50805115613d8e5780613dcf565b604051602001613dbf906020808252600d908201526c105b1b1bd8d85d194819985a5b609a1b604082015260600190565b6040516020818303038152906040525b915050613e1e565b613e1e565b604051602001613e0c906020808252600c908201526b12515490cc4d8d4819985a5b60a21b604082015260600190565b60405160208183030381529060405290505b805115613e7857613e35888a60c0015185896136b4565b60009250877f290b5df59e172593762964e4f8ed2b4a9192d3197bfd2be4bae123908f8007968a888433604051613e6f949392919061593d565b60405180910390a25b50506136aa565b6060870151156142da576060870151604051630862026560e41b81526000916001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691638620265091613f0f917f0000000000000000000000000000000000000000000000000000000000000000906004019182526001600160a01b0316602082015260400190565b602060405180830381865afa158015613f2c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f509190614bec565b90506001600160a01b038116613fb25760009150613f7187600080886136b4565b867f290b5df59e172593762964e4f8ed2b4a9192d3197bfd2be4bae123908f800796898733604051613fa593929190615980565b60405180910390a26142d4565b6001600160a01b0381163014801590613fcf5750633b9aca008314155b8015613ff457506001600160a01b03811660009081526004602052604090205460ff16155b156140095761400485858561233f565b820391505b87602001511561418657806001600160a01b0316630cf8e85861eeee6001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614614064576000614066565b835b8a60600151857f00000000000000000000000000000000000000000000000000000000000000008c6040516020016140a091815260200190565b6040516020818303038152906040526040518663ffffffff1660e01b81526004016140ce9493929190614c8f565b6000604051808303818588803b1580156140e757600080fd5b505af1935050505080156140f9575060015b614181573d808015614127576040519150601f19603f3d011682016040523d82523d6000602084013e61412c565b606091505b50614139888385896136b4565b60009250877f290b5df59e172593762964e4f8ed2b4a9192d3197bfd2be4bae123908f8007968a888433604051614173949392919061593d565b60405180910390a2506142d4565b6142d4565b806001600160a01b0316631ebc263f61eeee6001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316146141d75760006141d9565b835b60608b015160808c015186907f0000000000000000000000000000000000000000000000000000000000000000906001600160a01b031661421a5733614220565b8d608001515b60008f600001518f60405160200161423a91815260200190565b6040516020818303038152906040526040518963ffffffff1660e01b815260040161426b979695949392919061533d565b60206040518083038185885af1935050505080156142a6575060408051601f3d908101601f191682019092526142a391810190614c26565b60015b613e78573d808015614127576040519150601f19603f3d011682016040523d82523d6000602084013e61412c565b506136aa565b633b9aca0082146142f3576142f084848461233f565b90035b60808701516136aa9030906001600160a01b03166143115733614317565b88608001515b836117cb565b600061432883614339565b801561237e575061237e838361436c565b600061434c826301ffc9a760e01b61436c565b80156108485750614365826001600160e01b031961436c565b1592915050565b604080516001600160e01b0319831660248083019190915282518083039091018152604490910182526020810180516001600160e01b03166301ffc9a760e01b179052905160009190829081906001600160a01b03871690617530906143d39086906159dd565b6000604051808303818686fa925050503d806000811461440f576040519150601f19603f3d011682016040523d82523d6000602084013e614414565b606091505b509150915060208151101561442f5760009350505050610848565b8180156136aa5750808060200190518101906136aa9190614c09565b508054600082556002029060005260206000209081019061169c91906144c1565b6040518061012001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b03168152602001600081525090565b5b808211156144e857600081556001810180546001600160e01b03191690556002016144c2565b5090565b6000602082840312156144fe57600080fd5b81356001600160e01b03198116811461237e57600080fd5b6001600160a01b038116811461169c57600080fd5b60008083601f84011261453d57600080fd5b5081356001600160401b0381111561455457600080fd5b60208301915083602082850101111561456c57600080fd5b9250929050565b600080600080600080600060a0888a03121561458e57600080fd5b873596506020880135955060408801356145a781614516565b945060608801356001600160401b03808211156145c357600080fd5b6145cf8b838c0161452b565b909650945060808a01359150808211156145e857600080fd5b506145f58a828b0161452b565b989b979a50959850939692959293505050565b60006020828403121561461a57600080fd5b813561237e81614516565b801515811461169c57600080fd5b6000806000806000806000806000806101008b8d03121561465357600080fd5b8a35995060208b0135985060408b013561466c81614516565b975060608b013561467c81614516565b965060808b0135955060a08b013561469381614625565b945060c08b01356001600160401b03808211156146af57600080fd5b6146bb8e838f0161452b565b909650945060e08d01359150808211156146d457600080fd5b506146e18d828e0161452b565b915080935050809150509295989b9194979a5092959850565b6000806040838503121561470d57600080fd5b82359150602083013561471f81614516565b809150509250929050565b600080600080600080600060c0888a03121561474557600080fd5b873596506020880135955060408801359450606088013561476581614516565b93506080880135925060a08801356001600160401b0381111561478757600080fd5b6145f58a828b0161452b565b6000602082840312156147a557600080fd5b5035919050565b600080604083850312156147bf57600080fd5b82356147ca81614516565b9150602083013561471f81614625565b602080825282518282018190526000919060409081850190868401855b82811015614843578151805185528681015163ffffffff908116888701528682015116868601526060908101516001600160a01b031690850152608090930192908501906001016147f7565b5091979650505050505050565b634e487b7160e01b600052604160045260246000fd5b60405161012081016001600160401b038111828210171561488957614889614850565b60405290565b604051606081016001600160401b038111828210171561488957614889614850565b60405160e081016001600160401b038111828210171561488957614889614850565b604051601f8201601f191681016001600160401b03811182821017156148fb576148fb614850565b604052919050565b60006001600160401b0382111561491c5761491c614850565b50601f01601f191660200190565b600082601f83011261493b57600080fd5b813561494e61494982614903565b6148d3565b81815284602083860101111561496357600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060008060006101008a8c03121561499f57600080fd5b8935985060208a0135975060408a0135965060608a01356149bf81614516565b955060808a0135945060a08a01356149d681614516565b935060c08a01356001600160401b03808211156149f257600080fd5b6149fe8d838e0161492a565b945060e08c0135915080821115614a1457600080fd5b50614a218c828d0161452b565b915080935050809150509295985092959850929598565b60008060008060008060008060c0898b031215614a5457600080fd5b88359750602089013596506040890135614a6d81614516565b95506060890135614a7d81614625565b945060808901356001600160401b0380821115614a9957600080fd5b614aa58c838d0161452b565b909650945060a08b0135915080821115614abe57600080fd5b50614acb8b828c0161452b565b999c989b5096995094979396929594505050565b60008060408385031215614af257600080fd5b8235614afd81614516565b946020939093013593505050565b600080600080600080600080610100898b031215614b2857600080fd5b8835614b3381614516565b975060208901359650604089013595506060890135614b5181614516565b94506080890135935060a0890135614b6881614516565b925060c08901356001600160401b0380821115614b8457600080fd5b614b908c838d0161492a565b935060e08b0135915080821115614ba657600080fd5b50614bb38b828c0161492a565b9150509295985092959890939650565b634e487b7160e01b600052601160045260246000fd5b8181038181111561084857610848614bc3565b600060208284031215614bfe57600080fd5b815161237e81614516565b600060208284031215614c1b57600080fd5b815161237e81614625565b600060208284031215614c3857600080fd5b5051919050565b60005b83811015614c5a578181015183820152602001614c42565b50506000910152565b60008151808452614c7b816020860160208601614c3f565b601f01601f19169290920160200192915050565b84815283602082015260018060a01b038316604082015260a06060820152600060a082015260c0608082015260006136aa60c0830184614c63565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b634e487b7160e01b600052603260045260246000fd5b600181815b80851115614d50578160001904821115614d3657614d36614bc3565b80851615614d4357918102915b93841c9390800290614d1a565b509250929050565b600082614d6757506001610848565b81614d7457506000610848565b8160018114614d8a5760028114614d9457614db0565b6001915050610848565b60ff841115614da557614da5614bc3565b50506001821b610848565b5060208310610133831016604e8410600b8410161715614dd3575081810a610848565b614ddd8383614d15565b8060001904821115614df157614df1614bc3565b029392505050565b600061237e8383614d58565b80516001600160a01b031682526020808201519083015260408082015190830152606090810151910152565b6001600160a01b03888116825260009061014090614e52602085018b614e05565b8860a08501528760c085015280871660e08501525080610100840152614e7a81840186614c63565b9050828103610120840152614e8f8185614c63565b9a9950505050505050505050565b8051614ea881614516565b919050565b60006101208284031215614ec057600080fd5b614ec8614866565b9050815181526020820151602082015260408201516040820152606082015160608201526080820151608082015260a082015160a082015260c082015160c0820152614f1660e08301614e9d565b60e082015261010080830151818301525092915050565b60006001600160401b03821115614f4657614f46614850565b5060051b60200190565b600082601f830112614f6157600080fd5b8151614f6f61494982614903565b818152846020838601011115614f8457600080fd5b611500826020830160208701614c3f565b6000806000806101808587031215614fac57600080fd5b614fb68686614ead565b935061012085015192506101408501516001600160401b0380821115614fdb57600080fd5b818701915087601f830112614fef57600080fd5b8151614ffd61494982614f2d565b8082825260208201915060208360051b86010192508a83111561501f57600080fd5b602085015b838110156150a95780518581111561503b57600080fd5b86016060818e03601f1901121561505157600080fd5b61505961488f565b602082015161506781614516565b81526040820151602082015260608201518781111561508557600080fd5b6150948f602083860101614f50565b60408301525084525060209283019201615024565b506101608a015190965093505050808211156150c457600080fd5b506150d187828801614f50565b91505092959194509250565b80516001600160a01b031682526000610220602083015160208501526040830151604085015260608301516151156060860182614e05565b50608083015161512860e0860182614e05565b5060a083015161016085015260c08301516001600160a01b031661018085015260e083015115156101a08501526101008301516101c0850182905261516f82860182614c63565b9150506101208301518482036101e086015261518b8282614c63565b9150506101408301518482036102008601526151a78282614c63565b95945050505050565b60208152600061237e60208301846150dd565b6060815260006151d660608301866150dd565b6020830194909452506001600160a01b0391909116604090910152919050565b600060018060a01b03808a168352808916602084015287604084015286606084015260e0608084015261522c60e0840187614c63565b83810360a085015261523e8187614c63565b92505080841660c08401525098975050505050505050565b6001600160a01b0394851681529290931660208301526040820152606081019190915260800190565b600080610140838503121561529357600080fd5b61529d8484614ead565b915061012083015190509250929050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b600060018060a01b03808b16835289602084015288604084015287606084015286608084015260e060a084015261531260e0840186886152ae565b915080841660c0840152509998505050505050505050565b8082018082111561084857610848614bc3565b878152602081018790526001600160a01b038681166040830152851660608201526080810184905282151560a082015261010060c08201819052600090820181905261012060e08301819052614e8f81840185614c63565b8381526060602082015260006153ae6060830185614c63565b905060018060a01b0383166040830152949350505050565b600060018060a01b03808b16835289602084015288604084015287606084015260e060808401526153fa60e0840188614c63565b83810360a085015261540d8187896152ae565b92505080841660c0840152509998505050505050505050565b600081600019048311821515161561544057615440614bc3565b500290565b634e487b7160e01b600052601260045260246000fd5b60008261547857634e487b7160e01b600052601260045260246000fd5b500490565b85815284602082015260a06040820152600061549c60a0830186614c63565b82810360608401526154ae8186614c63565b91505060018060a01b03831660808301529695505050505050565b60018060a01b038616815284602082015283604082015260a0606082015260006154f660a0830185614c63565b8281036080840152610c838185614c63565b600080600080610180858703121561551f57600080fd5b6155298686614ead565b935061012085015192506101408501516001600160401b038082111561554e57600080fd5b818701915087601f83011261556257600080fd5b815161557061494982614f2d565b8082825260208201915060208360051b86010192508a83111561559257600080fd5b602085015b838110156150a9578051858111156155ae57600080fd5b86016060818e03601f190112156155c457600080fd5b6155cc61488f565b60208201516155da81614516565b8152604082015160208201526060820151878111156155f857600080fd5b6156078f602083860101614f50565b60408301525084525060209283019201615597565b80516001600160a01b031682526000610200602083015160208501526040830151604085015260608301516060850152608083015161565e6080860182614e05565b5060a083015161010061567381870183614e05565b60c08501516001600160a01b031661018087015260e08501516101a0870184905291506156a283870183614c63565b9250808501519150508482036101c08601526156be8282614c63565b9150506101208301518482036101e08601526151a78282614c63565b60208152600061237e602083018461561c565b608081526000615700608083018761561c565b60208301959095525060408101929092526001600160a01b0316606090910152919050565b828152604081016003831061574a57634e487b7160e01b600052602160045260246000fd5b8260208301529392505050565b6000602080838503121561576a57600080fd5b82516001600160401b0381111561578057600080fd5b8301601f8101851361579157600080fd5b805161579f61494982614f2d565b81815260e091820283018401918482019190888411156157be57600080fd5b938501935b838510156158545780858a0312156157db5760008081fd5b6157e36148b1565b85516157ee81614625565b8152858701516157fd81614625565b81880152604086810151908201526060808701519082015260808087015161582481614516565b9082015260a0868101519082015260c08087015161584181614516565b90820152835293840193918501916157c3565b50979650505050505050565b80511515825260208082015115159083015260408082015190830152606080820151908301526080808201516001600160a01b039081169184019190915260a0808301519084015260c09182015116910152565b61014081016158c38287615860565b60e08201949094526101008101929092526001600160a01b031661012090910152919050565b81516001600160a01b031681526020808301519082015260408083015190820152606080830151908201526080808301519082015260a08281015161018083019161593690840182615860565b5092915050565b600061014061594c8388615860565b8560e08401528061010084015261596581840186614c63565b91505060018060a01b03831661012083015295945050505050565b600061014061598f8387615860565b60e08301949094525061010081018390526012928101929092527115195c9b5a5b985b081b9bdd08199bdd5b9960721b6101608301526001600160a01b031661012082015261018001919050565b600082516159ef818460208701614c3f565b919091019291505056fea2646970667358221220558248dbc04ea10c612e57468002e5730c490a4a5abc710d603914a962691a5464736f6c63430008100033", + "devdoc": { + "kind": "dev", + "methods": { + "acceptsToken(address,uint256)": { + "params": { + "_projectId": "The project ID to check for token acceptance.", + "_token": "The token to check if this terminal accepts or not." + }, + "returns": { + "_0": "The flag." + } + }, + "addToBalanceOf(uint256,uint256,address,bool,string,bytes)": { + "params": { + "_amount": "The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.", + "_memo": "A memo to pass along to the emitted event.", + "_metadata": "Extra data to pass along to the emitted event.", + "_projectId": "The ID of the project to which the funds received belong.", + "_shouldRefundHeldFees": "A flag indicating if held fees should be refunded based on the amount being added.", + "_token": "The token being paid. This terminal ignores this property since it only manages one currency." + } + }, + "addToBalanceOf(uint256,uint256,address,string,bytes)": { + "params": { + "_amount": "The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.", + "_memo": "A memo to pass along to the emitted event.", + "_metadata": "Extra data to pass along to the emitted event.", + "_projectId": "The ID of the project to which the funds received belong.", + "_token": "The token being paid. This terminal ignores this property since it only manages one currency." + } + }, + "constructor": { + "params": { + "_baseWeightCurrency": "The currency to base token issuance on.", + "_directory": "A contract storing directories of terminals and controllers for each project.", + "_operatorStore": "A contract storing operator assignments.", + "_owner": "The address that will own this contract.", + "_prices": "A contract that exposes price feeds.", + "_projects": "A contract which mints ERC-721's that represent project ownership and transfers.", + "_splitsStore": "A contract that stores splits for each project.", + "_store": "A contract that stores the terminal's data." + } + }, + "currencyForToken(address)": { + "params": { + "_token": "The token to check for the currency of." + }, + "returns": { + "_0": "The currency index." + } + }, + "currentEthOverflowOf(uint256)": { + "details": "The current overflow is represented as a fixed point number with 18 decimals.", + "params": { + "_projectId": "The ID of the project to get overflow for." + }, + "returns": { + "_0": "The current amount of ETH overflow that project has in this terminal, as a fixed point number with 18 decimals." + } + }, + "decimalsForToken(address)": { + "params": { + "_token": "The token to check for the decimals of." + }, + "returns": { + "_0": "The number of decimals for the token." + } + }, + "distributePayoutsOf(uint256,uint256,uint256,address,uint256,bytes)": { + "details": "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.", + "params": { + "_amount": "The amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal.", + "_currency": "The expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency.", + "_metadata": "Bytes to send along to the emitted event, if provided.", + "_minReturnedTokens": "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.", + "_projectId": "The ID of the project having its payouts distributed.", + "_token": "The token being distributed. This terminal ignores this property since it only manages one token." + }, + "returns": { + "netLeftoverDistributionAmount": "The amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal." + } + }, + "heldFeesOf(uint256)": { + "params": { + "_projectId": "The ID of the project for which fees are being held." + }, + "returns": { + "_0": "An array of fees that are being held." + } + }, + "migrate(uint256,address)": { + "details": "Only a project's owner or a designated operator can migrate it.", + "params": { + "_projectId": "The ID of the project being migrated.", + "_to": "The terminal contract that will gain the project's funds." + }, + "returns": { + "balance": "The amount of funds that were migrated, as a fixed point number with the same amount of decimals as this terminal." + } + }, + "owner()": { + "details": "Returns the address of the current owner." + }, + "pay(uint256,uint256,address,address,uint256,bool,string,bytes)": { + "params": { + "_amount": "The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place.", + "_beneficiary": "The address to mint tokens for and pass along to the funding cycle's data source and delegate.", + "_memo": "A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.", + "_metadata": "Bytes to send along to the data source, delegate, and emitted event, if provided.", + "_minReturnedTokens": "The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal.", + "_preferClaimedTokens": "A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.", + "_projectId": "The ID of the project being paid.", + "_token": "The token being paid. This terminal ignores this property since it only manages one token." + }, + "returns": { + "_0": "The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals." + } + }, + "processFees(uint256)": { + "details": "Only a project owner, an operator, or the contract's owner can process held fees.", + "params": { + "_projectId": "The ID of the project whos held fees should be processed." + } + }, + "redeemTokensOf(address,uint256,uint256,address,uint256,address,string,bytes)": { + "details": "Only a token holder or a designated operator can redeem its tokens.", + "params": { + "_beneficiary": "The address to send the terminal tokens to.", + "_holder": "The account to redeem tokens for.", + "_memo": "A memo to pass along to the emitted event.", + "_metadata": "Bytes to send along to the data source, delegate, and emitted event, if provided.", + "_minReturnedTokens": "The minimum amount of terminal tokens expected in return, as a fixed point number with the same amount of decimals as the terminal.", + "_projectId": "The ID of the project to which the tokens being redeemed belong.", + "_token": "The token being reclaimed. This terminal ignores this property since it only manages one token.", + "_tokenCount": "The number of project tokens to redeem, as a fixed point number with 18 decimals." + }, + "returns": { + "reclaimAmount": "The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals." + } + }, + "renounceOwnership()": { + "details": "Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner." + }, + "setFee(uint256)": { + "details": "Only the owner of this contract can change the fee.", + "params": { + "_fee": "The new fee, out of MAX_FEE." + } + }, + "setFeeGauge(address)": { + "details": "Only the owner of this contract can change the fee gauge.", + "params": { + "_feeGauge": "The new fee gauge." + } + }, + "setFeelessAddress(address,bool)": { + "details": "Only the owner of this contract can set addresses as feeless.", + "params": { + "_address": "The address that can be paid towards while still bypassing fees.", + "_flag": "A flag indicating whether the terminal should be feeless or not." + } + }, + "supportsInterface(bytes4)": { + "details": "See {IERC165-supportsInterface}.", + "params": { + "_interfaceId": "The ID of the interface to check for adherance to." + }, + "returns": { + "_0": "A flag indicating if the provided interface ID is supported." + } + }, + "transferOwnership(address)": { + "details": "Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner." + }, + "useAllowanceOf(uint256,uint256,uint256,address,uint256,address,string,bytes)": { + "details": "Only a project's owner or a designated operator can use its allowance.Incurs the protocol fee.", + "params": { + "_amount": "The amount of terminal tokens to use from this project's current allowance, as a fixed point number with the same amount of decimals as this terminal.", + "_beneficiary": "The address to send the funds to.", + "_currency": "The expected currency of the amount being distributed. Must match the project's current funding cycle's overflow allowance currency.", + "_memo": "A memo to pass along to the emitted event.", + "_metadata": "Bytes to send along to the emitted event, if provided.", + "_minReturnedTokens": "The minimum number of tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with 18 decimals.", + "_projectId": "The ID of the project to use the allowance of.", + "_token": "The token being distributed. This terminal ignores this property since it only manages one token." + }, + "returns": { + "netDistributedAmount": "The amount of tokens that was distributed to the beneficiary, as a fixed point number with the same amount of decimals as the terminal." + } + } + }, + "version": 1 + }, + "userdoc": { + "errors": { + "PRBMath__MulDivOverflow(uint256,uint256)": [ + { + "notice": "Emitted when the result overflows uint256." + } + ] + }, + "kind": "user", + "methods": { + "acceptsToken(address,uint256)": { + "notice": "A flag indicating if this terminal accepts the specified token." + }, + "addToBalanceOf(uint256,uint256,address,bool,string,bytes)": { + "notice": "Receives funds belonging to the specified project." + }, + "addToBalanceOf(uint256,uint256,address,string,bytes)": { + "notice": "Receives funds belonging to the specified project." + }, + "baseWeightCurrency()": { + "notice": "The currency to base token issuance on." + }, + "currency()": { + "notice": "The currency to use when resolving price feeds for this terminal." + }, + "currencyForToken(address)": { + "notice": "The currency that should be used for the specified token." + }, + "currentEthOverflowOf(uint256)": { + "notice": "Gets the current overflowed amount in this terminal for a specified project, in terms of ETH." + }, + "decimals()": { + "notice": "The number of decimals the token fixed point amounts are expected to have." + }, + "decimalsForToken(address)": { + "notice": "The decimals that should be used in fixed number accounting for the specified token." + }, + "directory()": { + "notice": "The directory of terminals and controllers for projects." + }, + "distributePayoutsOf(uint256,uint256,uint256,address,uint256,bytes)": { + "notice": "Distributes payouts for a project with the distribution limit of its current funding cycle." + }, + "fee()": { + "notice": "The platform fee percent." + }, + "feeGauge()": { + "notice": "The data source that returns a discount to apply to a project's fee." + }, + "heldFeesOf(uint256)": { + "notice": "The fees that are currently being held to be processed later for each project." + }, + "isFeelessAddress(address)": { + "notice": "Addresses that can be paid towards from this terminal without incurring a fee." + }, + "migrate(uint256,address)": { + "notice": "Allows a project owner to migrate its funds and operations to a new terminal that accepts the same token type." + }, + "operatorStore()": { + "notice": "A contract storing operator assignments." + }, + "pay(uint256,uint256,address,address,uint256,bool,string,bytes)": { + "notice": "Contribute tokens to a project." + }, + "payoutSplitsGroup()": { + "notice": "The group that payout splits coming from this terminal are identified by." + }, + "prices()": { + "notice": "The contract that exposes price feeds." + }, + "processFees(uint256)": { + "notice": "Process any fees that are being held for the project." + }, + "projects()": { + "notice": "Mints ERC-721's that represent project ownership and transfers." + }, + "redeemTokensOf(address,uint256,uint256,address,uint256,address,string,bytes)": { + "notice": "Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source." + }, + "setFee(uint256)": { + "notice": "Allows the fee to be updated." + }, + "setFeeGauge(address)": { + "notice": "Allows the fee gauge to be updated." + }, + "setFeelessAddress(address,bool)": { + "notice": "Sets whether projects operating on this terminal can pay towards the specified address without incurring a fee." + }, + "splitsStore()": { + "notice": "The contract that stores splits for each project." + }, + "store()": { + "notice": "The contract that stores and manages the terminal's data." + }, + "supportsInterface(bytes4)": { + "notice": "Indicates if this contract adheres to the specified interface." + }, + "token()": { + "notice": "The token that this terminal accepts." + }, + "useAllowanceOf(uint256,uint256,uint256,address,uint256,address,string,bytes)": { + "notice": "Allows a project to send funds from its overflow up to the preconfigured allowance." + } + }, + "notice": "Manages all inflows and outflows of ETH funds into the protocol ecosystem.", + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 53, + "contract": "contracts/JBETHPaymentTerminal3_1_1.sol:JBETHPaymentTerminal3_1_1", + "label": "_owner", + "offset": 0, + "slot": "0", + "type": "t_address" + }, + { + "astId": 28823, + "contract": "contracts/JBETHPaymentTerminal3_1_1.sol:JBETHPaymentTerminal3_1_1", + "label": "_heldFeesOf", + "offset": 0, + "slot": "1", + "type": "t_mapping(t_uint256,t_array(t_struct(JBFee)36640_storage)dyn_storage)" + }, + { + "astId": 28860, + "contract": "contracts/JBETHPaymentTerminal3_1_1.sol:JBETHPaymentTerminal3_1_1", + "label": "fee", + "offset": 0, + "slot": "2", + "type": "t_uint256" + }, + { + "astId": 28864, + "contract": "contracts/JBETHPaymentTerminal3_1_1.sol:JBETHPaymentTerminal3_1_1", + "label": "feeGauge", + "offset": 0, + "slot": "3", + "type": "t_address" + }, + { + "astId": 28870, + "contract": "contracts/JBETHPaymentTerminal3_1_1.sol:JBETHPaymentTerminal3_1_1", + "label": "isFeelessAddress", + "offset": 0, + "slot": "4", + "type": "t_mapping(t_address,t_bool)" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_struct(JBFee)36640_storage)dyn_storage": { + "base": "t_struct(JBFee)36640_storage", + "encoding": "dynamic_array", + "label": "struct JBFee[]", + "numberOfBytes": "32" + }, + "t_bool": { + "encoding": "inplace", + "label": "bool", + "numberOfBytes": "1" + }, + "t_mapping(t_address,t_bool)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => bool)", + "numberOfBytes": "32", + "value": "t_bool" + }, + "t_mapping(t_uint256,t_array(t_struct(JBFee)36640_storage)dyn_storage)": { + "encoding": "mapping", + "key": "t_uint256", + "label": "mapping(uint256 => struct JBFee[])", + "numberOfBytes": "32", + "value": "t_array(t_struct(JBFee)36640_storage)dyn_storage" + }, + "t_struct(JBFee)36640_storage": { + "encoding": "inplace", + "label": "struct JBFee", + "members": [ + { + "astId": 36633, + "contract": "contracts/JBETHPaymentTerminal3_1_1.sol:JBETHPaymentTerminal3_1_1", + "label": "amount", + "offset": 0, + "slot": "0", + "type": "t_uint256" + }, + { + "astId": 36635, + "contract": "contracts/JBETHPaymentTerminal3_1_1.sol:JBETHPaymentTerminal3_1_1", + "label": "fee", + "offset": 0, + "slot": "1", + "type": "t_uint32" + }, + { + "astId": 36637, + "contract": "contracts/JBETHPaymentTerminal3_1_1.sol:JBETHPaymentTerminal3_1_1", + "label": "feeDiscount", + "offset": 4, + "slot": "1", + "type": "t_uint32" + }, + { + "astId": 36639, + "contract": "contracts/JBETHPaymentTerminal3_1_1.sol:JBETHPaymentTerminal3_1_1", + "label": "beneficiary", + "offset": 8, + "slot": "1", + "type": "t_address" + } + ], + "numberOfBytes": "64" + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint32": { + "encoding": "inplace", + "label": "uint32", + "numberOfBytes": "4" + } + } + } +} \ No newline at end of file diff --git a/deployments/sepolia/JBSingleTokenPaymentTerminalStore3_1_1.json b/deployments/sepolia/JBSingleTokenPaymentTerminalStore3_1_1.json new file mode 100644 index 000000000..47d452045 --- /dev/null +++ b/deployments/sepolia/JBSingleTokenPaymentTerminalStore3_1_1.json @@ -0,0 +1,1116 @@ +{ + "address": "0x981c8ECD009E3E84eE1fF99266BF1461a12e5c68", + "abi": [ + { + "inputs": [ + { + "internalType": "contract IJBDirectory", + "name": "_directory", + "type": "address" + }, + { + "internalType": "contract IJBFundingCycleStore", + "name": "_fundingCycleStore", + "type": "address" + }, + { + "internalType": "contract IJBPrices", + "name": "_prices", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "CURRENCY_MISMATCH", + "type": "error" + }, + { + "inputs": [], + "name": "DISTRIBUTION_AMOUNT_LIMIT_REACHED", + "type": "error" + }, + { + "inputs": [], + "name": "FUNDING_CYCLE_DISTRIBUTION_PAUSED", + "type": "error" + }, + { + "inputs": [], + "name": "FUNDING_CYCLE_PAYMENT_PAUSED", + "type": "error" + }, + { + "inputs": [], + "name": "FUNDING_CYCLE_REDEEM_PAUSED", + "type": "error" + }, + { + "inputs": [], + "name": "INADEQUATE_CONTROLLER_ALLOWANCE", + "type": "error" + }, + { + "inputs": [], + "name": "INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE", + "type": "error" + }, + { + "inputs": [], + "name": "INSUFFICIENT_TOKENS", + "type": "error" + }, + { + "inputs": [], + "name": "INVALID_AMOUNT_TO_SEND_DELEGATE", + "type": "error" + }, + { + "inputs": [], + "name": "INVALID_FUNDING_CYCLE", + "type": "error" + }, + { + "inputs": [], + "name": "PAYMENT_TERMINAL_MIGRATION_NOT_ALLOWED", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "prod1", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "denominator", + "type": "uint256" + } + ], + "name": "PRBMath__MulDivOverflow", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "contract IJBSingleTokenPaymentTerminal", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IJBSingleTokenPaymentTerminal", + "name": "_terminal", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + } + ], + "name": "currentOverflowOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_tokenCount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_totalSupply", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_overflow", + "type": "uint256" + } + ], + "name": "currentReclaimableOverflowOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IJBSingleTokenPaymentTerminal", + "name": "_terminal", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_tokenCount", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "_useTotalOverflow", + "type": "bool" + } + ], + "name": "currentReclaimableOverflowOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_decimals", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_currency", + "type": "uint256" + } + ], + "name": "currentTotalOverflowOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "directory", + "outputs": [ + { + "internalType": "contract IJBDirectory", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "fundingCycleStore", + "outputs": [ + { + "internalType": "contract IJBFundingCycleStore", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "prices", + "outputs": [ + { + "internalType": "contract IJBPrices", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "recordAddedBalanceFor", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_currency", + "type": "uint256" + } + ], + "name": "recordDistributionFor", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "number", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "configuration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "basedOn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "start", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "duration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "weight", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "discountRate", + "type": "uint256" + }, + { + "internalType": "contract IJBFundingCycleBallot", + "name": "ballot", + "type": "address" + }, + { + "internalType": "uint256", + "name": "metadata", + "type": "uint256" + } + ], + "internalType": "struct JBFundingCycle", + "name": "fundingCycle", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "distributedAmount", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + } + ], + "name": "recordMigration", + "outputs": [ + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_payer", + "type": "address" + }, + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "decimals", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "currency", + "type": "uint256" + } + ], + "internalType": "struct JBTokenAmount", + "name": "_amount", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_baseWeightCurrency", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_beneficiary", + "type": "address" + }, + { + "internalType": "string", + "name": "_memo", + "type": "string" + }, + { + "internalType": "bytes", + "name": "_metadata", + "type": "bytes" + } + ], + "name": "recordPaymentFrom", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "number", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "configuration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "basedOn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "start", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "duration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "weight", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "discountRate", + "type": "uint256" + }, + { + "internalType": "contract IJBFundingCycleBallot", + "name": "ballot", + "type": "address" + }, + { + "internalType": "uint256", + "name": "metadata", + "type": "uint256" + } + ], + "internalType": "struct JBFundingCycle", + "name": "fundingCycle", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "tokenCount", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "contract IJBPayDelegate3_1_1", + "name": "delegate", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "metadata", + "type": "bytes" + } + ], + "internalType": "struct JBPayDelegateAllocation3_1_1[]", + "name": "delegateAllocations", + "type": "tuple[]" + }, + { + "internalType": "string", + "name": "memo", + "type": "string" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_holder", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_tokenCount", + "type": "uint256" + }, + { + "internalType": "string", + "name": "_memo", + "type": "string" + }, + { + "internalType": "bytes", + "name": "_metadata", + "type": "bytes" + } + ], + "name": "recordRedemptionFor", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "number", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "configuration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "basedOn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "start", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "duration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "weight", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "discountRate", + "type": "uint256" + }, + { + "internalType": "contract IJBFundingCycleBallot", + "name": "ballot", + "type": "address" + }, + { + "internalType": "uint256", + "name": "metadata", + "type": "uint256" + } + ], + "internalType": "struct JBFundingCycle", + "name": "fundingCycle", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "reclaimAmount", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "contract IJBRedemptionDelegate3_1_1", + "name": "delegate", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "metadata", + "type": "bytes" + } + ], + "internalType": "struct JBRedemptionDelegateAllocation3_1_1[]", + "name": "delegateAllocations", + "type": "tuple[]" + }, + { + "internalType": "string", + "name": "memo", + "type": "string" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_projectId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_currency", + "type": "uint256" + } + ], + "name": "recordUsedAllowanceOf", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "number", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "configuration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "basedOn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "start", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "duration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "weight", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "discountRate", + "type": "uint256" + }, + { + "internalType": "contract IJBFundingCycleBallot", + "name": "ballot", + "type": "address" + }, + { + "internalType": "uint256", + "name": "metadata", + "type": "uint256" + } + ], + "internalType": "struct JBFundingCycle", + "name": "fundingCycle", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "usedAmount", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IJBSingleTokenPaymentTerminal", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "usedDistributionLimitOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IJBSingleTokenPaymentTerminal", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "usedOverflowAllowanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "transactionHash": "0xecaf3419082f2f8dbc75a41bf9611d444d3b4bab99030dd8caae40ba2326809b", + "receipt": { + "to": null, + "from": "0xE9bE6df23C7f9CaBa3005DA2fa2d8714d340D0aF", + "contractAddress": "0x981c8ECD009E3E84eE1fF99266BF1461a12e5c68", + "transactionIndex": 34, + "gasUsed": "2999374", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x623f7e1245123800a717e42f53083883f0cfd11828f83cd7c6e388bdbdb942c6", + "transactionHash": "0xecaf3419082f2f8dbc75a41bf9611d444d3b4bab99030dd8caae40ba2326809b", + "logs": [], + "blockNumber": 3797788, + "cumulativeGasUsed": "9282251", + "status": 1, + "byzantium": true + }, + "args": [ + "0x3B3Bd16cc76cd53218e00b600bFCa27aA5057794", + "0xCb881e166d527010B9eF11159b487f907040D7C4", + "0x6EF51C14045B386A0ae6374E48a9EeB928105ffb" + ], + "numDeployments": 1, + "solcInputHash": "f58e5b1a8ab27311c5c442a686fda095", + "metadata": "{\"compiler\":{\"version\":\"0.8.16+commit.07a7930e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract IJBDirectory\",\"name\":\"_directory\",\"type\":\"address\"},{\"internalType\":\"contract IJBFundingCycleStore\",\"name\":\"_fundingCycleStore\",\"type\":\"address\"},{\"internalType\":\"contract IJBPrices\",\"name\":\"_prices\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"CURRENCY_MISMATCH\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DISTRIBUTION_AMOUNT_LIMIT_REACHED\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FUNDING_CYCLE_DISTRIBUTION_PAUSED\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FUNDING_CYCLE_PAYMENT_PAUSED\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FUNDING_CYCLE_REDEEM_PAUSED\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"INADEQUATE_CONTROLLER_ALLOWANCE\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"INSUFFICIENT_TOKENS\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"INVALID_AMOUNT_TO_SEND_DELEGATE\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"INVALID_FUNDING_CYCLE\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PAYMENT_TERMINAL_MIGRATION_NOT_ALLOWED\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"prod1\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"denominator\",\"type\":\"uint256\"}],\"name\":\"PRBMath__MulDivOverflow\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"contract IJBSingleTokenPaymentTerminal\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IJBSingleTokenPaymentTerminal\",\"name\":\"_terminal\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"}],\"name\":\"currentOverflowOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_tokenCount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_totalSupply\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_overflow\",\"type\":\"uint256\"}],\"name\":\"currentReclaimableOverflowOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IJBSingleTokenPaymentTerminal\",\"name\":\"_terminal\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_tokenCount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"_useTotalOverflow\",\"type\":\"bool\"}],\"name\":\"currentReclaimableOverflowOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_decimals\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_currency\",\"type\":\"uint256\"}],\"name\":\"currentTotalOverflowOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"directory\",\"outputs\":[{\"internalType\":\"contract IJBDirectory\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fundingCycleStore\",\"outputs\":[{\"internalType\":\"contract IJBFundingCycleStore\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"prices\",\"outputs\":[{\"internalType\":\"contract IJBPrices\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"recordAddedBalanceFor\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_currency\",\"type\":\"uint256\"}],\"name\":\"recordDistributionFor\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"number\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"configuration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"basedOn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"start\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"duration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"weight\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"discountRate\",\"type\":\"uint256\"},{\"internalType\":\"contract IJBFundingCycleBallot\",\"name\":\"ballot\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"metadata\",\"type\":\"uint256\"}],\"internalType\":\"struct JBFundingCycle\",\"name\":\"fundingCycle\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"distributedAmount\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"}],\"name\":\"recordMigration\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_payer\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"decimals\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"currency\",\"type\":\"uint256\"}],\"internalType\":\"struct JBTokenAmount\",\"name\":\"_amount\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_baseWeightCurrency\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_beneficiary\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"_memo\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"_metadata\",\"type\":\"bytes\"}],\"name\":\"recordPaymentFrom\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"number\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"configuration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"basedOn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"start\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"duration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"weight\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"discountRate\",\"type\":\"uint256\"},{\"internalType\":\"contract IJBFundingCycleBallot\",\"name\":\"ballot\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"metadata\",\"type\":\"uint256\"}],\"internalType\":\"struct JBFundingCycle\",\"name\":\"fundingCycle\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"tokenCount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"contract IJBPayDelegate3_1_1\",\"name\":\"delegate\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"metadata\",\"type\":\"bytes\"}],\"internalType\":\"struct JBPayDelegateAllocation3_1_1[]\",\"name\":\"delegateAllocations\",\"type\":\"tuple[]\"},{\"internalType\":\"string\",\"name\":\"memo\",\"type\":\"string\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_holder\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_tokenCount\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"_memo\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"_metadata\",\"type\":\"bytes\"}],\"name\":\"recordRedemptionFor\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"number\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"configuration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"basedOn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"start\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"duration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"weight\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"discountRate\",\"type\":\"uint256\"},{\"internalType\":\"contract IJBFundingCycleBallot\",\"name\":\"ballot\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"metadata\",\"type\":\"uint256\"}],\"internalType\":\"struct JBFundingCycle\",\"name\":\"fundingCycle\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"reclaimAmount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"contract IJBRedemptionDelegate3_1_1\",\"name\":\"delegate\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"metadata\",\"type\":\"bytes\"}],\"internalType\":\"struct JBRedemptionDelegateAllocation3_1_1[]\",\"name\":\"delegateAllocations\",\"type\":\"tuple[]\"},{\"internalType\":\"string\",\"name\":\"memo\",\"type\":\"string\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_projectId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_currency\",\"type\":\"uint256\"}],\"name\":\"recordUsedAllowanceOf\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"number\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"configuration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"basedOn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"start\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"duration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"weight\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"discountRate\",\"type\":\"uint256\"},{\"internalType\":\"contract IJBFundingCycleBallot\",\"name\":\"ballot\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"metadata\",\"type\":\"uint256\"}],\"internalType\":\"struct JBFundingCycle\",\"name\":\"fundingCycle\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"usedAmount\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IJBSingleTokenPaymentTerminal\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"usedDistributionLimitOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IJBSingleTokenPaymentTerminal\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"usedOverflowAllowanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"This Store expects a project's controller to be an IJBController3_1.\",\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_directory\":\"A contract storing directories of terminals and controllers for each project.\",\"_fundingCycleStore\":\"A contract storing all funding cycle configurations.\",\"_prices\":\"A contract that exposes price feeds.\"}},\"currentOverflowOf(address,uint256)\":{\"details\":\"The current overflow is represented as a fixed point number with the same amount of decimals as the specified terminal.\",\"params\":{\"_projectId\":\"The ID of the project to get overflow for.\",\"_terminal\":\"The terminal for which the overflow is being calculated.\"},\"returns\":{\"_0\":\"The current amount of overflow that project has in the specified terminal.\"}},\"currentReclaimableOverflowOf(address,uint256,uint256,bool)\":{\"details\":\"If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.The current reclaimable overflow is returned in terms of the specified terminal's currency.The reclaimable overflow is represented as a fixed point number with the same amount of decimals as the specified terminal.\",\"params\":{\"_projectId\":\"The ID of the project to get the reclaimable overflow amount for.\",\"_terminal\":\"The terminal from which the reclaimable amount would come.\",\"_tokenCount\":\"The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\",\"_useTotalOverflow\":\"A flag indicating whether the overflow used in the calculation should be summed from all of the project's terminals. If false, overflow should be limited to the amount in the specified `_terminal`.\"},\"returns\":{\"_0\":\"The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_terminal`.\"}},\"currentReclaimableOverflowOf(uint256,uint256,uint256,uint256)\":{\"details\":\"If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\",\"params\":{\"_overflow\":\"The amount of overflow to make the calculation with, as a fixed point number.\",\"_projectId\":\"The ID of the project to get the reclaimable overflow amount for.\",\"_tokenCount\":\"The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\",\"_totalSupply\":\"The total number of tokens to make the calculation with, as a fixed point number with 18 decimals.\"},\"returns\":{\"_0\":\"The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_overflow`.\"}},\"currentTotalOverflowOf(uint256,uint256,uint256)\":{\"params\":{\"_currency\":\"The currency that the total overflow should be in terms of.\",\"_decimals\":\"The number of decimals that the fixed point overflow should include.\",\"_projectId\":\"The ID of the project to get total overflow for.\"},\"returns\":{\"_0\":\"The current total amount of overflow that project has across all terminals.\"}},\"recordAddedBalanceFor(uint256,uint256)\":{\"details\":\"The msg.sender must be an IJBSingleTokenPaymentTerminal.\",\"params\":{\"_amount\":\"The amount of terminal tokens added, as a fixed point number with the same amount of decimals as its relative terminal.\",\"_projectId\":\"The ID of the project to which the funds being added belong.\"}},\"recordDistributionFor(uint256,uint256,uint256)\":{\"details\":\"The msg.sender must be an IJBSingleTokenPaymentTerminal.\",\"params\":{\"_amount\":\"The amount to use from the distribution limit, as a fixed point number.\",\"_currency\":\"The currency of the `_amount`. This must match the project's current funding cycle's currency.\",\"_projectId\":\"The ID of the project that is having funds distributed.\"},\"returns\":{\"distributedAmount\":\"The amount of terminal tokens distributed, as a fixed point number with the same amount of decimals as its relative terminal.\",\"fundingCycle\":\"The funding cycle during which the distribution was made.\"}},\"recordMigration(uint256)\":{\"details\":\"The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount returned is in terms of the msg.senders tokens.\",\"params\":{\"_projectId\":\"The ID of the project being migrated.\"},\"returns\":{\"balance\":\"The project's migrated balance, as a fixed point number with the same amount of decimals as its relative terminal.\"}},\"recordPaymentFrom(address,(address,uint256,uint256,uint256),uint256,uint256,address,string,bytes)\":{\"details\":\"Mints the project's tokens according to values provided by a configured data source. If no data source is configured, mints tokens proportional to the amount of the contribution.The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.sender's tokens.\",\"params\":{\"_amount\":\"The amount of tokens being paid. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\",\"_baseWeightCurrency\":\"The currency to base token issuance on.\",\"_beneficiary\":\"The specified address that should be the beneficiary of anything that results from the payment.\",\"_memo\":\"A memo to pass along to the emitted event, and passed along to the funding cycle's data source.\",\"_metadata\":\"Bytes to send along to the data source, if one is provided.\",\"_payer\":\"The original address that sent the payment to the terminal.\",\"_projectId\":\"The ID of the project being paid.\"},\"returns\":{\"delegateAllocations\":\"The amount to send to delegates instead of adding to the local balance.\",\"fundingCycle\":\"The project's funding cycle during which payment was made.\",\"memo\":\"A memo that should be passed along to the emitted event.\",\"tokenCount\":\"The number of project tokens that were minted, as a fixed point number with 18 decimals.\"}},\"recordRedemptionFor(address,uint256,uint256,string,bytes)\":{\"details\":\"Redeems the project's tokens according to values provided by a configured data source. If no data source is configured, redeems tokens along a redemption bonding curve that is a function of the number of tokens being burned.The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.senders tokens.\",\"params\":{\"_holder\":\"The account that is having its tokens redeemed.\",\"_memo\":\"A memo to pass along to the emitted event.\",\"_metadata\":\"Bytes to send along to the data source, if one is provided.\",\"_projectId\":\"The ID of the project to which the tokens being redeemed belong.\",\"_tokenCount\":\"The number of project tokens to redeem, as a fixed point number with 18 decimals.\"},\"returns\":{\"delegateAllocations\":\"The amount to send to delegates instead of sending to the beneficiary.\",\"fundingCycle\":\"The funding cycle during which the redemption was made.\",\"memo\":\"A memo that should be passed along to the emitted event.\",\"reclaimAmount\":\"The amount of terminal tokens reclaimed, as a fixed point number with 18 decimals.\"}},\"recordUsedAllowanceOf(uint256,uint256,uint256)\":{\"details\":\"The msg.sender must be an IJBSingleTokenPaymentTerminal.\",\"params\":{\"_amount\":\"The amount to use from the allowance, as a fixed point number.\",\"_currency\":\"The currency of the `_amount`. Must match the currency of the overflow allowance.\",\"_projectId\":\"The ID of the project to use the allowance of.\"},\"returns\":{\"fundingCycle\":\"The funding cycle during which the overflow allowance is being used.\",\"usedAmount\":\"The amount of terminal tokens used, as a fixed point number with the same amount of decimals as its relative terminal.\"}}},\"stateVariables\":{\"balanceOf\":{\"custom:param\":\"_terminal The terminal to which the balance applies._projectId The ID of the project to get the balance of.\",\"details\":\"The balance is represented as a fixed point number with the same amount of decimals as its relative terminal.\"},\"usedDistributionLimitOf\":{\"custom:param\":\"_terminal The terminal to which the used distribution limit applies._projectId The ID of the project to get the used distribution limit of._fundingCycleNumber The number of the funding cycle during which the distribution limit was used.\",\"details\":\"Increases as projects use their preconfigured distribution limits.The used distribution limit is represented as a fixed point number with the same amount of decimals as its relative terminal.\"},\"usedOverflowAllowanceOf\":{\"custom:param\":\"_terminal The terminal to which the overflow allowance applies._projectId The ID of the project to get the used overflow allowance of._configuration The configuration of the during which the allowance was used.\",\"details\":\"Increases as projects use their allowance.The used allowance is represented as a fixed point number with the same amount of decimals as its relative terminal.\"}},\"version\":1},\"userdoc\":{\"errors\":{\"PRBMath__MulDivOverflow(uint256,uint256)\":[{\"notice\":\"Emitted when the result overflows uint256.\"}]},\"kind\":\"user\",\"methods\":{\"balanceOf(address,uint256)\":{\"notice\":\"The amount of tokens that each project has for each terminal, in terms of the terminal's token.\"},\"currentOverflowOf(address,uint256)\":{\"notice\":\"Gets the current overflowed amount in a terminal for a specified project.\"},\"currentReclaimableOverflowOf(address,uint256,uint256,bool)\":{\"notice\":\"The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the total token supply and overflow in the ecosystem.\"},\"currentReclaimableOverflowOf(uint256,uint256,uint256,uint256)\":{\"notice\":\"The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the specified total token supply and overflow amounts.\"},\"currentTotalOverflowOf(uint256,uint256,uint256)\":{\"notice\":\"Gets the current overflowed amount for a specified project across all terminals.\"},\"directory()\":{\"notice\":\"The directory of terminals and controllers for projects.\"},\"fundingCycleStore()\":{\"notice\":\"The contract storing all funding cycle configurations.\"},\"prices()\":{\"notice\":\"The contract that exposes price feeds.\"},\"recordAddedBalanceFor(uint256,uint256)\":{\"notice\":\"Records newly added funds for the project.\"},\"recordDistributionFor(uint256,uint256,uint256)\":{\"notice\":\"Records newly distributed funds for a project.\"},\"recordMigration(uint256)\":{\"notice\":\"Records the migration of funds from this store.\"},\"recordPaymentFrom(address,(address,uint256,uint256,uint256),uint256,uint256,address,string,bytes)\":{\"notice\":\"Records newly contributed tokens to a project.\"},\"recordRedemptionFor(address,uint256,uint256,string,bytes)\":{\"notice\":\"Records newly redeemed tokens of a project.\"},\"recordUsedAllowanceOf(uint256,uint256,uint256)\":{\"notice\":\"Records newly used allowance funds of a project.\"},\"usedDistributionLimitOf(address,uint256,uint256)\":{\"notice\":\"The amount of funds that a project has distributed from its limit during the current funding cycle for each terminal, in terms of the distribution limit's currency.\"},\"usedOverflowAllowanceOf(address,uint256,uint256)\":{\"notice\":\"The amount of funds that a project has used from its allowance during the current funding cycle configuration for each terminal, in terms of the overflow allowance's currency.\"}},\"notice\":\"Manages all bookkeeping for inflows and outflows of funds from any ISingleTokenPaymentTerminal.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/JBSingleTokenPaymentTerminalStore3_1_1.sol\":\"JBSingleTokenPaymentTerminalStore3_1_1\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/security/ReentrancyGuard.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Contract module that helps prevent reentrant calls to a function.\\n *\\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\\n * available, which can be applied to functions to make sure there are no nested\\n * (reentrant) calls to them.\\n *\\n * Note that because there is a single `nonReentrant` guard, functions marked as\\n * `nonReentrant` may not call one another. This can be worked around by making\\n * those functions `private`, and then adding `external` `nonReentrant` entry\\n * points to them.\\n *\\n * TIP: If you would like to learn more about reentrancy and alternative ways\\n * to protect against it, check out our blog post\\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\\n */\\nabstract contract ReentrancyGuard {\\n // Booleans are more expensive than uint256 or any type that takes up a full\\n // word because each write operation emits an extra SLOAD to first read the\\n // slot's contents, replace the bits taken up by the boolean, and then write\\n // back. This is the compiler's defense against contract upgrades and\\n // pointer aliasing, and it cannot be disabled.\\n\\n // The values being non-zero value makes deployment a bit more expensive,\\n // but in exchange the refund on every call to nonReentrant will be lower in\\n // amount. Since refunds are capped to a percentage of the total\\n // transaction's gas, it is best to keep them low in cases like this one, to\\n // increase the likelihood of the full refund coming into effect.\\n uint256 private constant _NOT_ENTERED = 1;\\n uint256 private constant _ENTERED = 2;\\n\\n uint256 private _status;\\n\\n constructor() {\\n _status = _NOT_ENTERED;\\n }\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * Calling a `nonReentrant` function from another `nonReentrant`\\n * function is not supported. It is possible to prevent this from happening\\n * by making the `nonReentrant` function external, and making it call a\\n * `private` function that does the actual work.\\n */\\n modifier nonReentrant() {\\n // On the first call to nonReentrant, _notEntered will be true\\n require(_status != _ENTERED, \\\"ReentrancyGuard: reentrant call\\\");\\n\\n // Any calls to nonReentrant after this point will fail\\n _status = _ENTERED;\\n\\n _;\\n\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _status = _NOT_ENTERED;\\n }\\n}\\n\",\"keccak256\":\"0x0e9621f60b2faabe65549f7ed0f24e8853a45c1b7990d47e8160e523683f3935\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC721/IERC721.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../../utils/introspection/IERC165.sol\\\";\\n\\n/**\\n * @dev Required interface of an ERC721 compliant contract.\\n */\\ninterface IERC721 is IERC165 {\\n /**\\n * @dev Emitted when `tokenId` token is transferred from `from` to `to`.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);\\n\\n /**\\n * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.\\n */\\n event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);\\n\\n /**\\n * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.\\n */\\n event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\\n\\n /**\\n * @dev Returns the number of tokens in ``owner``'s account.\\n */\\n function balanceOf(address owner) external view returns (uint256 balance);\\n\\n /**\\n * @dev Returns the owner of the `tokenId` token.\\n *\\n * Requirements:\\n *\\n * - `tokenId` must exist.\\n */\\n function ownerOf(uint256 tokenId) external view returns (address owner);\\n\\n /**\\n * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\\n * are aware of the ERC721 protocol to prevent tokens from being forever locked.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `tokenId` token must exist and be owned by `from`.\\n * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.\\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\\n *\\n * Emits a {Transfer} event.\\n */\\n function safeTransferFrom(\\n address from,\\n address to,\\n uint256 tokenId\\n ) external;\\n\\n /**\\n * @dev Transfers `tokenId` token from `from` to `to`.\\n *\\n * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `tokenId` token must be owned by `from`.\\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 tokenId\\n ) external;\\n\\n /**\\n * @dev Gives permission to `to` to transfer `tokenId` token to another account.\\n * The approval is cleared when the token is transferred.\\n *\\n * Only a single account can be approved at a time, so approving the zero address clears previous approvals.\\n *\\n * Requirements:\\n *\\n * - The caller must own the token or be an approved operator.\\n * - `tokenId` must exist.\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address to, uint256 tokenId) external;\\n\\n /**\\n * @dev Returns the account approved for `tokenId` token.\\n *\\n * Requirements:\\n *\\n * - `tokenId` must exist.\\n */\\n function getApproved(uint256 tokenId) external view returns (address operator);\\n\\n /**\\n * @dev Approve or remove `operator` as an operator for the caller.\\n * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.\\n *\\n * Requirements:\\n *\\n * - The `operator` cannot be the caller.\\n *\\n * Emits an {ApprovalForAll} event.\\n */\\n function setApprovalForAll(address operator, bool _approved) external;\\n\\n /**\\n * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.\\n *\\n * See {setApprovalForAll}\\n */\\n function isApprovedForAll(address owner, address operator) external view returns (bool);\\n\\n /**\\n * @dev Safely transfers `tokenId` token from `from` to `to`.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `tokenId` token must exist and be owned by `from`.\\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\\n *\\n * Emits a {Transfer} event.\\n */\\n function safeTransferFrom(\\n address from,\\n address to,\\n uint256 tokenId,\\n bytes calldata data\\n ) external;\\n}\\n\",\"keccak256\":\"0x516a22876c1fab47f49b1bc22b4614491cd05338af8bd2e7b382da090a079990\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/IERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC165 standard, as defined in the\\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\\n *\\n * Implementers can declare support of contract interfaces, which can then be\\n * queried by others ({ERC165Checker}).\\n *\\n * For an implementation, see {ERC165}.\\n */\\ninterface IERC165 {\\n /**\\n * @dev Returns true if this contract implements the interface defined by\\n * `interfaceId`. See the corresponding\\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\\n * to learn more about how these ids are created.\\n *\\n * This function call must use less than 30 000 gas.\\n */\\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\\n}\\n\",\"keccak256\":\"0x447a5f3ddc18419d41ff92b3773fb86471b1db25773e07f877f548918a185bf1\",\"license\":\"MIT\"},\"@paulrberg/contracts/math/PRBMath.sol\":{\"content\":\"// SPDX-License-Identifier: Unlicense\\npragma solidity >=0.8.4;\\n\\nimport \\\"prb-math/contracts/PRBMath.sol\\\";\\n\",\"keccak256\":\"0x42821345981bc0434a90ba2268a2f5278dfe9e38166981d72fc7f3b776a29495\",\"license\":\"Unlicense\"},\"contracts/JBSingleTokenPaymentTerminalStore3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.16;\\n\\nimport {ReentrancyGuard} from '@openzeppelin/contracts/security/ReentrancyGuard.sol';\\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\\nimport {JBBallotState} from './enums/JBBallotState.sol';\\nimport {IJBController3_1} from './interfaces/IJBController3_1.sol';\\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\\nimport {IJBFundingCycleDataSource3_1_1} from './interfaces/IJBFundingCycleDataSource3_1_1.sol';\\nimport {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol';\\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\\nimport {IJBSingleTokenPaymentTerminal} from './interfaces/IJBSingleTokenPaymentTerminal.sol';\\nimport {IJBSingleTokenPaymentTerminalStore3_1_1} from './interfaces/IJBSingleTokenPaymentTerminalStore3_1_1.sol';\\nimport {JBConstants} from './libraries/JBConstants.sol';\\nimport {JBCurrencies} from './libraries/JBCurrencies.sol';\\nimport {JBFixedPointNumber} from './libraries/JBFixedPointNumber.sol';\\nimport {JBFundingCycleMetadataResolver} from './libraries/JBFundingCycleMetadataResolver.sol';\\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\\nimport {JBPayDelegateAllocation3_1_1} from './structs/JBPayDelegateAllocation3_1_1.sol';\\nimport {JBPayParamsData} from './structs/JBPayParamsData.sol';\\nimport {JBRedeemParamsData} from './structs/JBRedeemParamsData.sol';\\nimport {JBRedemptionDelegateAllocation3_1_1} from './structs/JBRedemptionDelegateAllocation3_1_1.sol';\\nimport {JBTokenAmount} from './structs/JBTokenAmount.sol';\\n\\n/// @notice Manages all bookkeeping for inflows and outflows of funds from any ISingleTokenPaymentTerminal.\\n/// @dev This Store expects a project's controller to be an IJBController3_1.\\ncontract JBSingleTokenPaymentTerminalStore3_1_1 is\\n ReentrancyGuard,\\n IJBSingleTokenPaymentTerminalStore3_1_1\\n{\\n // A library that parses the packed funding cycle metadata into a friendlier format.\\n using JBFundingCycleMetadataResolver for JBFundingCycle;\\n\\n //*********************************************************************//\\n // --------------------------- custom errors ------------------------- //\\n //*********************************************************************//\\n error INVALID_AMOUNT_TO_SEND_DELEGATE();\\n error CURRENCY_MISMATCH();\\n error DISTRIBUTION_AMOUNT_LIMIT_REACHED();\\n error FUNDING_CYCLE_PAYMENT_PAUSED();\\n error FUNDING_CYCLE_DISTRIBUTION_PAUSED();\\n error FUNDING_CYCLE_REDEEM_PAUSED();\\n error INADEQUATE_CONTROLLER_ALLOWANCE();\\n error INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\\n error INSUFFICIENT_TOKENS();\\n error INVALID_FUNDING_CYCLE();\\n error PAYMENT_TERMINAL_MIGRATION_NOT_ALLOWED();\\n\\n //*********************************************************************//\\n // -------------------------- private constants ---------------------- //\\n //*********************************************************************//\\n\\n /// @notice Ensures a maximum number of decimal points of persisted fidelity on mulDiv operations of fixed point numbers.\\n uint256 private constant _MAX_FIXED_POINT_FIDELITY = 18;\\n\\n //*********************************************************************//\\n // ---------------- public immutable stored properties --------------- //\\n //*********************************************************************//\\n\\n /// @notice The directory of terminals and controllers for projects.\\n IJBDirectory public immutable override directory;\\n\\n /// @notice The contract storing all funding cycle configurations.\\n IJBFundingCycleStore public immutable override fundingCycleStore;\\n\\n /// @notice The contract that exposes price feeds.\\n IJBPrices public immutable override prices;\\n\\n //*********************************************************************//\\n // --------------------- public stored properties -------------------- //\\n //*********************************************************************//\\n\\n /// @notice The amount of tokens that each project has for each terminal, in terms of the terminal's token.\\n /// @dev The balance is represented as a fixed point number with the same amount of decimals as its relative terminal.\\n /// @custom:param _terminal The terminal to which the balance applies.\\n /// @custom:param _projectId The ID of the project to get the balance of.\\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => uint256)) public override balanceOf;\\n\\n /// @notice The amount of funds that a project has distributed from its limit during the current funding cycle for each terminal, in terms of the distribution limit's currency.\\n /// @dev Increases as projects use their preconfigured distribution limits.\\n /// @dev The used distribution limit is represented as a fixed point number with the same amount of decimals as its relative terminal.\\n /// @custom:param _terminal The terminal to which the used distribution limit applies.\\n /// @custom:param _projectId The ID of the project to get the used distribution limit of.\\n /// @custom:param _fundingCycleNumber The number of the funding cycle during which the distribution limit was used.\\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => mapping(uint256 => uint256)))\\n public\\n override usedDistributionLimitOf;\\n\\n /// @notice The amount of funds that a project has used from its allowance during the current funding cycle configuration for each terminal, in terms of the overflow allowance's currency.\\n /// @dev Increases as projects use their allowance.\\n /// @dev The used allowance is represented as a fixed point number with the same amount of decimals as its relative terminal.\\n /// @custom:param _terminal The terminal to which the overflow allowance applies.\\n /// @custom:param _projectId The ID of the project to get the used overflow allowance of.\\n /// @custom:param _configuration The configuration of the during which the allowance was used.\\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => mapping(uint256 => uint256)))\\n public\\n override usedOverflowAllowanceOf;\\n\\n //*********************************************************************//\\n // ------------------------- external views -------------------------- //\\n //*********************************************************************//\\n\\n /// @notice Gets the current overflowed amount in a terminal for a specified project.\\n /// @dev The current overflow is represented as a fixed point number with the same amount of decimals as the specified terminal.\\n /// @param _terminal The terminal for which the overflow is being calculated.\\n /// @param _projectId The ID of the project to get overflow for.\\n /// @return The current amount of overflow that project has in the specified terminal.\\n function currentOverflowOf(\\n IJBSingleTokenPaymentTerminal _terminal,\\n uint256 _projectId\\n ) external view override returns (uint256) {\\n // Return the overflow during the project's current funding cycle.\\n return\\n _overflowDuring(\\n _terminal,\\n _projectId,\\n fundingCycleStore.currentOf(_projectId),\\n _terminal.currency()\\n );\\n }\\n\\n /// @notice Gets the current overflowed amount for a specified project across all terminals.\\n /// @param _projectId The ID of the project to get total overflow for.\\n /// @param _decimals The number of decimals that the fixed point overflow should include.\\n /// @param _currency The currency that the total overflow should be in terms of.\\n /// @return The current total amount of overflow that project has across all terminals.\\n function currentTotalOverflowOf(\\n uint256 _projectId,\\n uint256 _decimals,\\n uint256 _currency\\n ) external view override returns (uint256) {\\n return _currentTotalOverflowOf(_projectId, _decimals, _currency);\\n }\\n\\n /// @notice The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the total token supply and overflow in the ecosystem.\\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\\n /// @dev The current reclaimable overflow is returned in terms of the specified terminal's currency.\\n /// @dev The reclaimable overflow is represented as a fixed point number with the same amount of decimals as the specified terminal.\\n /// @param _terminal The terminal from which the reclaimable amount would come.\\n /// @param _projectId The ID of the project to get the reclaimable overflow amount for.\\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\\n /// @param _useTotalOverflow A flag indicating whether the overflow used in the calculation should be summed from all of the project's terminals. If false, overflow should be limited to the amount in the specified `_terminal`.\\n /// @return The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_terminal`.\\n function currentReclaimableOverflowOf(\\n IJBSingleTokenPaymentTerminal _terminal,\\n uint256 _projectId,\\n uint256 _tokenCount,\\n bool _useTotalOverflow\\n ) external view override returns (uint256) {\\n // Get a reference to the project's current funding cycle.\\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\\n\\n // Get the amount of current overflow.\\n // Use the project's total overflow across all of its terminals if the flag species specifies so. Otherwise, use the overflow local to the specified terminal.\\n uint256 _currentOverflow = _useTotalOverflow\\n ? _currentTotalOverflowOf(_projectId, _terminal.decimals(), _terminal.currency())\\n : _overflowDuring(_terminal, _projectId, _fundingCycle, _terminal.currency());\\n\\n // If there's no overflow, there's no reclaimable overflow.\\n if (_currentOverflow == 0) return 0;\\n\\n // Get the number of outstanding tokens the project has.\\n uint256 _totalSupply = IJBController3_1(directory.controllerOf(_projectId))\\n .totalOutstandingTokensOf(_projectId);\\n\\n // Can't redeem more tokens that is in the supply.\\n if (_tokenCount > _totalSupply) return 0;\\n\\n // Return the reclaimable overflow amount.\\n return\\n _reclaimableOverflowDuring(\\n _projectId,\\n _fundingCycle,\\n _tokenCount,\\n _totalSupply,\\n _currentOverflow\\n );\\n }\\n\\n /// @notice The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the specified total token supply and overflow amounts.\\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\\n /// @param _projectId The ID of the project to get the reclaimable overflow amount for.\\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\\n /// @param _totalSupply The total number of tokens to make the calculation with, as a fixed point number with 18 decimals.\\n /// @param _overflow The amount of overflow to make the calculation with, as a fixed point number.\\n /// @return The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_overflow`.\\n function currentReclaimableOverflowOf(\\n uint256 _projectId,\\n uint256 _tokenCount,\\n uint256 _totalSupply,\\n uint256 _overflow\\n ) external view override returns (uint256) {\\n // If there's no overflow, there's no reclaimable overflow.\\n if (_overflow == 0) return 0;\\n\\n // Can't redeem more tokens that is in the supply.\\n if (_tokenCount > _totalSupply) return 0;\\n\\n // Get a reference to the project's current funding cycle.\\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\\n\\n // Return the reclaimable overflow amount.\\n return\\n _reclaimableOverflowDuring(_projectId, _fundingCycle, _tokenCount, _totalSupply, _overflow);\\n }\\n\\n //*********************************************************************//\\n // -------------------------- constructor ---------------------------- //\\n //*********************************************************************//\\n\\n /// @param _directory A contract storing directories of terminals and controllers for each project.\\n /// @param _fundingCycleStore A contract storing all funding cycle configurations.\\n /// @param _prices A contract that exposes price feeds.\\n constructor(IJBDirectory _directory, IJBFundingCycleStore _fundingCycleStore, IJBPrices _prices) {\\n directory = _directory;\\n fundingCycleStore = _fundingCycleStore;\\n prices = _prices;\\n }\\n\\n //*********************************************************************//\\n // ---------------------- external transactions ---------------------- //\\n //*********************************************************************//\\n\\n /// @notice Records newly contributed tokens to a project.\\n /// @dev Mints the project's tokens according to values provided by a configured data source. If no data source is configured, mints tokens proportional to the amount of the contribution.\\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.sender's tokens.\\n /// @param _payer The original address that sent the payment to the terminal.\\n /// @param _amount The amount of tokens being paid. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\\n /// @param _projectId The ID of the project being paid.\\n /// @param _baseWeightCurrency The currency to base token issuance on.\\n /// @param _beneficiary The specified address that should be the beneficiary of anything that results from the payment.\\n /// @param _memo A memo to pass along to the emitted event, and passed along to the funding cycle's data source.\\n /// @param _metadata Bytes to send along to the data source, if one is provided.\\n /// @return fundingCycle The project's funding cycle during which payment was made.\\n /// @return tokenCount The number of project tokens that were minted, as a fixed point number with 18 decimals.\\n /// @return delegateAllocations The amount to send to delegates instead of adding to the local balance.\\n /// @return memo A memo that should be passed along to the emitted event.\\n function recordPaymentFrom(\\n address _payer,\\n JBTokenAmount calldata _amount,\\n uint256 _projectId,\\n uint256 _baseWeightCurrency,\\n address _beneficiary,\\n string calldata _memo,\\n bytes memory _metadata\\n )\\n external\\n override\\n nonReentrant\\n returns (\\n JBFundingCycle memory fundingCycle,\\n uint256 tokenCount,\\n JBPayDelegateAllocation3_1_1[] memory delegateAllocations,\\n string memory memo\\n )\\n {\\n // Get a reference to the current funding cycle for the project.\\n fundingCycle = fundingCycleStore.currentOf(_projectId);\\n\\n // The project must have a funding cycle configured.\\n if (fundingCycle.number == 0) revert INVALID_FUNDING_CYCLE();\\n\\n // Must not be paused.\\n if (fundingCycle.payPaused()) revert FUNDING_CYCLE_PAYMENT_PAUSED();\\n\\n // The weight according to which new token supply is to be minted, as a fixed point number with 18 decimals.\\n uint256 _weight;\\n\\n // If the funding cycle has configured a data source, use it to derive a weight and memo.\\n if (fundingCycle.useDataSourceForPay() && fundingCycle.dataSource() != address(0)) {\\n // Create the params that'll be sent to the data source.\\n JBPayParamsData memory _data = JBPayParamsData(\\n IJBSingleTokenPaymentTerminal(msg.sender),\\n _payer,\\n _amount,\\n _projectId,\\n fundingCycle.configuration,\\n _beneficiary,\\n fundingCycle.weight,\\n fundingCycle.reservedRate(),\\n _memo,\\n _metadata\\n );\\n (_weight, memo, delegateAllocations) = IJBFundingCycleDataSource3_1_1(\\n fundingCycle.dataSource()\\n ).payParams(_data);\\n }\\n // Otherwise use the funding cycle's weight\\n else {\\n _weight = fundingCycle.weight;\\n memo = _memo;\\n }\\n\\n // Scoped section prevents stack too deep. `_balanceDiff` only used within scope.\\n {\\n // Keep a reference to the amount that should be added to the project's balance.\\n uint256 _balanceDiff = _amount.value;\\n\\n // Validate all delegated amounts. This needs to be done before returning the delegate allocations to ensure valid delegated amounts.\\n if (delegateAllocations.length != 0) {\\n for (uint256 _i; _i < delegateAllocations.length; ) {\\n // Get a reference to the amount to be delegated.\\n uint256 _delegatedAmount = delegateAllocations[_i].amount;\\n\\n // Validate if non-zero.\\n if (_delegatedAmount != 0) {\\n // Can't delegate more than was paid.\\n if (_delegatedAmount > _balanceDiff) revert INVALID_AMOUNT_TO_SEND_DELEGATE();\\n\\n // Decrement the total amount being added to the balance.\\n _balanceDiff = _balanceDiff - _delegatedAmount;\\n }\\n\\n unchecked {\\n ++_i;\\n }\\n }\\n }\\n\\n // If there's no amount being recorded, there's nothing left to do.\\n if (_amount.value == 0) return (fundingCycle, 0, delegateAllocations, memo);\\n\\n // Add the correct balance difference to the token balance of the project.\\n if (_balanceDiff != 0)\\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] +\\n _balanceDiff;\\n }\\n\\n // If there's no weight, token count must be 0 so there's nothing left to do.\\n if (_weight == 0) return (fundingCycle, 0, delegateAllocations, memo);\\n\\n // Get a reference to the number of decimals in the amount. (prevents stack too deep).\\n uint256 _decimals = _amount.decimals;\\n\\n // If the terminal should base its weight on a different currency from the terminal's currency, determine the factor.\\n // The weight is always a fixed point mumber with 18 decimals. To ensure this, the ratio should use the same number of decimals as the `_amount`.\\n uint256 _weightRatio = _amount.currency == _baseWeightCurrency\\n ? 10 ** _decimals\\n : prices.priceFor(_amount.currency, _baseWeightCurrency, _decimals);\\n\\n // Find the number of tokens to mint, as a fixed point number with as many decimals as `weight` has.\\n tokenCount = PRBMath.mulDiv(_amount.value, _weight, _weightRatio);\\n }\\n\\n /// @notice Records newly redeemed tokens of a project.\\n /// @dev Redeems the project's tokens according to values provided by a configured data source. If no data source is configured, redeems tokens along a redemption bonding curve that is a function of the number of tokens being burned.\\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.senders tokens.\\n /// @param _holder The account that is having its tokens redeemed.\\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\\n /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals.\\n /// @param _memo A memo to pass along to the emitted event.\\n /// @param _metadata Bytes to send along to the data source, if one is provided.\\n /// @return fundingCycle The funding cycle during which the redemption was made.\\n /// @return reclaimAmount The amount of terminal tokens reclaimed, as a fixed point number with 18 decimals.\\n /// @return delegateAllocations The amount to send to delegates instead of sending to the beneficiary.\\n /// @return memo A memo that should be passed along to the emitted event.\\n function recordRedemptionFor(\\n address _holder,\\n uint256 _projectId,\\n uint256 _tokenCount,\\n string memory _memo,\\n bytes memory _metadata\\n )\\n external\\n override\\n nonReentrant\\n returns (\\n JBFundingCycle memory fundingCycle,\\n uint256 reclaimAmount,\\n JBRedemptionDelegateAllocation3_1_1[] memory delegateAllocations,\\n string memory memo\\n )\\n {\\n // Get a reference to the project's current funding cycle.\\n fundingCycle = fundingCycleStore.currentOf(_projectId);\\n\\n // The current funding cycle must not be paused.\\n if (fundingCycle.redeemPaused()) revert FUNDING_CYCLE_REDEEM_PAUSED();\\n\\n // Scoped section prevents stack too deep. `_reclaimedTokenAmount`, `_currentOverflow`, and `_totalSupply` only used within scope.\\n {\\n // Get a reference to the reclaimed token amount struct, the current overflow, and the total token supply.\\n JBTokenAmount memory _reclaimedTokenAmount;\\n uint256 _currentOverflow;\\n uint256 _totalSupply;\\n\\n // Another scoped section prevents stack too deep. `_token`, `_decimals`, and `_currency` only used within scope.\\n {\\n // Get a reference to the terminal's tokens.\\n address _token = IJBSingleTokenPaymentTerminal(msg.sender).token();\\n\\n // Get a reference to the terminal's decimals.\\n uint256 _decimals = IJBSingleTokenPaymentTerminal(msg.sender).decimals();\\n\\n // Get areference to the terminal's currency.\\n uint256 _currency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\\n\\n // Get the amount of current overflow.\\n // Use the local overflow if the funding cycle specifies that it should be used. Otherwise, use the project's total overflow across all of its terminals.\\n _currentOverflow = fundingCycle.useTotalOverflowForRedemptions()\\n ? _currentTotalOverflowOf(_projectId, _decimals, _currency)\\n : _overflowDuring(\\n IJBSingleTokenPaymentTerminal(msg.sender),\\n _projectId,\\n fundingCycle,\\n _currency\\n );\\n\\n // Get the number of outstanding tokens the project has.\\n _totalSupply = IJBController3_1(directory.controllerOf(_projectId))\\n .totalOutstandingTokensOf(_projectId);\\n\\n // Can't redeem more tokens that is in the supply.\\n if (_tokenCount > _totalSupply) revert INSUFFICIENT_TOKENS();\\n\\n if (_currentOverflow != 0)\\n // Calculate reclaim amount using the current overflow amount.\\n reclaimAmount = _reclaimableOverflowDuring(\\n _projectId,\\n fundingCycle,\\n _tokenCount,\\n _totalSupply,\\n _currentOverflow\\n );\\n\\n _reclaimedTokenAmount = JBTokenAmount(_token, reclaimAmount, _decimals, _currency);\\n }\\n\\n // If the funding cycle has configured a data source, use it to derive a claim amount and memo.\\n if (fundingCycle.useDataSourceForRedeem() && fundingCycle.dataSource() != address(0)) {\\n // Yet another scoped section prevents stack too deep. `_state` only used within scope.\\n {\\n // Get a reference to the ballot state.\\n JBBallotState _state = fundingCycleStore.currentBallotStateOf(_projectId);\\n\\n // Create the params that'll be sent to the data source.\\n JBRedeemParamsData memory _data = JBRedeemParamsData(\\n IJBSingleTokenPaymentTerminal(msg.sender),\\n _holder,\\n _projectId,\\n fundingCycle.configuration,\\n _tokenCount,\\n _totalSupply,\\n _currentOverflow,\\n _reclaimedTokenAmount,\\n fundingCycle.useTotalOverflowForRedemptions(),\\n _state == JBBallotState.Active\\n ? fundingCycle.ballotRedemptionRate()\\n : fundingCycle.redemptionRate(),\\n _memo,\\n _metadata\\n );\\n (reclaimAmount, memo, delegateAllocations) = IJBFundingCycleDataSource3_1_1(\\n fundingCycle.dataSource()\\n ).redeemParams(_data);\\n }\\n } else {\\n memo = _memo;\\n }\\n }\\n\\n // Keep a reference to the amount that should be subtracted from the project's balance.\\n uint256 _balanceDiff = reclaimAmount;\\n\\n if (delegateAllocations.length != 0) {\\n // Validate all delegated amounts.\\n for (uint256 _i; _i < delegateAllocations.length; ) {\\n // Get a reference to the amount to be delegated.\\n uint256 _delegatedAmount = delegateAllocations[_i].amount;\\n\\n // Validate if non-zero.\\n if (_delegatedAmount != 0)\\n // Increment the total amount being subtracted from the balance.\\n _balanceDiff = _balanceDiff + _delegatedAmount;\\n\\n unchecked {\\n ++_i;\\n }\\n }\\n }\\n\\n // The amount being reclaimed must be within the project's balance.\\n if (_balanceDiff > balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId])\\n revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\\n\\n // Remove the reclaimed funds from the project's balance.\\n if (_balanceDiff != 0) {\\n unchecked {\\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\\n _balanceDiff;\\n }\\n }\\n }\\n\\n /// @notice Records newly distributed funds for a project.\\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\\n /// @param _projectId The ID of the project that is having funds distributed.\\n /// @param _amount The amount to use from the distribution limit, as a fixed point number.\\n /// @param _currency The currency of the `_amount`. This must match the project's current funding cycle's currency.\\n /// @return fundingCycle The funding cycle during which the distribution was made.\\n /// @return distributedAmount The amount of terminal tokens distributed, as a fixed point number with the same amount of decimals as its relative terminal.\\n function recordDistributionFor(\\n uint256 _projectId,\\n uint256 _amount,\\n uint256 _currency\\n )\\n external\\n override\\n nonReentrant\\n returns (JBFundingCycle memory fundingCycle, uint256 distributedAmount)\\n {\\n // Get a reference to the project's current funding cycle.\\n fundingCycle = fundingCycleStore.currentOf(_projectId);\\n\\n // The funding cycle must not be configured to have distributions paused.\\n if (fundingCycle.distributionsPaused()) revert FUNDING_CYCLE_DISTRIBUTION_PAUSED();\\n\\n // The new total amount that has been distributed during this funding cycle.\\n uint256 _newUsedDistributionLimitOf = usedDistributionLimitOf[\\n IJBSingleTokenPaymentTerminal(msg.sender)\\n ][_projectId][fundingCycle.number] + _amount;\\n\\n // Amount must be within what is still distributable.\\n (uint256 _distributionLimitOf, uint256 _distributionLimitCurrencyOf) = IJBController3_1(\\n directory.controllerOf(_projectId)\\n ).fundAccessConstraintsStore().distributionLimitOf(\\n _projectId,\\n fundingCycle.configuration,\\n IJBSingleTokenPaymentTerminal(msg.sender),\\n IJBSingleTokenPaymentTerminal(msg.sender).token()\\n );\\n\\n // Make sure the new used amount is within the distribution limit.\\n if (_newUsedDistributionLimitOf > _distributionLimitOf || _distributionLimitOf == 0)\\n revert DISTRIBUTION_AMOUNT_LIMIT_REACHED();\\n\\n // Make sure the currencies match.\\n if (_currency != _distributionLimitCurrencyOf) revert CURRENCY_MISMATCH();\\n\\n // Get a reference to the terminal's currency.\\n uint256 _balanceCurrency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\\n\\n // Convert the amount to the balance's currency.\\n distributedAmount = (_currency == _balanceCurrency)\\n ? _amount\\n : PRBMath.mulDiv(\\n _amount,\\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\\n prices.priceFor(_currency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\\n );\\n\\n // The amount being distributed must be available.\\n if (distributedAmount > balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId])\\n revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\\n\\n // Store the new amount.\\n usedDistributionLimitOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId][\\n fundingCycle.number\\n ] = _newUsedDistributionLimitOf;\\n\\n // Removed the distributed funds from the project's token balance.\\n unchecked {\\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\\n distributedAmount;\\n }\\n }\\n\\n /// @notice Records newly used allowance funds of a project.\\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\\n /// @param _projectId The ID of the project to use the allowance of.\\n /// @param _amount The amount to use from the allowance, as a fixed point number.\\n /// @param _currency The currency of the `_amount`. Must match the currency of the overflow allowance.\\n /// @return fundingCycle The funding cycle during which the overflow allowance is being used.\\n /// @return usedAmount The amount of terminal tokens used, as a fixed point number with the same amount of decimals as its relative terminal.\\n function recordUsedAllowanceOf(\\n uint256 _projectId,\\n uint256 _amount,\\n uint256 _currency\\n )\\n external\\n override\\n nonReentrant\\n returns (JBFundingCycle memory fundingCycle, uint256 usedAmount)\\n {\\n // Get a reference to the project's current funding cycle.\\n fundingCycle = fundingCycleStore.currentOf(_projectId);\\n\\n // Get a reference to the new used overflow allowance for this funding cycle configuration.\\n uint256 _newUsedOverflowAllowanceOf = usedOverflowAllowanceOf[\\n IJBSingleTokenPaymentTerminal(msg.sender)\\n ][_projectId][fundingCycle.configuration] + _amount;\\n\\n // There must be sufficient allowance available.\\n (uint256 _overflowAllowanceOf, uint256 _overflowAllowanceCurrency) = IJBController3_1(\\n directory.controllerOf(_projectId)\\n ).fundAccessConstraintsStore().overflowAllowanceOf(\\n _projectId,\\n fundingCycle.configuration,\\n IJBSingleTokenPaymentTerminal(msg.sender),\\n IJBSingleTokenPaymentTerminal(msg.sender).token()\\n );\\n\\n // Make sure the new used amount is within the allowance.\\n if (_newUsedOverflowAllowanceOf > _overflowAllowanceOf || _overflowAllowanceOf == 0)\\n revert INADEQUATE_CONTROLLER_ALLOWANCE();\\n\\n // Make sure the currencies match.\\n if (_currency != _overflowAllowanceCurrency) revert CURRENCY_MISMATCH();\\n\\n // Get a reference to the terminal's currency.\\n uint256 _balanceCurrency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\\n\\n // Convert the amount to this store's terminal's token.\\n usedAmount = (_currency == _balanceCurrency)\\n ? _amount\\n : PRBMath.mulDiv(\\n _amount,\\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\\n prices.priceFor(_currency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\\n );\\n\\n // The amount being distributed must be available in the overflow.\\n if (\\n usedAmount >\\n _overflowDuring(\\n IJBSingleTokenPaymentTerminal(msg.sender),\\n _projectId,\\n fundingCycle,\\n _balanceCurrency\\n )\\n ) revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\\n\\n // Store the incremented value.\\n usedOverflowAllowanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId][\\n fundingCycle.configuration\\n ] = _newUsedOverflowAllowanceOf;\\n\\n // Update the project's balance.\\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\\n usedAmount;\\n }\\n\\n /// @notice Records newly added funds for the project.\\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\\n /// @param _projectId The ID of the project to which the funds being added belong.\\n /// @param _amount The amount of terminal tokens added, as a fixed point number with the same amount of decimals as its relative terminal.\\n function recordAddedBalanceFor(uint256 _projectId, uint256 _amount) external override {\\n // Increment the balance.\\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] +\\n _amount;\\n }\\n\\n /// @notice Records the migration of funds from this store.\\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount returned is in terms of the msg.senders tokens.\\n /// @param _projectId The ID of the project being migrated.\\n /// @return balance The project's migrated balance, as a fixed point number with the same amount of decimals as its relative terminal.\\n function recordMigration(\\n uint256 _projectId\\n ) external override nonReentrant returns (uint256 balance) {\\n // Get a reference to the project's current funding cycle.\\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\\n\\n // Migration must be allowed.\\n if (!_fundingCycle.terminalMigrationAllowed()) revert PAYMENT_TERMINAL_MIGRATION_NOT_ALLOWED();\\n\\n // Return the current balance.\\n balance = balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId];\\n\\n // Set the balance to 0.\\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] = 0;\\n }\\n\\n //*********************************************************************//\\n // --------------------- private helper functions -------------------- //\\n //*********************************************************************//\\n\\n /// @notice The amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens when measured from the specified.\\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\\n /// @param _projectId The ID of the project to get the reclaimable overflow amount for.\\n /// @param _fundingCycle The funding cycle during which reclaimable overflow is being calculated.\\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\\n /// @param _totalSupply The total supply of tokens to make the calculation with, as a fixed point number with 18 decimals.\\n /// @param _overflow The amount of overflow to make the calculation with.\\n /// @return The amount of overflowed tokens that can be reclaimed.\\n function _reclaimableOverflowDuring(\\n uint256 _projectId,\\n JBFundingCycle memory _fundingCycle,\\n uint256 _tokenCount,\\n uint256 _totalSupply,\\n uint256 _overflow\\n ) private view returns (uint256) {\\n // If the amount being redeemed is the total supply, return the rest of the overflow.\\n if (_tokenCount == _totalSupply) return _overflow;\\n\\n // Use the ballot redemption rate if the queued cycle is pending approval according to the previous funding cycle's ballot.\\n uint256 _redemptionRate = fundingCycleStore.currentBallotStateOf(_projectId) ==\\n JBBallotState.Active\\n ? _fundingCycle.ballotRedemptionRate()\\n : _fundingCycle.redemptionRate();\\n\\n // If the redemption rate is 0, nothing is claimable.\\n if (_redemptionRate == 0) return 0;\\n\\n // Get a reference to the linear proportion.\\n uint256 _base = PRBMath.mulDiv(_overflow, _tokenCount, _totalSupply);\\n\\n // These conditions are all part of the same curve. Edge conditions are separated because fewer operation are necessary.\\n if (_redemptionRate == JBConstants.MAX_REDEMPTION_RATE) return _base;\\n\\n return\\n PRBMath.mulDiv(\\n _base,\\n _redemptionRate +\\n PRBMath.mulDiv(\\n _tokenCount,\\n JBConstants.MAX_REDEMPTION_RATE - _redemptionRate,\\n _totalSupply\\n ),\\n JBConstants.MAX_REDEMPTION_RATE\\n );\\n }\\n\\n /// @notice Gets the amount that is overflowing when measured from the specified funding cycle.\\n /// @dev This amount changes as the value of the balance changes in relation to the currency being used to measure the distribution limit.\\n /// @param _terminal The terminal for which the overflow is being calculated.\\n /// @param _projectId The ID of the project to get overflow for.\\n /// @param _fundingCycle The ID of the funding cycle to base the overflow on.\\n /// @param _balanceCurrency The currency that the stored balance is expected to be in terms of.\\n /// @return overflow The overflow of funds, as a fixed point number with 18 decimals.\\n function _overflowDuring(\\n IJBSingleTokenPaymentTerminal _terminal,\\n uint256 _projectId,\\n JBFundingCycle memory _fundingCycle,\\n uint256 _balanceCurrency\\n ) private view returns (uint256) {\\n // Get the current balance of the project.\\n uint256 _balanceOf = balanceOf[_terminal][_projectId];\\n\\n // If there's no balance, there's no overflow.\\n if (_balanceOf == 0) return 0;\\n\\n // Get a reference to the distribution limit during the funding cycle.\\n (uint256 _distributionLimit, uint256 _distributionLimitCurrency) = IJBController3_1(\\n directory.controllerOf(_projectId)\\n ).fundAccessConstraintsStore().distributionLimitOf(\\n _projectId,\\n _fundingCycle.configuration,\\n _terminal,\\n _terminal.token()\\n );\\n\\n // Get a reference to the amount still distributable during the funding cycle.\\n uint256 _distributionLimitRemaining = _distributionLimit -\\n usedDistributionLimitOf[_terminal][_projectId][_fundingCycle.number];\\n\\n // Convert the _distributionRemaining to be in terms of the provided currency.\\n if (_distributionLimitRemaining != 0 && _distributionLimitCurrency != _balanceCurrency)\\n _distributionLimitRemaining = PRBMath.mulDiv(\\n _distributionLimitRemaining,\\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\\n prices.priceFor(_distributionLimitCurrency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\\n );\\n\\n // Overflow is the balance of this project minus the amount that can still be distributed.\\n unchecked {\\n return\\n _balanceOf > _distributionLimitRemaining ? _balanceOf - _distributionLimitRemaining : 0;\\n }\\n }\\n\\n /// @notice Gets the amount that is currently overflowing across all of a project's terminals.\\n /// @dev This amount changes as the value of the balances changes in relation to the currency being used to measure the project's distribution limits.\\n /// @param _projectId The ID of the project to get the total overflow for.\\n /// @param _decimals The number of decimals that the fixed point overflow should include.\\n /// @param _currency The currency that the overflow should be in terms of.\\n /// @return overflow The total overflow of a project's funds.\\n function _currentTotalOverflowOf(\\n uint256 _projectId,\\n uint256 _decimals,\\n uint256 _currency\\n ) private view returns (uint256) {\\n // Get a reference to the project's terminals.\\n IJBPaymentTerminal[] memory _terminals = directory.terminalsOf(_projectId);\\n\\n // Keep a reference to the ETH overflow across all terminals, as a fixed point number with 18 decimals.\\n uint256 _ethOverflow;\\n\\n // Add the current ETH overflow for each terminal.\\n for (uint256 _i; _i < _terminals.length; ) {\\n _ethOverflow = _ethOverflow + _terminals[_i].currentEthOverflowOf(_projectId);\\n unchecked {\\n ++_i;\\n }\\n }\\n\\n // Convert the ETH overflow to the specified currency if needed, maintaining a fixed point number with 18 decimals.\\n uint256 _totalOverflow18Decimal = _currency == JBCurrencies.ETH\\n ? _ethOverflow\\n : PRBMath.mulDiv(_ethOverflow, 10 ** 18, prices.priceFor(JBCurrencies.ETH, _currency, 18));\\n\\n // Adjust the decimals of the fixed point number if needed to match the target decimals.\\n return\\n (_decimals == 18)\\n ? _totalOverflow18Decimal\\n : JBFixedPointNumber.adjustDecimals(_totalOverflow18Decimal, 18, _decimals);\\n }\\n}\\n\",\"keccak256\":\"0xb0cde3ddcf06733537717094bb426d8817812ade5f5f594da1b3cc54cbfe9263\",\"license\":\"MIT\"},\"contracts/enums/JBBallotState.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nenum JBBallotState {\\n Active,\\n Approved,\\n Failed\\n}\\n\",\"keccak256\":\"0x891fcac63470398b3a11239da7feba6b07d640809fcefd2404303b823d7378f8\",\"license\":\"MIT\"},\"contracts/interfaces/IJBController3_0_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IJBController3_0_1 {\\n function reservedTokenBalanceOf(uint256 projectId) external view returns (uint256);\\n\\n function totalOutstandingTokensOf(uint256 projectId) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0xf64926bf7ab5850ea9b7ec27d92a021f02344a3fadb0396af80966ad08b3dd2b\",\"license\":\"MIT\"},\"contracts/interfaces/IJBController3_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\\nimport {JBBallotState} from './../enums/JBBallotState.sol';\\nimport {JBFundAccessConstraints} from './../structs/JBFundAccessConstraints.sol';\\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\\nimport {JBFundingCycleData} from './../structs/JBFundingCycleData.sol';\\nimport {JBFundingCycleMetadata} from './../structs/JBFundingCycleMetadata.sol';\\nimport {JBGroupedSplits} from './../structs/JBGroupedSplits.sol';\\nimport {JBProjectMetadata} from './../structs/JBProjectMetadata.sol';\\nimport {JBSplit} from './../structs/JBSplit.sol';\\nimport {IJBController3_0_1} from './IJBController3_0_1.sol';\\nimport {IJBDirectory} from './IJBDirectory.sol';\\nimport {IJBFundAccessConstraintsStore} from './IJBFundAccessConstraintsStore.sol';\\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\\nimport {IJBMigratable} from './IJBMigratable.sol';\\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\\nimport {IJBProjects} from './IJBProjects.sol';\\nimport {IJBSplitsStore} from './IJBSplitsStore.sol';\\nimport {IJBTokenStore} from './IJBTokenStore.sol';\\n\\ninterface IJBController3_1 is IJBController3_0_1, IERC165 {\\n event LaunchProject(uint256 configuration, uint256 projectId, string memo, address caller);\\n\\n event LaunchFundingCycles(uint256 configuration, uint256 projectId, string memo, address caller);\\n\\n event ReconfigureFundingCycles(\\n uint256 configuration,\\n uint256 projectId,\\n string memo,\\n address caller\\n );\\n\\n event DistributeReservedTokens(\\n uint256 indexed fundingCycleConfiguration,\\n uint256 indexed fundingCycleNumber,\\n uint256 indexed projectId,\\n address beneficiary,\\n uint256 tokenCount,\\n uint256 beneficiaryTokenCount,\\n string memo,\\n address caller\\n );\\n\\n event DistributeToReservedTokenSplit(\\n uint256 indexed projectId,\\n uint256 indexed domain,\\n uint256 indexed group,\\n JBSplit split,\\n uint256 tokenCount,\\n address caller\\n );\\n\\n event MintTokens(\\n address indexed beneficiary,\\n uint256 indexed projectId,\\n uint256 tokenCount,\\n uint256 beneficiaryTokenCount,\\n string memo,\\n uint256 reservedRate,\\n address caller\\n );\\n\\n event BurnTokens(\\n address indexed holder,\\n uint256 indexed projectId,\\n uint256 tokenCount,\\n string memo,\\n address caller\\n );\\n\\n event Migrate(uint256 indexed projectId, IJBMigratable to, address caller);\\n\\n event PrepMigration(uint256 indexed projectId, address from, address caller);\\n\\n function projects() external view returns (IJBProjects);\\n\\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\\n\\n function tokenStore() external view returns (IJBTokenStore);\\n\\n function splitsStore() external view returns (IJBSplitsStore);\\n\\n function fundAccessConstraintsStore() external view returns (IJBFundAccessConstraintsStore);\\n\\n function directory() external view returns (IJBDirectory);\\n\\n function reservedTokenBalanceOf(uint256 projectId) external view returns (uint256);\\n\\n function totalOutstandingTokensOf(uint256 projectId) external view returns (uint256);\\n\\n function getFundingCycleOf(\\n uint256 projectId,\\n uint256 configuration\\n )\\n external\\n view\\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata);\\n\\n function latestConfiguredFundingCycleOf(\\n uint256 projectId\\n )\\n external\\n view\\n returns (JBFundingCycle memory, JBFundingCycleMetadata memory metadata, JBBallotState);\\n\\n function currentFundingCycleOf(\\n uint256 projectId\\n )\\n external\\n view\\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata);\\n\\n function queuedFundingCycleOf(\\n uint256 projectId\\n )\\n external\\n view\\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata);\\n\\n function launchProjectFor(\\n address owner,\\n JBProjectMetadata calldata projectMetadata,\\n JBFundingCycleData calldata data,\\n JBFundingCycleMetadata calldata metadata,\\n uint256 mustStartAtOrAfter,\\n JBGroupedSplits[] memory groupedSplits,\\n JBFundAccessConstraints[] memory fundAccessConstraints,\\n IJBPaymentTerminal[] memory terminals,\\n string calldata memo\\n ) external returns (uint256 projectId);\\n\\n function launchFundingCyclesFor(\\n uint256 projectId,\\n JBFundingCycleData calldata data,\\n JBFundingCycleMetadata calldata metadata,\\n uint256 mustStartAtOrAfter,\\n JBGroupedSplits[] memory groupedSplits,\\n JBFundAccessConstraints[] memory fundAccessConstraints,\\n IJBPaymentTerminal[] memory terminals,\\n string calldata memo\\n ) external returns (uint256 configuration);\\n\\n function reconfigureFundingCyclesOf(\\n uint256 projectId,\\n JBFundingCycleData calldata data,\\n JBFundingCycleMetadata calldata metadata,\\n uint256 mustStartAtOrAfter,\\n JBGroupedSplits[] memory groupedSplits,\\n JBFundAccessConstraints[] memory fundAccessConstraints,\\n string calldata memo\\n ) external returns (uint256);\\n\\n function mintTokensOf(\\n uint256 projectId,\\n uint256 tokenCount,\\n address beneficiary,\\n string calldata memo,\\n bool preferClaimedTokens,\\n bool useReservedRate\\n ) external returns (uint256 beneficiaryTokenCount);\\n\\n function burnTokensOf(\\n address holder,\\n uint256 projectId,\\n uint256 tokenCount,\\n string calldata memo,\\n bool preferClaimedTokens\\n ) external;\\n\\n function distributeReservedTokensOf(\\n uint256 projectId,\\n string memory memo\\n ) external returns (uint256);\\n\\n function migrate(uint256 projectId, IJBMigratable to) external;\\n}\\n\",\"keccak256\":\"0xe09f3d0d670a40e5d66d3fddc8a63f51b8ccb24175ffbb703ba95496deb85bdb\",\"license\":\"MIT\"},\"contracts/interfaces/IJBDirectory.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\\nimport {IJBProjects} from './IJBProjects.sol';\\n\\ninterface IJBDirectory {\\n event SetController(uint256 indexed projectId, address indexed controller, address caller);\\n\\n event AddTerminal(uint256 indexed projectId, IJBPaymentTerminal indexed terminal, address caller);\\n\\n event SetTerminals(uint256 indexed projectId, IJBPaymentTerminal[] terminals, address caller);\\n\\n event SetPrimaryTerminal(\\n uint256 indexed projectId,\\n address indexed token,\\n IJBPaymentTerminal indexed terminal,\\n address caller\\n );\\n\\n event SetIsAllowedToSetFirstController(address indexed addr, bool indexed flag, address caller);\\n\\n function projects() external view returns (IJBProjects);\\n\\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\\n\\n function controllerOf(uint256 projectId) external view returns (address);\\n\\n function isAllowedToSetFirstController(address account) external view returns (bool);\\n\\n function terminalsOf(uint256 projectId) external view returns (IJBPaymentTerminal[] memory);\\n\\n function isTerminalOf(\\n uint256 projectId,\\n IJBPaymentTerminal terminal\\n ) external view returns (bool);\\n\\n function primaryTerminalOf(\\n uint256 projectId,\\n address token\\n ) external view returns (IJBPaymentTerminal);\\n\\n function setControllerOf(uint256 projectId, address controller) external;\\n\\n function setTerminalsOf(uint256 projectId, IJBPaymentTerminal[] calldata terminals) external;\\n\\n function setPrimaryTerminalOf(\\n uint256 projectId,\\n address token,\\n IJBPaymentTerminal terminal\\n ) external;\\n\\n function setIsAllowedToSetFirstController(address account, bool flag) external;\\n}\\n\",\"keccak256\":\"0x490d5fe691ee7d9c9179fa19964de279882176513d92f3efc0aa98dc34799d1c\",\"license\":\"MIT\"},\"contracts/interfaces/IJBFundAccessConstraintsStore.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\\nimport {JBFundAccessConstraints} from './../structs/JBFundAccessConstraints.sol';\\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\\n\\ninterface IJBFundAccessConstraintsStore is IERC165 {\\n event SetFundAccessConstraints(\\n uint256 indexed fundingCycleConfiguration,\\n uint256 indexed projectId,\\n JBFundAccessConstraints constraints,\\n address caller\\n );\\n\\n function distributionLimitOf(\\n uint256 projectId,\\n uint256 configuration,\\n IJBPaymentTerminal terminal,\\n address token\\n ) external view returns (uint256 distributionLimit, uint256 distributionLimitCurrency);\\n\\n function overflowAllowanceOf(\\n uint256 projectId,\\n uint256 configuration,\\n IJBPaymentTerminal terminal,\\n address token\\n ) external view returns (uint256 overflowAllowance, uint256 overflowAllowanceCurrency);\\n\\n function setFor(\\n uint256 projectId,\\n uint256 configuration,\\n JBFundAccessConstraints[] memory fundAccessConstaints\\n ) external;\\n}\\n\",\"keccak256\":\"0x82e3daec501e6f4d27ad7b9ab67f449e3cd4ef83a75062cd8b6fbffc17ae634d\",\"license\":\"MIT\"},\"contracts/interfaces/IJBFundingCycleBallot.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\\nimport {JBBallotState} from './../enums/JBBallotState.sol';\\n\\ninterface IJBFundingCycleBallot is IERC165 {\\n function duration() external view returns (uint256);\\n\\n function stateOf(\\n uint256 projectId,\\n uint256 configuration,\\n uint256 start\\n ) external view returns (JBBallotState);\\n}\\n\",\"keccak256\":\"0x729b4a700618f890e434d31ef9252e1cce9d0473fe7f8f070872df5b348bed23\",\"license\":\"MIT\"},\"contracts/interfaces/IJBFundingCycleDataSource3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\\nimport {JBPayDelegateAllocation3_1_1} from './../structs/JBPayDelegateAllocation3_1_1.sol';\\nimport {JBPayParamsData} from './../structs/JBPayParamsData.sol';\\nimport {JBRedeemParamsData} from './../structs/JBRedeemParamsData.sol';\\nimport {JBRedemptionDelegateAllocation3_1_1} from './../structs/JBRedemptionDelegateAllocation3_1_1.sol';\\n\\n/// @title Datasource\\n/// @notice The datasource is called by JBPayoutRedemptionPaymentTerminals on pay and redemption, and provide an extra layer of logic to use a custom weight, a custom memo and/or a pay/redeem delegate\\ninterface IJBFundingCycleDataSource3_1_1 is IERC165 {\\n /// @notice The datasource implementation for JBPaymentTerminal.pay(..)\\n /// @param data the data passed to the data source in terminal.pay(..), as a JBPayParamsData struct:\\n /// @return weight the weight to use to override the funding cycle weight\\n /// @return memo the memo to override the pay(..) memo\\n /// @return delegateAllocations The amount to send to delegates instead of adding to the local balance.\\n function payParams(\\n JBPayParamsData calldata data\\n )\\n external\\n returns (\\n uint256 weight,\\n string memory memo,\\n JBPayDelegateAllocation3_1_1[] memory delegateAllocations\\n );\\n\\n /// @notice The datasource implementation for JBPaymentTerminal.redeemTokensOf(..)\\n /// @param data the data passed to the data source in terminal.redeemTokensOf(..), as a JBRedeemParamsData struct:\\n /// @return reclaimAmount The amount to claim, overriding the terminal logic.\\n /// @return memo The memo to override the redeemTokensOf(..) memo.\\n /// @return delegateAllocations The amount to send to delegates instead of adding to the beneficiary.\\n function redeemParams(\\n JBRedeemParamsData calldata data\\n )\\n external\\n returns (\\n uint256 reclaimAmount,\\n string memory memo,\\n JBRedemptionDelegateAllocation3_1_1[] memory delegateAllocations\\n );\\n}\\n\",\"keccak256\":\"0x7315c10ae1fc6c401704ac3dec2a4c3e60ab4ac3ae051bea581d7db2ded38f34\",\"license\":\"MIT\"},\"contracts/interfaces/IJBFundingCycleStore.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBBallotState} from './../enums/JBBallotState.sol';\\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\\nimport {JBFundingCycleData} from './../structs/JBFundingCycleData.sol';\\n\\ninterface IJBFundingCycleStore {\\n event Configure(\\n uint256 indexed configuration,\\n uint256 indexed projectId,\\n JBFundingCycleData data,\\n uint256 metadata,\\n uint256 mustStartAtOrAfter,\\n address caller\\n );\\n\\n event Init(uint256 indexed configuration, uint256 indexed projectId, uint256 indexed basedOn);\\n\\n function latestConfigurationOf(uint256 projectId) external view returns (uint256);\\n\\n function get(\\n uint256 projectId,\\n uint256 configuration\\n ) external view returns (JBFundingCycle memory);\\n\\n function latestConfiguredOf(\\n uint256 projectId\\n ) external view returns (JBFundingCycle memory fundingCycle, JBBallotState ballotState);\\n\\n function queuedOf(uint256 projectId) external view returns (JBFundingCycle memory fundingCycle);\\n\\n function currentOf(uint256 projectId) external view returns (JBFundingCycle memory fundingCycle);\\n\\n function currentBallotStateOf(uint256 projectId) external view returns (JBBallotState);\\n\\n function configureFor(\\n uint256 projectId,\\n JBFundingCycleData calldata data,\\n uint256 metadata,\\n uint256 mustStartAtOrAfter\\n ) external returns (JBFundingCycle memory fundingCycle);\\n}\\n\",\"keccak256\":\"0x524350f6c6fcb45eaf927f4e6d13cd2f5029c2b858233bb9a338fe411ce34dab\",\"license\":\"MIT\"},\"contracts/interfaces/IJBMigratable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IJBMigratable {\\n function prepForMigrationOf(uint256 projectId, address from) external;\\n}\\n\",\"keccak256\":\"0xdee578477bbb7a66e9a1735e45a7795e95cfd374d85f55b61b3302476844c418\",\"license\":\"MIT\"},\"contracts/interfaces/IJBPayDelegate3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\\nimport {JBDidPayData3_1_1} from './../structs/JBDidPayData3_1_1.sol';\\n\\n/// @title Pay delegate\\n/// @notice Delegate called after JBTerminal.pay(..) logic completion (if passed by the funding cycle datasource)\\ninterface IJBPayDelegate3_1_1 is IERC165 {\\n /// @notice This function is called by JBPaymentTerminal.pay(..), after the execution of its logic\\n /// @dev Critical business logic should be protected by an appropriate access control\\n /// @param data the data passed by the terminal, as a JBDidPayData3_1_1 struct:\\n function didPay(JBDidPayData3_1_1 calldata data) external payable;\\n}\\n\",\"keccak256\":\"0x9448d24cd9c559b44c468c6a76d850f6eaadf31446db903092a2f32503a67294\",\"license\":\"MIT\"},\"contracts/interfaces/IJBPaymentTerminal.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\\n\\ninterface IJBPaymentTerminal is IERC165 {\\n function acceptsToken(address token, uint256 projectId) external view returns (bool);\\n\\n function currencyForToken(address token) external view returns (uint256);\\n\\n function decimalsForToken(address token) external view returns (uint256);\\n\\n // Return value must be a fixed point number with 18 decimals.\\n function currentEthOverflowOf(uint256 projectId) external view returns (uint256);\\n\\n function pay(\\n uint256 projectId,\\n uint256 amount,\\n address token,\\n address beneficiary,\\n uint256 minReturnedTokens,\\n bool preferClaimedTokens,\\n string calldata memo,\\n bytes calldata metadata\\n ) external payable returns (uint256 beneficiaryTokenCount);\\n\\n function addToBalanceOf(\\n uint256 projectId,\\n uint256 amount,\\n address token,\\n string calldata memo,\\n bytes calldata metadata\\n ) external payable;\\n}\\n\",\"keccak256\":\"0x273bc1fa373fac08e5635fce7d38fd92e9fabba353568b3f7a5be54c01fe4d27\",\"license\":\"MIT\"},\"contracts/interfaces/IJBPriceFeed.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IJBPriceFeed {\\n function currentPrice(uint256 targetDecimals) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0x9328b2b52bc112641f3a6167c8cf242831a52c85016ce1310626bdc3489bded7\",\"license\":\"MIT\"},\"contracts/interfaces/IJBPrices.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBPriceFeed} from './IJBPriceFeed.sol';\\n\\ninterface IJBPrices {\\n event AddFeed(uint256 indexed currency, uint256 indexed base, IJBPriceFeed feed);\\n\\n function feedFor(uint256 currency, uint256 base) external view returns (IJBPriceFeed);\\n\\n function priceFor(\\n uint256 currency,\\n uint256 base,\\n uint256 decimals\\n ) external view returns (uint256);\\n\\n function addFeedFor(uint256 currency, uint256 base, IJBPriceFeed priceFeed) external;\\n}\\n\",\"keccak256\":\"0xc1623499fa541b15891e27a59288e03360ce78c7933d28bf575b48b68ce4981c\",\"license\":\"MIT\"},\"contracts/interfaces/IJBProjects.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC721} from '@openzeppelin/contracts/token/ERC721/IERC721.sol';\\nimport {JBProjectMetadata} from './../structs/JBProjectMetadata.sol';\\nimport {IJBTokenUriResolver} from './IJBTokenUriResolver.sol';\\n\\ninterface IJBProjects is IERC721 {\\n event Create(\\n uint256 indexed projectId,\\n address indexed owner,\\n JBProjectMetadata metadata,\\n address caller\\n );\\n\\n event SetMetadata(uint256 indexed projectId, JBProjectMetadata metadata, address caller);\\n\\n event SetTokenUriResolver(IJBTokenUriResolver indexed resolver, address caller);\\n\\n function count() external view returns (uint256);\\n\\n function metadataContentOf(\\n uint256 projectId,\\n uint256 domain\\n ) external view returns (string memory);\\n\\n function tokenUriResolver() external view returns (IJBTokenUriResolver);\\n\\n function createFor(\\n address owner,\\n JBProjectMetadata calldata metadata\\n ) external returns (uint256 projectId);\\n\\n function setMetadataOf(uint256 projectId, JBProjectMetadata calldata metadata) external;\\n\\n function setTokenUriResolver(IJBTokenUriResolver newResolver) external;\\n}\\n\",\"keccak256\":\"0x00235f20975e6a9465ac921076c85125a3834e29893f93f93e287a89f9e6b915\",\"license\":\"MIT\"},\"contracts/interfaces/IJBRedemptionDelegate3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\\nimport {JBDidRedeemData3_1_1} from './../structs/JBDidRedeemData3_1_1.sol';\\n\\n/// @title Redemption delegate\\n/// @notice Delegate called after JBTerminal.redeemTokensOf(..) logic completion (if passed by the funding cycle datasource)\\ninterface IJBRedemptionDelegate3_1_1 is IERC165 {\\n /// @notice This function is called by JBPaymentTerminal.redeemTokensOf(..), after the execution of its logic\\n /// @dev Critical business logic should be protected by an appropriate access control\\n /// @param data the data passed by the terminal, as a JBDidRedeemData struct:\\n function didRedeem(JBDidRedeemData3_1_1 calldata data) external payable;\\n}\\n\",\"keccak256\":\"0x6034773b78e98902625563bd176a97267e729cb5205d25b06e8a2262b131c0d8\",\"license\":\"MIT\"},\"contracts/interfaces/IJBSingleTokenPaymentTerminal.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\\n\\ninterface IJBSingleTokenPaymentTerminal is IJBPaymentTerminal {\\n function token() external view returns (address);\\n\\n function currency() external view returns (uint256);\\n\\n function decimals() external view returns (uint256);\\n}\\n\",\"keccak256\":\"0x8e00670c66dea368dc523615425c2a79fcee10ec3c3355bf94feb82638172b3f\",\"license\":\"MIT\"},\"contracts/interfaces/IJBSingleTokenPaymentTerminalStore3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\\nimport {JBPayDelegateAllocation3_1_1} from './../structs/JBPayDelegateAllocation3_1_1.sol';\\nimport {JBRedemptionDelegateAllocation3_1_1} from './../structs/JBRedemptionDelegateAllocation3_1_1.sol';\\nimport {JBTokenAmount} from './../structs/JBTokenAmount.sol';\\nimport {IJBDirectory} from './IJBDirectory.sol';\\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\\nimport {IJBPrices} from './IJBPrices.sol';\\nimport {IJBSingleTokenPaymentTerminal} from './IJBSingleTokenPaymentTerminal.sol';\\n\\ninterface IJBSingleTokenPaymentTerminalStore3_1_1 {\\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\\n\\n function directory() external view returns (IJBDirectory);\\n\\n function prices() external view returns (IJBPrices);\\n\\n function balanceOf(\\n IJBSingleTokenPaymentTerminal terminal,\\n uint256 projectId\\n ) external view returns (uint256);\\n\\n function usedDistributionLimitOf(\\n IJBSingleTokenPaymentTerminal terminal,\\n uint256 projectId,\\n uint256 fundingCycleNumber\\n ) external view returns (uint256);\\n\\n function usedOverflowAllowanceOf(\\n IJBSingleTokenPaymentTerminal terminal,\\n uint256 projectId,\\n uint256 fundingCycleConfiguration\\n ) external view returns (uint256);\\n\\n function currentOverflowOf(\\n IJBSingleTokenPaymentTerminal terminal,\\n uint256 projectId\\n ) external view returns (uint256);\\n\\n function currentTotalOverflowOf(\\n uint256 projectId,\\n uint256 decimals,\\n uint256 currency\\n ) external view returns (uint256);\\n\\n function currentReclaimableOverflowOf(\\n IJBSingleTokenPaymentTerminal terminal,\\n uint256 projectId,\\n uint256 tokenCount,\\n bool useTotalOverflow\\n ) external view returns (uint256);\\n\\n function currentReclaimableOverflowOf(\\n uint256 projectId,\\n uint256 tokenCount,\\n uint256 totalSupply,\\n uint256 overflow\\n ) external view returns (uint256);\\n\\n function recordPaymentFrom(\\n address payer,\\n JBTokenAmount memory amount,\\n uint256 projectId,\\n uint256 baseWeightCurrency,\\n address beneficiary,\\n string calldata inputMemo,\\n bytes calldata metadata\\n )\\n external\\n returns (\\n JBFundingCycle memory fundingCycle,\\n uint256 tokenCount,\\n JBPayDelegateAllocation3_1_1[] memory delegateAllocations,\\n string memory outputMemo\\n );\\n\\n function recordRedemptionFor(\\n address holder,\\n uint256 projectId,\\n uint256 tokenCount,\\n string calldata inputMemo,\\n bytes calldata metadata\\n )\\n external\\n returns (\\n JBFundingCycle memory fundingCycle,\\n uint256 reclaimAmount,\\n JBRedemptionDelegateAllocation3_1_1[] memory delegateAllocations,\\n string memory outputMemo\\n );\\n\\n function recordDistributionFor(\\n uint256 projectId,\\n uint256 amount,\\n uint256 currency\\n ) external returns (JBFundingCycle memory fundingCycle, uint256 distributedAmount);\\n\\n function recordUsedAllowanceOf(\\n uint256 projectId,\\n uint256 amount,\\n uint256 currency\\n ) external returns (JBFundingCycle memory fundingCycle, uint256 withdrawnAmount);\\n\\n function recordAddedBalanceFor(uint256 projectId, uint256 amount) external;\\n\\n function recordMigration(uint256 projectId) external returns (uint256 balance);\\n}\\n\",\"keccak256\":\"0xf009c9fb787cda2a18805b9a9e2105c7f1309ade1eac3af229816cfd27ba1d64\",\"license\":\"MIT\"},\"contracts/interfaces/IJBSplitAllocator.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\\nimport {JBSplitAllocationData} from '../structs/JBSplitAllocationData.sol';\\n\\n/// @title Split allocator\\n/// @notice Provide a way to process a single split with extra logic\\n/// @dev The contract address should be set as an allocator in the adequate split\\ninterface IJBSplitAllocator is IERC165 {\\n /// @notice This function is called by JBPaymentTerminal.distributePayoutOf(..), during the processing of the split including it\\n /// @dev Critical business logic should be protected by an appropriate access control. The token and/or eth are optimistically transfered to the allocator for its logic.\\n /// @param data the data passed by the terminal, as a JBSplitAllocationData struct:\\n function allocate(JBSplitAllocationData calldata data) external payable;\\n}\\n\",\"keccak256\":\"0x1643b444409d91858eb86f67abf3d757d2deb3ccd7265eb8e68d6ffdac083de6\",\"license\":\"MIT\"},\"contracts/interfaces/IJBSplitsStore.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBGroupedSplits} from './../structs/JBGroupedSplits.sol';\\nimport {JBSplit} from './../structs/JBSplit.sol';\\nimport {IJBDirectory} from './IJBDirectory.sol';\\nimport {IJBProjects} from './IJBProjects.sol';\\n\\ninterface IJBSplitsStore {\\n event SetSplit(\\n uint256 indexed projectId,\\n uint256 indexed domain,\\n uint256 indexed group,\\n JBSplit split,\\n address caller\\n );\\n\\n function projects() external view returns (IJBProjects);\\n\\n function directory() external view returns (IJBDirectory);\\n\\n function splitsOf(\\n uint256 projectId,\\n uint256 domain,\\n uint256 group\\n ) external view returns (JBSplit[] memory);\\n\\n function set(uint256 projectId, uint256 domain, JBGroupedSplits[] memory groupedSplits) external;\\n}\\n\",\"keccak256\":\"0x3ce0eb12f10282481a3bf86e62b368bcff254081088cfabb20353d60cfadbc7a\",\"license\":\"MIT\"},\"contracts/interfaces/IJBToken.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IJBToken {\\n function projectId() external view returns (uint256);\\n\\n function decimals() external view returns (uint8);\\n\\n function totalSupply(uint256 projectId) external view returns (uint256);\\n\\n function balanceOf(address account, uint256 projectId) external view returns (uint256);\\n\\n function mint(uint256 projectId, address account, uint256 amount) external;\\n\\n function burn(uint256 projectId, address account, uint256 amount) external;\\n\\n function approve(uint256, address spender, uint256 amount) external;\\n\\n function transfer(uint256 projectId, address to, uint256 amount) external;\\n\\n function transferFrom(uint256 projectId, address from, address to, uint256 amount) external;\\n}\\n\",\"keccak256\":\"0xeefe58d140e4e13f255d5c7c5cdf5ba66dd00835f04015c446ff224f8ad14c34\",\"license\":\"MIT\"},\"contracts/interfaces/IJBTokenStore.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\\nimport {IJBProjects} from './IJBProjects.sol';\\nimport {IJBToken} from './IJBToken.sol';\\n\\ninterface IJBTokenStore {\\n event Issue(\\n uint256 indexed projectId,\\n IJBToken indexed token,\\n string name,\\n string symbol,\\n address caller\\n );\\n\\n event Mint(\\n address indexed holder,\\n uint256 indexed projectId,\\n uint256 amount,\\n bool tokensWereClaimed,\\n bool preferClaimedTokens,\\n address caller\\n );\\n\\n event Burn(\\n address indexed holder,\\n uint256 indexed projectId,\\n uint256 amount,\\n uint256 initialUnclaimedBalance,\\n uint256 initialClaimedBalance,\\n bool preferClaimedTokens,\\n address caller\\n );\\n\\n event Claim(\\n address indexed holder,\\n uint256 indexed projectId,\\n uint256 initialUnclaimedBalance,\\n uint256 amount,\\n address caller\\n );\\n\\n event Set(uint256 indexed projectId, IJBToken indexed newToken, address caller);\\n\\n event Transfer(\\n address indexed holder,\\n uint256 indexed projectId,\\n address indexed recipient,\\n uint256 amount,\\n address caller\\n );\\n\\n function tokenOf(uint256 projectId) external view returns (IJBToken);\\n\\n function projects() external view returns (IJBProjects);\\n\\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\\n\\n function unclaimedBalanceOf(address holder, uint256 projectId) external view returns (uint256);\\n\\n function unclaimedTotalSupplyOf(uint256 projectId) external view returns (uint256);\\n\\n function totalSupplyOf(uint256 projectId) external view returns (uint256);\\n\\n function balanceOf(address holder, uint256 projectId) external view returns (uint256 result);\\n\\n function issueFor(\\n uint256 projectId,\\n string calldata name,\\n string calldata symbol\\n ) external returns (IJBToken token);\\n\\n function setFor(uint256 projectId, IJBToken token) external;\\n\\n function burnFrom(\\n address holder,\\n uint256 projectId,\\n uint256 amount,\\n bool preferClaimedTokens\\n ) external;\\n\\n function mintFor(\\n address holder,\\n uint256 projectId,\\n uint256 amount,\\n bool preferClaimedTokens\\n ) external;\\n\\n function claimFor(address holder, uint256 projectId, uint256 amount) external;\\n\\n function transferFrom(\\n address holder,\\n uint256 projectId,\\n address recipient,\\n uint256 amount\\n ) external;\\n}\\n\",\"keccak256\":\"0x4db7bb4fe824dc9bfbc997ea3e07f42be8900bcad4e0b991e726c23c2de84ba4\",\"license\":\"MIT\"},\"contracts/interfaces/IJBTokenUriResolver.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IJBTokenUriResolver {\\n function getUri(uint256 projectId) external view returns (string memory tokenUri);\\n}\\n\",\"keccak256\":\"0xc7c9537184a1a36bc30874e5ac29b0fbccf45a99d40806837cfe30d6d9a1c84a\",\"license\":\"MIT\"},\"contracts/libraries/JBConstants.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/// @notice Global constants used across Juicebox contracts.\\nlibrary JBConstants {\\n uint256 public constant MAX_RESERVED_RATE = 10_000;\\n uint256 public constant MAX_REDEMPTION_RATE = 10_000;\\n uint256 public constant MAX_DISCOUNT_RATE = 1_000_000_000;\\n uint256 public constant SPLITS_TOTAL_PERCENT = 1_000_000_000;\\n uint256 public constant MAX_FEE = 1_000_000_000;\\n uint256 public constant MAX_FEE_DISCOUNT = 1_000_000_000;\\n}\\n\",\"keccak256\":\"0x7f2741e86062c5019f51d7e1a7b192ec1880d7e15a9a1589362ae7424de3003b\",\"license\":\"MIT\"},\"contracts/libraries/JBCurrencies.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nlibrary JBCurrencies {\\n uint256 public constant ETH = 1;\\n uint256 public constant USD = 2;\\n}\\n\",\"keccak256\":\"0x7e417ff25c173608ee4fe6d9fc3dcd5e1458c78c889af12bac47b1189a436076\",\"license\":\"MIT\"},\"contracts/libraries/JBFixedPointNumber.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.16;\\n\\nlibrary JBFixedPointNumber {\\n function adjustDecimals(\\n uint256 _value,\\n uint256 _decimals,\\n uint256 _targetDecimals\\n ) internal pure returns (uint256) {\\n // If decimals need adjusting, multiply or divide the price by the decimal adjuster to get the normalized result.\\n if (_targetDecimals == _decimals) return _value;\\n else if (_targetDecimals > _decimals) return _value * 10**(_targetDecimals - _decimals);\\n else return _value / 10**(_decimals - _targetDecimals);\\n }\\n}\\n\",\"keccak256\":\"0x18efac48269f3a3bd7e9a1c770776f950e0afa86769e6f8b128002c3b8c6742c\",\"license\":\"MIT\"},\"contracts/libraries/JBFundingCycleMetadataResolver.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.16;\\n\\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\\nimport {JBFundingCycleMetadata} from './../structs/JBFundingCycleMetadata.sol';\\nimport {JBGlobalFundingCycleMetadata} from './../structs/JBGlobalFundingCycleMetadata.sol';\\nimport {JBConstants} from './JBConstants.sol';\\nimport {JBGlobalFundingCycleMetadataResolver} from './JBGlobalFundingCycleMetadataResolver.sol';\\n\\nlibrary JBFundingCycleMetadataResolver {\\n function global(JBFundingCycle memory _fundingCycle)\\n internal\\n pure\\n returns (JBGlobalFundingCycleMetadata memory)\\n {\\n return JBGlobalFundingCycleMetadataResolver.expandMetadata(uint8(_fundingCycle.metadata >> 8));\\n }\\n\\n function reservedRate(JBFundingCycle memory _fundingCycle) internal pure returns (uint256) {\\n return uint256(uint16(_fundingCycle.metadata >> 24));\\n }\\n\\n function redemptionRate(JBFundingCycle memory _fundingCycle) internal pure returns (uint256) {\\n // Redemption rate is a number 0-10000. It's inverse was stored so the most common case of 100% results in no storage needs.\\n return JBConstants.MAX_REDEMPTION_RATE - uint256(uint16(_fundingCycle.metadata >> 40));\\n }\\n\\n function ballotRedemptionRate(JBFundingCycle memory _fundingCycle)\\n internal\\n pure\\n returns (uint256)\\n {\\n // Redemption rate is a number 0-10000. It's inverse was stored so the most common case of 100% results in no storage needs.\\n return JBConstants.MAX_REDEMPTION_RATE - uint256(uint16(_fundingCycle.metadata >> 56));\\n }\\n\\n function payPaused(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\\n return ((_fundingCycle.metadata >> 72) & 1) == 1;\\n }\\n\\n function distributionsPaused(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\\n return ((_fundingCycle.metadata >> 73) & 1) == 1;\\n }\\n\\n function redeemPaused(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\\n return ((_fundingCycle.metadata >> 74) & 1) == 1;\\n }\\n\\n function burnPaused(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\\n return ((_fundingCycle.metadata >> 75) & 1) == 1;\\n }\\n\\n function mintingAllowed(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\\n return ((_fundingCycle.metadata >> 76) & 1) == 1;\\n }\\n\\n function terminalMigrationAllowed(JBFundingCycle memory _fundingCycle)\\n internal\\n pure\\n returns (bool)\\n {\\n return ((_fundingCycle.metadata >> 77) & 1) == 1;\\n }\\n\\n function controllerMigrationAllowed(JBFundingCycle memory _fundingCycle)\\n internal\\n pure\\n returns (bool)\\n {\\n return ((_fundingCycle.metadata >> 78) & 1) == 1;\\n }\\n\\n function shouldHoldFees(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\\n return ((_fundingCycle.metadata >> 79) & 1) == 1;\\n }\\n\\n function preferClaimedTokenOverride(JBFundingCycle memory _fundingCycle)\\n internal\\n pure\\n returns (bool)\\n {\\n return ((_fundingCycle.metadata >> 80) & 1) == 1;\\n }\\n\\n function useTotalOverflowForRedemptions(JBFundingCycle memory _fundingCycle)\\n internal\\n pure\\n returns (bool)\\n {\\n return ((_fundingCycle.metadata >> 81) & 1) == 1;\\n }\\n\\n function useDataSourceForPay(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\\n return (_fundingCycle.metadata >> 82) & 1 == 1;\\n }\\n\\n function useDataSourceForRedeem(JBFundingCycle memory _fundingCycle)\\n internal\\n pure\\n returns (bool)\\n {\\n return (_fundingCycle.metadata >> 83) & 1 == 1;\\n }\\n\\n function dataSource(JBFundingCycle memory _fundingCycle) internal pure returns (address) {\\n return address(uint160(_fundingCycle.metadata >> 84));\\n }\\n\\n function metadata(JBFundingCycle memory _fundingCycle) internal pure returns (uint256) {\\n return uint256(uint8(_fundingCycle.metadata >> 244));\\n }\\n\\n /// @notice Pack the funding cycle metadata.\\n /// @param _metadata The metadata to validate and pack.\\n /// @return packed The packed uint256 of all metadata params. The first 8 bits specify the version. \\n function packFundingCycleMetadata(JBFundingCycleMetadata memory _metadata)\\n internal\\n pure\\n returns (uint256 packed)\\n {\\n // version 1 in the bits 0-7 (8 bits).\\n packed = 1;\\n // global metadta in bits 8-23 (16 bits).\\n packed |=\\n JBGlobalFundingCycleMetadataResolver.packFundingCycleGlobalMetadata(_metadata.global) <<\\n 8;\\n // reserved rate in bits 24-39 (16 bits).\\n packed |= _metadata.reservedRate << 24;\\n // redemption rate in bits 40-55 (16 bits).\\n // redemption rate is a number 0-10000. Store the reverse so the most common case of 100% results in no storage needs.\\n packed |= (JBConstants.MAX_REDEMPTION_RATE - _metadata.redemptionRate) << 40;\\n // ballot redemption rate rate in bits 56-71 (16 bits).\\n // ballot redemption rate is a number 0-10000. Store the reverse so the most common case of 100% results in no storage needs.\\n packed |= (JBConstants.MAX_REDEMPTION_RATE - _metadata.ballotRedemptionRate) << 56;\\n // pause pay in bit 72.\\n if (_metadata.pausePay) packed |= 1 << 72;\\n // pause tap in bit 73.\\n if (_metadata.pauseDistributions) packed |= 1 << 73;\\n // pause redeem in bit 74.\\n if (_metadata.pauseRedeem) packed |= 1 << 74;\\n // pause burn in bit 75.\\n if (_metadata.pauseBurn) packed |= 1 << 75;\\n // allow minting in bit 76.\\n if (_metadata.allowMinting) packed |= 1 << 76;\\n // allow terminal migration in bit 77.\\n if (_metadata.allowTerminalMigration) packed |= 1 << 77;\\n // allow controller migration in bit 78.\\n if (_metadata.allowControllerMigration) packed |= 1 << 78;\\n // hold fees in bit 79.\\n if (_metadata.holdFees) packed |= 1 << 79;\\n // prefer claimed token override in bit 80.\\n if (_metadata.preferClaimedTokenOverride) packed |= 1 << 80;\\n // useTotalOverflowForRedemptions in bit 81.\\n if (_metadata.useTotalOverflowForRedemptions) packed |= 1 << 81;\\n // use pay data source in bit 82.\\n if (_metadata.useDataSourceForPay) packed |= 1 << 82;\\n // use redeem data source in bit 83.\\n if (_metadata.useDataSourceForRedeem) packed |= 1 << 83;\\n // data source address in bits 84-243.\\n packed |= uint256(uint160(address(_metadata.dataSource))) << 84;\\n // metadata in bits 244-252 (8 bits).\\n packed |= _metadata.metadata << 244;\\n }\\n\\n /// @notice Expand the funding cycle metadata.\\n /// @param _fundingCycle The funding cycle having its metadata expanded.\\n /// @return metadata The metadata object. \\n function expandMetadata(JBFundingCycle memory _fundingCycle)\\n internal\\n pure\\n returns (JBFundingCycleMetadata memory)\\n {\\n return\\n JBFundingCycleMetadata(\\n global(_fundingCycle),\\n reservedRate(_fundingCycle),\\n redemptionRate(_fundingCycle),\\n ballotRedemptionRate(_fundingCycle),\\n payPaused(_fundingCycle),\\n distributionsPaused(_fundingCycle),\\n redeemPaused(_fundingCycle),\\n burnPaused(_fundingCycle),\\n mintingAllowed(_fundingCycle),\\n terminalMigrationAllowed(_fundingCycle),\\n controllerMigrationAllowed(_fundingCycle),\\n shouldHoldFees(_fundingCycle),\\n preferClaimedTokenOverride(_fundingCycle),\\n useTotalOverflowForRedemptions(_fundingCycle),\\n useDataSourceForPay(_fundingCycle),\\n useDataSourceForRedeem(_fundingCycle),\\n dataSource(_fundingCycle),\\n metadata(_fundingCycle)\\n );\\n }\\n}\\n\",\"keccak256\":\"0xedb0b93d5578ca5a21ab55f65274e441513bce982b04ffc76f26e627abfbbe0c\",\"license\":\"MIT\"},\"contracts/libraries/JBGlobalFundingCycleMetadataResolver.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.16;\\n\\nimport {JBFundingCycleMetadata} from './../structs/JBFundingCycleMetadata.sol';\\nimport {JBGlobalFundingCycleMetadata} from './../structs/JBGlobalFundingCycleMetadata.sol';\\n\\nlibrary JBGlobalFundingCycleMetadataResolver {\\n function setTerminalsAllowed(uint8 _data) internal pure returns (bool) {\\n return (_data & 1) == 1;\\n }\\n\\n function setControllerAllowed(uint8 _data) internal pure returns (bool) {\\n return ((_data >> 1) & 1) == 1;\\n }\\n\\n function transfersPaused(uint8 _data) internal pure returns (bool) {\\n return ((_data >> 2) & 1) == 1;\\n }\\n\\n /// @notice Pack the global funding cycle metadata.\\n /// @param _metadata The metadata to validate and pack.\\n /// @return packed The packed uint256 of all global metadata params. The first 8 bits specify the version.\\n function packFundingCycleGlobalMetadata(\\n JBGlobalFundingCycleMetadata memory _metadata\\n ) internal pure returns (uint256 packed) {\\n // allow set terminals in bit 0.\\n if (_metadata.allowSetTerminals) packed |= 1;\\n // allow set controller in bit 1.\\n if (_metadata.allowSetController) packed |= 1 << 1;\\n // pause transfers in bit 2.\\n if (_metadata.pauseTransfers) packed |= 1 << 2;\\n }\\n\\n /// @notice Expand the global funding cycle metadata.\\n /// @param _packedMetadata The packed metadata to expand.\\n /// @return metadata The global metadata object.\\n function expandMetadata(\\n uint8 _packedMetadata\\n ) internal pure returns (JBGlobalFundingCycleMetadata memory metadata) {\\n return\\n JBGlobalFundingCycleMetadata(\\n setTerminalsAllowed(_packedMetadata),\\n setControllerAllowed(_packedMetadata),\\n transfersPaused(_packedMetadata)\\n );\\n }\\n}\\n\",\"keccak256\":\"0x8a016001787db05e3bbd442db7eaa3f49f1d3a3210d2b5c6e52254a241f3b161\",\"license\":\"MIT\"},\"contracts/structs/JBDidPayData3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBTokenAmount} from './JBTokenAmount.sol';\\n\\n/// @custom:member payer The address from which the payment originated.\\n/// @custom:member projectId The ID of the project for which the payment was made.\\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the payment is being made.\\n/// @custom:member amount The amount of the payment. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\\n/// @custom:member forwardedAmount The amount of the payment that is being sent to the delegate. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\\n/// @custom:member projectTokenCount The number of project tokens minted for the beneficiary.\\n/// @custom:member beneficiary The address to which the tokens were minted.\\n/// @custom:member preferClaimedTokens A flag indicating whether the request prefered to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract.\\n/// @custom:member memo The memo that is being emitted alongside the payment.\\n/// @custom:member dataSourceMetadata Extra data to send to the delegate sent by the data source.\\n/// @custom:member payerMetadata Extra data to send to the delegate sent by the payer.\\nstruct JBDidPayData3_1_1 {\\n address payer;\\n uint256 projectId;\\n uint256 currentFundingCycleConfiguration;\\n JBTokenAmount amount;\\n JBTokenAmount forwardedAmount;\\n uint256 projectTokenCount;\\n address beneficiary;\\n bool preferClaimedTokens;\\n string memo;\\n bytes dataSourceMetadata;\\n bytes payerMetadata;\\n}\\n\",\"keccak256\":\"0x2e659555149ff14c045b749b1d1a3156b8296ab08375ac2abec92afc43bf3acf\",\"license\":\"MIT\"},\"contracts/structs/JBDidRedeemData3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBTokenAmount} from './JBTokenAmount.sol';\\n\\n/// @custom:member holder The holder of the tokens being redeemed.\\n/// @custom:member projectId The ID of the project with which the redeemed tokens are associated.\\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the redemption is being made.\\n/// @custom:member projectTokenCount The number of project tokens being redeemed.\\n/// @custom:member reclaimedAmount The amount reclaimed from the treasury. Includes the token being reclaimed, the value, the number of decimals included, and the currency of the amount.\\n/// @custom:member forwardedAmount The amount of the payment that is being sent to the delegate. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\\n/// @custom:member beneficiary The address to which the reclaimed amount will be sent.\\n/// @custom:member memo The memo that is being emitted alongside the redemption.\\n/// @custom:member dataSourceMetadata Extra data to send to the delegate sent by the data source.\\n/// @custom:member redeemerMetadata Extra data to send to the delegate sent by the redeemer.\\nstruct JBDidRedeemData3_1_1 {\\n address holder;\\n uint256 projectId;\\n uint256 currentFundingCycleConfiguration;\\n uint256 projectTokenCount;\\n JBTokenAmount reclaimedAmount;\\n JBTokenAmount forwardedAmount;\\n address payable beneficiary;\\n string memo;\\n bytes dataSourceMetadata;\\n bytes redeemerMetadata;\\n}\\n\",\"keccak256\":\"0x23848d41aa179d16e9b7033befd3a855d43f6a009e24030c2ba1bb5b06cb3924\",\"license\":\"MIT\"},\"contracts/structs/JBFundAccessConstraints.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\\n\\n/// @custom:member terminal The terminal within which the distribution limit and the overflow allowance applies.\\n/// @custom:member token The token for which the fund access constraints apply.\\n/// @custom:member distributionLimit The amount of the distribution limit, as a fixed point number with the same number of decimals as the terminal within which the limit applies.\\n/// @custom:member distributionLimitCurrency The currency of the distribution limit.\\n/// @custom:member overflowAllowance The amount of the allowance, as a fixed point number with the same number of decimals as the terminal within which the allowance applies.\\n/// @custom:member overflowAllowanceCurrency The currency of the overflow allowance.\\nstruct JBFundAccessConstraints {\\n IJBPaymentTerminal terminal;\\n address token;\\n uint256 distributionLimit;\\n uint256 distributionLimitCurrency;\\n uint256 overflowAllowance;\\n uint256 overflowAllowanceCurrency;\\n}\\n\",\"keccak256\":\"0xbef975eb73e58c00eaaa7abbd449db545056b049907bb2034aefcdde10bcf11f\",\"license\":\"MIT\"},\"contracts/structs/JBFundingCycle.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBFundingCycleBallot} from './../interfaces/IJBFundingCycleBallot.sol';\\n\\n/// @custom:member number The funding cycle number for the cycle's project. Each funding cycle has a number that is an increment of the cycle that directly preceded it. Each project's first funding cycle has a number of 1.\\n/// @custom:member configuration The timestamp when the parameters for this funding cycle were configured. This value will stay the same for subsequent funding cycles that roll over from an originally configured cycle.\\n/// @custom:member basedOn The `configuration` of the funding cycle that was active when this cycle was created.\\n/// @custom:member start The timestamp marking the moment from which the funding cycle is considered active. It is a unix timestamp measured in seconds.\\n/// @custom:member duration The number of seconds the funding cycle lasts for, after which a new funding cycle will start. A duration of 0 means that the funding cycle will stay active until the project owner explicitly issues a reconfiguration, at which point a new funding cycle will immediately start with the updated properties. If the duration is greater than 0, a project owner cannot make changes to a funding cycle's parameters while it is active \\u2013 any proposed changes will apply to the subsequent cycle. If no changes are proposed, a funding cycle rolls over to another one with the same properties but new `start` timestamp and a discounted `weight`.\\n/// @custom:member weight A fixed point number with 18 decimals that contracts can use to base arbitrary calculations on. For example, payment terminals can use this to determine how many tokens should be minted when a payment is received.\\n/// @custom:member discountRate A percent by how much the `weight` of the subsequent funding cycle should be reduced, if the project owner hasn't configured the subsequent funding cycle with an explicit `weight`. If it's 0, each funding cycle will have equal weight. If the number is 90%, the next funding cycle will have a 10% smaller weight. This weight is out of `JBConstants.MAX_DISCOUNT_RATE`.\\n/// @custom:member ballot An address of a contract that says whether a proposed reconfiguration should be accepted or rejected. It can be used to create rules around how a project owner can change funding cycle parameters over time.\\n/// @custom:member metadata Extra data that can be associated with a funding cycle.\\nstruct JBFundingCycle {\\n uint256 number;\\n uint256 configuration;\\n uint256 basedOn;\\n uint256 start;\\n uint256 duration;\\n uint256 weight;\\n uint256 discountRate;\\n IJBFundingCycleBallot ballot;\\n uint256 metadata;\\n}\\n\",\"keccak256\":\"0x01d2ee9ae017694097985a08a36421b6801d96badd16e38c6085f3a5ac796ed1\",\"license\":\"MIT\"},\"contracts/structs/JBFundingCycleData.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBFundingCycleBallot} from './../interfaces/IJBFundingCycleBallot.sol';\\n\\n/// @custom:member duration The number of seconds the funding cycle lasts for, after which a new funding cycle will start. A duration of 0 means that the funding cycle will stay active until the project owner explicitly issues a reconfiguration, at which point a new funding cycle will immediately start with the updated properties. If the duration is greater than 0, a project owner cannot make changes to a funding cycle's parameters while it is active \\u2013 any proposed changes will apply to the subsequent cycle. If no changes are proposed, a funding cycle rolls over to another one with the same properties but new `start` timestamp and a discounted `weight`.\\n/// @custom:member weight A fixed point number with 18 decimals that contracts can use to base arbitrary calculations on. For example, payment terminals can use this to determine how many tokens should be minted when a payment is received.\\n/// @custom:member discountRate A percent by how much the `weight` of the subsequent funding cycle should be reduced, if the project owner hasn't configured the subsequent funding cycle with an explicit `weight`. If it's 0, each funding cycle will have equal weight. If the number is 90%, the next funding cycle will have a 10% smaller weight. This weight is out of `JBConstants.MAX_DISCOUNT_RATE`.\\n/// @custom:member ballot An address of a contract that says whether a proposed reconfiguration should be accepted or rejected. It can be used to create rules around how a project owner can change funding cycle parameters over time.\\nstruct JBFundingCycleData {\\n uint256 duration;\\n uint256 weight;\\n uint256 discountRate;\\n IJBFundingCycleBallot ballot;\\n}\\n\",\"keccak256\":\"0x3cd9257969fdd54bee497b01be2c623e33c941306662002b3b88fa0ab8a27db5\",\"license\":\"MIT\"},\"contracts/structs/JBFundingCycleMetadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBGlobalFundingCycleMetadata} from './JBGlobalFundingCycleMetadata.sol';\\n\\n/// @custom:member global Data used globally in non-migratable ecosystem contracts.\\n/// @custom:member reservedRate The reserved rate of the funding cycle. This number is a percentage calculated out of `JBConstants.MAX_RESERVED_RATE`.\\n/// @custom:member redemptionRate The redemption rate of the funding cycle. This number is a percentage calculated out of `JBConstants.MAX_REDEMPTION_RATE`.\\n/// @custom:member ballotRedemptionRate The redemption rate to use during an active ballot of the funding cycle. This number is a percentage calculated out of `JBConstants.MAX_REDEMPTION_RATE`.\\n/// @custom:member pausePay A flag indicating if the pay functionality should be paused during the funding cycle.\\n/// @custom:member pauseDistributions A flag indicating if the distribute functionality should be paused during the funding cycle.\\n/// @custom:member pauseRedeem A flag indicating if the redeem functionality should be paused during the funding cycle.\\n/// @custom:member pauseBurn A flag indicating if the burn functionality should be paused during the funding cycle.\\n/// @custom:member allowMinting A flag indicating if minting tokens should be allowed during this funding cycle.\\n/// @custom:member allowTerminalMigration A flag indicating if migrating terminals should be allowed during this funding cycle.\\n/// @custom:member allowControllerMigration A flag indicating if migrating controllers should be allowed during this funding cycle.\\n/// @custom:member holdFees A flag indicating if fees should be held during this funding cycle.\\n/// @custom:member preferClaimedTokenOverride A flag indicating if claimed tokens should always be prefered to unclaimed tokens when minting.\\n/// @custom:member useTotalOverflowForRedemptions A flag indicating if redemptions should use the project's balance held in all terminals instead of the project's local terminal balance from which the redemption is being fulfilled.\\n/// @custom:member useDataSourceForPay A flag indicating if the data source should be used for pay transactions during this funding cycle.\\n/// @custom:member useDataSourceForRedeem A flag indicating if the data source should be used for redeem transactions during this funding cycle.\\n/// @custom:member dataSource The data source to use during this funding cycle.\\n/// @custom:member metadata Metadata of the metadata, up to uint8 in size.\\nstruct JBFundingCycleMetadata {\\n JBGlobalFundingCycleMetadata global;\\n uint256 reservedRate;\\n uint256 redemptionRate;\\n uint256 ballotRedemptionRate;\\n bool pausePay;\\n bool pauseDistributions;\\n bool pauseRedeem;\\n bool pauseBurn;\\n bool allowMinting;\\n bool allowTerminalMigration;\\n bool allowControllerMigration;\\n bool holdFees;\\n bool preferClaimedTokenOverride;\\n bool useTotalOverflowForRedemptions;\\n bool useDataSourceForPay;\\n bool useDataSourceForRedeem;\\n address dataSource;\\n uint256 metadata;\\n}\\n\",\"keccak256\":\"0x477bbd36c94da3f56fac6c8c60b2e2e3c5b8fc557a880b5359980bc556ccd300\",\"license\":\"MIT\"},\"contracts/structs/JBGlobalFundingCycleMetadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/// @custom:member allowSetTerminals A flag indicating if setting terminals should be allowed during this funding cycle.\\n/// @custom:member allowSetController A flag indicating if setting a new controller should be allowed during this funding cycle.\\n/// @custom:member pauseTransfers A flag indicating if the project token transfer functionality should be paused during the funding cycle.\\nstruct JBGlobalFundingCycleMetadata {\\n bool allowSetTerminals;\\n bool allowSetController;\\n bool pauseTransfers;\\n}\\n\",\"keccak256\":\"0x5f95bce22550c69bb7b1ee17279d51415ae8bae10c5b759c8b88f0b0aba854ed\",\"license\":\"MIT\"},\"contracts/structs/JBGroupedSplits.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBSplit} from './JBSplit.sol';\\n\\n/// @custom:member group The group indentifier.\\n/// @custom:member splits The splits to associate with the group.\\nstruct JBGroupedSplits {\\n uint256 group;\\n JBSplit[] splits;\\n}\\n\",\"keccak256\":\"0x71fcdbff5cd055cee8d06b73568c44cedda8f5a2351e7d8ce9dd71d8a1f914a8\",\"license\":\"MIT\"},\"contracts/structs/JBPayDelegateAllocation3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBPayDelegate3_1_1} from '../interfaces/IJBPayDelegate3_1_1.sol';\\n\\n/// @custom:member delegate A delegate contract to use for subsequent calls.\\n/// @custom:member amount The amount to send to the delegate.\\n/// @custom:member metadata Metadata to pass the delegate.\\nstruct JBPayDelegateAllocation3_1_1 {\\n IJBPayDelegate3_1_1 delegate;\\n uint256 amount;\\n bytes metadata;\\n}\\n\",\"keccak256\":\"0x8d87206a7015af9ec9e5fc059e39bfcea44aa007f8812213c6fd489d0a9c2e17\",\"license\":\"MIT\"},\"contracts/structs/JBPayParamsData.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\\nimport {JBTokenAmount} from './JBTokenAmount.sol';\\n\\n/// @custom:member terminal The terminal that is facilitating the payment.\\n/// @custom:member payer The address from which the payment originated.\\n/// @custom:member amount The amount of the payment. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\\n/// @custom:member projectId The ID of the project being paid.\\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the payment is being made.\\n/// @custom:member beneficiary The specified address that should be the beneficiary of anything that results from the payment.\\n/// @custom:member weight The weight of the funding cycle during which the payment is being made.\\n/// @custom:member reservedRate The reserved rate of the funding cycle during which the payment is being made.\\n/// @custom:member memo The memo that was sent alongside the payment.\\n/// @custom:member metadata Extra data provided by the payer.\\nstruct JBPayParamsData {\\n IJBPaymentTerminal terminal;\\n address payer;\\n JBTokenAmount amount;\\n uint256 projectId;\\n uint256 currentFundingCycleConfiguration;\\n address beneficiary;\\n uint256 weight;\\n uint256 reservedRate;\\n string memo;\\n bytes metadata;\\n}\\n\",\"keccak256\":\"0xc7909dfe6de88faca33a47a588559c80e14d3d1256f2c17e13f5ea6e23ce8732\",\"license\":\"MIT\"},\"contracts/structs/JBProjectMetadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/// @custom:member content The metadata content.\\n/// @custom:member domain The domain within which the metadata applies.\\nstruct JBProjectMetadata {\\n string content;\\n uint256 domain;\\n}\\n\",\"keccak256\":\"0x9545ea42927f3451c9d901a2f7ab7c1aeef3242e5ed2b75521a90225a5a0f891\",\"license\":\"MIT\"},\"contracts/structs/JBRedeemParamsData.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\\nimport {JBTokenAmount} from './JBTokenAmount.sol';\\n\\n/// @custom:member terminal The terminal that is facilitating the redemption.\\n/// @custom:member holder The holder of the tokens being redeemed.\\n/// @custom:member projectId The ID of the project whos tokens are being redeemed.\\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the redemption is being made.\\n/// @custom:member tokenCount The proposed number of tokens being redeemed, as a fixed point number with 18 decimals.\\n/// @custom:member totalSupply The total supply of tokens used in the calculation, as a fixed point number with 18 decimals.\\n/// @custom:member overflow The amount of overflow used in the reclaim amount calculation.\\n/// @custom:member reclaimAmount The amount that should be reclaimed by the redeemer using the protocol's standard bonding curve redemption formula. Includes the token being reclaimed, the reclaim value, the number of decimals included, and the currency of the reclaim amount.\\n/// @custom:member useTotalOverflow If overflow across all of a project's terminals is being used when making redemptions.\\n/// @custom:member redemptionRate The redemption rate of the funding cycle during which the redemption is being made.\\n/// @custom:member memo The proposed memo that is being emitted alongside the redemption.\\n/// @custom:member metadata Extra data provided by the redeemer.\\nstruct JBRedeemParamsData {\\n IJBPaymentTerminal terminal;\\n address holder;\\n uint256 projectId;\\n uint256 currentFundingCycleConfiguration;\\n uint256 tokenCount;\\n uint256 totalSupply;\\n uint256 overflow;\\n JBTokenAmount reclaimAmount;\\n bool useTotalOverflow;\\n uint256 redemptionRate;\\n string memo;\\n bytes metadata;\\n}\\n\",\"keccak256\":\"0x2eada17b425e75bfeffa786dc5b5ef13407b798cc1822597dd0d3389e67e9229\",\"license\":\"MIT\"},\"contracts/structs/JBRedemptionDelegateAllocation3_1_1.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBRedemptionDelegate3_1_1} from '../interfaces/IJBRedemptionDelegate3_1_1.sol';\\n\\n/// @custom:member delegate A delegate contract to use for subsequent calls.\\n/// @custom:member amount The amount to send to the delegate.\\n/// @custom:member metadata Metadata to pass the delegate.\\nstruct JBRedemptionDelegateAllocation3_1_1 {\\n IJBRedemptionDelegate3_1_1 delegate;\\n uint256 amount;\\n bytes metadata;\\n}\\n\",\"keccak256\":\"0x16d2b586f4591b0d18324f233b4d4a13c6dc687b5f2c5becadbedbbdc373cdc4\",\"license\":\"MIT\"},\"contracts/structs/JBSplit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IJBSplitAllocator} from './../interfaces/IJBSplitAllocator.sol';\\n\\n/// @custom:member preferClaimed A flag that only has effect if a projectId is also specified, and the project has a token contract attached. If so, this flag indicates if the tokens that result from making a payment to the project should be delivered claimed into the beneficiary's wallet, or unclaimed to save gas.\\n/// @custom:member preferAddToBalance A flag indicating if a distribution to a project should prefer triggering it's addToBalance function instead of its pay function.\\n/// @custom:member percent The percent of the whole group that this split occupies. This number is out of `JBConstants.SPLITS_TOTAL_PERCENT`.\\n/// @custom:member projectId The ID of a project. If an allocator is not set but a projectId is set, funds will be sent to the protocol treasury belonging to the project who's ID is specified. Resulting tokens will be routed to the beneficiary with the claimed token preference respected.\\n/// @custom:member beneficiary An address. The role the of the beneficary depends on whether or not projectId is specified, and whether or not an allocator is specified. If allocator is set, the beneficiary will be forwarded to the allocator for it to use. If allocator is not set but projectId is set, the beneficiary is the address to which the project's tokens will be sent that result from a payment to it. If neither allocator or projectId are set, the beneficiary is where the funds from the split will be sent.\\n/// @custom:member lockedUntil Specifies if the split should be unchangeable until the specified time, with the exception of extending the locked period.\\n/// @custom:member allocator If an allocator is specified, funds will be sent to the allocator contract along with all properties of this split.\\nstruct JBSplit {\\n bool preferClaimed;\\n bool preferAddToBalance;\\n uint256 percent;\\n uint256 projectId;\\n address payable beneficiary;\\n uint256 lockedUntil;\\n IJBSplitAllocator allocator;\\n}\\n\",\"keccak256\":\"0x7bf3f79f95cf6211dcdcf5af68ddc963f2304379ea50a5feaf27c645879fe3fe\",\"license\":\"MIT\"},\"contracts/structs/JBSplitAllocationData.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {JBSplit} from './JBSplit.sol';\\n\\n/// @custom:member token The token being sent to the split allocator.\\n/// @custom:member amount The amount being sent to the split allocator, as a fixed point number.\\n/// @custom:member decimals The number of decimals in the amount.\\n/// @custom:member projectId The project to which the split belongs.\\n/// @custom:member group The group to which the split belongs.\\n/// @custom:member split The split that caused the allocation.\\nstruct JBSplitAllocationData {\\n address token;\\n uint256 amount;\\n uint256 decimals;\\n uint256 projectId;\\n uint256 group;\\n JBSplit split;\\n}\\n\",\"keccak256\":\"0x85dcbcad02f315a1a3cc44140ffc77fdfbcafed7089eab55ffb66f1bebc2b40b\",\"license\":\"MIT\"},\"contracts/structs/JBTokenAmount.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/// @custom:member token The token the payment was made in.\\n/// @custom:member value The amount of tokens that was paid, as a fixed point number.\\n/// @custom:member decimals The number of decimals included in the value fixed point number.\\n/// @custom:member currency The expected currency of the value.\\nstruct JBTokenAmount {\\n address token;\\n uint256 value;\\n uint256 decimals;\\n uint256 currency;\\n}\\n\",\"keccak256\":\"0x9317f1f47aef544de592a48a4b20fa3d54586d988c8bb7420b40076920ea200d\",\"license\":\"MIT\"},\"prb-math/contracts/PRBMath.sol\":{\"content\":\"// SPDX-License-Identifier: Unlicense\\npragma solidity >=0.8.4;\\n\\n/// @notice Emitted when the result overflows uint256.\\nerror PRBMath__MulDivFixedPointOverflow(uint256 prod1);\\n\\n/// @notice Emitted when the result overflows uint256.\\nerror PRBMath__MulDivOverflow(uint256 prod1, uint256 denominator);\\n\\n/// @notice Emitted when one of the inputs is type(int256).min.\\nerror PRBMath__MulDivSignedInputTooSmall();\\n\\n/// @notice Emitted when the intermediary absolute result overflows int256.\\nerror PRBMath__MulDivSignedOverflow(uint256 rAbs);\\n\\n/// @notice Emitted when the input is MIN_SD59x18.\\nerror PRBMathSD59x18__AbsInputTooSmall();\\n\\n/// @notice Emitted when ceiling a number overflows SD59x18.\\nerror PRBMathSD59x18__CeilOverflow(int256 x);\\n\\n/// @notice Emitted when one of the inputs is MIN_SD59x18.\\nerror PRBMathSD59x18__DivInputTooSmall();\\n\\n/// @notice Emitted when one of the intermediary unsigned results overflows SD59x18.\\nerror PRBMathSD59x18__DivOverflow(uint256 rAbs);\\n\\n/// @notice Emitted when the input is greater than 133.084258667509499441.\\nerror PRBMathSD59x18__ExpInputTooBig(int256 x);\\n\\n/// @notice Emitted when the input is greater than 192.\\nerror PRBMathSD59x18__Exp2InputTooBig(int256 x);\\n\\n/// @notice Emitted when flooring a number underflows SD59x18.\\nerror PRBMathSD59x18__FloorUnderflow(int256 x);\\n\\n/// @notice Emitted when converting a basic integer to the fixed-point format overflows SD59x18.\\nerror PRBMathSD59x18__FromIntOverflow(int256 x);\\n\\n/// @notice Emitted when converting a basic integer to the fixed-point format underflows SD59x18.\\nerror PRBMathSD59x18__FromIntUnderflow(int256 x);\\n\\n/// @notice Emitted when the product of the inputs is negative.\\nerror PRBMathSD59x18__GmNegativeProduct(int256 x, int256 y);\\n\\n/// @notice Emitted when multiplying the inputs overflows SD59x18.\\nerror PRBMathSD59x18__GmOverflow(int256 x, int256 y);\\n\\n/// @notice Emitted when the input is less than or equal to zero.\\nerror PRBMathSD59x18__LogInputTooSmall(int256 x);\\n\\n/// @notice Emitted when one of the inputs is MIN_SD59x18.\\nerror PRBMathSD59x18__MulInputTooSmall();\\n\\n/// @notice Emitted when the intermediary absolute result overflows SD59x18.\\nerror PRBMathSD59x18__MulOverflow(uint256 rAbs);\\n\\n/// @notice Emitted when the intermediary absolute result overflows SD59x18.\\nerror PRBMathSD59x18__PowuOverflow(uint256 rAbs);\\n\\n/// @notice Emitted when the input is negative.\\nerror PRBMathSD59x18__SqrtNegativeInput(int256 x);\\n\\n/// @notice Emitted when the calculating the square root overflows SD59x18.\\nerror PRBMathSD59x18__SqrtOverflow(int256 x);\\n\\n/// @notice Emitted when addition overflows UD60x18.\\nerror PRBMathUD60x18__AddOverflow(uint256 x, uint256 y);\\n\\n/// @notice Emitted when ceiling a number overflows UD60x18.\\nerror PRBMathUD60x18__CeilOverflow(uint256 x);\\n\\n/// @notice Emitted when the input is greater than 133.084258667509499441.\\nerror PRBMathUD60x18__ExpInputTooBig(uint256 x);\\n\\n/// @notice Emitted when the input is greater than 192.\\nerror PRBMathUD60x18__Exp2InputTooBig(uint256 x);\\n\\n/// @notice Emitted when converting a basic integer to the fixed-point format format overflows UD60x18.\\nerror PRBMathUD60x18__FromUintOverflow(uint256 x);\\n\\n/// @notice Emitted when multiplying the inputs overflows UD60x18.\\nerror PRBMathUD60x18__GmOverflow(uint256 x, uint256 y);\\n\\n/// @notice Emitted when the input is less than 1.\\nerror PRBMathUD60x18__LogInputTooSmall(uint256 x);\\n\\n/// @notice Emitted when the calculating the square root overflows UD60x18.\\nerror PRBMathUD60x18__SqrtOverflow(uint256 x);\\n\\n/// @notice Emitted when subtraction underflows UD60x18.\\nerror PRBMathUD60x18__SubUnderflow(uint256 x, uint256 y);\\n\\n/// @dev Common mathematical functions used in both PRBMathSD59x18 and PRBMathUD60x18. Note that this shared library\\n/// does not always assume the signed 59.18-decimal fixed-point or the unsigned 60.18-decimal fixed-point\\n/// representation. When it does not, it is explicitly mentioned in the NatSpec documentation.\\nlibrary PRBMath {\\n /// STRUCTS ///\\n\\n struct SD59x18 {\\n int256 value;\\n }\\n\\n struct UD60x18 {\\n uint256 value;\\n }\\n\\n /// STORAGE ///\\n\\n /// @dev How many trailing decimals can be represented.\\n uint256 internal constant SCALE = 1e18;\\n\\n /// @dev Largest power of two divisor of SCALE.\\n uint256 internal constant SCALE_LPOTD = 262144;\\n\\n /// @dev SCALE inverted mod 2^256.\\n uint256 internal constant SCALE_INVERSE =\\n 78156646155174841979727994598816262306175212592076161876661_508869554232690281;\\n\\n /// FUNCTIONS ///\\n\\n /// @notice Calculates the binary exponent of x using the binary fraction method.\\n /// @dev Has to use 192.64-bit fixed-point numbers.\\n /// See https://ethereum.stackexchange.com/a/96594/24693.\\n /// @param x The exponent as an unsigned 192.64-bit fixed-point number.\\n /// @return result The result as an unsigned 60.18-decimal fixed-point number.\\n function exp2(uint256 x) internal pure returns (uint256 result) {\\n unchecked {\\n // Start from 0.5 in the 192.64-bit fixed-point format.\\n result = 0x800000000000000000000000000000000000000000000000;\\n\\n // Multiply the result by root(2, 2^-i) when the bit at position i is 1. None of the intermediary results overflows\\n // because the initial result is 2^191 and all magic factors are less than 2^65.\\n if (x & 0x8000000000000000 > 0) {\\n result = (result * 0x16A09E667F3BCC909) >> 64;\\n }\\n if (x & 0x4000000000000000 > 0) {\\n result = (result * 0x1306FE0A31B7152DF) >> 64;\\n }\\n if (x & 0x2000000000000000 > 0) {\\n result = (result * 0x1172B83C7D517ADCE) >> 64;\\n }\\n if (x & 0x1000000000000000 > 0) {\\n result = (result * 0x10B5586CF9890F62A) >> 64;\\n }\\n if (x & 0x800000000000000 > 0) {\\n result = (result * 0x1059B0D31585743AE) >> 64;\\n }\\n if (x & 0x400000000000000 > 0) {\\n result = (result * 0x102C9A3E778060EE7) >> 64;\\n }\\n if (x & 0x200000000000000 > 0) {\\n result = (result * 0x10163DA9FB33356D8) >> 64;\\n }\\n if (x & 0x100000000000000 > 0) {\\n result = (result * 0x100B1AFA5ABCBED61) >> 64;\\n }\\n if (x & 0x80000000000000 > 0) {\\n result = (result * 0x10058C86DA1C09EA2) >> 64;\\n }\\n if (x & 0x40000000000000 > 0) {\\n result = (result * 0x1002C605E2E8CEC50) >> 64;\\n }\\n if (x & 0x20000000000000 > 0) {\\n result = (result * 0x100162F3904051FA1) >> 64;\\n }\\n if (x & 0x10000000000000 > 0) {\\n result = (result * 0x1000B175EFFDC76BA) >> 64;\\n }\\n if (x & 0x8000000000000 > 0) {\\n result = (result * 0x100058BA01FB9F96D) >> 64;\\n }\\n if (x & 0x4000000000000 > 0) {\\n result = (result * 0x10002C5CC37DA9492) >> 64;\\n }\\n if (x & 0x2000000000000 > 0) {\\n result = (result * 0x1000162E525EE0547) >> 64;\\n }\\n if (x & 0x1000000000000 > 0) {\\n result = (result * 0x10000B17255775C04) >> 64;\\n }\\n if (x & 0x800000000000 > 0) {\\n result = (result * 0x1000058B91B5BC9AE) >> 64;\\n }\\n if (x & 0x400000000000 > 0) {\\n result = (result * 0x100002C5C89D5EC6D) >> 64;\\n }\\n if (x & 0x200000000000 > 0) {\\n result = (result * 0x10000162E43F4F831) >> 64;\\n }\\n if (x & 0x100000000000 > 0) {\\n result = (result * 0x100000B1721BCFC9A) >> 64;\\n }\\n if (x & 0x80000000000 > 0) {\\n result = (result * 0x10000058B90CF1E6E) >> 64;\\n }\\n if (x & 0x40000000000 > 0) {\\n result = (result * 0x1000002C5C863B73F) >> 64;\\n }\\n if (x & 0x20000000000 > 0) {\\n result = (result * 0x100000162E430E5A2) >> 64;\\n }\\n if (x & 0x10000000000 > 0) {\\n result = (result * 0x1000000B172183551) >> 64;\\n }\\n if (x & 0x8000000000 > 0) {\\n result = (result * 0x100000058B90C0B49) >> 64;\\n }\\n if (x & 0x4000000000 > 0) {\\n result = (result * 0x10000002C5C8601CC) >> 64;\\n }\\n if (x & 0x2000000000 > 0) {\\n result = (result * 0x1000000162E42FFF0) >> 64;\\n }\\n if (x & 0x1000000000 > 0) {\\n result = (result * 0x10000000B17217FBB) >> 64;\\n }\\n if (x & 0x800000000 > 0) {\\n result = (result * 0x1000000058B90BFCE) >> 64;\\n }\\n if (x & 0x400000000 > 0) {\\n result = (result * 0x100000002C5C85FE3) >> 64;\\n }\\n if (x & 0x200000000 > 0) {\\n result = (result * 0x10000000162E42FF1) >> 64;\\n }\\n if (x & 0x100000000 > 0) {\\n result = (result * 0x100000000B17217F8) >> 64;\\n }\\n if (x & 0x80000000 > 0) {\\n result = (result * 0x10000000058B90BFC) >> 64;\\n }\\n if (x & 0x40000000 > 0) {\\n result = (result * 0x1000000002C5C85FE) >> 64;\\n }\\n if (x & 0x20000000 > 0) {\\n result = (result * 0x100000000162E42FF) >> 64;\\n }\\n if (x & 0x10000000 > 0) {\\n result = (result * 0x1000000000B17217F) >> 64;\\n }\\n if (x & 0x8000000 > 0) {\\n result = (result * 0x100000000058B90C0) >> 64;\\n }\\n if (x & 0x4000000 > 0) {\\n result = (result * 0x10000000002C5C860) >> 64;\\n }\\n if (x & 0x2000000 > 0) {\\n result = (result * 0x1000000000162E430) >> 64;\\n }\\n if (x & 0x1000000 > 0) {\\n result = (result * 0x10000000000B17218) >> 64;\\n }\\n if (x & 0x800000 > 0) {\\n result = (result * 0x1000000000058B90C) >> 64;\\n }\\n if (x & 0x400000 > 0) {\\n result = (result * 0x100000000002C5C86) >> 64;\\n }\\n if (x & 0x200000 > 0) {\\n result = (result * 0x10000000000162E43) >> 64;\\n }\\n if (x & 0x100000 > 0) {\\n result = (result * 0x100000000000B1721) >> 64;\\n }\\n if (x & 0x80000 > 0) {\\n result = (result * 0x10000000000058B91) >> 64;\\n }\\n if (x & 0x40000 > 0) {\\n result = (result * 0x1000000000002C5C8) >> 64;\\n }\\n if (x & 0x20000 > 0) {\\n result = (result * 0x100000000000162E4) >> 64;\\n }\\n if (x & 0x10000 > 0) {\\n result = (result * 0x1000000000000B172) >> 64;\\n }\\n if (x & 0x8000 > 0) {\\n result = (result * 0x100000000000058B9) >> 64;\\n }\\n if (x & 0x4000 > 0) {\\n result = (result * 0x10000000000002C5D) >> 64;\\n }\\n if (x & 0x2000 > 0) {\\n result = (result * 0x1000000000000162E) >> 64;\\n }\\n if (x & 0x1000 > 0) {\\n result = (result * 0x10000000000000B17) >> 64;\\n }\\n if (x & 0x800 > 0) {\\n result = (result * 0x1000000000000058C) >> 64;\\n }\\n if (x & 0x400 > 0) {\\n result = (result * 0x100000000000002C6) >> 64;\\n }\\n if (x & 0x200 > 0) {\\n result = (result * 0x10000000000000163) >> 64;\\n }\\n if (x & 0x100 > 0) {\\n result = (result * 0x100000000000000B1) >> 64;\\n }\\n if (x & 0x80 > 0) {\\n result = (result * 0x10000000000000059) >> 64;\\n }\\n if (x & 0x40 > 0) {\\n result = (result * 0x1000000000000002C) >> 64;\\n }\\n if (x & 0x20 > 0) {\\n result = (result * 0x10000000000000016) >> 64;\\n }\\n if (x & 0x10 > 0) {\\n result = (result * 0x1000000000000000B) >> 64;\\n }\\n if (x & 0x8 > 0) {\\n result = (result * 0x10000000000000006) >> 64;\\n }\\n if (x & 0x4 > 0) {\\n result = (result * 0x10000000000000003) >> 64;\\n }\\n if (x & 0x2 > 0) {\\n result = (result * 0x10000000000000001) >> 64;\\n }\\n if (x & 0x1 > 0) {\\n result = (result * 0x10000000000000001) >> 64;\\n }\\n\\n // We're doing two things at the same time:\\n //\\n // 1. Multiply the result by 2^n + 1, where \\\"2^n\\\" is the integer part and the one is added to account for\\n // the fact that we initially set the result to 0.5. This is accomplished by subtracting from 191\\n // rather than 192.\\n // 2. Convert the result to the unsigned 60.18-decimal fixed-point format.\\n //\\n // This works because 2^(191-ip) = 2^ip / 2^191, where \\\"ip\\\" is the integer part \\\"2^n\\\".\\n result *= SCALE;\\n result >>= (191 - (x >> 64));\\n }\\n }\\n\\n /// @notice Finds the zero-based index of the first one in the binary representation of x.\\n /// @dev See the note on msb in the \\\"Find First Set\\\" Wikipedia article https://en.wikipedia.org/wiki/Find_first_set\\n /// @param x The uint256 number for which to find the index of the most significant bit.\\n /// @return msb The index of the most significant bit as an uint256.\\n function mostSignificantBit(uint256 x) internal pure returns (uint256 msb) {\\n if (x >= 2**128) {\\n x >>= 128;\\n msb += 128;\\n }\\n if (x >= 2**64) {\\n x >>= 64;\\n msb += 64;\\n }\\n if (x >= 2**32) {\\n x >>= 32;\\n msb += 32;\\n }\\n if (x >= 2**16) {\\n x >>= 16;\\n msb += 16;\\n }\\n if (x >= 2**8) {\\n x >>= 8;\\n msb += 8;\\n }\\n if (x >= 2**4) {\\n x >>= 4;\\n msb += 4;\\n }\\n if (x >= 2**2) {\\n x >>= 2;\\n msb += 2;\\n }\\n if (x >= 2**1) {\\n // No need to shift x any more.\\n msb += 1;\\n }\\n }\\n\\n /// @notice Calculates floor(x*y\\u00f7denominator) with full precision.\\n ///\\n /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv.\\n ///\\n /// Requirements:\\n /// - The denominator cannot be zero.\\n /// - The result must fit within uint256.\\n ///\\n /// Caveats:\\n /// - This function does not work with fixed-point numbers.\\n ///\\n /// @param x The multiplicand as an uint256.\\n /// @param y The multiplier as an uint256.\\n /// @param denominator The divisor as an uint256.\\n /// @return result The result as an uint256.\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator\\n ) internal pure returns (uint256 result) {\\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\\n // variables such that product = prod1 * 2^256 + prod0.\\n uint256 prod0; // Least significant 256 bits of the product\\n uint256 prod1; // Most significant 256 bits of the product\\n assembly {\\n let mm := mulmod(x, y, not(0))\\n prod0 := mul(x, y)\\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\\n }\\n\\n // Handle non-overflow cases, 256 by 256 division.\\n if (prod1 == 0) {\\n unchecked {\\n result = prod0 / denominator;\\n }\\n return result;\\n }\\n\\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\\n if (prod1 >= denominator) {\\n revert PRBMath__MulDivOverflow(prod1, denominator);\\n }\\n\\n ///////////////////////////////////////////////\\n // 512 by 256 division.\\n ///////////////////////////////////////////////\\n\\n // Make division exact by subtracting the remainder from [prod1 prod0].\\n uint256 remainder;\\n assembly {\\n // Compute remainder using mulmod.\\n remainder := mulmod(x, y, denominator)\\n\\n // Subtract 256 bit number from 512 bit number.\\n prod1 := sub(prod1, gt(remainder, prod0))\\n prod0 := sub(prod0, remainder)\\n }\\n\\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\\n // See https://cs.stackexchange.com/q/138556/92363.\\n unchecked {\\n // Does not overflow because the denominator cannot be zero at this stage in the function.\\n uint256 lpotdod = denominator & (~denominator + 1);\\n assembly {\\n // Divide denominator by lpotdod.\\n denominator := div(denominator, lpotdod)\\n\\n // Divide [prod1 prod0] by lpotdod.\\n prod0 := div(prod0, lpotdod)\\n\\n // Flip lpotdod such that it is 2^256 / lpotdod. If lpotdod is zero, then it becomes one.\\n lpotdod := add(div(sub(0, lpotdod), lpotdod), 1)\\n }\\n\\n // Shift in bits from prod1 into prod0.\\n prod0 |= prod1 * lpotdod;\\n\\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\\n // four bits. That is, denominator * inv = 1 mod 2^4.\\n uint256 inverse = (3 * denominator) ^ 2;\\n\\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\\n // in modular arithmetic, doubling the correct bits in each step.\\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\\n\\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\\n // is no longer required.\\n result = prod0 * inverse;\\n return result;\\n }\\n }\\n\\n /// @notice Calculates floor(x*y\\u00f71e18) with full precision.\\n ///\\n /// @dev Variant of \\\"mulDiv\\\" with constant folding, i.e. in which the denominator is always 1e18. Before returning the\\n /// final result, we add 1 if (x * y) % SCALE >= HALF_SCALE. Without this, 6.6e-19 would be truncated to 0 instead of\\n /// being rounded to 1e-18. See \\\"Listing 6\\\" and text above it at https://accu.org/index.php/journals/1717.\\n ///\\n /// Requirements:\\n /// - The result must fit within uint256.\\n ///\\n /// Caveats:\\n /// - The body is purposely left uncommented; see the NatSpec comments in \\\"PRBMath.mulDiv\\\" to understand how this works.\\n /// - It is assumed that the result can never be type(uint256).max when x and y solve the following two equations:\\n /// 1. x * y = type(uint256).max * SCALE\\n /// 2. (x * y) % SCALE >= SCALE / 2\\n ///\\n /// @param x The multiplicand as an unsigned 60.18-decimal fixed-point number.\\n /// @param y The multiplier as an unsigned 60.18-decimal fixed-point number.\\n /// @return result The result as an unsigned 60.18-decimal fixed-point number.\\n function mulDivFixedPoint(uint256 x, uint256 y) internal pure returns (uint256 result) {\\n uint256 prod0;\\n uint256 prod1;\\n assembly {\\n let mm := mulmod(x, y, not(0))\\n prod0 := mul(x, y)\\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\\n }\\n\\n if (prod1 >= SCALE) {\\n revert PRBMath__MulDivFixedPointOverflow(prod1);\\n }\\n\\n uint256 remainder;\\n uint256 roundUpUnit;\\n assembly {\\n remainder := mulmod(x, y, SCALE)\\n roundUpUnit := gt(remainder, 499999999999999999)\\n }\\n\\n if (prod1 == 0) {\\n unchecked {\\n result = (prod0 / SCALE) + roundUpUnit;\\n return result;\\n }\\n }\\n\\n assembly {\\n result := add(\\n mul(\\n or(\\n div(sub(prod0, remainder), SCALE_LPOTD),\\n mul(sub(prod1, gt(remainder, prod0)), add(div(sub(0, SCALE_LPOTD), SCALE_LPOTD), 1))\\n ),\\n SCALE_INVERSE\\n ),\\n roundUpUnit\\n )\\n }\\n }\\n\\n /// @notice Calculates floor(x*y\\u00f7denominator) with full precision.\\n ///\\n /// @dev An extension of \\\"mulDiv\\\" for signed numbers. Works by computing the signs and the absolute values separately.\\n ///\\n /// Requirements:\\n /// - None of the inputs can be type(int256).min.\\n /// - The result must fit within int256.\\n ///\\n /// @param x The multiplicand as an int256.\\n /// @param y The multiplier as an int256.\\n /// @param denominator The divisor as an int256.\\n /// @return result The result as an int256.\\n function mulDivSigned(\\n int256 x,\\n int256 y,\\n int256 denominator\\n ) internal pure returns (int256 result) {\\n if (x == type(int256).min || y == type(int256).min || denominator == type(int256).min) {\\n revert PRBMath__MulDivSignedInputTooSmall();\\n }\\n\\n // Get hold of the absolute values of x, y and the denominator.\\n uint256 ax;\\n uint256 ay;\\n uint256 ad;\\n unchecked {\\n ax = x < 0 ? uint256(-x) : uint256(x);\\n ay = y < 0 ? uint256(-y) : uint256(y);\\n ad = denominator < 0 ? uint256(-denominator) : uint256(denominator);\\n }\\n\\n // Compute the absolute value of (x*y)\\u00f7denominator. The result must fit within int256.\\n uint256 rAbs = mulDiv(ax, ay, ad);\\n if (rAbs > uint256(type(int256).max)) {\\n revert PRBMath__MulDivSignedOverflow(rAbs);\\n }\\n\\n // Get the signs of x, y and the denominator.\\n uint256 sx;\\n uint256 sy;\\n uint256 sd;\\n assembly {\\n sx := sgt(x, sub(0, 1))\\n sy := sgt(y, sub(0, 1))\\n sd := sgt(denominator, sub(0, 1))\\n }\\n\\n // XOR over sx, sy and sd. This is checking whether there are one or three negative signs in the inputs.\\n // If yes, the result should be negative.\\n result = sx ^ sy ^ sd == 0 ? -int256(rAbs) : int256(rAbs);\\n }\\n\\n /// @notice Calculates the square root of x, rounding down.\\n /// @dev Uses the Babylonian method https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method.\\n ///\\n /// Caveats:\\n /// - This function does not work with fixed-point numbers.\\n ///\\n /// @param x The uint256 number for which to calculate the square root.\\n /// @return result The result as an uint256.\\n function sqrt(uint256 x) internal pure returns (uint256 result) {\\n if (x == 0) {\\n return 0;\\n }\\n\\n // Set the initial guess to the closest power of two that is higher than x.\\n uint256 xAux = uint256(x);\\n result = 1;\\n if (xAux >= 0x100000000000000000000000000000000) {\\n xAux >>= 128;\\n result <<= 64;\\n }\\n if (xAux >= 0x10000000000000000) {\\n xAux >>= 64;\\n result <<= 32;\\n }\\n if (xAux >= 0x100000000) {\\n xAux >>= 32;\\n result <<= 16;\\n }\\n if (xAux >= 0x10000) {\\n xAux >>= 16;\\n result <<= 8;\\n }\\n if (xAux >= 0x100) {\\n xAux >>= 8;\\n result <<= 4;\\n }\\n if (xAux >= 0x10) {\\n xAux >>= 4;\\n result <<= 2;\\n }\\n if (xAux >= 0x8) {\\n result <<= 1;\\n }\\n\\n // The operations can never overflow because the result is max 2^127 when it enters this block.\\n unchecked {\\n result = (result + x / result) >> 1;\\n result = (result + x / result) >> 1;\\n result = (result + x / result) >> 1;\\n result = (result + x / result) >> 1;\\n result = (result + x / result) >> 1;\\n result = (result + x / result) >> 1;\\n result = (result + x / result) >> 1; // Seven iterations should be enough\\n uint256 roundedDownResult = x / result;\\n return result >= roundedDownResult ? roundedDownResult : result;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x62cbabae4910e168e99b9c2c3e3b5c9c7ad5e7abd961dcc63b7ea3d83d8ea87e\",\"license\":\"Unlicense\"}},\"version\":1}", + "bytecode": "0x60e06040523480156200001157600080fd5b506040516200366a3803806200366a833981016040819052620000349162000070565b60016000556001600160a01b0392831660805290821660a0521660c052620000c4565b6001600160a01b03811681146200006d57600080fd5b50565b6000806000606084860312156200008657600080fd5b8351620000938162000057565b6020850151909350620000a68162000057565b6040850151909250620000b98162000057565b809150509250925092565b60805160a05160c0516134ea6200018060003960008181610273015281816106d201528181610c1c0152818161214c015261232901526000818161018b0152818161036f0152818161083f01528181610d0601528181610e1c0152818161120d015281816114d7015281816115a0015281816118d901528181611cdf01526123b00152600081816102390152818161041f0152818161105c01528181611782015281816119b201528181611f2201526121c801526134ea6000f3fe608060405234801561001057600080fd5b50600436106100ff5760003560e01c8063c294b2f411610097578063d49031c011610066578063d49031c014610295578063d4c3a8d2146102a8578063e7c8e3e3146102d9578063e8ba563a146102ee57600080fd5b8063c294b2f414610221578063c41c2f2414610234578063c66445971461025b578063d3419bf31461026e57600080fd5b80636bb6a5ad116100d35780636bb6a5ad146101c5578063a2df1f95146101d8578063a57c7f59146101fb578063b753d7e91461020e57600080fd5b8062fdd58e1461010457806325386715146101425780632fa1b39114610163578063557e715514610186575b600080fd5b61012f6101123660046125c3565b600160209081526000928352604080842090915290825290205481565b6040519081526020015b60405180910390f35b6101556101503660046125ef565b61031f565b60405161013992919061267a565b6101766101713660046127fa565b6107f5565b604051610139949392919061290b565b6101ad7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610139565b61012f6101d33660046129bd565b610cc5565b6101eb6101e63660046129d6565b610dd2565b6040516101399493929190612a77565b61012f610209366004612b12565b61149c565b61012f61021c3660046125ef565b611566565b61012f61022f366004612b44565b61157d565b6101ad7f000000000000000000000000000000000000000000000000000000000000000081565b6101556102693660046125ef565b611892565b6101ad7f000000000000000000000000000000000000000000000000000000000000000081565b61012f6102a33660046125c3565b611cd6565b61012f6102b6366004612b93565b600360209081526000938452604080852082529284528284209052825290205481565b6102ec6102e7366004612bc8565b611db4565b005b61012f6102fc366004612b93565b600260209081526000938452604080852082529284528284209052825290205481565b610327612556565b60006002600054036103545760405162461bcd60e51b815260040161034b90612bea565b60405180910390fd5b60026000556040516321d1336160e11b8152600481018690527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906343a266c29060240161012060405180830381865afa1580156103bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103e39190612c31565b336000908152600360209081526040808320898452825280832082850151845290915281205491935090610418908690612cc7565b90506000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635dd8f6aa896040518263ffffffff1660e01b815260040161046b91815260200190565b602060405180830381865afa158015610488573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104ac9190612cda565b6001600160a01b031663a29a68146040518163ffffffff1660e01b8152600401602060405180830381865afa1580156104e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061050d9190612cda565b6001600160a01b0316637a81b56289876020015133336001600160a01b031663fc0c546a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610560573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105849190612cda565b6040518563ffffffff1660e01b81526004016105a39493929190612cf7565b6040805180830381865afa1580156105bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105e39190612d1e565b91509150818311806105f3575081155b1561061157604051635b76558960e11b815260040160405180910390fd5b8086146106315760405163e56ea4e760e01b815260040160405180910390fd5b6000336001600160a01b031663e5a6b10f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610671573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106959190612d42565b90508087146107505761074b886106ae6012600a612e3f565b604051635268657960e11b8152600481018b905260248101859052601260448201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a4d0caf2906064015b602060405180830381865afa158015610722573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107469190612d42565b611dfd565b610752565b875b9450610760338a8884611eca565b851115610780576040516317e53f6760e11b815260040160405180910390fd5b3360008181526003602090815260408083208d845282528083208a83015184528252808320889055928252600181528282208c8352905220546107c4908690612e4b565b3360009081526001602081815260408084209d84529c90529a81209190915598909855509296919550909350505050565b6107fd612556565b60006060806002600054036108245760405162461bcd60e51b815260040161034b90612bea565b60026000556040516321d1336160e11b8152600481018b90527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906343a266c29060240161012060405180830381865afa15801561088f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108b39190612c31565b80519094506000036108d85760405163174b338d60e11b815260040160405180910390fd5b61010084015160481c6001908116036109045760405163a3bb913360e01b815260040160405180910390fd5b61010084015160009060521c600190811614801561093a5750600061092e86610100015160541c90565b6001600160a01b031614155b15610a8c576000604051806101400160405280336001600160a01b031681526020018f6001600160a01b031681526020018e80360381019061097c9190612e5e565b815260208082018f905288015160408201526001600160a01b038c16606082015260a080890151608083015261010089015191019060181c61ffff1681526020018a8a8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050908252506020018890529050610a0d86610100015160541c90565b6001600160a01b031663d46cf171826040518263ffffffff1660e01b8152600401610a389190612ecd565b6000604051808303816000875af1158015610a57573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610a7f9190810190613038565b955093509150610acd9050565b8460a00151905087878080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509294505050505b825160208d01359015610b495760005b8451811015610b47576000858281518110610afa57610afa613169565b602002602001015160200151905080600014610b3e5782811115610b31576040516336a8da9360e11b815260040160405180910390fd5b610b3b8184612e4b565b92505b50600101610add565b505b8c60200135600003610b61575060009350610cae9050565b8015610bc8573360009081526001602090815260408083208f8452909152902054610b8d908290612cc7565b60016000336001600160a01b03166001600160a01b0316815260200190815260200160002060008e8152602001908152602001600020819055505b5080600003610bdb575060009250610cae565b60408c0135600060608e01358c14610c8c57604051635268657960e11b815260608f01356004820152602481018d9052604481018390526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063a4d0caf290606401602060405180830381865afa158015610c63573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c879190612d42565b610c97565b610c9782600a612e3f565b9050610ca88e602001358483611dfd565b95505050505b600160008190555098509850985098945050505050565b6000600260005403610ce95760405162461bcd60e51b815260040161034b90612bea565b600260009081556040516321d1336160e11b8152600481018490527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906343a266c29060240161012060405180830381865afa158015610d56573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d7a9190612c31565b610100810151909150604d1c600190811614610da9576040516373e4f05f60e11b815260040160405180910390fd5b505033600090815260016020818152604080842094845293905291812080549082905591905590565b610dda612556565b6000606080600260005403610e015760405162461bcd60e51b815260040161034b90612bea565b60026000556040516321d1336160e11b8152600481018990527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906343a266c29060240161012060405180830381865afa158015610e6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e909190612c31565b610100810151909450604a1c600190811603610ebf5760405163a97cf58f60e01b815260040160405180910390fd5b610ef3604051806080016040528060006001600160a01b031681526020016000815260200160008152602001600081525090565b6000806000336001600160a01b031663fc0c546a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f5a9190612cda565b90506000336001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f9c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fc09190612d42565b90506000336001600160a01b031663e5a6b10f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611002573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110269190612d42565b6101008b015190915060511c60019081161461104d57611048338f8c84611eca565b611058565b6110588e83836121a5565b94507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635dd8f6aa8f6040518263ffffffff1660e01b81526004016110a891815260200190565b602060405180830381865afa1580156110c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110e99190612cda565b6001600160a01b031663c18f2d318f6040518263ffffffff1660e01b815260040161111691815260200190565b602060405180830381865afa158015611133573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111579190612d42565b9350838d111561117957604051625c579160e91b815260040160405180910390fd5b841561118f5761118c8e8b8f8789612387565b98505b604080516080810182526001600160a01b03949094168452602084018a9052830191909152606082015261010088015190935060531c60019081161480156111ef575060006111e388610100015160541c90565b6001600160a01b031614155b156113c657604051633157d5c760e21b8152600481018c90526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063c55f571c90602401602060405180830381865afa15801561125c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611280919061317f565b90506000604051806101800160405280336001600160a01b031681526020018f6001600160a01b031681526020018e81526020018a6020015181526020018d81526020018481526020018581526020018681526020016112ed8b6101000151600160519190911c81161490565b151581526020016000846002811115611308576113086131a0565b1461131b576113168b6124bf565b611324565b6113248b6124dc565b81526020018c81526020018b815250905061134489610100015160541c90565b6001600160a01b031663a51cfd18826040518263ffffffff1660e01b815260040161136f91906131b6565b6000604051808303816000875af115801561138e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526113b691908101906132ae565b91995090975095506113ca915050565b8893505b50508251849150156114245760005b83518110156114225760008482815181106113f6576113f6613169565b602002602001015160200151905080600014611419576114168184612cc7565b92505b506001016113d9565b505b3360009081526001602090815260408083208c845290915290205481111561145f576040516317e53f6760e11b815260040160405180910390fd5b8015611487573360009081526001602090815260408083208c84529091529020805482900390555b50600160008190555095509550955095915050565b6000816000036114ae5750600061155e565b828411156114be5750600061155e565b6040516321d1336160e11b8152600481018690526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906343a266c29060240161012060405180830381865afa158015611527573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061154b9190612c31565b905061155a8682878787612387565b9150505b949350505050565b60006115738484846121a5565b90505b9392505050565b6040516321d1336160e11b81526004810184905260009081906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906343a266c29060240161012060405180830381865afa1580156115e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061160c9190612c31565b9050600083611687576116828787848a6001600160a01b031663e5a6b10f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611659573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061167d9190612d42565b611eca565b611754565b61175486886001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156116c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116ed9190612d42565b896001600160a01b031663e5a6b10f6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561172b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061174f9190612d42565b6121a5565b9050806000036117695760009250505061155e565b604051632eec7b5560e11b8152600481018790526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635dd8f6aa90602401602060405180830381865afa1580156117d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117f59190612cda565b6001600160a01b031663c18f2d31886040518263ffffffff1660e01b815260040161182291815260200190565b602060405180830381865afa15801561183f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118639190612d42565b905080861115611879576000935050505061155e565b6118868784888486612387565b98975050505050505050565b61189a612556565b60006002600054036118be5760405162461bcd60e51b815260040161034b90612bea565b60026000556040516321d1336160e11b8152600481018690527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906343a266c29060240161012060405180830381865afa158015611929573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061194d9190612c31565b61010081015190925060491c60019081160361197c5760405163861e9dcd60e01b815260040160405180910390fd5b3360009081526002602090815260408083208884528252808320855184529091528120546119ab908690612cc7565b90506000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635dd8f6aa896040518263ffffffff1660e01b81526004016119fe91815260200190565b602060405180830381865afa158015611a1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a3f9190612cda565b6001600160a01b031663a29a68146040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aa09190612cda565b6001600160a01b031663e8db213089876020015133336001600160a01b031663fc0c546a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611af3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b179190612cda565b6040518563ffffffff1660e01b8152600401611b369493929190612cf7565b6040805180830381865afa158015611b52573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b769190612d1e565b9150915081831180611b86575081155b15611ba457604051630236b92b60e21b815260040160405180910390fd5b808614611bc45760405163e56ea4e760e01b815260040160405180910390fd5b6000336001600160a01b031663e5a6b10f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611c04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c289190612d42565b9050808714611c4657611c41886106ae6012600a612e3f565b611c48565b875b3360009081526001602090815260408083208d8452909152902054909550851115611c86576040516317e53f6760e11b815260040160405180910390fd5b50503360008181526002602090815260408083208b845282528083208851845282528083209590955591815260018083528482209982529890915291822080548490039055509490945593915050565b6000611dab83837f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166343a266c2866040518263ffffffff1660e01b8152600401611d2b91815260200190565b61012060405180830381865afa158015611d49573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d6d9190612c31565b866001600160a01b031663e5a6b10f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611659573d6000803e3d6000fd5b90505b92915050565b336000908152600160209081526040808320858452909152902054611dda908290612cc7565b336000908152600160209081526040808320958352949052929092209190915550565b6000808060001985870985870292508281108382030391505080600003611e3757838281611e2d57611e2d6133ce565b0492505050611576565b838110611e6157604051631dcf306360e21b8152600481018290526024810185905260440161034b565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b6001600160a01b0384166000908152600160209081526040808320868452909152812054808203611eff57600091505061155e565b604051632eec7b5560e11b81526004810186905260009081906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690635dd8f6aa90602401602060405180830381865afa158015611f69573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f8d9190612cda565b6001600160a01b031663a29a68146040518163ffffffff1660e01b8152600401602060405180830381865afa158015611fca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fee9190612cda565b6001600160a01b031663e8db21308888602001518b8c6001600160a01b031663fc0c546a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612041573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120659190612cda565b6040518563ffffffff1660e01b81526004016120849493929190612cf7565b6040805180830381865afa1580156120a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120c49190612d1e565b6001600160a01b038a1660009081526002602090815260408083208c845282528083208b518452909152812054929450909250906121029084612e4b565b905080158015906121135750858214155b1561218657612183816121286012600a612e3f565b604051635268657960e11b815260048101869052602481018a9052601260448201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a4d0caf290606401610705565b90505b808411612194576000612198565b8084035b9998505050505050505050565b60405163d175415360e01b81526004810184905260009081906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063d175415390602401600060405180830381865afa15801561220f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261223791908101906133e4565b90506000805b82518110156122e25782818151811061225857612258613169565b60200260200101516001600160a01b031663a32e1e96886040518263ffffffff1660e01b815260040161228d91815260200190565b602060405180830381865afa1580156122aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122ce9190612d42565b6122d89083612cc7565b915060010161223d565b5060006001851461235d57604051635268657960e11b8152600160048201526024810186905260126044820152612358908390670de0b6b3a7640000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063a4d0caf290606401610705565b61235f565b815b90508560121461237a57612375816012886124f9565b61237c565b805b979650505050505050565b60008284036123975750806124b6565b600080604051633157d5c760e21b8152600481018990527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063c55f571c90602401602060405180830381865afa1580156123ff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612423919061317f565b6002811115612434576124346131a0565b1461244757612442866124bf565b612450565b612450866124dc565b9050806000036124645760009150506124b6565b6000612471848787611dfd565b905061271082036124855791506124b69050565b6124b18161249f8861249986612710612e4b565b89611dfd565b6124a99085612cc7565b612710611dfd565b925050505b95945050505050565b60006028826101000151901c61ffff16612710611dae9190612e4b565b60006038826101000151901c61ffff16612710611dae9190612e4b565b6000828203612509575082611576565b828211156125375761251b8383612e4b565b61252690600a612e3f565b6125309085613473565b9050611576565b6125418284612e4b565b61254c90600a612e3f565b6125309085613492565b6040518061012001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b03168152602001600081525090565b6001600160a01b03811681146125c057600080fd5b50565b600080604083850312156125d657600080fd5b82356125e1816125ab565b946020939093013593505050565b60008060006060848603121561260457600080fd5b505081359360208301359350604090920135919050565b805182526020808201519083015260408082015190830152606080820151908301526080808201519083015260a0808201519083015260c0808201519083015260e0808201516001600160a01b03169083015261010090810151910152565b6101408101612689828561261b565b826101208301529392505050565b60008083601f8401126126a957600080fd5b50813567ffffffffffffffff8111156126c157600080fd5b6020830191508360208285010111156126d957600080fd5b9250929050565b634e487b7160e01b600052604160045260246000fd5b604051610120810167ffffffffffffffff8111828210171561271a5761271a6126e0565b60405290565b6040516060810167ffffffffffffffff8111828210171561271a5761271a6126e0565b604051601f8201601f1916810167ffffffffffffffff8111828210171561276c5761276c6126e0565b604052919050565b600067ffffffffffffffff82111561278e5761278e6126e0565b50601f01601f191660200190565b60006127af6127aa84612774565b612743565b90508281528383830111156127c357600080fd5b828260208301376000602084830101529392505050565b600082601f8301126127eb57600080fd5b611dab8383356020850161279c565b600080600080600080600080888a0361014081121561281857600080fd5b8935612823816125ab565b98506080601f198201121561283757600080fd5b5060208901965060a0890135955060c0890135945060e089013561285a816125ab565b935061010089013567ffffffffffffffff8082111561287857600080fd5b6128848c838d01612697565b90955093506101208b013591508082111561289e57600080fd5b506128ab8b828c016127da565b9150509295985092959890939650565b60005b838110156128d65781810151838201526020016128be565b50506000910152565b600081518084526128f78160208601602086016128bb565b601f01601f19169290920160200192915050565b600061018080830161291d848961261b565b61012084018790526101408401919091528451908190526101a080840191600581901b850190910190602080880160005b838110156129a65787850361019f19018652815180516001600160a01b031686528381015184870152604090810151606091870182905290612992818801836128df565b97850197965050509082019060010161294e565b505050508381036101608501526124b181866128df565b6000602082840312156129cf57600080fd5b5035919050565b600080600080600060a086880312156129ee57600080fd5b85356129f9816125ab565b94506020860135935060408601359250606086013567ffffffffffffffff80821115612a2457600080fd5b818801915088601f830112612a3857600080fd5b612a478983356020850161279c565b93506080880135915080821115612a5d57600080fd5b50612a6a888289016127da565b9150509295509295909350565b6000610180808301612a89848961261b565b61012084018790526101408401919091528451908190526101a080840191600581901b850190910190602080880160005b838110156129a65787850361019f19018652815180516001600160a01b031686528381015184870152604090810151606091870182905290612afe818801836128df565b978501979650505090820190600101612aba565b60008060008060808587031215612b2857600080fd5b5050823594602084013594506040840135936060013592509050565b60008060008060808587031215612b5a57600080fd5b8435612b65816125ab565b9350602085013592506040850135915060608501358015158114612b8857600080fd5b939692955090935050565b600080600060608486031215612ba857600080fd5b8335612bb3816125ab565b95602085013595506040909401359392505050565b60008060408385031215612bdb57600080fd5b50508035926020909101359150565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b8051612c2c816125ab565b919050565b60006101208284031215612c4457600080fd5b612c4c6126f6565b825181526020830151602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c0820152612c9860e08401612c21565b60e0820152610100928301519281019290925250919050565b634e487b7160e01b600052601160045260246000fd5b80820180821115611dae57611dae612cb1565b600060208284031215612cec57600080fd5b8151611576816125ab565b93845260208401929092526001600160a01b03908116604084015216606082015260800190565b60008060408385031215612d3157600080fd5b505080516020909101519092909150565b600060208284031215612d5457600080fd5b5051919050565b600181815b80851115612d96578160001904821115612d7c57612d7c612cb1565b80851615612d8957918102915b93841c9390800290612d60565b509250929050565b600082612dad57506001611dae565b81612dba57506000611dae565b8160018114612dd05760028114612dda57612df6565b6001915050611dae565b60ff841115612deb57612deb612cb1565b50506001821b611dae565b5060208310610133831016604e8410600b8410161715612e19575081810a611dae565b612e238383612d5b565b8060001904821115612e3757612e37612cb1565b029392505050565b6000611dab8383612d9e565b81810381811115611dae57611dae612cb1565b600060808284031215612e7057600080fd5b6040516080810181811067ffffffffffffffff82111715612e9357612e936126e0565b6040528235612ea1816125ab565b808252506020830135602082015260408301356040820152606083013560608201528091505092915050565b60208152612ee76020820183516001600160a01b03169052565b60006020830151612f0360408401826001600160a01b03169052565b506040830151612f3d606084018280516001600160a01b031682526020808201519083015260408082015190830152606090810151910152565b50606083015160e08301526080830151610100818185015260a08501519150610120612f73818601846001600160a01b03169052565b60c086015161014086015260e08601516101608601528186015192506101a0915081610180860152612fa96101c08601846128df565b90860151858203601f190183870152909250612fc583826128df565b9695505050505050565b600082601f830112612fe057600080fd5b8151612fee6127aa82612774565b81815284602083860101111561300357600080fd5b61155e8260208301602087016128bb565b600067ffffffffffffffff82111561302e5761302e6126e0565b5060051b60200190565b60008060006060848603121561304d57600080fd5b8351925060208085015167ffffffffffffffff8082111561306d57600080fd5b61307988838901612fcf565b9450604087015191508082111561308f57600080fd5b818701915087601f8301126130a357600080fd5b81516130b16127aa82613014565b81815260059190911b8301840190848101908a8311156130d057600080fd5b8585015b83811015613158578051858111156130ec5760008081fd5b86016060818e03601f190112156131035760008081fd5b61310b612720565b88820151613118816125ab565b81526040820151898201526060820151878111156131365760008081fd5b6131448f8b83860101612fcf565b6040830152508452509186019186016130d4565b508096505050505050509250925092565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561319157600080fd5b81516003811061157657600080fd5b634e487b7160e01b600052602160045260246000fd5b602081526131d06020820183516001600160a01b03169052565b600060208301516131ec60408401826001600160a01b03169052565b506040830151606083015260608301516080830152608083015160a083015260a083015160c083015260c083015160e083015260e083015161010061325a8185018380516001600160a01b031682526020808201519083015260408082015190830152606090810151910152565b8401511515610180840152506101208301516101a08301526101408301516101e06101c084018190526132916102008501836128df565b9150610160850151601f198584030182860152612fc583826128df565b6000806000606084860312156132c357600080fd5b8351925060208085015167ffffffffffffffff808211156132e357600080fd5b6132ef88838901612fcf565b9450604087015191508082111561330557600080fd5b818701915087601f83011261331957600080fd5b81516133276127aa82613014565b81815260059190911b8301840190848101908a83111561334657600080fd5b8585015b83811015613158578051858111156133625760008081fd5b86016060818e03601f190112156133795760008081fd5b613381612720565b8882015161338e816125ab565b81526040820151898201526060820151878111156133ac5760008081fd5b6133ba8f8b83860101612fcf565b60408301525084525091860191860161334a565b634e487b7160e01b600052601260045260246000fd5b600060208083850312156133f757600080fd5b825167ffffffffffffffff81111561340e57600080fd5b8301601f8101851361341f57600080fd5b805161342d6127aa82613014565b81815260059190911b8201830190838101908783111561344c57600080fd5b928401925b8284101561237c578351613464816125ab565b82529284019290840190613451565b600081600019048311821515161561348d5761348d612cb1565b500290565b6000826134af57634e487b7160e01b600052601260045260246000fd5b50049056fea26469706673582212207c0b0d6ef21a30936e47f919249183a609014eddc061713ac513cccd6177f36164736f6c63430008100033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100ff5760003560e01c8063c294b2f411610097578063d49031c011610066578063d49031c014610295578063d4c3a8d2146102a8578063e7c8e3e3146102d9578063e8ba563a146102ee57600080fd5b8063c294b2f414610221578063c41c2f2414610234578063c66445971461025b578063d3419bf31461026e57600080fd5b80636bb6a5ad116100d35780636bb6a5ad146101c5578063a2df1f95146101d8578063a57c7f59146101fb578063b753d7e91461020e57600080fd5b8062fdd58e1461010457806325386715146101425780632fa1b39114610163578063557e715514610186575b600080fd5b61012f6101123660046125c3565b600160209081526000928352604080842090915290825290205481565b6040519081526020015b60405180910390f35b6101556101503660046125ef565b61031f565b60405161013992919061267a565b6101766101713660046127fa565b6107f5565b604051610139949392919061290b565b6101ad7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610139565b61012f6101d33660046129bd565b610cc5565b6101eb6101e63660046129d6565b610dd2565b6040516101399493929190612a77565b61012f610209366004612b12565b61149c565b61012f61021c3660046125ef565b611566565b61012f61022f366004612b44565b61157d565b6101ad7f000000000000000000000000000000000000000000000000000000000000000081565b6101556102693660046125ef565b611892565b6101ad7f000000000000000000000000000000000000000000000000000000000000000081565b61012f6102a33660046125c3565b611cd6565b61012f6102b6366004612b93565b600360209081526000938452604080852082529284528284209052825290205481565b6102ec6102e7366004612bc8565b611db4565b005b61012f6102fc366004612b93565b600260209081526000938452604080852082529284528284209052825290205481565b610327612556565b60006002600054036103545760405162461bcd60e51b815260040161034b90612bea565b60405180910390fd5b60026000556040516321d1336160e11b8152600481018690527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906343a266c29060240161012060405180830381865afa1580156103bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103e39190612c31565b336000908152600360209081526040808320898452825280832082850151845290915281205491935090610418908690612cc7565b90506000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635dd8f6aa896040518263ffffffff1660e01b815260040161046b91815260200190565b602060405180830381865afa158015610488573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104ac9190612cda565b6001600160a01b031663a29a68146040518163ffffffff1660e01b8152600401602060405180830381865afa1580156104e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061050d9190612cda565b6001600160a01b0316637a81b56289876020015133336001600160a01b031663fc0c546a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610560573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105849190612cda565b6040518563ffffffff1660e01b81526004016105a39493929190612cf7565b6040805180830381865afa1580156105bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105e39190612d1e565b91509150818311806105f3575081155b1561061157604051635b76558960e11b815260040160405180910390fd5b8086146106315760405163e56ea4e760e01b815260040160405180910390fd5b6000336001600160a01b031663e5a6b10f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610671573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106959190612d42565b90508087146107505761074b886106ae6012600a612e3f565b604051635268657960e11b8152600481018b905260248101859052601260448201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a4d0caf2906064015b602060405180830381865afa158015610722573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107469190612d42565b611dfd565b610752565b875b9450610760338a8884611eca565b851115610780576040516317e53f6760e11b815260040160405180910390fd5b3360008181526003602090815260408083208d845282528083208a83015184528252808320889055928252600181528282208c8352905220546107c4908690612e4b565b3360009081526001602081815260408084209d84529c90529a81209190915598909855509296919550909350505050565b6107fd612556565b60006060806002600054036108245760405162461bcd60e51b815260040161034b90612bea565b60026000556040516321d1336160e11b8152600481018b90527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906343a266c29060240161012060405180830381865afa15801561088f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108b39190612c31565b80519094506000036108d85760405163174b338d60e11b815260040160405180910390fd5b61010084015160481c6001908116036109045760405163a3bb913360e01b815260040160405180910390fd5b61010084015160009060521c600190811614801561093a5750600061092e86610100015160541c90565b6001600160a01b031614155b15610a8c576000604051806101400160405280336001600160a01b031681526020018f6001600160a01b031681526020018e80360381019061097c9190612e5e565b815260208082018f905288015160408201526001600160a01b038c16606082015260a080890151608083015261010089015191019060181c61ffff1681526020018a8a8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050908252506020018890529050610a0d86610100015160541c90565b6001600160a01b031663d46cf171826040518263ffffffff1660e01b8152600401610a389190612ecd565b6000604051808303816000875af1158015610a57573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610a7f9190810190613038565b955093509150610acd9050565b8460a00151905087878080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509294505050505b825160208d01359015610b495760005b8451811015610b47576000858281518110610afa57610afa613169565b602002602001015160200151905080600014610b3e5782811115610b31576040516336a8da9360e11b815260040160405180910390fd5b610b3b8184612e4b565b92505b50600101610add565b505b8c60200135600003610b61575060009350610cae9050565b8015610bc8573360009081526001602090815260408083208f8452909152902054610b8d908290612cc7565b60016000336001600160a01b03166001600160a01b0316815260200190815260200160002060008e8152602001908152602001600020819055505b5080600003610bdb575060009250610cae565b60408c0135600060608e01358c14610c8c57604051635268657960e11b815260608f01356004820152602481018d9052604481018390526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063a4d0caf290606401602060405180830381865afa158015610c63573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c879190612d42565b610c97565b610c9782600a612e3f565b9050610ca88e602001358483611dfd565b95505050505b600160008190555098509850985098945050505050565b6000600260005403610ce95760405162461bcd60e51b815260040161034b90612bea565b600260009081556040516321d1336160e11b8152600481018490527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906343a266c29060240161012060405180830381865afa158015610d56573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d7a9190612c31565b610100810151909150604d1c600190811614610da9576040516373e4f05f60e11b815260040160405180910390fd5b505033600090815260016020818152604080842094845293905291812080549082905591905590565b610dda612556565b6000606080600260005403610e015760405162461bcd60e51b815260040161034b90612bea565b60026000556040516321d1336160e11b8152600481018990527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906343a266c29060240161012060405180830381865afa158015610e6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e909190612c31565b610100810151909450604a1c600190811603610ebf5760405163a97cf58f60e01b815260040160405180910390fd5b610ef3604051806080016040528060006001600160a01b031681526020016000815260200160008152602001600081525090565b6000806000336001600160a01b031663fc0c546a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f5a9190612cda565b90506000336001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f9c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fc09190612d42565b90506000336001600160a01b031663e5a6b10f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611002573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110269190612d42565b6101008b015190915060511c60019081161461104d57611048338f8c84611eca565b611058565b6110588e83836121a5565b94507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635dd8f6aa8f6040518263ffffffff1660e01b81526004016110a891815260200190565b602060405180830381865afa1580156110c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110e99190612cda565b6001600160a01b031663c18f2d318f6040518263ffffffff1660e01b815260040161111691815260200190565b602060405180830381865afa158015611133573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111579190612d42565b9350838d111561117957604051625c579160e91b815260040160405180910390fd5b841561118f5761118c8e8b8f8789612387565b98505b604080516080810182526001600160a01b03949094168452602084018a9052830191909152606082015261010088015190935060531c60019081161480156111ef575060006111e388610100015160541c90565b6001600160a01b031614155b156113c657604051633157d5c760e21b8152600481018c90526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063c55f571c90602401602060405180830381865afa15801561125c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611280919061317f565b90506000604051806101800160405280336001600160a01b031681526020018f6001600160a01b031681526020018e81526020018a6020015181526020018d81526020018481526020018581526020018681526020016112ed8b6101000151600160519190911c81161490565b151581526020016000846002811115611308576113086131a0565b1461131b576113168b6124bf565b611324565b6113248b6124dc565b81526020018c81526020018b815250905061134489610100015160541c90565b6001600160a01b031663a51cfd18826040518263ffffffff1660e01b815260040161136f91906131b6565b6000604051808303816000875af115801561138e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526113b691908101906132ae565b91995090975095506113ca915050565b8893505b50508251849150156114245760005b83518110156114225760008482815181106113f6576113f6613169565b602002602001015160200151905080600014611419576114168184612cc7565b92505b506001016113d9565b505b3360009081526001602090815260408083208c845290915290205481111561145f576040516317e53f6760e11b815260040160405180910390fd5b8015611487573360009081526001602090815260408083208c84529091529020805482900390555b50600160008190555095509550955095915050565b6000816000036114ae5750600061155e565b828411156114be5750600061155e565b6040516321d1336160e11b8152600481018690526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906343a266c29060240161012060405180830381865afa158015611527573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061154b9190612c31565b905061155a8682878787612387565b9150505b949350505050565b60006115738484846121a5565b90505b9392505050565b6040516321d1336160e11b81526004810184905260009081906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906343a266c29060240161012060405180830381865afa1580156115e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061160c9190612c31565b9050600083611687576116828787848a6001600160a01b031663e5a6b10f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611659573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061167d9190612d42565b611eca565b611754565b61175486886001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156116c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116ed9190612d42565b896001600160a01b031663e5a6b10f6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561172b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061174f9190612d42565b6121a5565b9050806000036117695760009250505061155e565b604051632eec7b5560e11b8152600481018790526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635dd8f6aa90602401602060405180830381865afa1580156117d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117f59190612cda565b6001600160a01b031663c18f2d31886040518263ffffffff1660e01b815260040161182291815260200190565b602060405180830381865afa15801561183f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118639190612d42565b905080861115611879576000935050505061155e565b6118868784888486612387565b98975050505050505050565b61189a612556565b60006002600054036118be5760405162461bcd60e51b815260040161034b90612bea565b60026000556040516321d1336160e11b8152600481018690527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906343a266c29060240161012060405180830381865afa158015611929573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061194d9190612c31565b61010081015190925060491c60019081160361197c5760405163861e9dcd60e01b815260040160405180910390fd5b3360009081526002602090815260408083208884528252808320855184529091528120546119ab908690612cc7565b90506000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635dd8f6aa896040518263ffffffff1660e01b81526004016119fe91815260200190565b602060405180830381865afa158015611a1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a3f9190612cda565b6001600160a01b031663a29a68146040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aa09190612cda565b6001600160a01b031663e8db213089876020015133336001600160a01b031663fc0c546a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611af3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b179190612cda565b6040518563ffffffff1660e01b8152600401611b369493929190612cf7565b6040805180830381865afa158015611b52573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b769190612d1e565b9150915081831180611b86575081155b15611ba457604051630236b92b60e21b815260040160405180910390fd5b808614611bc45760405163e56ea4e760e01b815260040160405180910390fd5b6000336001600160a01b031663e5a6b10f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611c04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c289190612d42565b9050808714611c4657611c41886106ae6012600a612e3f565b611c48565b875b3360009081526001602090815260408083208d8452909152902054909550851115611c86576040516317e53f6760e11b815260040160405180910390fd5b50503360008181526002602090815260408083208b845282528083208851845282528083209590955591815260018083528482209982529890915291822080548490039055509490945593915050565b6000611dab83837f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166343a266c2866040518263ffffffff1660e01b8152600401611d2b91815260200190565b61012060405180830381865afa158015611d49573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d6d9190612c31565b866001600160a01b031663e5a6b10f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611659573d6000803e3d6000fd5b90505b92915050565b336000908152600160209081526040808320858452909152902054611dda908290612cc7565b336000908152600160209081526040808320958352949052929092209190915550565b6000808060001985870985870292508281108382030391505080600003611e3757838281611e2d57611e2d6133ce565b0492505050611576565b838110611e6157604051631dcf306360e21b8152600481018290526024810185905260440161034b565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b6001600160a01b0384166000908152600160209081526040808320868452909152812054808203611eff57600091505061155e565b604051632eec7b5560e11b81526004810186905260009081906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690635dd8f6aa90602401602060405180830381865afa158015611f69573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f8d9190612cda565b6001600160a01b031663a29a68146040518163ffffffff1660e01b8152600401602060405180830381865afa158015611fca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fee9190612cda565b6001600160a01b031663e8db21308888602001518b8c6001600160a01b031663fc0c546a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612041573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120659190612cda565b6040518563ffffffff1660e01b81526004016120849493929190612cf7565b6040805180830381865afa1580156120a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120c49190612d1e565b6001600160a01b038a1660009081526002602090815260408083208c845282528083208b518452909152812054929450909250906121029084612e4b565b905080158015906121135750858214155b1561218657612183816121286012600a612e3f565b604051635268657960e11b815260048101869052602481018a9052601260448201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a4d0caf290606401610705565b90505b808411612194576000612198565b8084035b9998505050505050505050565b60405163d175415360e01b81526004810184905260009081906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063d175415390602401600060405180830381865afa15801561220f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261223791908101906133e4565b90506000805b82518110156122e25782818151811061225857612258613169565b60200260200101516001600160a01b031663a32e1e96886040518263ffffffff1660e01b815260040161228d91815260200190565b602060405180830381865afa1580156122aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122ce9190612d42565b6122d89083612cc7565b915060010161223d565b5060006001851461235d57604051635268657960e11b8152600160048201526024810186905260126044820152612358908390670de0b6b3a7640000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063a4d0caf290606401610705565b61235f565b815b90508560121461237a57612375816012886124f9565b61237c565b805b979650505050505050565b60008284036123975750806124b6565b600080604051633157d5c760e21b8152600481018990527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063c55f571c90602401602060405180830381865afa1580156123ff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612423919061317f565b6002811115612434576124346131a0565b1461244757612442866124bf565b612450565b612450866124dc565b9050806000036124645760009150506124b6565b6000612471848787611dfd565b905061271082036124855791506124b69050565b6124b18161249f8861249986612710612e4b565b89611dfd565b6124a99085612cc7565b612710611dfd565b925050505b95945050505050565b60006028826101000151901c61ffff16612710611dae9190612e4b565b60006038826101000151901c61ffff16612710611dae9190612e4b565b6000828203612509575082611576565b828211156125375761251b8383612e4b565b61252690600a612e3f565b6125309085613473565b9050611576565b6125418284612e4b565b61254c90600a612e3f565b6125309085613492565b6040518061012001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b03168152602001600081525090565b6001600160a01b03811681146125c057600080fd5b50565b600080604083850312156125d657600080fd5b82356125e1816125ab565b946020939093013593505050565b60008060006060848603121561260457600080fd5b505081359360208301359350604090920135919050565b805182526020808201519083015260408082015190830152606080820151908301526080808201519083015260a0808201519083015260c0808201519083015260e0808201516001600160a01b03169083015261010090810151910152565b6101408101612689828561261b565b826101208301529392505050565b60008083601f8401126126a957600080fd5b50813567ffffffffffffffff8111156126c157600080fd5b6020830191508360208285010111156126d957600080fd5b9250929050565b634e487b7160e01b600052604160045260246000fd5b604051610120810167ffffffffffffffff8111828210171561271a5761271a6126e0565b60405290565b6040516060810167ffffffffffffffff8111828210171561271a5761271a6126e0565b604051601f8201601f1916810167ffffffffffffffff8111828210171561276c5761276c6126e0565b604052919050565b600067ffffffffffffffff82111561278e5761278e6126e0565b50601f01601f191660200190565b60006127af6127aa84612774565b612743565b90508281528383830111156127c357600080fd5b828260208301376000602084830101529392505050565b600082601f8301126127eb57600080fd5b611dab8383356020850161279c565b600080600080600080600080888a0361014081121561281857600080fd5b8935612823816125ab565b98506080601f198201121561283757600080fd5b5060208901965060a0890135955060c0890135945060e089013561285a816125ab565b935061010089013567ffffffffffffffff8082111561287857600080fd5b6128848c838d01612697565b90955093506101208b013591508082111561289e57600080fd5b506128ab8b828c016127da565b9150509295985092959890939650565b60005b838110156128d65781810151838201526020016128be565b50506000910152565b600081518084526128f78160208601602086016128bb565b601f01601f19169290920160200192915050565b600061018080830161291d848961261b565b61012084018790526101408401919091528451908190526101a080840191600581901b850190910190602080880160005b838110156129a65787850361019f19018652815180516001600160a01b031686528381015184870152604090810151606091870182905290612992818801836128df565b97850197965050509082019060010161294e565b505050508381036101608501526124b181866128df565b6000602082840312156129cf57600080fd5b5035919050565b600080600080600060a086880312156129ee57600080fd5b85356129f9816125ab565b94506020860135935060408601359250606086013567ffffffffffffffff80821115612a2457600080fd5b818801915088601f830112612a3857600080fd5b612a478983356020850161279c565b93506080880135915080821115612a5d57600080fd5b50612a6a888289016127da565b9150509295509295909350565b6000610180808301612a89848961261b565b61012084018790526101408401919091528451908190526101a080840191600581901b850190910190602080880160005b838110156129a65787850361019f19018652815180516001600160a01b031686528381015184870152604090810151606091870182905290612afe818801836128df565b978501979650505090820190600101612aba565b60008060008060808587031215612b2857600080fd5b5050823594602084013594506040840135936060013592509050565b60008060008060808587031215612b5a57600080fd5b8435612b65816125ab565b9350602085013592506040850135915060608501358015158114612b8857600080fd5b939692955090935050565b600080600060608486031215612ba857600080fd5b8335612bb3816125ab565b95602085013595506040909401359392505050565b60008060408385031215612bdb57600080fd5b50508035926020909101359150565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b8051612c2c816125ab565b919050565b60006101208284031215612c4457600080fd5b612c4c6126f6565b825181526020830151602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c0820152612c9860e08401612c21565b60e0820152610100928301519281019290925250919050565b634e487b7160e01b600052601160045260246000fd5b80820180821115611dae57611dae612cb1565b600060208284031215612cec57600080fd5b8151611576816125ab565b93845260208401929092526001600160a01b03908116604084015216606082015260800190565b60008060408385031215612d3157600080fd5b505080516020909101519092909150565b600060208284031215612d5457600080fd5b5051919050565b600181815b80851115612d96578160001904821115612d7c57612d7c612cb1565b80851615612d8957918102915b93841c9390800290612d60565b509250929050565b600082612dad57506001611dae565b81612dba57506000611dae565b8160018114612dd05760028114612dda57612df6565b6001915050611dae565b60ff841115612deb57612deb612cb1565b50506001821b611dae565b5060208310610133831016604e8410600b8410161715612e19575081810a611dae565b612e238383612d5b565b8060001904821115612e3757612e37612cb1565b029392505050565b6000611dab8383612d9e565b81810381811115611dae57611dae612cb1565b600060808284031215612e7057600080fd5b6040516080810181811067ffffffffffffffff82111715612e9357612e936126e0565b6040528235612ea1816125ab565b808252506020830135602082015260408301356040820152606083013560608201528091505092915050565b60208152612ee76020820183516001600160a01b03169052565b60006020830151612f0360408401826001600160a01b03169052565b506040830151612f3d606084018280516001600160a01b031682526020808201519083015260408082015190830152606090810151910152565b50606083015160e08301526080830151610100818185015260a08501519150610120612f73818601846001600160a01b03169052565b60c086015161014086015260e08601516101608601528186015192506101a0915081610180860152612fa96101c08601846128df565b90860151858203601f190183870152909250612fc583826128df565b9695505050505050565b600082601f830112612fe057600080fd5b8151612fee6127aa82612774565b81815284602083860101111561300357600080fd5b61155e8260208301602087016128bb565b600067ffffffffffffffff82111561302e5761302e6126e0565b5060051b60200190565b60008060006060848603121561304d57600080fd5b8351925060208085015167ffffffffffffffff8082111561306d57600080fd5b61307988838901612fcf565b9450604087015191508082111561308f57600080fd5b818701915087601f8301126130a357600080fd5b81516130b16127aa82613014565b81815260059190911b8301840190848101908a8311156130d057600080fd5b8585015b83811015613158578051858111156130ec5760008081fd5b86016060818e03601f190112156131035760008081fd5b61310b612720565b88820151613118816125ab565b81526040820151898201526060820151878111156131365760008081fd5b6131448f8b83860101612fcf565b6040830152508452509186019186016130d4565b508096505050505050509250925092565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561319157600080fd5b81516003811061157657600080fd5b634e487b7160e01b600052602160045260246000fd5b602081526131d06020820183516001600160a01b03169052565b600060208301516131ec60408401826001600160a01b03169052565b506040830151606083015260608301516080830152608083015160a083015260a083015160c083015260c083015160e083015260e083015161010061325a8185018380516001600160a01b031682526020808201519083015260408082015190830152606090810151910152565b8401511515610180840152506101208301516101a08301526101408301516101e06101c084018190526132916102008501836128df565b9150610160850151601f198584030182860152612fc583826128df565b6000806000606084860312156132c357600080fd5b8351925060208085015167ffffffffffffffff808211156132e357600080fd5b6132ef88838901612fcf565b9450604087015191508082111561330557600080fd5b818701915087601f83011261331957600080fd5b81516133276127aa82613014565b81815260059190911b8301840190848101908a83111561334657600080fd5b8585015b83811015613158578051858111156133625760008081fd5b86016060818e03601f190112156133795760008081fd5b613381612720565b8882015161338e816125ab565b81526040820151898201526060820151878111156133ac5760008081fd5b6133ba8f8b83860101612fcf565b60408301525084525091860191860161334a565b634e487b7160e01b600052601260045260246000fd5b600060208083850312156133f757600080fd5b825167ffffffffffffffff81111561340e57600080fd5b8301601f8101851361341f57600080fd5b805161342d6127aa82613014565b81815260059190911b8201830190838101908783111561344c57600080fd5b928401925b8284101561237c578351613464816125ab565b82529284019290840190613451565b600081600019048311821515161561348d5761348d612cb1565b500290565b6000826134af57634e487b7160e01b600052601260045260246000fd5b50049056fea26469706673582212207c0b0d6ef21a30936e47f919249183a609014eddc061713ac513cccd6177f36164736f6c63430008100033", + "devdoc": { + "details": "This Store expects a project's controller to be an IJBController3_1.", + "kind": "dev", + "methods": { + "constructor": { + "params": { + "_directory": "A contract storing directories of terminals and controllers for each project.", + "_fundingCycleStore": "A contract storing all funding cycle configurations.", + "_prices": "A contract that exposes price feeds." + } + }, + "currentOverflowOf(address,uint256)": { + "details": "The current overflow is represented as a fixed point number with the same amount of decimals as the specified terminal.", + "params": { + "_projectId": "The ID of the project to get overflow for.", + "_terminal": "The terminal for which the overflow is being calculated." + }, + "returns": { + "_0": "The current amount of overflow that project has in the specified terminal." + } + }, + "currentReclaimableOverflowOf(address,uint256,uint256,bool)": { + "details": "If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.The current reclaimable overflow is returned in terms of the specified terminal's currency.The reclaimable overflow is represented as a fixed point number with the same amount of decimals as the specified terminal.", + "params": { + "_projectId": "The ID of the project to get the reclaimable overflow amount for.", + "_terminal": "The terminal from which the reclaimable amount would come.", + "_tokenCount": "The number of tokens to make the calculation with, as a fixed point number with 18 decimals.", + "_useTotalOverflow": "A flag indicating whether the overflow used in the calculation should be summed from all of the project's terminals. If false, overflow should be limited to the amount in the specified `_terminal`." + }, + "returns": { + "_0": "The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_terminal`." + } + }, + "currentReclaimableOverflowOf(uint256,uint256,uint256,uint256)": { + "details": "If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.", + "params": { + "_overflow": "The amount of overflow to make the calculation with, as a fixed point number.", + "_projectId": "The ID of the project to get the reclaimable overflow amount for.", + "_tokenCount": "The number of tokens to make the calculation with, as a fixed point number with 18 decimals.", + "_totalSupply": "The total number of tokens to make the calculation with, as a fixed point number with 18 decimals." + }, + "returns": { + "_0": "The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_overflow`." + } + }, + "currentTotalOverflowOf(uint256,uint256,uint256)": { + "params": { + "_currency": "The currency that the total overflow should be in terms of.", + "_decimals": "The number of decimals that the fixed point overflow should include.", + "_projectId": "The ID of the project to get total overflow for." + }, + "returns": { + "_0": "The current total amount of overflow that project has across all terminals." + } + }, + "recordAddedBalanceFor(uint256,uint256)": { + "details": "The msg.sender must be an IJBSingleTokenPaymentTerminal.", + "params": { + "_amount": "The amount of terminal tokens added, as a fixed point number with the same amount of decimals as its relative terminal.", + "_projectId": "The ID of the project to which the funds being added belong." + } + }, + "recordDistributionFor(uint256,uint256,uint256)": { + "details": "The msg.sender must be an IJBSingleTokenPaymentTerminal.", + "params": { + "_amount": "The amount to use from the distribution limit, as a fixed point number.", + "_currency": "The currency of the `_amount`. This must match the project's current funding cycle's currency.", + "_projectId": "The ID of the project that is having funds distributed." + }, + "returns": { + "distributedAmount": "The amount of terminal tokens distributed, as a fixed point number with the same amount of decimals as its relative terminal.", + "fundingCycle": "The funding cycle during which the distribution was made." + } + }, + "recordMigration(uint256)": { + "details": "The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount returned is in terms of the msg.senders tokens.", + "params": { + "_projectId": "The ID of the project being migrated." + }, + "returns": { + "balance": "The project's migrated balance, as a fixed point number with the same amount of decimals as its relative terminal." + } + }, + "recordPaymentFrom(address,(address,uint256,uint256,uint256),uint256,uint256,address,string,bytes)": { + "details": "Mints the project's tokens according to values provided by a configured data source. If no data source is configured, mints tokens proportional to the amount of the contribution.The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.sender's tokens.", + "params": { + "_amount": "The amount of tokens being paid. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.", + "_baseWeightCurrency": "The currency to base token issuance on.", + "_beneficiary": "The specified address that should be the beneficiary of anything that results from the payment.", + "_memo": "A memo to pass along to the emitted event, and passed along to the funding cycle's data source.", + "_metadata": "Bytes to send along to the data source, if one is provided.", + "_payer": "The original address that sent the payment to the terminal.", + "_projectId": "The ID of the project being paid." + }, + "returns": { + "delegateAllocations": "The amount to send to delegates instead of adding to the local balance.", + "fundingCycle": "The project's funding cycle during which payment was made.", + "memo": "A memo that should be passed along to the emitted event.", + "tokenCount": "The number of project tokens that were minted, as a fixed point number with 18 decimals." + } + }, + "recordRedemptionFor(address,uint256,uint256,string,bytes)": { + "details": "Redeems the project's tokens according to values provided by a configured data source. If no data source is configured, redeems tokens along a redemption bonding curve that is a function of the number of tokens being burned.The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.senders tokens.", + "params": { + "_holder": "The account that is having its tokens redeemed.", + "_memo": "A memo to pass along to the emitted event.", + "_metadata": "Bytes to send along to the data source, if one is provided.", + "_projectId": "The ID of the project to which the tokens being redeemed belong.", + "_tokenCount": "The number of project tokens to redeem, as a fixed point number with 18 decimals." + }, + "returns": { + "delegateAllocations": "The amount to send to delegates instead of sending to the beneficiary.", + "fundingCycle": "The funding cycle during which the redemption was made.", + "memo": "A memo that should be passed along to the emitted event.", + "reclaimAmount": "The amount of terminal tokens reclaimed, as a fixed point number with 18 decimals." + } + }, + "recordUsedAllowanceOf(uint256,uint256,uint256)": { + "details": "The msg.sender must be an IJBSingleTokenPaymentTerminal.", + "params": { + "_amount": "The amount to use from the allowance, as a fixed point number.", + "_currency": "The currency of the `_amount`. Must match the currency of the overflow allowance.", + "_projectId": "The ID of the project to use the allowance of." + }, + "returns": { + "fundingCycle": "The funding cycle during which the overflow allowance is being used.", + "usedAmount": "The amount of terminal tokens used, as a fixed point number with the same amount of decimals as its relative terminal." + } + } + }, + "stateVariables": { + "balanceOf": { + "custom:param": "_terminal The terminal to which the balance applies._projectId The ID of the project to get the balance of.", + "details": "The balance is represented as a fixed point number with the same amount of decimals as its relative terminal." + }, + "usedDistributionLimitOf": { + "custom:param": "_terminal The terminal to which the used distribution limit applies._projectId The ID of the project to get the used distribution limit of._fundingCycleNumber The number of the funding cycle during which the distribution limit was used.", + "details": "Increases as projects use their preconfigured distribution limits.The used distribution limit is represented as a fixed point number with the same amount of decimals as its relative terminal." + }, + "usedOverflowAllowanceOf": { + "custom:param": "_terminal The terminal to which the overflow allowance applies._projectId The ID of the project to get the used overflow allowance of._configuration The configuration of the during which the allowance was used.", + "details": "Increases as projects use their allowance.The used allowance is represented as a fixed point number with the same amount of decimals as its relative terminal." + } + }, + "version": 1 + }, + "userdoc": { + "errors": { + "PRBMath__MulDivOverflow(uint256,uint256)": [ + { + "notice": "Emitted when the result overflows uint256." + } + ] + }, + "kind": "user", + "methods": { + "balanceOf(address,uint256)": { + "notice": "The amount of tokens that each project has for each terminal, in terms of the terminal's token." + }, + "currentOverflowOf(address,uint256)": { + "notice": "Gets the current overflowed amount in a terminal for a specified project." + }, + "currentReclaimableOverflowOf(address,uint256,uint256,bool)": { + "notice": "The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the total token supply and overflow in the ecosystem." + }, + "currentReclaimableOverflowOf(uint256,uint256,uint256,uint256)": { + "notice": "The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the specified total token supply and overflow amounts." + }, + "currentTotalOverflowOf(uint256,uint256,uint256)": { + "notice": "Gets the current overflowed amount for a specified project across all terminals." + }, + "directory()": { + "notice": "The directory of terminals and controllers for projects." + }, + "fundingCycleStore()": { + "notice": "The contract storing all funding cycle configurations." + }, + "prices()": { + "notice": "The contract that exposes price feeds." + }, + "recordAddedBalanceFor(uint256,uint256)": { + "notice": "Records newly added funds for the project." + }, + "recordDistributionFor(uint256,uint256,uint256)": { + "notice": "Records newly distributed funds for a project." + }, + "recordMigration(uint256)": { + "notice": "Records the migration of funds from this store." + }, + "recordPaymentFrom(address,(address,uint256,uint256,uint256),uint256,uint256,address,string,bytes)": { + "notice": "Records newly contributed tokens to a project." + }, + "recordRedemptionFor(address,uint256,uint256,string,bytes)": { + "notice": "Records newly redeemed tokens of a project." + }, + "recordUsedAllowanceOf(uint256,uint256,uint256)": { + "notice": "Records newly used allowance funds of a project." + }, + "usedDistributionLimitOf(address,uint256,uint256)": { + "notice": "The amount of funds that a project has distributed from its limit during the current funding cycle for each terminal, in terms of the distribution limit's currency." + }, + "usedOverflowAllowanceOf(address,uint256,uint256)": { + "notice": "The amount of funds that a project has used from its allowance during the current funding cycle configuration for each terminal, in terms of the overflow allowance's currency." + } + }, + "notice": "Manages all bookkeeping for inflows and outflows of funds from any ISingleTokenPaymentTerminal.", + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 773, + "contract": "contracts/JBSingleTokenPaymentTerminalStore3_1_1.sol:JBSingleTokenPaymentTerminalStore3_1_1", + "label": "_status", + "offset": 0, + "slot": "0", + "type": "t_uint256" + }, + { + "astId": 19905, + "contract": "contracts/JBSingleTokenPaymentTerminalStore3_1_1.sol:JBSingleTokenPaymentTerminalStore3_1_1", + "label": "balanceOf", + "offset": 0, + "slot": "1", + "type": "t_mapping(t_contract(IJBSingleTokenPaymentTerminal)34671,t_mapping(t_uint256,t_uint256))" + }, + { + "astId": 19916, + "contract": "contracts/JBSingleTokenPaymentTerminalStore3_1_1.sol:JBSingleTokenPaymentTerminalStore3_1_1", + "label": "usedDistributionLimitOf", + "offset": 0, + "slot": "2", + "type": "t_mapping(t_contract(IJBSingleTokenPaymentTerminal)34671,t_mapping(t_uint256,t_mapping(t_uint256,t_uint256)))" + }, + { + "astId": 19927, + "contract": "contracts/JBSingleTokenPaymentTerminalStore3_1_1.sol:JBSingleTokenPaymentTerminalStore3_1_1", + "label": "usedOverflowAllowanceOf", + "offset": 0, + "slot": "3", + "type": "t_mapping(t_contract(IJBSingleTokenPaymentTerminal)34671,t_mapping(t_uint256,t_mapping(t_uint256,t_uint256)))" + } + ], + "types": { + "t_contract(IJBSingleTokenPaymentTerminal)34671": { + "encoding": "inplace", + "label": "contract IJBSingleTokenPaymentTerminal", + "numberOfBytes": "20" + }, + "t_mapping(t_contract(IJBSingleTokenPaymentTerminal)34671,t_mapping(t_uint256,t_mapping(t_uint256,t_uint256)))": { + "encoding": "mapping", + "key": "t_contract(IJBSingleTokenPaymentTerminal)34671", + "label": "mapping(contract IJBSingleTokenPaymentTerminal => mapping(uint256 => mapping(uint256 => uint256)))", + "numberOfBytes": "32", + "value": "t_mapping(t_uint256,t_mapping(t_uint256,t_uint256))" + }, + "t_mapping(t_contract(IJBSingleTokenPaymentTerminal)34671,t_mapping(t_uint256,t_uint256))": { + "encoding": "mapping", + "key": "t_contract(IJBSingleTokenPaymentTerminal)34671", + "label": "mapping(contract IJBSingleTokenPaymentTerminal => mapping(uint256 => uint256))", + "numberOfBytes": "32", + "value": "t_mapping(t_uint256,t_uint256)" + }, + "t_mapping(t_uint256,t_mapping(t_uint256,t_uint256))": { + "encoding": "mapping", + "key": "t_uint256", + "label": "mapping(uint256 => mapping(uint256 => uint256))", + "numberOfBytes": "32", + "value": "t_mapping(t_uint256,t_uint256)" + }, + "t_mapping(t_uint256,t_uint256)": { + "encoding": "mapping", + "key": "t_uint256", + "label": "mapping(uint256 => uint256)", + "numberOfBytes": "32", + "value": "t_uint256" + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + } + } + } +} \ No newline at end of file diff --git a/deployments/sepolia/solcInputs/11cb1f66a0f8213d7bf83deb0ae9d2f7.json b/deployments/sepolia/solcInputs/11cb1f66a0f8213d7bf83deb0ae9d2f7.json new file mode 100644 index 000000000..45acfbc43 --- /dev/null +++ b/deployments/sepolia/solcInputs/11cb1f66a0f8213d7bf83deb0ae9d2f7.json @@ -0,0 +1,461 @@ +{ + "language": "Solidity", + "sources": { + "contracts/abstract/JBControllerUtility.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {IJBControllerUtility} from './../interfaces/IJBControllerUtility.sol';\nimport {IJBDirectory} from './../interfaces/IJBDirectory.sol';\n\n/// @notice Provides tools for contracts with functionality that can only be accessed by a project's controller.\nabstract contract JBControllerUtility is IJBControllerUtility {\n //*********************************************************************//\n // --------------------------- custom errors -------------------------- //\n //*********************************************************************//\n error CONTROLLER_UNAUTHORIZED();\n\n //*********************************************************************//\n // ---------------------------- modifiers ---------------------------- //\n //*********************************************************************//\n\n /// @notice Only allows the controller of the specified project to proceed.\n /// @param _projectId The ID of the project.\n modifier onlyController(uint256 _projectId) {\n if (address(directory.controllerOf(_projectId)) != msg.sender) revert CONTROLLER_UNAUTHORIZED();\n _;\n }\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n constructor(IJBDirectory _directory) {\n directory = _directory;\n }\n}\n" + }, + "contracts/interfaces/IJBControllerUtility.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBDirectory} from './IJBDirectory.sol';\n\ninterface IJBControllerUtility {\n function directory() external view returns (IJBDirectory);\n}\n" + }, + "contracts/interfaces/IJBDirectory.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\nimport {IJBProjects} from './IJBProjects.sol';\n\ninterface IJBDirectory {\n event SetController(uint256 indexed projectId, address indexed controller, address caller);\n\n event AddTerminal(uint256 indexed projectId, IJBPaymentTerminal indexed terminal, address caller);\n\n event SetTerminals(uint256 indexed projectId, IJBPaymentTerminal[] terminals, address caller);\n\n event SetPrimaryTerminal(\n uint256 indexed projectId,\n address indexed token,\n IJBPaymentTerminal indexed terminal,\n address caller\n );\n\n event SetIsAllowedToSetFirstController(address indexed addr, bool indexed flag, address caller);\n\n function projects() external view returns (IJBProjects);\n\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\n\n function controllerOf(uint256 projectId) external view returns (address);\n\n function isAllowedToSetFirstController(address account) external view returns (bool);\n\n function terminalsOf(uint256 projectId) external view returns (IJBPaymentTerminal[] memory);\n\n function isTerminalOf(\n uint256 projectId,\n IJBPaymentTerminal terminal\n ) external view returns (bool);\n\n function primaryTerminalOf(\n uint256 projectId,\n address token\n ) external view returns (IJBPaymentTerminal);\n\n function setControllerOf(uint256 projectId, address controller) external;\n\n function setTerminalsOf(uint256 projectId, IJBPaymentTerminal[] calldata terminals) external;\n\n function setPrimaryTerminalOf(\n uint256 projectId,\n address token,\n IJBPaymentTerminal terminal\n ) external;\n\n function setIsAllowedToSetFirstController(address account, bool flag) external;\n}\n" + }, + "contracts/interfaces/IJBFundingCycleStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBBallotState} from './../enums/JBBallotState.sol';\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\nimport {JBFundingCycleData} from './../structs/JBFundingCycleData.sol';\n\ninterface IJBFundingCycleStore {\n event Configure(\n uint256 indexed configuration,\n uint256 indexed projectId,\n JBFundingCycleData data,\n uint256 metadata,\n uint256 mustStartAtOrAfter,\n address caller\n );\n\n event Init(uint256 indexed configuration, uint256 indexed projectId, uint256 indexed basedOn);\n\n function latestConfigurationOf(uint256 projectId) external view returns (uint256);\n\n function get(\n uint256 projectId,\n uint256 configuration\n ) external view returns (JBFundingCycle memory);\n\n function latestConfiguredOf(\n uint256 projectId\n ) external view returns (JBFundingCycle memory fundingCycle, JBBallotState ballotState);\n\n function queuedOf(uint256 projectId) external view returns (JBFundingCycle memory fundingCycle);\n\n function currentOf(uint256 projectId) external view returns (JBFundingCycle memory fundingCycle);\n\n function currentBallotStateOf(uint256 projectId) external view returns (JBBallotState);\n\n function configureFor(\n uint256 projectId,\n JBFundingCycleData calldata data,\n uint256 metadata,\n uint256 mustStartAtOrAfter\n ) external returns (JBFundingCycle memory fundingCycle);\n}\n" + }, + "contracts/interfaces/IJBPaymentTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\n\ninterface IJBPaymentTerminal is IERC165 {\n function acceptsToken(address token, uint256 projectId) external view returns (bool);\n\n function currencyForToken(address token) external view returns (uint256);\n\n function decimalsForToken(address token) external view returns (uint256);\n\n // Return value must be a fixed point number with 18 decimals.\n function currentEthOverflowOf(uint256 projectId) external view returns (uint256);\n\n function pay(\n uint256 projectId,\n uint256 amount,\n address token,\n address beneficiary,\n uint256 minReturnedTokens,\n bool preferClaimedTokens,\n string calldata memo,\n bytes calldata metadata\n ) external payable returns (uint256 beneficiaryTokenCount);\n\n function addToBalanceOf(\n uint256 projectId,\n uint256 amount,\n address token,\n string calldata memo,\n bytes calldata metadata\n ) external payable;\n}\n" + }, + "contracts/interfaces/IJBProjects.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC721} from '@openzeppelin/contracts/token/ERC721/IERC721.sol';\nimport {JBProjectMetadata} from './../structs/JBProjectMetadata.sol';\nimport {IJBTokenUriResolver} from './IJBTokenUriResolver.sol';\n\ninterface IJBProjects is IERC721 {\n event Create(\n uint256 indexed projectId,\n address indexed owner,\n JBProjectMetadata metadata,\n address caller\n );\n\n event SetMetadata(uint256 indexed projectId, JBProjectMetadata metadata, address caller);\n\n event SetTokenUriResolver(IJBTokenUriResolver indexed resolver, address caller);\n\n function count() external view returns (uint256);\n\n function metadataContentOf(\n uint256 projectId,\n uint256 domain\n ) external view returns (string memory);\n\n function tokenUriResolver() external view returns (IJBTokenUriResolver);\n\n function createFor(\n address owner,\n JBProjectMetadata calldata metadata\n ) external returns (uint256 projectId);\n\n function setMetadataOf(uint256 projectId, JBProjectMetadata calldata metadata) external;\n\n function setTokenUriResolver(IJBTokenUriResolver newResolver) external;\n}\n" + }, + "contracts/enums/JBBallotState.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nenum JBBallotState {\n Active,\n Approved,\n Failed\n}\n" + }, + "contracts/structs/JBFundingCycle.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBFundingCycleBallot} from './../interfaces/IJBFundingCycleBallot.sol';\n\n/// @custom:member number The funding cycle number for the cycle's project. Each funding cycle has a number that is an increment of the cycle that directly preceded it. Each project's first funding cycle has a number of 1.\n/// @custom:member configuration The timestamp when the parameters for this funding cycle were configured. This value will stay the same for subsequent funding cycles that roll over from an originally configured cycle.\n/// @custom:member basedOn The `configuration` of the funding cycle that was active when this cycle was created.\n/// @custom:member start The timestamp marking the moment from which the funding cycle is considered active. It is a unix timestamp measured in seconds.\n/// @custom:member duration The number of seconds the funding cycle lasts for, after which a new funding cycle will start. A duration of 0 means that the funding cycle will stay active until the project owner explicitly issues a reconfiguration, at which point a new funding cycle will immediately start with the updated properties. If the duration is greater than 0, a project owner cannot make changes to a funding cycle's parameters while it is active – any proposed changes will apply to the subsequent cycle. If no changes are proposed, a funding cycle rolls over to another one with the same properties but new `start` timestamp and a discounted `weight`.\n/// @custom:member weight A fixed point number with 18 decimals that contracts can use to base arbitrary calculations on. For example, payment terminals can use this to determine how many tokens should be minted when a payment is received.\n/// @custom:member discountRate A percent by how much the `weight` of the subsequent funding cycle should be reduced, if the project owner hasn't configured the subsequent funding cycle with an explicit `weight`. If it's 0, each funding cycle will have equal weight. If the number is 90%, the next funding cycle will have a 10% smaller weight. This weight is out of `JBConstants.MAX_DISCOUNT_RATE`.\n/// @custom:member ballot An address of a contract that says whether a proposed reconfiguration should be accepted or rejected. It can be used to create rules around how a project owner can change funding cycle parameters over time.\n/// @custom:member metadata Extra data that can be associated with a funding cycle.\nstruct JBFundingCycle {\n uint256 number;\n uint256 configuration;\n uint256 basedOn;\n uint256 start;\n uint256 duration;\n uint256 weight;\n uint256 discountRate;\n IJBFundingCycleBallot ballot;\n uint256 metadata;\n}\n" + }, + "contracts/structs/JBFundingCycleData.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBFundingCycleBallot} from './../interfaces/IJBFundingCycleBallot.sol';\n\n/// @custom:member duration The number of seconds the funding cycle lasts for, after which a new funding cycle will start. A duration of 0 means that the funding cycle will stay active until the project owner explicitly issues a reconfiguration, at which point a new funding cycle will immediately start with the updated properties. If the duration is greater than 0, a project owner cannot make changes to a funding cycle's parameters while it is active – any proposed changes will apply to the subsequent cycle. If no changes are proposed, a funding cycle rolls over to another one with the same properties but new `start` timestamp and a discounted `weight`.\n/// @custom:member weight A fixed point number with 18 decimals that contracts can use to base arbitrary calculations on. For example, payment terminals can use this to determine how many tokens should be minted when a payment is received.\n/// @custom:member discountRate A percent by how much the `weight` of the subsequent funding cycle should be reduced, if the project owner hasn't configured the subsequent funding cycle with an explicit `weight`. If it's 0, each funding cycle will have equal weight. If the number is 90%, the next funding cycle will have a 10% smaller weight. This weight is out of `JBConstants.MAX_DISCOUNT_RATE`.\n/// @custom:member ballot An address of a contract that says whether a proposed reconfiguration should be accepted or rejected. It can be used to create rules around how a project owner can change funding cycle parameters over time.\nstruct JBFundingCycleData {\n uint256 duration;\n uint256 weight;\n uint256 discountRate;\n IJBFundingCycleBallot ballot;\n}\n" + }, + "contracts/interfaces/IJBFundingCycleBallot.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBBallotState} from './../enums/JBBallotState.sol';\n\ninterface IJBFundingCycleBallot is IERC165 {\n function duration() external view returns (uint256);\n\n function stateOf(\n uint256 projectId,\n uint256 configuration,\n uint256 start\n ) external view returns (JBBallotState);\n}\n" + }, + "@openzeppelin/contracts/utils/introspection/IERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n" + }, + "@openzeppelin/contracts/token/ERC721/IERC721.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../../utils/introspection/IERC165.sol\";\n\n/**\n * @dev Required interface of an ERC721 compliant contract.\n */\ninterface IERC721 is IERC165 {\n /**\n * @dev Emitted when `tokenId` token is transferred from `from` to `to`.\n */\n event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);\n\n /**\n * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.\n */\n event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);\n\n /**\n * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.\n */\n event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n /**\n * @dev Returns the number of tokens in ``owner``'s account.\n */\n function balanceOf(address owner) external view returns (uint256 balance);\n\n /**\n * @dev Returns the owner of the `tokenId` token.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n */\n function ownerOf(uint256 tokenId) external view returns (address owner);\n\n /**\n * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\n * are aware of the ERC721 protocol to prevent tokens from being forever locked.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must exist and be owned by `from`.\n * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId\n ) external;\n\n /**\n * @dev Transfers `tokenId` token from `from` to `to`.\n *\n * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must be owned by `from`.\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 tokenId\n ) external;\n\n /**\n * @dev Gives permission to `to` to transfer `tokenId` token to another account.\n * The approval is cleared when the token is transferred.\n *\n * Only a single account can be approved at a time, so approving the zero address clears previous approvals.\n *\n * Requirements:\n *\n * - The caller must own the token or be an approved operator.\n * - `tokenId` must exist.\n *\n * Emits an {Approval} event.\n */\n function approve(address to, uint256 tokenId) external;\n\n /**\n * @dev Returns the account approved for `tokenId` token.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n */\n function getApproved(uint256 tokenId) external view returns (address operator);\n\n /**\n * @dev Approve or remove `operator` as an operator for the caller.\n * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.\n *\n * Requirements:\n *\n * - The `operator` cannot be the caller.\n *\n * Emits an {ApprovalForAll} event.\n */\n function setApprovalForAll(address operator, bool _approved) external;\n\n /**\n * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.\n *\n * See {setApprovalForAll}\n */\n function isApprovedForAll(address owner, address operator) external view returns (bool);\n\n /**\n * @dev Safely transfers `tokenId` token from `from` to `to`.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must exist and be owned by `from`.\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId,\n bytes calldata data\n ) external;\n}\n" + }, + "contracts/structs/JBProjectMetadata.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @custom:member content The metadata content.\n/// @custom:member domain The domain within which the metadata applies.\nstruct JBProjectMetadata {\n string content;\n uint256 domain;\n}\n" + }, + "contracts/interfaces/IJBTokenUriResolver.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBTokenUriResolver {\n function getUri(uint256 projectId) external view returns (string memory tokenUri);\n}\n" + }, + "contracts/JBTokenStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {JBControllerUtility} from './abstract/JBControllerUtility.sol';\nimport {JBOperatable} from './abstract/JBOperatable.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {IJBToken} from './interfaces/IJBToken.sol';\nimport {IJBTokenStore} from './interfaces/IJBTokenStore.sol';\nimport {JBFundingCycleMetadataResolver} from './libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBOperations} from './libraries/JBOperations.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\nimport {JBToken} from './JBToken.sol';\n\n/// @notice Manage token minting, burning, and account balances.\n/// @dev Token balances can be either represented internally or claimed as ERC-20s into wallets. This contract manages these two representations and allows claiming.\n/// @dev The total supply of a project's tokens and the balance of each account are calculated in this contract.\n/// @dev Each project can bring their own token if they prefer, and swap between tokens at any time.\ncontract JBTokenStore is JBControllerUtility, JBOperatable, IJBTokenStore {\n // A library that parses the packed funding cycle metadata into a friendlier format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error ALREADY_SET();\n error EMPTY_NAME();\n error EMPTY_SYMBOL();\n error EMPTY_TOKEN();\n error INSUFFICIENT_FUNDS();\n error INSUFFICIENT_UNCLAIMED_TOKENS();\n error PROJECT_ALREADY_HAS_TOKEN();\n error RECIPIENT_ZERO_ADDRESS();\n error TOKEN_NOT_FOUND();\n error TOKENS_MUST_HAVE_18_DECIMALS();\n error TRANSFERS_PAUSED();\n error OVERFLOW_ALERT();\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice Mints ERC-721's that represent project ownership and transfers. \n IJBProjects public immutable override projects;\n\n /// @notice The contract storing all funding cycle configurations. \n IJBFundingCycleStore public immutable override fundingCycleStore;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice Each project's attached token contract.\n /// @custom:param _projectId The ID of the project to which the token belongs. \n mapping(uint256 => IJBToken) public override tokenOf;\n\n /// @notice The total supply of unclaimed tokens for each project.\n /// @custom:param _projectId The ID of the project to which the token belongs. \n mapping(uint256 => uint256) public override unclaimedTotalSupplyOf;\n\n /// @notice Each holder's balance of unclaimed tokens for each project.\n /// @custom:param _holder The holder of balance.\n /// @custom:param _projectId The ID of the project to which the token belongs.\n mapping(address => mapping(uint256 => uint256)) public override unclaimedBalanceOf;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice The total balance of tokens a holder has for a specified project, including claimed and unclaimed tokens.\n /// @param _holder The token holder to get a balance for.\n /// @param _projectId The project to get the `_holder`s balance of.\n /// @return balance The project token balance of the `_holder \n function balanceOf(address _holder, uint256 _projectId)\n external\n view\n override\n returns (uint256 balance)\n {\n // Get a reference to the holder's unclaimed balance for the project.\n balance = unclaimedBalanceOf[_holder][_projectId];\n\n // Get a reference to the project's current token.\n IJBToken _token = tokenOf[_projectId];\n\n // If the project has a current token, add the holder's balance to the total.\n if (_token != IJBToken(address(0))) balance = balance + _token.balanceOf(_holder, _projectId);\n }\n\n //*********************************************************************//\n // --------------------------- public views -------------------------- //\n //*********************************************************************//\n\n /// @notice The total supply of tokens for each project, including claimed and unclaimed tokens.\n /// @param _projectId The ID of the project to get the total token supply of.\n /// @return totalSupply The total supply of the project's tokens.\n function totalSupplyOf(uint256 _projectId) public view override returns (uint256 totalSupply) {\n // Get a reference to the total supply of the project's unclaimed tokens.\n totalSupply = unclaimedTotalSupplyOf[_projectId];\n\n // Get a reference to the project's current token.\n IJBToken _token = tokenOf[_projectId];\n\n // If the project has a current token, add its total supply to the total.\n if (_token != IJBToken(address(0))) totalSupply = totalSupply + _token.totalSupply(_projectId);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _fundingCycleStore A contract storing all funding cycle configurations.\n constructor(\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBFundingCycleStore _fundingCycleStore\n ) JBOperatable(_operatorStore) JBControllerUtility(_directory) {\n projects = _projects;\n fundingCycleStore = _fundingCycleStore;\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Issues a project's ERC-20 tokens that'll be used when claiming tokens.\n /// @dev Deploys a project's ERC-20 token contract.\n /// @dev Only a project's owner or operator can issue its token.\n /// @param _projectId The ID of the project being issued tokens.\n /// @param _name The ERC-20's name.\n /// @param _symbol The ERC-20's symbol.\n /// @return token The token that was issued.\n function issueFor(\n uint256 _projectId,\n string calldata _name,\n string calldata _symbol\n )\n external\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.ISSUE)\n returns (IJBToken token)\n {\n // There must be a name.\n if (bytes(_name).length == 0) revert EMPTY_NAME();\n\n // There must be a symbol.\n if (bytes(_symbol).length == 0) revert EMPTY_SYMBOL();\n \n // The project shouldn't already have a token.\n if (tokenOf[_projectId] != IJBToken(address(0))) revert PROJECT_ALREADY_HAS_TOKEN();\n\n // Deploy the token contract.\n token = new JBToken(_name, _symbol, _projectId);\n\n // Store the token contract.\n tokenOf[_projectId] = token;\n\n emit Issue(_projectId, token, _name, _symbol, msg.sender);\n }\n\n /// @notice Set a project's token if not already set.\n /// @dev Only a project's owner or operator can set its token.\n /// @param _projectId The ID of the project to which the set token belongs.\n /// @param _token The new token. \n function setFor(uint256 _projectId, IJBToken _token)\n external\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.SET_TOKEN)\n {\n // Can't set to the zero address.\n if (_token == IJBToken(address(0))) revert EMPTY_TOKEN();\n\n // Can't set token if already set.\n if (tokenOf[_projectId] != IJBToken(address(0))) revert ALREADY_SET();\n\n // Can't change to a token that doesn't use 18 decimals.\n if (_token.decimals() != 18) revert TOKENS_MUST_HAVE_18_DECIMALS();\n\n // Store the new token.\n tokenOf[_projectId] = _token;\n\n emit Set(_projectId, _token, msg.sender);\n }\n\n /// @notice Mint new project tokens.\n /// @dev Only a project's current controller can mint its tokens.\n /// @param _holder The address receiving the new tokens.\n /// @param _projectId The ID of the project to which the tokens belong.\n /// @param _amount The amount of tokens to mint.\n /// @param _preferClaimedTokens A flag indicating whether there's a preference for minted tokens to be claimed automatically into the `_holder`s wallet if the project currently has a token contract attached.\n function mintFor(\n address _holder,\n uint256 _projectId,\n uint256 _amount,\n bool _preferClaimedTokens\n ) external override onlyController(_projectId) {\n // Get a reference to the project's current token.\n IJBToken _token = tokenOf[_projectId];\n\n // Save a reference to whether there exists a token and the caller prefers these claimed tokens.\n bool _shouldClaimTokens = _preferClaimedTokens && _token != IJBToken(address(0));\n\n if (_shouldClaimTokens)\n // If tokens should be claimed, mint tokens into the holder's wallet.\n _token.mint(_projectId, _holder, _amount);\n else {\n // Otherwise, add the tokens to the unclaimed balance and total supply.\n unclaimedBalanceOf[_holder][_projectId] = unclaimedBalanceOf[_holder][_projectId] + _amount;\n unclaimedTotalSupplyOf[_projectId] = unclaimedTotalSupplyOf[_projectId] + _amount;\n }\n\n // The total supply can't exceed the maximum value storable in a uint224.\n if (totalSupplyOf(_projectId) > type(uint224).max) revert OVERFLOW_ALERT();\n\n emit Mint(_holder, _projectId, _amount, _shouldClaimTokens, _preferClaimedTokens, msg.sender);\n }\n\n /// @notice Burns a project's tokens.\n /// @dev Only a project's current controller can burn its tokens.\n /// @param _holder The address that owns the tokens being burned.\n /// @param _projectId The ID of the project to which the burned tokens belong.\n /// @param _amount The amount of tokens to burn.\n /// @param _preferClaimedTokens A flag indicating whether there's a preference for tokens to burned from the `_holder`s wallet if the project currently has a token contract attached.\n function burnFrom(\n address _holder,\n uint256 _projectId,\n uint256 _amount,\n bool _preferClaimedTokens\n ) external override onlyController(_projectId) {\n // Get a reference to the project's current token.\n IJBToken _token = tokenOf[_projectId];\n\n // Get a reference to the amount of unclaimed project tokens the holder has.\n uint256 _unclaimedBalance = unclaimedBalanceOf[_holder][_projectId];\n\n // Get a reference to the amount of the project's current token the holder has in their wallet.\n uint256 _claimedBalance = _token == IJBToken(address(0))\n ? 0\n : _token.balanceOf(_holder, _projectId);\n\n // There must be adequate tokens to burn across the holder's claimed and unclaimed balance.\n if (_amount > _claimedBalance + _unclaimedBalance) revert INSUFFICIENT_FUNDS();\n\n // The amount of tokens to burn.\n uint256 _claimedTokensToBurn;\n\n // Get a reference to how many claimed tokens should be burned\n if (_claimedBalance != 0)\n if (_preferClaimedTokens)\n // If prefer converted, burn the claimed tokens before the unclaimed.\n _claimedTokensToBurn = _claimedBalance < _amount ? _claimedBalance : _amount;\n // Otherwise, burn unclaimed tokens before claimed tokens.\n else {\n unchecked {\n _claimedTokensToBurn = _unclaimedBalance < _amount ? _amount - _unclaimedBalance : 0;\n }\n }\n\n // The amount of unclaimed tokens to burn.\n uint256 _unclaimedTokensToBurn;\n unchecked {\n _unclaimedTokensToBurn = _amount - _claimedTokensToBurn;\n }\n\n // Subtract the tokens from the unclaimed balance and total supply.\n if (_unclaimedTokensToBurn > 0) {\n // Reduce the holders balance and the total supply.\n unclaimedBalanceOf[_holder][_projectId] =\n unclaimedBalanceOf[_holder][_projectId] -\n _unclaimedTokensToBurn;\n unclaimedTotalSupplyOf[_projectId] =\n unclaimedTotalSupplyOf[_projectId] -\n _unclaimedTokensToBurn;\n }\n\n // Burn the claimed tokens.\n if (_claimedTokensToBurn > 0) _token.burn(_projectId, _holder, _claimedTokensToBurn);\n\n emit Burn(\n _holder,\n _projectId,\n _amount,\n _unclaimedBalance,\n _claimedBalance,\n _preferClaimedTokens,\n msg.sender\n );\n }\n\n /// @notice Claims internally accounted for tokens into a holder's wallet.\n /// @dev Only a token holder or an operator specified by the token holder can claim its unclaimed tokens.\n /// @param _holder The owner of the tokens being claimed.\n /// @param _projectId The ID of the project whose tokens are being claimed.\n /// @param _amount The amount of tokens to claim.\n function claimFor(\n address _holder,\n uint256 _projectId,\n uint256 _amount\n ) external override requirePermission(_holder, _projectId, JBOperations.CLAIM) {\n // Get a reference to the project's current token.\n IJBToken _token = tokenOf[_projectId];\n\n // The project must have a token contract attached.\n if (_token == IJBToken(address(0))) revert TOKEN_NOT_FOUND();\n\n // Get a reference to the amount of unclaimed project tokens the holder has.\n uint256 _unclaimedBalance = unclaimedBalanceOf[_holder][_projectId];\n\n // There must be enough unclaimed tokens to claim.\n if (_unclaimedBalance < _amount) revert INSUFFICIENT_UNCLAIMED_TOKENS();\n\n unchecked {\n // Subtract the claim amount from the holder's unclaimed project token balance.\n unclaimedBalanceOf[_holder][_projectId] = _unclaimedBalance - _amount;\n\n // Subtract the claim amount from the project's unclaimed total supply.\n unclaimedTotalSupplyOf[_projectId] = unclaimedTotalSupplyOf[_projectId] - _amount;\n }\n\n // Mint the equivalent amount of the project's token for the holder.\n _token.mint(_projectId, _holder, _amount);\n\n emit Claim(_holder, _projectId, _unclaimedBalance, _amount, msg.sender);\n }\n\n /// @notice Allows a holder to transfer unclaimed tokens to another account.\n /// @dev Only a token holder or an operator can transfer its unclaimed tokens.\n /// @param _holder The address to transfer tokens from.\n /// @param _projectId The ID of the project whose tokens are being transferred.\n /// @param _recipient The recipient of the tokens.\n /// @param _amount The amount of tokens to transfer.\n function transferFrom(\n address _holder,\n uint256 _projectId,\n address _recipient,\n uint256 _amount\n ) external override requirePermission(_holder, _projectId, JBOperations.TRANSFER) {\n // Get a reference to the current funding cycle for the project.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Must not be paused.\n if (_fundingCycle.global().pauseTransfers) revert TRANSFERS_PAUSED();\n\n // Can't transfer to the zero address.\n if (_recipient == address(0)) revert RECIPIENT_ZERO_ADDRESS();\n\n // Get a reference to the holder's unclaimed project token balance.\n uint256 _unclaimedBalance = unclaimedBalanceOf[_holder][_projectId];\n\n // The holder must have enough unclaimed tokens to transfer.\n if (_amount > _unclaimedBalance) revert INSUFFICIENT_UNCLAIMED_TOKENS();\n\n // Subtract from the holder's unclaimed token balance.\n unchecked {\n unclaimedBalanceOf[_holder][_projectId] = _unclaimedBalance - _amount;\n }\n\n // Add the unclaimed project tokens to the recipient's balance.\n unclaimedBalanceOf[_recipient][_projectId] =\n unclaimedBalanceOf[_recipient][_projectId] +\n _amount;\n\n emit Transfer(_holder, _projectId, _recipient, _amount, msg.sender);\n }\n}\n" + }, + "contracts/abstract/JBOperatable.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {IJBOperatable} from './../interfaces/IJBOperatable.sol';\nimport {IJBOperatorStore} from './../interfaces/IJBOperatorStore.sol';\n\n/// @notice Modifiers to allow access to functions based on the message sender's operator status.\nabstract contract JBOperatable is IJBOperatable {\n //*********************************************************************//\n // --------------------------- custom errors -------------------------- //\n //*********************************************************************//\n error UNAUTHORIZED();\n\n //*********************************************************************//\n // ---------------------------- modifiers ---------------------------- //\n //*********************************************************************//\n\n /// @notice Only allows the speficied account or an operator of the account to proceed.\n /// @param _account The account to check for.\n /// @param _domain The domain namespace to look for an operator within.\n /// @param _permissionIndex The index of the permission to check for.\n modifier requirePermission(\n address _account,\n uint256 _domain,\n uint256 _permissionIndex\n ) {\n _requirePermission(_account, _domain, _permissionIndex);\n _;\n }\n\n /// @notice Only allows the speficied account, an operator of the account to proceed, or a truthy override flag.\n /// @param _account The account to check for.\n /// @param _domain The domain namespace to look for an operator within.\n /// @param _permissionIndex The index of the permission to check for.\n /// @param _override A condition to force allowance for.\n modifier requirePermissionAllowingOverride(\n address _account,\n uint256 _domain,\n uint256 _permissionIndex,\n bool _override\n ) {\n _requirePermissionAllowingOverride(_account, _domain, _permissionIndex, _override);\n _;\n }\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice A contract storing operator assignments.\n IJBOperatorStore public immutable override operatorStore;\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _operatorStore A contract storing operator assignments.\n constructor(IJBOperatorStore _operatorStore) {\n operatorStore = _operatorStore;\n }\n\n //*********************************************************************//\n // -------------------------- internal views ------------------------- //\n //*********************************************************************//\n\n /// @notice Require the message sender is either the account or has the specified permission.\n /// @param _account The account to allow.\n /// @param _domain The domain namespace within which the permission index will be checked.\n /// @param _permissionIndex The permission index that an operator must have within the specified domain to be allowed.\n function _requirePermission(\n address _account,\n uint256 _domain,\n uint256 _permissionIndex\n ) internal view {\n if (\n msg.sender != _account &&\n !operatorStore.hasPermission(msg.sender, _account, _domain, _permissionIndex) &&\n !operatorStore.hasPermission(msg.sender, _account, 0, _permissionIndex)\n ) revert UNAUTHORIZED();\n }\n\n /// @notice Require the message sender is either the account, has the specified permission, or the override condition is true.\n /// @param _account The account to allow.\n /// @param _domain The domain namespace within which the permission index will be checked.\n /// @param _domain The permission index that an operator must have within the specified domain to be allowed.\n /// @param _override The override condition to allow.\n function _requirePermissionAllowingOverride(\n address _account,\n uint256 _domain,\n uint256 _permissionIndex,\n bool _override\n ) internal view {\n if (\n !_override &&\n msg.sender != _account &&\n !operatorStore.hasPermission(msg.sender, _account, _domain, _permissionIndex) &&\n !operatorStore.hasPermission(msg.sender, _account, 0, _permissionIndex)\n ) revert UNAUTHORIZED();\n }\n}\n" + }, + "contracts/interfaces/IJBOperatorStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBOperatorData} from './../structs/JBOperatorData.sol';\n\ninterface IJBOperatorStore {\n event SetOperator(\n address indexed operator,\n address indexed account,\n uint256 indexed domain,\n uint256[] permissionIndexes,\n uint256 packed\n );\n\n function permissionsOf(\n address operator,\n address account,\n uint256 domain\n ) external view returns (uint256);\n\n function hasPermission(\n address operator,\n address account,\n uint256 domain,\n uint256 permissionIndex\n ) external view returns (bool);\n\n function hasPermissions(\n address operator,\n address account,\n uint256 domain,\n uint256[] calldata permissionIndexes\n ) external view returns (bool);\n\n function setOperator(JBOperatorData calldata operatorData) external;\n\n function setOperators(JBOperatorData[] calldata operatorData) external;\n}\n" + }, + "contracts/interfaces/IJBToken.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBToken {\n function projectId() external view returns (uint256);\n\n function decimals() external view returns (uint8);\n\n function totalSupply(uint256 projectId) external view returns (uint256);\n\n function balanceOf(address account, uint256 projectId) external view returns (uint256);\n\n function mint(uint256 projectId, address account, uint256 amount) external;\n\n function burn(uint256 projectId, address account, uint256 amount) external;\n\n function approve(uint256, address spender, uint256 amount) external;\n\n function transfer(uint256 projectId, address to, uint256 amount) external;\n\n function transferFrom(uint256 projectId, address from, address to, uint256 amount) external;\n}\n" + }, + "contracts/interfaces/IJBTokenStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\nimport {IJBProjects} from './IJBProjects.sol';\nimport {IJBToken} from './IJBToken.sol';\n\ninterface IJBTokenStore {\n event Issue(\n uint256 indexed projectId,\n IJBToken indexed token,\n string name,\n string symbol,\n address caller\n );\n\n event Mint(\n address indexed holder,\n uint256 indexed projectId,\n uint256 amount,\n bool tokensWereClaimed,\n bool preferClaimedTokens,\n address caller\n );\n\n event Burn(\n address indexed holder,\n uint256 indexed projectId,\n uint256 amount,\n uint256 initialUnclaimedBalance,\n uint256 initialClaimedBalance,\n bool preferClaimedTokens,\n address caller\n );\n\n event Claim(\n address indexed holder,\n uint256 indexed projectId,\n uint256 initialUnclaimedBalance,\n uint256 amount,\n address caller\n );\n\n event Set(uint256 indexed projectId, IJBToken indexed newToken, address caller);\n\n event Transfer(\n address indexed holder,\n uint256 indexed projectId,\n address indexed recipient,\n uint256 amount,\n address caller\n );\n\n function tokenOf(uint256 projectId) external view returns (IJBToken);\n\n function projects() external view returns (IJBProjects);\n\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\n\n function unclaimedBalanceOf(address holder, uint256 projectId) external view returns (uint256);\n\n function unclaimedTotalSupplyOf(uint256 projectId) external view returns (uint256);\n\n function totalSupplyOf(uint256 projectId) external view returns (uint256);\n\n function balanceOf(address holder, uint256 projectId) external view returns (uint256 result);\n\n function issueFor(\n uint256 projectId,\n string calldata name,\n string calldata symbol\n ) external returns (IJBToken token);\n\n function setFor(uint256 projectId, IJBToken token) external;\n\n function burnFrom(\n address holder,\n uint256 projectId,\n uint256 amount,\n bool preferClaimedTokens\n ) external;\n\n function mintFor(\n address holder,\n uint256 projectId,\n uint256 amount,\n bool preferClaimedTokens\n ) external;\n\n function claimFor(address holder, uint256 projectId, uint256 amount) external;\n\n function transferFrom(\n address holder,\n uint256 projectId,\n address recipient,\n uint256 amount\n ) external;\n}\n" + }, + "contracts/libraries/JBFundingCycleMetadataResolver.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\nimport {JBFundingCycleMetadata} from './../structs/JBFundingCycleMetadata.sol';\nimport {JBGlobalFundingCycleMetadata} from './../structs/JBGlobalFundingCycleMetadata.sol';\nimport {JBConstants} from './JBConstants.sol';\nimport {JBGlobalFundingCycleMetadataResolver} from './JBGlobalFundingCycleMetadataResolver.sol';\n\nlibrary JBFundingCycleMetadataResolver {\n function global(JBFundingCycle memory _fundingCycle)\n internal\n pure\n returns (JBGlobalFundingCycleMetadata memory)\n {\n return JBGlobalFundingCycleMetadataResolver.expandMetadata(uint8(_fundingCycle.metadata >> 8));\n }\n\n function reservedRate(JBFundingCycle memory _fundingCycle) internal pure returns (uint256) {\n return uint256(uint16(_fundingCycle.metadata >> 24));\n }\n\n function redemptionRate(JBFundingCycle memory _fundingCycle) internal pure returns (uint256) {\n // Redemption rate is a number 0-10000. It's inverse was stored so the most common case of 100% results in no storage needs.\n return JBConstants.MAX_REDEMPTION_RATE - uint256(uint16(_fundingCycle.metadata >> 40));\n }\n\n function ballotRedemptionRate(JBFundingCycle memory _fundingCycle)\n internal\n pure\n returns (uint256)\n {\n // Redemption rate is a number 0-10000. It's inverse was stored so the most common case of 100% results in no storage needs.\n return JBConstants.MAX_REDEMPTION_RATE - uint256(uint16(_fundingCycle.metadata >> 56));\n }\n\n function payPaused(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\n return ((_fundingCycle.metadata >> 72) & 1) == 1;\n }\n\n function distributionsPaused(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\n return ((_fundingCycle.metadata >> 73) & 1) == 1;\n }\n\n function redeemPaused(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\n return ((_fundingCycle.metadata >> 74) & 1) == 1;\n }\n\n function burnPaused(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\n return ((_fundingCycle.metadata >> 75) & 1) == 1;\n }\n\n function mintingAllowed(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\n return ((_fundingCycle.metadata >> 76) & 1) == 1;\n }\n\n function terminalMigrationAllowed(JBFundingCycle memory _fundingCycle)\n internal\n pure\n returns (bool)\n {\n return ((_fundingCycle.metadata >> 77) & 1) == 1;\n }\n\n function controllerMigrationAllowed(JBFundingCycle memory _fundingCycle)\n internal\n pure\n returns (bool)\n {\n return ((_fundingCycle.metadata >> 78) & 1) == 1;\n }\n\n function shouldHoldFees(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\n return ((_fundingCycle.metadata >> 79) & 1) == 1;\n }\n\n function preferClaimedTokenOverride(JBFundingCycle memory _fundingCycle)\n internal\n pure\n returns (bool)\n {\n return ((_fundingCycle.metadata >> 80) & 1) == 1;\n }\n\n function useTotalOverflowForRedemptions(JBFundingCycle memory _fundingCycle)\n internal\n pure\n returns (bool)\n {\n return ((_fundingCycle.metadata >> 81) & 1) == 1;\n }\n\n function useDataSourceForPay(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\n return (_fundingCycle.metadata >> 82) & 1 == 1;\n }\n\n function useDataSourceForRedeem(JBFundingCycle memory _fundingCycle)\n internal\n pure\n returns (bool)\n {\n return (_fundingCycle.metadata >> 83) & 1 == 1;\n }\n\n function dataSource(JBFundingCycle memory _fundingCycle) internal pure returns (address) {\n return address(uint160(_fundingCycle.metadata >> 84));\n }\n\n function metadata(JBFundingCycle memory _fundingCycle) internal pure returns (uint256) {\n return uint256(uint8(_fundingCycle.metadata >> 244));\n }\n\n /// @notice Pack the funding cycle metadata.\n /// @param _metadata The metadata to validate and pack.\n /// @return packed The packed uint256 of all metadata params. The first 8 bits specify the version. \n function packFundingCycleMetadata(JBFundingCycleMetadata memory _metadata)\n internal\n pure\n returns (uint256 packed)\n {\n // version 1 in the bits 0-7 (8 bits).\n packed = 1;\n // global metadta in bits 8-23 (16 bits).\n packed |=\n JBGlobalFundingCycleMetadataResolver.packFundingCycleGlobalMetadata(_metadata.global) <<\n 8;\n // reserved rate in bits 24-39 (16 bits).\n packed |= _metadata.reservedRate << 24;\n // redemption rate in bits 40-55 (16 bits).\n // redemption rate is a number 0-10000. Store the reverse so the most common case of 100% results in no storage needs.\n packed |= (JBConstants.MAX_REDEMPTION_RATE - _metadata.redemptionRate) << 40;\n // ballot redemption rate rate in bits 56-71 (16 bits).\n // ballot redemption rate is a number 0-10000. Store the reverse so the most common case of 100% results in no storage needs.\n packed |= (JBConstants.MAX_REDEMPTION_RATE - _metadata.ballotRedemptionRate) << 56;\n // pause pay in bit 72.\n if (_metadata.pausePay) packed |= 1 << 72;\n // pause tap in bit 73.\n if (_metadata.pauseDistributions) packed |= 1 << 73;\n // pause redeem in bit 74.\n if (_metadata.pauseRedeem) packed |= 1 << 74;\n // pause burn in bit 75.\n if (_metadata.pauseBurn) packed |= 1 << 75;\n // allow minting in bit 76.\n if (_metadata.allowMinting) packed |= 1 << 76;\n // allow terminal migration in bit 77.\n if (_metadata.allowTerminalMigration) packed |= 1 << 77;\n // allow controller migration in bit 78.\n if (_metadata.allowControllerMigration) packed |= 1 << 78;\n // hold fees in bit 79.\n if (_metadata.holdFees) packed |= 1 << 79;\n // prefer claimed token override in bit 80.\n if (_metadata.preferClaimedTokenOverride) packed |= 1 << 80;\n // useTotalOverflowForRedemptions in bit 81.\n if (_metadata.useTotalOverflowForRedemptions) packed |= 1 << 81;\n // use pay data source in bit 82.\n if (_metadata.useDataSourceForPay) packed |= 1 << 82;\n // use redeem data source in bit 83.\n if (_metadata.useDataSourceForRedeem) packed |= 1 << 83;\n // data source address in bits 84-243.\n packed |= uint256(uint160(address(_metadata.dataSource))) << 84;\n // metadata in bits 244-252 (8 bits).\n packed |= _metadata.metadata << 244;\n }\n\n /// @notice Expand the funding cycle metadata.\n /// @param _fundingCycle The funding cycle having its metadata expanded.\n /// @return metadata The metadata object. \n function expandMetadata(JBFundingCycle memory _fundingCycle)\n internal\n pure\n returns (JBFundingCycleMetadata memory)\n {\n return\n JBFundingCycleMetadata(\n global(_fundingCycle),\n reservedRate(_fundingCycle),\n redemptionRate(_fundingCycle),\n ballotRedemptionRate(_fundingCycle),\n payPaused(_fundingCycle),\n distributionsPaused(_fundingCycle),\n redeemPaused(_fundingCycle),\n burnPaused(_fundingCycle),\n mintingAllowed(_fundingCycle),\n terminalMigrationAllowed(_fundingCycle),\n controllerMigrationAllowed(_fundingCycle),\n shouldHoldFees(_fundingCycle),\n preferClaimedTokenOverride(_fundingCycle),\n useTotalOverflowForRedemptions(_fundingCycle),\n useDataSourceForPay(_fundingCycle),\n useDataSourceForRedeem(_fundingCycle),\n dataSource(_fundingCycle),\n metadata(_fundingCycle)\n );\n }\n}\n" + }, + "contracts/libraries/JBOperations.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nlibrary JBOperations {\n uint256 public constant RECONFIGURE = 1;\n uint256 public constant REDEEM = 2;\n uint256 public constant MIGRATE_CONTROLLER = 3;\n uint256 public constant MIGRATE_TERMINAL = 4;\n uint256 public constant PROCESS_FEES = 5;\n uint256 public constant SET_METADATA = 6;\n uint256 public constant ISSUE = 7;\n uint256 public constant SET_TOKEN = 8;\n uint256 public constant MINT = 9;\n uint256 public constant BURN = 10;\n uint256 public constant CLAIM = 11;\n uint256 public constant TRANSFER = 12;\n uint256 public constant REQUIRE_CLAIM = 13; // unused in v3\n uint256 public constant SET_CONTROLLER = 14;\n uint256 public constant SET_TERMINALS = 15;\n uint256 public constant SET_PRIMARY_TERMINAL = 16;\n uint256 public constant USE_ALLOWANCE = 17;\n uint256 public constant SET_SPLITS = 18;\n}\n" + }, + "contracts/JBToken.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';\nimport {ERC20Votes, ERC20, ERC20Permit} from '@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.sol';\nimport {IJBToken} from './interfaces/IJBToken.sol';\n\n/// @notice An ERC-20 token that can be used by a project in the `JBTokenStore`.\ncontract JBToken is ERC20Votes, Ownable, IJBToken {\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error BAD_PROJECT();\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The ID of the project that this token should be exclusively used for. Send 0 to support any project.\n uint256 public immutable override projectId;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice The total supply of this ERC20.\n /// @param _projectId the ID of the project to which the token belongs. This is ignored.\n /// @return The total supply of this ERC20, as a fixed point number.\n function totalSupply(uint256 _projectId) external view override returns (uint256) {\n _projectId; // Prevents unused var compiler and natspec complaints.\n\n return super.totalSupply();\n }\n\n /// @notice An account's balance of this ERC20.\n /// @param _account The account to get a balance of.\n /// @param _projectId is the ID of the project to which the token belongs. This is ignored.\n /// @return The balance of the `_account` of this ERC20, as a fixed point number with 18 decimals.\n function balanceOf(\n address _account,\n uint256 _projectId\n ) external view override returns (uint256) {\n _account; // Prevents unused var compiler and natspec complaints.\n _projectId; // Prevents unused var compiler and natspec complaints.\n\n return super.balanceOf(_account);\n }\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice The number of decimals included in the fixed point accounting of this token.\n /// @return The number of decimals.\n function decimals() public view override(ERC20, IJBToken) returns (uint8) {\n return super.decimals();\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _name The name of the token.\n /// @param _symbol The symbol that the token should be represented by.\n /// @param _projectId The ID of the project that this token should be exclusively used for. Send 0 to support any project.\n constructor(\n string memory _name,\n string memory _symbol,\n uint256 _projectId\n ) ERC20(_name, _symbol) ERC20Permit(_name) {\n projectId = _projectId;\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Mints more of the token.\n /// @dev Only the owner of this contract cant mint more of it.\n /// @param _projectId The ID of the project to which the token belongs.\n /// @param _account The account to mint the tokens for.\n /// @param _amount The amount of tokens to mint, as a fixed point number with 18 decimals.\n function mint(uint256 _projectId, address _account, uint256 _amount) external override onlyOwner {\n // Can't mint for a wrong project.\n if (projectId != 0 && _projectId != projectId) revert BAD_PROJECT();\n\n return _mint(_account, _amount);\n }\n\n /// @notice Burn some outstanding tokens.\n /// @dev Only the owner of this contract cant burn some of its supply.\n /// @param _projectId The ID of the project to which the token belongs.\n /// @param _account The account to burn tokens from.\n /// @param _amount The amount of tokens to burn, as a fixed point number with 18 decimals.\n function burn(uint256 _projectId, address _account, uint256 _amount) external override onlyOwner {\n // Can't burn for a wrong project.\n if (projectId != 0 && _projectId != projectId) revert BAD_PROJECT();\n\n return _burn(_account, _amount);\n }\n\n /// @notice Approves an account to spend tokens on the `msg.sender`s behalf.\n /// @param _projectId the ID of the project to which the token belongs.\n /// @param _spender The address that will be spending tokens on the `msg.sender`s behalf.\n /// @param _amount The amount the `_spender` is allowed to spend.\n function approve(uint256 _projectId, address _spender, uint256 _amount) external override {\n // Can't approve for a wrong project.\n if (projectId != 0 && _projectId != projectId) revert BAD_PROJECT();\n\n approve(_spender, _amount);\n }\n\n /// @notice Transfer tokens to an account.\n /// @param _projectId The ID of the project to which the token belongs.\n /// @param _to The destination address.\n /// @param _amount The amount of the transfer, as a fixed point number with 18 decimals.\n function transfer(uint256 _projectId, address _to, uint256 _amount) external override {\n // Can't transfer for a wrong project.\n if (projectId != 0 && _projectId != projectId) revert BAD_PROJECT();\n\n transfer(_to, _amount);\n }\n\n /// @notice Transfer tokens between accounts.\n /// @param _projectId The ID of the project to which the token belongs.\n /// @param _from The originating address.\n /// @param _to The destination address.\n /// @param _amount The amount of the transfer, as a fixed point number with 18 decimals.\n function transferFrom(\n uint256 _projectId,\n address _from,\n address _to,\n uint256 _amount\n ) external override {\n // Can't transfer for a wrong project.\n if (projectId != 0 && _projectId != projectId) revert BAD_PROJECT();\n\n transferFrom(_from, _to, _amount);\n }\n}\n" + }, + "contracts/interfaces/IJBOperatable.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBOperatorStore} from './IJBOperatorStore.sol';\n\ninterface IJBOperatable {\n function operatorStore() external view returns (IJBOperatorStore);\n}\n" + }, + "contracts/structs/JBOperatorData.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @custom:member operator The address of the operator.\n/// @custom:member domain The domain within which the operator is being given permissions. A domain of 0 is a wildcard domain, which gives an operator access to all domains.\n/// @custom:member permissionIndexes The indexes of the permissions the operator is being given.\nstruct JBOperatorData {\n address operator;\n uint256 domain;\n uint256[] permissionIndexes;\n}\n" + }, + "contracts/structs/JBFundingCycleMetadata.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBGlobalFundingCycleMetadata} from './JBGlobalFundingCycleMetadata.sol';\n\n/// @custom:member global Data used globally in non-migratable ecosystem contracts.\n/// @custom:member reservedRate The reserved rate of the funding cycle. This number is a percentage calculated out of `JBConstants.MAX_RESERVED_RATE`.\n/// @custom:member redemptionRate The redemption rate of the funding cycle. This number is a percentage calculated out of `JBConstants.MAX_REDEMPTION_RATE`.\n/// @custom:member ballotRedemptionRate The redemption rate to use during an active ballot of the funding cycle. This number is a percentage calculated out of `JBConstants.MAX_REDEMPTION_RATE`.\n/// @custom:member pausePay A flag indicating if the pay functionality should be paused during the funding cycle.\n/// @custom:member pauseDistributions A flag indicating if the distribute functionality should be paused during the funding cycle.\n/// @custom:member pauseRedeem A flag indicating if the redeem functionality should be paused during the funding cycle.\n/// @custom:member pauseBurn A flag indicating if the burn functionality should be paused during the funding cycle.\n/// @custom:member allowMinting A flag indicating if minting tokens should be allowed during this funding cycle.\n/// @custom:member allowTerminalMigration A flag indicating if migrating terminals should be allowed during this funding cycle.\n/// @custom:member allowControllerMigration A flag indicating if migrating controllers should be allowed during this funding cycle.\n/// @custom:member holdFees A flag indicating if fees should be held during this funding cycle.\n/// @custom:member preferClaimedTokenOverride A flag indicating if claimed tokens should always be prefered to unclaimed tokens when minting.\n/// @custom:member useTotalOverflowForRedemptions A flag indicating if redemptions should use the project's balance held in all terminals instead of the project's local terminal balance from which the redemption is being fulfilled.\n/// @custom:member useDataSourceForPay A flag indicating if the data source should be used for pay transactions during this funding cycle.\n/// @custom:member useDataSourceForRedeem A flag indicating if the data source should be used for redeem transactions during this funding cycle.\n/// @custom:member dataSource The data source to use during this funding cycle.\n/// @custom:member metadata Metadata of the metadata, up to uint8 in size.\nstruct JBFundingCycleMetadata {\n JBGlobalFundingCycleMetadata global;\n uint256 reservedRate;\n uint256 redemptionRate;\n uint256 ballotRedemptionRate;\n bool pausePay;\n bool pauseDistributions;\n bool pauseRedeem;\n bool pauseBurn;\n bool allowMinting;\n bool allowTerminalMigration;\n bool allowControllerMigration;\n bool holdFees;\n bool preferClaimedTokenOverride;\n bool useTotalOverflowForRedemptions;\n bool useDataSourceForPay;\n bool useDataSourceForRedeem;\n address dataSource;\n uint256 metadata;\n}\n" + }, + "contracts/structs/JBGlobalFundingCycleMetadata.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @custom:member allowSetTerminals A flag indicating if setting terminals should be allowed during this funding cycle.\n/// @custom:member allowSetController A flag indicating if setting a new controller should be allowed during this funding cycle.\n/// @custom:member pauseTransfers A flag indicating if the project token transfer functionality should be paused during the funding cycle.\nstruct JBGlobalFundingCycleMetadata {\n bool allowSetTerminals;\n bool allowSetController;\n bool pauseTransfers;\n}\n" + }, + "contracts/libraries/JBConstants.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @notice Global constants used across Juicebox contracts.\nlibrary JBConstants {\n uint256 public constant MAX_RESERVED_RATE = 10_000;\n uint256 public constant MAX_REDEMPTION_RATE = 10_000;\n uint256 public constant MAX_DISCOUNT_RATE = 1_000_000_000;\n uint256 public constant SPLITS_TOTAL_PERCENT = 1_000_000_000;\n uint256 public constant MAX_FEE = 1_000_000_000;\n uint256 public constant MAX_FEE_DISCOUNT = 1_000_000_000;\n}\n" + }, + "contracts/libraries/JBGlobalFundingCycleMetadataResolver.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {JBFundingCycleMetadata} from './../structs/JBFundingCycleMetadata.sol';\nimport {JBGlobalFundingCycleMetadata} from './../structs/JBGlobalFundingCycleMetadata.sol';\n\nlibrary JBGlobalFundingCycleMetadataResolver {\n function setTerminalsAllowed(uint8 _data) internal pure returns (bool) {\n return (_data & 1) == 1;\n }\n\n function setControllerAllowed(uint8 _data) internal pure returns (bool) {\n return ((_data >> 1) & 1) == 1;\n }\n\n function transfersPaused(uint8 _data) internal pure returns (bool) {\n return ((_data >> 2) & 1) == 1;\n }\n\n /// @notice Pack the global funding cycle metadata.\n /// @param _metadata The metadata to validate and pack.\n /// @return packed The packed uint256 of all global metadata params. The first 8 bits specify the version.\n function packFundingCycleGlobalMetadata(\n JBGlobalFundingCycleMetadata memory _metadata\n ) internal pure returns (uint256 packed) {\n // allow set terminals in bit 0.\n if (_metadata.allowSetTerminals) packed |= 1;\n // allow set controller in bit 1.\n if (_metadata.allowSetController) packed |= 1 << 1;\n // pause transfers in bit 2.\n if (_metadata.pauseTransfers) packed |= 1 << 2;\n }\n\n /// @notice Expand the global funding cycle metadata.\n /// @param _packedMetadata The packed metadata to expand.\n /// @return metadata The global metadata object.\n function expandMetadata(\n uint8 _packedMetadata\n ) internal pure returns (JBGlobalFundingCycleMetadata memory metadata) {\n return\n JBGlobalFundingCycleMetadata(\n setTerminalsAllowed(_packedMetadata),\n setControllerAllowed(_packedMetadata),\n transfersPaused(_packedMetadata)\n );\n }\n}\n" + }, + "@openzeppelin/contracts/access/Ownable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n _;\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (token/ERC20/extensions/ERC20Votes.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./draft-ERC20Permit.sol\";\nimport \"../../../utils/math/Math.sol\";\nimport \"../../../governance/utils/IVotes.sol\";\nimport \"../../../utils/math/SafeCast.sol\";\nimport \"../../../utils/cryptography/ECDSA.sol\";\n\n/**\n * @dev Extension of ERC20 to support Compound-like voting and delegation. This version is more generic than Compound's,\n * and supports token supply up to 2^224^ - 1, while COMP is limited to 2^96^ - 1.\n *\n * NOTE: If exact COMP compatibility is required, use the {ERC20VotesComp} variant of this module.\n *\n * This extension keeps a history (checkpoints) of each account's vote power. Vote power can be delegated either\n * by calling the {delegate} function directly, or by providing a signature to be used with {delegateBySig}. Voting\n * power can be queried through the public accessors {getVotes} and {getPastVotes}.\n *\n * By default, token balance does not account for voting power. This makes transfers cheaper. The downside is that it\n * requires users to delegate to themselves in order to activate checkpoints and have their voting power tracked.\n *\n * _Available since v4.2._\n */\nabstract contract ERC20Votes is IVotes, ERC20Permit {\n struct Checkpoint {\n uint32 fromBlock;\n uint224 votes;\n }\n\n bytes32 private constant _DELEGATION_TYPEHASH =\n keccak256(\"Delegation(address delegatee,uint256 nonce,uint256 expiry)\");\n\n mapping(address => address) private _delegates;\n mapping(address => Checkpoint[]) private _checkpoints;\n Checkpoint[] private _totalSupplyCheckpoints;\n\n /**\n * @dev Get the `pos`-th checkpoint for `account`.\n */\n function checkpoints(address account, uint32 pos) public view virtual returns (Checkpoint memory) {\n return _checkpoints[account][pos];\n }\n\n /**\n * @dev Get number of checkpoints for `account`.\n */\n function numCheckpoints(address account) public view virtual returns (uint32) {\n return SafeCast.toUint32(_checkpoints[account].length);\n }\n\n /**\n * @dev Get the address `account` is currently delegating to.\n */\n function delegates(address account) public view virtual override returns (address) {\n return _delegates[account];\n }\n\n /**\n * @dev Gets the current votes balance for `account`\n */\n function getVotes(address account) public view virtual override returns (uint256) {\n uint256 pos = _checkpoints[account].length;\n return pos == 0 ? 0 : _checkpoints[account][pos - 1].votes;\n }\n\n /**\n * @dev Retrieve the number of votes for `account` at the end of `blockNumber`.\n *\n * Requirements:\n *\n * - `blockNumber` must have been already mined\n */\n function getPastVotes(address account, uint256 blockNumber) public view virtual override returns (uint256) {\n require(blockNumber < block.number, \"ERC20Votes: block not yet mined\");\n return _checkpointsLookup(_checkpoints[account], blockNumber);\n }\n\n /**\n * @dev Retrieve the `totalSupply` at the end of `blockNumber`. Note, this value is the sum of all balances.\n * It is but NOT the sum of all the delegated votes!\n *\n * Requirements:\n *\n * - `blockNumber` must have been already mined\n */\n function getPastTotalSupply(uint256 blockNumber) public view virtual override returns (uint256) {\n require(blockNumber < block.number, \"ERC20Votes: block not yet mined\");\n return _checkpointsLookup(_totalSupplyCheckpoints, blockNumber);\n }\n\n /**\n * @dev Lookup a value in a list of (sorted) checkpoints.\n */\n function _checkpointsLookup(Checkpoint[] storage ckpts, uint256 blockNumber) private view returns (uint256) {\n // We run a binary search to look for the earliest checkpoint taken after `blockNumber`.\n //\n // During the loop, the index of the wanted checkpoint remains in the range [low-1, high).\n // With each iteration, either `low` or `high` is moved towards the middle of the range to maintain the invariant.\n // - If the middle checkpoint is after `blockNumber`, we look in [low, mid)\n // - If the middle checkpoint is before or equal to `blockNumber`, we look in [mid+1, high)\n // Once we reach a single value (when low == high), we've found the right checkpoint at the index high-1, if not\n // out of bounds (in which case we're looking too far in the past and the result is 0).\n // Note that if the latest checkpoint available is exactly for `blockNumber`, we end up with an index that is\n // past the end of the array, so we technically don't find a checkpoint after `blockNumber`, but it works out\n // the same.\n uint256 high = ckpts.length;\n uint256 low = 0;\n while (low < high) {\n uint256 mid = Math.average(low, high);\n if (ckpts[mid].fromBlock > blockNumber) {\n high = mid;\n } else {\n low = mid + 1;\n }\n }\n\n return high == 0 ? 0 : ckpts[high - 1].votes;\n }\n\n /**\n * @dev Delegate votes from the sender to `delegatee`.\n */\n function delegate(address delegatee) public virtual override {\n _delegate(_msgSender(), delegatee);\n }\n\n /**\n * @dev Delegates votes from signer to `delegatee`\n */\n function delegateBySig(\n address delegatee,\n uint256 nonce,\n uint256 expiry,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) public virtual override {\n require(block.timestamp <= expiry, \"ERC20Votes: signature expired\");\n address signer = ECDSA.recover(\n _hashTypedDataV4(keccak256(abi.encode(_DELEGATION_TYPEHASH, delegatee, nonce, expiry))),\n v,\n r,\n s\n );\n require(nonce == _useNonce(signer), \"ERC20Votes: invalid nonce\");\n _delegate(signer, delegatee);\n }\n\n /**\n * @dev Maximum token supply. Defaults to `type(uint224).max` (2^224^ - 1).\n */\n function _maxSupply() internal view virtual returns (uint224) {\n return type(uint224).max;\n }\n\n /**\n * @dev Snapshots the totalSupply after it has been increased.\n */\n function _mint(address account, uint256 amount) internal virtual override {\n super._mint(account, amount);\n require(totalSupply() <= _maxSupply(), \"ERC20Votes: total supply risks overflowing votes\");\n\n _writeCheckpoint(_totalSupplyCheckpoints, _add, amount);\n }\n\n /**\n * @dev Snapshots the totalSupply after it has been decreased.\n */\n function _burn(address account, uint256 amount) internal virtual override {\n super._burn(account, amount);\n\n _writeCheckpoint(_totalSupplyCheckpoints, _subtract, amount);\n }\n\n /**\n * @dev Move voting power when tokens are transferred.\n *\n * Emits a {DelegateVotesChanged} event.\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual override {\n super._afterTokenTransfer(from, to, amount);\n\n _moveVotingPower(delegates(from), delegates(to), amount);\n }\n\n /**\n * @dev Change delegation for `delegator` to `delegatee`.\n *\n * Emits events {DelegateChanged} and {DelegateVotesChanged}.\n */\n function _delegate(address delegator, address delegatee) internal virtual {\n address currentDelegate = delegates(delegator);\n uint256 delegatorBalance = balanceOf(delegator);\n _delegates[delegator] = delegatee;\n\n emit DelegateChanged(delegator, currentDelegate, delegatee);\n\n _moveVotingPower(currentDelegate, delegatee, delegatorBalance);\n }\n\n function _moveVotingPower(\n address src,\n address dst,\n uint256 amount\n ) private {\n if (src != dst && amount > 0) {\n if (src != address(0)) {\n (uint256 oldWeight, uint256 newWeight) = _writeCheckpoint(_checkpoints[src], _subtract, amount);\n emit DelegateVotesChanged(src, oldWeight, newWeight);\n }\n\n if (dst != address(0)) {\n (uint256 oldWeight, uint256 newWeight) = _writeCheckpoint(_checkpoints[dst], _add, amount);\n emit DelegateVotesChanged(dst, oldWeight, newWeight);\n }\n }\n }\n\n function _writeCheckpoint(\n Checkpoint[] storage ckpts,\n function(uint256, uint256) view returns (uint256) op,\n uint256 delta\n ) private returns (uint256 oldWeight, uint256 newWeight) {\n uint256 pos = ckpts.length;\n oldWeight = pos == 0 ? 0 : ckpts[pos - 1].votes;\n newWeight = op(oldWeight, delta);\n\n if (pos > 0 && ckpts[pos - 1].fromBlock == block.number) {\n ckpts[pos - 1].votes = SafeCast.toUint224(newWeight);\n } else {\n ckpts.push(Checkpoint({fromBlock: SafeCast.toUint32(block.number), votes: SafeCast.toUint224(newWeight)}));\n }\n }\n\n function _add(uint256 a, uint256 b) private pure returns (uint256) {\n return a + b;\n }\n\n function _subtract(uint256 a, uint256 b) private pure returns (uint256) {\n return a - b;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Context.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-ERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./draft-IERC20Permit.sol\";\nimport \"../ERC20.sol\";\nimport \"../../../utils/cryptography/draft-EIP712.sol\";\nimport \"../../../utils/cryptography/ECDSA.sol\";\nimport \"../../../utils/Counters.sol\";\n\n/**\n * @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * _Available since v3.4._\n */\nabstract contract ERC20Permit is ERC20, IERC20Permit, EIP712 {\n using Counters for Counters.Counter;\n\n mapping(address => Counters.Counter) private _nonces;\n\n // solhint-disable-next-line var-name-mixedcase\n bytes32 private immutable _PERMIT_TYPEHASH =\n keccak256(\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\");\n\n /**\n * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `\"1\"`.\n *\n * It's a good idea to use the same `name` that is defined as the ERC20 token name.\n */\n constructor(string memory name) EIP712(name, \"1\") {}\n\n /**\n * @dev See {IERC20Permit-permit}.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) public virtual override {\n require(block.timestamp <= deadline, \"ERC20Permit: expired deadline\");\n\n bytes32 structHash = keccak256(abi.encode(_PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline));\n\n bytes32 hash = _hashTypedDataV4(structHash);\n\n address signer = ECDSA.recover(hash, v, r, s);\n require(signer == owner, \"ERC20Permit: invalid signature\");\n\n _approve(owner, spender, value);\n }\n\n /**\n * @dev See {IERC20Permit-nonces}.\n */\n function nonces(address owner) public view virtual override returns (uint256) {\n return _nonces[owner].current();\n }\n\n /**\n * @dev See {IERC20Permit-DOMAIN_SEPARATOR}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view override returns (bytes32) {\n return _domainSeparatorV4();\n }\n\n /**\n * @dev \"Consume a nonce\": return the current value and increment.\n *\n * _Available since v4.1._\n */\n function _useNonce(address owner) internal virtual returns (uint256 current) {\n Counters.Counter storage nonce = _nonces[owner];\n current = nonce.current();\n nonce.increment();\n }\n}\n" + }, + "@openzeppelin/contracts/utils/math/Math.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n /**\n * @dev Returns the largest of two numbers.\n */\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\n return a >= b ? a : b;\n }\n\n /**\n * @dev Returns the smallest of two numbers.\n */\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\n return a < b ? a : b;\n }\n\n /**\n * @dev Returns the average of two numbers. The result is rounded towards\n * zero.\n */\n function average(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b) / 2 can overflow.\n return (a & b) + (a ^ b) / 2;\n }\n\n /**\n * @dev Returns the ceiling of the division of two numbers.\n *\n * This differs from standard division with `/` in that it rounds up instead\n * of rounding down.\n */\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b - 1) / b can overflow on addition, so we distribute.\n return a / b + (a % b == 0 ? 0 : 1);\n }\n\n /**\n * @dev Returns the absolute unsigned value of a signed value.\n */\n function abs(int256 n) internal pure returns (uint256) {\n unchecked {\n // must be unchecked in order to support `n = type(int256).min`\n return uint256(n >= 0 ? n : -n);\n }\n }\n}\n" + }, + "@openzeppelin/contracts/governance/utils/IVotes.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (governance/utils/IVotes.sol)\npragma solidity ^0.8.0;\n\n/**\n * @dev Common interface for {ERC20Votes}, {ERC721Votes}, and other {Votes}-enabled contracts.\n *\n * _Available since v4.5._\n */\ninterface IVotes {\n /**\n * @dev Emitted when an account changes their delegate.\n */\n event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);\n\n /**\n * @dev Emitted when a token transfer or delegate change results in changes to a delegate's number of votes.\n */\n event DelegateVotesChanged(address indexed delegate, uint256 previousBalance, uint256 newBalance);\n\n /**\n * @dev Returns the current amount of votes that `account` has.\n */\n function getVotes(address account) external view returns (uint256);\n\n /**\n * @dev Returns the amount of votes that `account` had at the end of a past block (`blockNumber`).\n */\n function getPastVotes(address account, uint256 blockNumber) external view returns (uint256);\n\n /**\n * @dev Returns the total supply of votes available at the end of a past block (`blockNumber`).\n *\n * NOTE: This value is the sum of all available votes, which is not necessarily the sum of all delegated votes.\n * Votes that have not been delegated are still part of total supply, even though they would not participate in a\n * vote.\n */\n function getPastTotalSupply(uint256 blockNumber) external view returns (uint256);\n\n /**\n * @dev Returns the delegate that `account` has chosen.\n */\n function delegates(address account) external view returns (address);\n\n /**\n * @dev Delegates votes from the sender to `delegatee`.\n */\n function delegate(address delegatee) external;\n\n /**\n * @dev Delegates votes from signer to `delegatee`.\n */\n function delegateBySig(\n address delegatee,\n uint256 nonce,\n uint256 expiry,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n}\n" + }, + "@openzeppelin/contracts/utils/math/SafeCast.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeCast.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow\n * checks.\n *\n * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can\n * easily result in undesired exploitation or bugs, since developers usually\n * assume that overflows raise errors. `SafeCast` restores this intuition by\n * reverting the transaction when such an operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n *\n * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing\n * all math on `uint256` and `int256` and then downcasting.\n */\nlibrary SafeCast {\n /**\n * @dev Returns the downcasted uint224 from uint256, reverting on\n * overflow (when the input is greater than largest uint224).\n *\n * Counterpart to Solidity's `uint224` operator.\n *\n * Requirements:\n *\n * - input must fit into 224 bits\n */\n function toUint224(uint256 value) internal pure returns (uint224) {\n require(value <= type(uint224).max, \"SafeCast: value doesn't fit in 224 bits\");\n return uint224(value);\n }\n\n /**\n * @dev Returns the downcasted uint128 from uint256, reverting on\n * overflow (when the input is greater than largest uint128).\n *\n * Counterpart to Solidity's `uint128` operator.\n *\n * Requirements:\n *\n * - input must fit into 128 bits\n */\n function toUint128(uint256 value) internal pure returns (uint128) {\n require(value <= type(uint128).max, \"SafeCast: value doesn't fit in 128 bits\");\n return uint128(value);\n }\n\n /**\n * @dev Returns the downcasted uint96 from uint256, reverting on\n * overflow (when the input is greater than largest uint96).\n *\n * Counterpart to Solidity's `uint96` operator.\n *\n * Requirements:\n *\n * - input must fit into 96 bits\n */\n function toUint96(uint256 value) internal pure returns (uint96) {\n require(value <= type(uint96).max, \"SafeCast: value doesn't fit in 96 bits\");\n return uint96(value);\n }\n\n /**\n * @dev Returns the downcasted uint64 from uint256, reverting on\n * overflow (when the input is greater than largest uint64).\n *\n * Counterpart to Solidity's `uint64` operator.\n *\n * Requirements:\n *\n * - input must fit into 64 bits\n */\n function toUint64(uint256 value) internal pure returns (uint64) {\n require(value <= type(uint64).max, \"SafeCast: value doesn't fit in 64 bits\");\n return uint64(value);\n }\n\n /**\n * @dev Returns the downcasted uint32 from uint256, reverting on\n * overflow (when the input is greater than largest uint32).\n *\n * Counterpart to Solidity's `uint32` operator.\n *\n * Requirements:\n *\n * - input must fit into 32 bits\n */\n function toUint32(uint256 value) internal pure returns (uint32) {\n require(value <= type(uint32).max, \"SafeCast: value doesn't fit in 32 bits\");\n return uint32(value);\n }\n\n /**\n * @dev Returns the downcasted uint16 from uint256, reverting on\n * overflow (when the input is greater than largest uint16).\n *\n * Counterpart to Solidity's `uint16` operator.\n *\n * Requirements:\n *\n * - input must fit into 16 bits\n */\n function toUint16(uint256 value) internal pure returns (uint16) {\n require(value <= type(uint16).max, \"SafeCast: value doesn't fit in 16 bits\");\n return uint16(value);\n }\n\n /**\n * @dev Returns the downcasted uint8 from uint256, reverting on\n * overflow (when the input is greater than largest uint8).\n *\n * Counterpart to Solidity's `uint8` operator.\n *\n * Requirements:\n *\n * - input must fit into 8 bits.\n */\n function toUint8(uint256 value) internal pure returns (uint8) {\n require(value <= type(uint8).max, \"SafeCast: value doesn't fit in 8 bits\");\n return uint8(value);\n }\n\n /**\n * @dev Converts a signed int256 into an unsigned uint256.\n *\n * Requirements:\n *\n * - input must be greater than or equal to 0.\n */\n function toUint256(int256 value) internal pure returns (uint256) {\n require(value >= 0, \"SafeCast: value must be positive\");\n return uint256(value);\n }\n\n /**\n * @dev Returns the downcasted int128 from int256, reverting on\n * overflow (when the input is less than smallest int128 or\n * greater than largest int128).\n *\n * Counterpart to Solidity's `int128` operator.\n *\n * Requirements:\n *\n * - input must fit into 128 bits\n *\n * _Available since v3.1._\n */\n function toInt128(int256 value) internal pure returns (int128) {\n require(value >= type(int128).min && value <= type(int128).max, \"SafeCast: value doesn't fit in 128 bits\");\n return int128(value);\n }\n\n /**\n * @dev Returns the downcasted int64 from int256, reverting on\n * overflow (when the input is less than smallest int64 or\n * greater than largest int64).\n *\n * Counterpart to Solidity's `int64` operator.\n *\n * Requirements:\n *\n * - input must fit into 64 bits\n *\n * _Available since v3.1._\n */\n function toInt64(int256 value) internal pure returns (int64) {\n require(value >= type(int64).min && value <= type(int64).max, \"SafeCast: value doesn't fit in 64 bits\");\n return int64(value);\n }\n\n /**\n * @dev Returns the downcasted int32 from int256, reverting on\n * overflow (when the input is less than smallest int32 or\n * greater than largest int32).\n *\n * Counterpart to Solidity's `int32` operator.\n *\n * Requirements:\n *\n * - input must fit into 32 bits\n *\n * _Available since v3.1._\n */\n function toInt32(int256 value) internal pure returns (int32) {\n require(value >= type(int32).min && value <= type(int32).max, \"SafeCast: value doesn't fit in 32 bits\");\n return int32(value);\n }\n\n /**\n * @dev Returns the downcasted int16 from int256, reverting on\n * overflow (when the input is less than smallest int16 or\n * greater than largest int16).\n *\n * Counterpart to Solidity's `int16` operator.\n *\n * Requirements:\n *\n * - input must fit into 16 bits\n *\n * _Available since v3.1._\n */\n function toInt16(int256 value) internal pure returns (int16) {\n require(value >= type(int16).min && value <= type(int16).max, \"SafeCast: value doesn't fit in 16 bits\");\n return int16(value);\n }\n\n /**\n * @dev Returns the downcasted int8 from int256, reverting on\n * overflow (when the input is less than smallest int8 or\n * greater than largest int8).\n *\n * Counterpart to Solidity's `int8` operator.\n *\n * Requirements:\n *\n * - input must fit into 8 bits.\n *\n * _Available since v3.1._\n */\n function toInt8(int256 value) internal pure returns (int8) {\n require(value >= type(int8).min && value <= type(int8).max, \"SafeCast: value doesn't fit in 8 bits\");\n return int8(value);\n }\n\n /**\n * @dev Converts an unsigned uint256 into a signed int256.\n *\n * Requirements:\n *\n * - input must be less than or equal to maxInt256.\n */\n function toInt256(uint256 value) internal pure returns (int256) {\n // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive\n require(value <= uint256(type(int256).max), \"SafeCast: value doesn't fit in an int256\");\n return int256(value);\n }\n}\n" + }, + "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n // Check the signature length\n // - case 65: r,s,v signature (standard)\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else if (signature.length == 64) {\n bytes32 r;\n bytes32 vs;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n vs := mload(add(signature, 0x40))\n }\n return tryRecover(hash, r, vs);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/ERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `recipient` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address recipient, uint256 amount) public virtual override returns (bool) {\n _transfer(_msgSender(), recipient, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n _approve(_msgSender(), spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `sender` and `recipient` cannot be the zero address.\n * - `sender` must have a balance of at least `amount`.\n * - the caller must have allowance for ``sender``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) public virtual override returns (bool) {\n uint256 currentAllowance = _allowances[sender][_msgSender()];\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: transfer amount exceeds allowance\");\n unchecked {\n _approve(sender, _msgSender(), currentAllowance - amount);\n }\n }\n\n _transfer(sender, recipient, amount);\n\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n _approve(_msgSender(), spender, _allowances[_msgSender()][spender] + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n uint256 currentAllowance = _allowances[_msgSender()][spender];\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(_msgSender(), spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `sender` cannot be the zero address.\n * - `recipient` cannot be the zero address.\n * - `sender` must have a balance of at least `amount`.\n */\n function _transfer(\n address sender,\n address recipient,\n uint256 amount\n ) internal virtual {\n require(sender != address(0), \"ERC20: transfer from the zero address\");\n require(recipient != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(sender, recipient, amount);\n\n uint256 senderBalance = _balances[sender];\n require(senderBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[sender] = senderBalance - amount;\n }\n _balances[recipient] += amount;\n\n emit Transfer(sender, recipient, amount);\n\n _afterTokenTransfer(sender, recipient, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" + }, + "@openzeppelin/contracts/utils/cryptography/draft-EIP712.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/cryptography/draft-EIP712.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./ECDSA.sol\";\n\n/**\n * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.\n *\n * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,\n * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding\n * they need in their contracts using a combination of `abi.encode` and `keccak256`.\n *\n * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding\n * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA\n * ({_hashTypedDataV4}).\n *\n * The implementation of the domain separator was designed to be as efficient as possible while still properly updating\n * the chain id to protect against replay attacks on an eventual fork of the chain.\n *\n * NOTE: This contract implements the version of the encoding known as \"v4\", as implemented by the JSON RPC method\n * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].\n *\n * _Available since v3.4._\n */\nabstract contract EIP712 {\n /* solhint-disable var-name-mixedcase */\n // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to\n // invalidate the cached domain separator if the chain id changes.\n bytes32 private immutable _CACHED_DOMAIN_SEPARATOR;\n uint256 private immutable _CACHED_CHAIN_ID;\n address private immutable _CACHED_THIS;\n\n bytes32 private immutable _HASHED_NAME;\n bytes32 private immutable _HASHED_VERSION;\n bytes32 private immutable _TYPE_HASH;\n\n /* solhint-enable var-name-mixedcase */\n\n /**\n * @dev Initializes the domain separator and parameter caches.\n *\n * The meaning of `name` and `version` is specified in\n * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:\n *\n * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.\n * - `version`: the current major version of the signing domain.\n *\n * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart\n * contract upgrade].\n */\n constructor(string memory name, string memory version) {\n bytes32 hashedName = keccak256(bytes(name));\n bytes32 hashedVersion = keccak256(bytes(version));\n bytes32 typeHash = keccak256(\n \"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\"\n );\n _HASHED_NAME = hashedName;\n _HASHED_VERSION = hashedVersion;\n _CACHED_CHAIN_ID = block.chainid;\n _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion);\n _CACHED_THIS = address(this);\n _TYPE_HASH = typeHash;\n }\n\n /**\n * @dev Returns the domain separator for the current chain.\n */\n function _domainSeparatorV4() internal view returns (bytes32) {\n if (address(this) == _CACHED_THIS && block.chainid == _CACHED_CHAIN_ID) {\n return _CACHED_DOMAIN_SEPARATOR;\n } else {\n return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION);\n }\n }\n\n function _buildDomainSeparator(\n bytes32 typeHash,\n bytes32 nameHash,\n bytes32 versionHash\n ) private view returns (bytes32) {\n return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this)));\n }\n\n /**\n * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this\n * function returns the hash of the fully encoded EIP712 message for this domain.\n *\n * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:\n *\n * ```solidity\n * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(\n * keccak256(\"Mail(address to,string contents)\"),\n * mailTo,\n * keccak256(bytes(mailContents))\n * )));\n * address signer = ECDSA.recover(digest, signature);\n * ```\n */\n function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {\n return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Counters.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Counters.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @title Counters\n * @author Matt Condon (@shrugs)\n * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number\n * of elements in a mapping, issuing ERC721 ids, or counting request ids.\n *\n * Include with `using Counters for Counters.Counter;`\n */\nlibrary Counters {\n struct Counter {\n // This variable should never be directly accessed by users of the library: interactions must be restricted to\n // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add\n // this feature: see https://github.com/ethereum/solidity/issues/4637\n uint256 _value; // default: 0\n }\n\n function current(Counter storage counter) internal view returns (uint256) {\n return counter._value;\n }\n\n function increment(Counter storage counter) internal {\n unchecked {\n counter._value += 1;\n }\n }\n\n function decrement(Counter storage counter) internal {\n uint256 value = counter._value;\n require(value > 0, \"Counter: decrement overflow\");\n unchecked {\n counter._value = value - 1;\n }\n }\n\n function reset(Counter storage counter) internal {\n counter._value = 0;\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/IERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address recipient, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) external returns (bool);\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" + }, + "@openzeppelin/contracts/utils/Strings.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n}\n" + }, + "contracts/JBController3_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {ERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {JBOperatable} from './abstract/JBOperatable.sol';\nimport {JBBallotState} from './enums/JBBallotState.sol';\nimport {IJBController3_0_1} from './interfaces/IJBController3_0_1.sol';\nimport {IJBController3_1} from './interfaces/IJBController3_1.sol';\nimport {IJBController} from './interfaces/IJBController.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBFundAccessConstraintsStore} from './interfaces/IJBFundAccessConstraintsStore.sol';\nimport {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol';\nimport {IJBMigratable} from './interfaces/IJBMigratable.sol';\nimport {IJBOperatable} from './interfaces/IJBOperatable.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {IJBSplitAllocator} from './interfaces/IJBSplitAllocator.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {IJBTokenStore} from './interfaces/IJBTokenStore.sol';\nimport {JBConstants} from './libraries/JBConstants.sol';\nimport {JBFundingCycleMetadataResolver} from './libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBOperations} from './libraries/JBOperations.sol';\nimport {JBSplitsGroups} from './libraries/JBSplitsGroups.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\nimport {JBSplitAllocationData} from './structs/JBSplitAllocationData.sol';\nimport {JBFundAccessConstraints} from './structs/JBFundAccessConstraints.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\nimport {JBFundingCycleData} from './structs/JBFundingCycleData.sol';\nimport {JBFundingCycleMetadata} from './structs/JBFundingCycleMetadata.sol';\nimport {JBGroupedSplits} from './structs/JBGroupedSplits.sol';\nimport {JBProjectMetadata} from './structs/JBProjectMetadata.sol';\nimport {JBSplit} from './structs/JBSplit.sol';\n\n/// @notice Stitches together funding cycles and project tokens, making sure all activity is accounted for and correct.\n/// @dev This Controller has the same functionality as JBController3_0_1, except it is not backwards compatible with the original IJBController view methods.\ncontract JBController3_1 is JBOperatable, ERC165, IJBController3_1, IJBMigratable {\n // A library that parses the packed funding cycle metadata into a more friendly format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n\n error BURN_PAUSED_AND_SENDER_NOT_VALID_TERMINAL_DELEGATE();\n error FUNDING_CYCLE_ALREADY_LAUNCHED();\n error INVALID_BALLOT_REDEMPTION_RATE();\n error INVALID_REDEMPTION_RATE();\n error INVALID_RESERVED_RATE();\n error MIGRATION_NOT_ALLOWED();\n error MINT_NOT_ALLOWED_AND_NOT_TERMINAL_DELEGATE();\n error NO_BURNABLE_TOKENS();\n error NOT_CURRENT_CONTROLLER();\n error ZERO_TOKENS_TO_MINT();\n\n //*********************************************************************//\n // --------------------- internal stored properties ------------------ //\n //*********************************************************************//\n\n /// @notice Data regarding the distribution limit of a project during a configuration.\n /// @dev bits 0-231: The amount of token that a project can distribute per funding cycle.\n /// @dev bits 232-255: The currency of amount that a project can distribute.\n /// @custom:param _projectId The ID of the project to get the packed distribution limit data of.\n /// @custom:param _configuration The configuration during which the packed distribution limit data applies.\n /// @custom:param _terminal The terminal from which distributions are being limited.\n /// @custom:param _token The token for which distributions are being limited.\n mapping(uint256 => mapping(uint256 => mapping(IJBPaymentTerminal => mapping(address => uint256))))\n internal _packedDistributionLimitDataOf;\n\n /// @notice Data regarding the overflow allowance of a project during a configuration.\n /// @dev bits 0-231: The amount of overflow that a project is allowed to tap into on-demand throughout the configuration.\n /// @dev bits 232-255: The currency of the amount of overflow that a project is allowed to tap.\n /// @custom:param _projectId The ID of the project to get the packed overflow allowance data of.\n /// @custom:param _configuration The configuration during which the packed overflow allowance data applies.\n /// @custom:param _terminal The terminal managing the overflow.\n /// @custom:param _token The token for which overflow is being allowed.\n mapping(uint256 => mapping(uint256 => mapping(IJBPaymentTerminal => mapping(address => uint256))))\n internal _packedOverflowAllowanceDataOf;\n\n //*********************************************************************//\n // --------------- public immutable stored properties ---------------- //\n //*********************************************************************//\n\n /// @notice Mints ERC-721's that represent project ownership.\n IJBProjects public immutable override projects;\n\n /// @notice The contract storing all funding cycle configurations.\n IJBFundingCycleStore public immutable override fundingCycleStore;\n\n /// @notice The contract that manages token minting and burning.\n IJBTokenStore public immutable override tokenStore;\n\n /// @notice The contract that stores splits for each project.\n IJBSplitsStore public immutable override splitsStore;\n\n /// @notice A contract that stores fund access constraints for each project.\n IJBFundAccessConstraintsStore public immutable override fundAccessConstraintsStore;\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The current undistributed reserved token balance of.\n mapping(uint256 => uint256) public override reservedTokenBalanceOf;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice A project's funding cycle for the specified configuration along with its metadata.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The funding cycle.\n /// @return metadata The funding cycle's metadata.\n function getFundingCycleOf(\n uint256 _projectId,\n uint256 _configuration\n )\n external\n view\n override\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata)\n {\n fundingCycle = fundingCycleStore.get(_projectId, _configuration);\n metadata = fundingCycle.expandMetadata();\n }\n\n /// @notice A project's latest configured funding cycle along with its metadata and the ballot state of the configuration.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The latest configured funding cycle.\n /// @return metadata The latest configured funding cycle's metadata.\n /// @return ballotState The state of the configuration.\n function latestConfiguredFundingCycleOf(\n uint256 _projectId\n )\n external\n view\n override\n returns (\n JBFundingCycle memory fundingCycle,\n JBFundingCycleMetadata memory metadata,\n JBBallotState ballotState\n )\n {\n (fundingCycle, ballotState) = fundingCycleStore.latestConfiguredOf(_projectId);\n metadata = fundingCycle.expandMetadata();\n }\n\n /// @notice A project's current funding cycle along with its metadata.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The current funding cycle.\n /// @return metadata The current funding cycle's metadata.\n function currentFundingCycleOf(\n uint256 _projectId\n )\n external\n view\n override\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata)\n {\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n metadata = fundingCycle.expandMetadata();\n }\n\n /// @notice A project's queued funding cycle along with its metadata.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The queued funding cycle.\n /// @return metadata The queued funding cycle's metadata.\n function queuedFundingCycleOf(\n uint256 _projectId\n )\n external\n view\n override\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata)\n {\n fundingCycle = fundingCycleStore.queuedOf(_projectId);\n metadata = fundingCycle.expandMetadata();\n }\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice Gets the current total amount of outstanding tokens for a project.\n /// @param _projectId The ID of the project to get total outstanding tokens of.\n /// @return The current total amount of outstanding tokens for the project.\n function totalOutstandingTokensOf(uint256 _projectId) public view override returns (uint256) {\n // Add the reserved tokens to the total supply.\n return tokenStore.totalSupplyOf(_projectId) + reservedTokenBalanceOf[_projectId];\n }\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if the provided interface ID is supported.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(ERC165, IERC165) returns (bool) {\n return\n _interfaceId == type(IJBController3_1).interfaceId ||\n _interfaceId == type(IJBController3_0_1).interfaceId ||\n _interfaceId == type(IJBMigratable).interfaceId ||\n _interfaceId == type(IJBOperatable).interfaceId ||\n super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // ---------------------------- constructor -------------------------- //\n //*********************************************************************//\n\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _fundingCycleStore A contract storing all funding cycle configurations.\n /// @param _tokenStore A contract that manages token minting and burning.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _fundAccessConstraintsStore A contract that stores fund access constraints for each project.\n constructor(\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBFundingCycleStore _fundingCycleStore,\n IJBTokenStore _tokenStore,\n IJBSplitsStore _splitsStore,\n IJBFundAccessConstraintsStore _fundAccessConstraintsStore\n ) JBOperatable(_operatorStore) {\n projects = _projects;\n directory = _directory;\n fundingCycleStore = _fundingCycleStore;\n tokenStore = _tokenStore;\n splitsStore = _splitsStore;\n fundAccessConstraintsStore = _fundAccessConstraintsStore;\n }\n\n //*********************************************************************//\n // --------------------- external transactions ----------------------- //\n //*********************************************************************//\n\n /// @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.\n /// @dev Each operation within this transaction can be done in sequence separately.\n /// @dev Anyone can deploy a project on an owner's behalf.\n /// @param _owner The address to set as the owner of the project. The project ERC-721 will be owned by this address.\n /// @param _projectMetadata Metadata to associate with the project within a particular domain. This can be updated any time by the owner of the project.\n /// @param _data Data that defines the project's first funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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`.\n /// @param _terminals Payment terminals to add for the project.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return projectId The ID of the project.\n function launchProjectFor(\n address _owner,\n JBProjectMetadata calldata _projectMetadata,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] calldata _groupedSplits,\n JBFundAccessConstraints[] calldata _fundAccessConstraints,\n IJBPaymentTerminal[] memory _terminals,\n string memory _memo\n ) external virtual override returns (uint256 projectId) {\n // Keep a reference to the directory.\n IJBDirectory _directory = directory;\n\n // Mint the project into the wallet of the owner.\n projectId = projects.createFor(_owner, _projectMetadata);\n\n // Set this contract as the project's controller in the directory.\n _directory.setControllerOf(projectId, address(this));\n\n // Configure the first funding cycle.\n uint256 _configuration = _configure(\n projectId,\n _data,\n _metadata,\n _mustStartAtOrAfter,\n _groupedSplits,\n _fundAccessConstraints\n );\n\n // Add the provided terminals to the list of terminals.\n if (_terminals.length > 0) _directory.setTerminalsOf(projectId, _terminals);\n\n emit LaunchProject(_configuration, projectId, _memo, msg.sender);\n }\n\n /// @notice Creates a funding cycle for an already existing project ERC-721.\n /// @dev Each operation within this transaction can be done in sequence separately.\n /// @dev Only a project owner or operator can launch its funding cycles.\n /// @param _projectId The ID of the project to launch funding cycles for.\n /// @param _data Data that defines the project's first funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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`.\n /// @param _terminals Payment terminals to add for the project.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return configuration The configuration of the funding cycle that was successfully created.\n function launchFundingCyclesFor(\n uint256 _projectId,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] calldata _groupedSplits,\n JBFundAccessConstraints[] memory _fundAccessConstraints,\n IJBPaymentTerminal[] memory _terminals,\n string memory _memo\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.RECONFIGURE)\n returns (uint256 configuration)\n {\n // If there is a previous configuration, reconfigureFundingCyclesOf should be called instead\n if (fundingCycleStore.latestConfigurationOf(_projectId) > 0)\n revert FUNDING_CYCLE_ALREADY_LAUNCHED();\n\n // Set this contract as the project's controller in the directory.\n directory.setControllerOf(_projectId, address(this));\n\n // Configure the first funding cycle.\n configuration = _configure(\n _projectId,\n _data,\n _metadata,\n _mustStartAtOrAfter,\n _groupedSplits,\n _fundAccessConstraints\n );\n\n // Add the provided terminals to the list of terminals.\n if (_terminals.length > 0) directory.setTerminalsOf(_projectId, _terminals);\n\n emit LaunchFundingCycles(configuration, _projectId, _memo, msg.sender);\n }\n\n /// @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.\n /// @dev Only a project's owner or a designated operator can configure its funding cycles.\n /// @param _projectId The ID of the project whose funding cycles are being reconfigured.\n /// @param _data Data that defines the funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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`.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return configuration The configuration of the funding cycle that was successfully reconfigured.\n function reconfigureFundingCyclesOf(\n uint256 _projectId,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] calldata _groupedSplits,\n JBFundAccessConstraints[] calldata _fundAccessConstraints,\n string calldata _memo\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.RECONFIGURE)\n returns (uint256 configuration)\n {\n // Configure the next funding cycle.\n configuration = _configure(\n _projectId,\n _data,\n _metadata,\n _mustStartAtOrAfter,\n _groupedSplits,\n _fundAccessConstraints\n );\n\n emit ReconfigureFundingCycles(configuration, _projectId, _memo, msg.sender);\n }\n\n /// @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.\n /// @dev Only a project's owner, a designated operator, one of its terminals, or the current data source can mint its tokens.\n /// @param _projectId The ID of the project to which the tokens being minted belong.\n /// @param _tokenCount The amount of tokens to mint in total, counting however many should be reserved.\n /// @param _beneficiary The account that the tokens are being minted for.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _preferClaimedTokens A flag indicating whether a project's attached token contract should be minted if they have been issued.\n /// @param _useReservedRate Whether to use the current funding cycle's reserved rate in the mint calculation.\n /// @return beneficiaryTokenCount The amount of tokens minted for the beneficiary.\n function mintTokensOf(\n uint256 _projectId,\n uint256 _tokenCount,\n address _beneficiary,\n string calldata _memo,\n bool _preferClaimedTokens,\n bool _useReservedRate\n ) external virtual override returns (uint256 beneficiaryTokenCount) {\n // There should be tokens to mint.\n if (_tokenCount == 0) revert ZERO_TOKENS_TO_MINT();\n\n // Define variables that will be needed outside scoped section below.\n // Keep a reference to the reserved rate to use\n uint256 _reservedRate;\n\n // Scoped section prevents stack too deep. `_fundingCycle` only used within scope.\n {\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Minting limited to: project owner, authorized callers, project terminal and current funding cycle data source\n _requirePermissionAllowingOverride(\n projects.ownerOf(_projectId),\n _projectId,\n JBOperations.MINT,\n directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender)) ||\n msg.sender == address(_fundingCycle.dataSource())\n );\n\n // If the message sender is not a terminal or a datasource, the current funding cycle must allow minting.\n if (\n !_fundingCycle.mintingAllowed() &&\n !directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender)) &&\n msg.sender != address(_fundingCycle.dataSource())\n ) revert MINT_NOT_ALLOWED_AND_NOT_TERMINAL_DELEGATE();\n\n // Determine the reserved rate to use.\n _reservedRate = _useReservedRate ? _fundingCycle.reservedRate() : 0;\n\n // Override the claimed token preference with the funding cycle value.\n _preferClaimedTokens = _preferClaimedTokens == true\n ? _preferClaimedTokens\n : _fundingCycle.preferClaimedTokenOverride();\n }\n\n if (_reservedRate != JBConstants.MAX_RESERVED_RATE) {\n // The unreserved token count that will be minted for the beneficiary.\n beneficiaryTokenCount = PRBMath.mulDiv(\n _tokenCount,\n JBConstants.MAX_RESERVED_RATE - _reservedRate,\n JBConstants.MAX_RESERVED_RATE\n );\n\n // Mint the tokens.\n tokenStore.mintFor(_beneficiary, _projectId, beneficiaryTokenCount, _preferClaimedTokens);\n }\n\n // Add reserved tokens if needed\n if (_reservedRate > 0)\n reservedTokenBalanceOf[_projectId] += _tokenCount - beneficiaryTokenCount;\n\n emit MintTokens(\n _beneficiary,\n _projectId,\n _tokenCount,\n beneficiaryTokenCount,\n _memo,\n _reservedRate,\n msg.sender\n );\n }\n\n /// @notice Burns a token holder's supply.\n /// @dev Only a token's holder, a designated operator, or a project's terminal can burn it.\n /// @param _holder The account that is having its tokens burned.\n /// @param _projectId The ID of the project to which the tokens being burned belong.\n /// @param _tokenCount The number of tokens to burn.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _preferClaimedTokens A flag indicating whether a project's attached token contract should be burned first if they have been issued.\n function burnTokensOf(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n string calldata _memo,\n bool _preferClaimedTokens\n )\n external\n virtual\n override\n requirePermissionAllowingOverride(\n _holder,\n _projectId,\n JBOperations.BURN,\n directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender))\n )\n {\n // There should be tokens to burn\n if (_tokenCount == 0) revert NO_BURNABLE_TOKENS();\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // If the message sender is a terminal, the current funding cycle must not be paused.\n if (\n _fundingCycle.burnPaused() &&\n !directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender))\n ) revert BURN_PAUSED_AND_SENDER_NOT_VALID_TERMINAL_DELEGATE();\n\n // Burn the tokens.\n tokenStore.burnFrom(_holder, _projectId, _tokenCount, _preferClaimedTokens);\n\n emit BurnTokens(_holder, _projectId, _tokenCount, _memo, msg.sender);\n }\n\n /// @notice Distributes all outstanding reserved tokens for a project.\n /// @param _projectId The ID of the project to which the reserved tokens belong.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return The amount of minted reserved tokens.\n function distributeReservedTokensOf(\n uint256 _projectId,\n string calldata _memo\n ) external virtual override returns (uint256) {\n return _distributeReservedTokensOf(_projectId, _memo);\n }\n\n /// @notice Allows other controllers to signal to this one that a migration is expected for the specified project.\n /// @dev This controller should not yet be the project's controller.\n /// @param _projectId The ID of the project that will be migrated to this controller.\n /// @param _from The controller being migrated from.\n function prepForMigrationOf(uint256 _projectId, address _from) external virtual override {\n _projectId; // Prevents unused var compiler and natspec complaints.\n _from; // Prevents unused var compiler and natspec complaints.\n }\n\n /// @notice Allows a project to migrate from this controller to another.\n /// @dev Only a project's owner or a designated operator can migrate it.\n /// @param _projectId The ID of the project that will be migrated from this controller.\n /// @param _to The controller to which the project is migrating.\n function migrate(\n uint256 _projectId,\n IJBMigratable _to\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.MIGRATE_CONTROLLER)\n {\n // Keep a reference to the directory.\n IJBDirectory _directory = directory;\n\n // This controller must be the project's current controller.\n if (_directory.controllerOf(_projectId) != address(this)) revert NOT_CURRENT_CONTROLLER();\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Migration must be allowed.\n if (!_fundingCycle.controllerMigrationAllowed()) revert MIGRATION_NOT_ALLOWED();\n\n // All reserved tokens must be minted before migrating.\n if (reservedTokenBalanceOf[_projectId] != 0) _distributeReservedTokensOf(_projectId, '');\n\n // Make sure the new controller is prepped for the migration.\n _to.prepForMigrationOf(_projectId, address(this));\n\n // Set the new controller.\n _directory.setControllerOf(_projectId, address(_to));\n\n emit Migrate(_projectId, _to, msg.sender);\n }\n\n //*********************************************************************//\n // ------------------------ internal functions ----------------------- //\n //*********************************************************************//\n\n /// @notice Distributes all outstanding reserved tokens for a project.\n /// @param _projectId The ID of the project to which the reserved tokens belong.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return tokenCount The amount of minted reserved tokens.\n function _distributeReservedTokensOf(\n uint256 _projectId,\n string memory _memo\n ) internal returns (uint256 tokenCount) {\n // Keep a reference to the token store.\n IJBTokenStore _tokenStore = tokenStore;\n\n // Get the current funding cycle to read the reserved rate from.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Get a reference to the number of tokens that need to be minted.\n tokenCount = reservedTokenBalanceOf[_projectId];\n\n // Reset the reserved token balance\n reservedTokenBalanceOf[_projectId] = 0;\n\n // Get a reference to the project owner.\n address _owner = projects.ownerOf(_projectId);\n\n // Distribute tokens to splits and get a reference to the leftover amount to mint after all splits have gotten their share.\n uint256 _leftoverTokenCount = tokenCount == 0\n ? 0\n : _distributeToReservedTokenSplitsOf(\n _projectId,\n _fundingCycle.configuration,\n JBSplitsGroups.RESERVED_TOKENS,\n tokenCount\n );\n\n // Mint any leftover tokens to the project owner.\n if (_leftoverTokenCount > 0)\n _tokenStore.mintFor(_owner, _projectId, _leftoverTokenCount, false);\n\n emit DistributeReservedTokens(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _owner,\n tokenCount,\n _leftoverTokenCount,\n _memo,\n msg.sender\n );\n }\n\n /// @notice Distribute tokens to the splits according to the specified funding cycle configuration.\n /// @param _projectId The ID of the project for which reserved token splits are being distributed.\n /// @param _domain The domain of the splits to distribute the reserved tokens between.\n /// @param _group The group of the splits to distribute the reserved tokens between.\n /// @param _amount The total amount of tokens to mint.\n /// @return leftoverAmount If the splits percents dont add up to 100%, the leftover amount is returned.\n function _distributeToReservedTokenSplitsOf(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group,\n uint256 _amount\n ) internal returns (uint256 leftoverAmount) {\n // Keep a reference to the token store.\n IJBTokenStore _tokenStore = tokenStore;\n\n // Set the leftover amount to the initial amount.\n leftoverAmount = _amount;\n\n // Get a reference to the project's reserved token splits.\n JBSplit[] memory _splits = splitsStore.splitsOf(_projectId, _domain, _group);\n\n //Transfer between all splits.\n for (uint256 _i; _i < _splits.length; ) {\n // Get a reference to the split being iterated on.\n JBSplit memory _split = _splits[_i];\n\n // The amount to send towards the split.\n uint256 _tokenCount = PRBMath.mulDiv(\n _amount,\n _split.percent,\n JBConstants.SPLITS_TOTAL_PERCENT\n );\n\n // Mints tokens for the split if needed.\n if (_tokenCount > 0) {\n _tokenStore.mintFor(\n // If an allocator is set in the splits, set it as the beneficiary.\n // Otherwise if a projectId is set in the split, set the project's owner as the beneficiary.\n // If the split has a beneficiary send to the split's beneficiary. Otherwise send to the msg.sender.\n _split.allocator != IJBSplitAllocator(address(0))\n ? address(_split.allocator)\n : _split.projectId != 0\n ? projects.ownerOf(_split.projectId)\n : _split.beneficiary != address(0)\n ? _split.beneficiary\n : msg.sender,\n _projectId,\n _tokenCount,\n _split.preferClaimed\n );\n\n // If there's an allocator set, trigger its `allocate` function.\n if (_split.allocator != IJBSplitAllocator(address(0)))\n _split.allocator.allocate(\n JBSplitAllocationData(\n address(_tokenStore.tokenOf(_projectId)),\n _tokenCount,\n 18,\n _projectId,\n _group,\n _split\n )\n );\n\n // Subtract from the amount to be sent to the beneficiary.\n leftoverAmount = leftoverAmount - _tokenCount;\n }\n\n emit DistributeToReservedTokenSplit(\n _projectId,\n _domain,\n _group,\n _split,\n _tokenCount,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n\n /// @notice Configures a funding cycle and stores information pertinent to the configuration.\n /// @param _projectId The ID of the project whose funding cycles are being reconfigured.\n /// @param _data Data that defines the funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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.\n /// @return configuration The configuration of the funding cycle that was successfully reconfigured.\n function _configure(\n uint256 _projectId,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] memory _groupedSplits,\n JBFundAccessConstraints[] memory _fundAccessConstraints\n ) internal returns (uint256) {\n // Make sure the provided reserved rate is valid.\n if (_metadata.reservedRate > JBConstants.MAX_RESERVED_RATE) revert INVALID_RESERVED_RATE();\n\n // Make sure the provided redemption rate is valid.\n if (_metadata.redemptionRate > JBConstants.MAX_REDEMPTION_RATE)\n revert INVALID_REDEMPTION_RATE();\n\n // Make sure the provided ballot redemption rate is valid.\n if (_metadata.ballotRedemptionRate > JBConstants.MAX_REDEMPTION_RATE)\n revert INVALID_BALLOT_REDEMPTION_RATE();\n\n // Configure the funding cycle's properties.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.configureFor(\n _projectId,\n _data,\n JBFundingCycleMetadataResolver.packFundingCycleMetadata(_metadata),\n _mustStartAtOrAfter\n );\n\n // Set splits for the group.\n splitsStore.set(_projectId, _fundingCycle.configuration, _groupedSplits);\n\n // Set the funds access constraints.\n fundAccessConstraintsStore.setFor(\n _projectId,\n _fundingCycle.configuration,\n _fundAccessConstraints\n );\n\n return _fundingCycle.configuration;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/introspection/ERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC165.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n *\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n" + }, + "@paulrberg/contracts/math/PRBMath.sol": { + "content": "// SPDX-License-Identifier: Unlicense\npragma solidity >=0.8.4;\n\nimport \"prb-math/contracts/PRBMath.sol\";\n" + }, + "contracts/interfaces/IJBController3_0_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBController3_0_1 {\n function reservedTokenBalanceOf(uint256 projectId) external view returns (uint256);\n\n function totalOutstandingTokensOf(uint256 projectId) external view returns (uint256);\n}\n" + }, + "contracts/interfaces/IJBController3_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBBallotState} from './../enums/JBBallotState.sol';\nimport {JBFundAccessConstraints} from './../structs/JBFundAccessConstraints.sol';\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\nimport {JBFundingCycleData} from './../structs/JBFundingCycleData.sol';\nimport {JBFundingCycleMetadata} from './../structs/JBFundingCycleMetadata.sol';\nimport {JBGroupedSplits} from './../structs/JBGroupedSplits.sol';\nimport {JBProjectMetadata} from './../structs/JBProjectMetadata.sol';\nimport {JBSplit} from './../structs/JBSplit.sol';\nimport {IJBController3_0_1} from './IJBController3_0_1.sol';\nimport {IJBDirectory} from './IJBDirectory.sol';\nimport {IJBFundAccessConstraintsStore} from './IJBFundAccessConstraintsStore.sol';\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\nimport {IJBMigratable} from './IJBMigratable.sol';\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\nimport {IJBProjects} from './IJBProjects.sol';\nimport {IJBSplitsStore} from './IJBSplitsStore.sol';\nimport {IJBTokenStore} from './IJBTokenStore.sol';\n\ninterface IJBController3_1 is IJBController3_0_1, IERC165 {\n event LaunchProject(uint256 configuration, uint256 projectId, string memo, address caller);\n\n event LaunchFundingCycles(uint256 configuration, uint256 projectId, string memo, address caller);\n\n event ReconfigureFundingCycles(\n uint256 configuration,\n uint256 projectId,\n string memo,\n address caller\n );\n\n event DistributeReservedTokens(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n address beneficiary,\n uint256 tokenCount,\n uint256 beneficiaryTokenCount,\n string memo,\n address caller\n );\n\n event DistributeToReservedTokenSplit(\n uint256 indexed projectId,\n uint256 indexed domain,\n uint256 indexed group,\n JBSplit split,\n uint256 tokenCount,\n address caller\n );\n\n event MintTokens(\n address indexed beneficiary,\n uint256 indexed projectId,\n uint256 tokenCount,\n uint256 beneficiaryTokenCount,\n string memo,\n uint256 reservedRate,\n address caller\n );\n\n event BurnTokens(\n address indexed holder,\n uint256 indexed projectId,\n uint256 tokenCount,\n string memo,\n address caller\n );\n\n event Migrate(uint256 indexed projectId, IJBMigratable to, address caller);\n\n event PrepMigration(uint256 indexed projectId, address from, address caller);\n\n function projects() external view returns (IJBProjects);\n\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\n\n function tokenStore() external view returns (IJBTokenStore);\n\n function splitsStore() external view returns (IJBSplitsStore);\n\n function fundAccessConstraintsStore() external view returns (IJBFundAccessConstraintsStore);\n\n function directory() external view returns (IJBDirectory);\n\n function reservedTokenBalanceOf(uint256 projectId) external view returns (uint256);\n\n function totalOutstandingTokensOf(uint256 projectId) external view returns (uint256);\n\n function getFundingCycleOf(\n uint256 projectId,\n uint256 configuration\n )\n external\n view\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata);\n\n function latestConfiguredFundingCycleOf(\n uint256 projectId\n )\n external\n view\n returns (JBFundingCycle memory, JBFundingCycleMetadata memory metadata, JBBallotState);\n\n function currentFundingCycleOf(\n uint256 projectId\n )\n external\n view\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata);\n\n function queuedFundingCycleOf(\n uint256 projectId\n )\n external\n view\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata);\n\n function launchProjectFor(\n address owner,\n JBProjectMetadata calldata projectMetadata,\n JBFundingCycleData calldata data,\n JBFundingCycleMetadata calldata metadata,\n uint256 mustStartAtOrAfter,\n JBGroupedSplits[] memory groupedSplits,\n JBFundAccessConstraints[] memory fundAccessConstraints,\n IJBPaymentTerminal[] memory terminals,\n string calldata memo\n ) external returns (uint256 projectId);\n\n function launchFundingCyclesFor(\n uint256 projectId,\n JBFundingCycleData calldata data,\n JBFundingCycleMetadata calldata metadata,\n uint256 mustStartAtOrAfter,\n JBGroupedSplits[] memory groupedSplits,\n JBFundAccessConstraints[] memory fundAccessConstraints,\n IJBPaymentTerminal[] memory terminals,\n string calldata memo\n ) external returns (uint256 configuration);\n\n function reconfigureFundingCyclesOf(\n uint256 projectId,\n JBFundingCycleData calldata data,\n JBFundingCycleMetadata calldata metadata,\n uint256 mustStartAtOrAfter,\n JBGroupedSplits[] memory groupedSplits,\n JBFundAccessConstraints[] memory fundAccessConstraints,\n string calldata memo\n ) external returns (uint256);\n\n function mintTokensOf(\n uint256 projectId,\n uint256 tokenCount,\n address beneficiary,\n string calldata memo,\n bool preferClaimedTokens,\n bool useReservedRate\n ) external returns (uint256 beneficiaryTokenCount);\n\n function burnTokensOf(\n address holder,\n uint256 projectId,\n uint256 tokenCount,\n string calldata memo,\n bool preferClaimedTokens\n ) external;\n\n function distributeReservedTokensOf(\n uint256 projectId,\n string memory memo\n ) external returns (uint256);\n\n function migrate(uint256 projectId, IJBMigratable to) external;\n}\n" + }, + "contracts/interfaces/IJBController.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBBallotState} from './../enums/JBBallotState.sol';\nimport {JBFundAccessConstraints} from './../structs/JBFundAccessConstraints.sol';\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\nimport {JBFundingCycleData} from './../structs/JBFundingCycleData.sol';\nimport {JBFundingCycleMetadata} from './../structs/JBFundingCycleMetadata.sol';\nimport {JBGroupedSplits} from './../structs/JBGroupedSplits.sol';\nimport {JBProjectMetadata} from './../structs/JBProjectMetadata.sol';\nimport {JBSplit} from './../structs/JBSplit.sol';\nimport {IJBDirectory} from './IJBDirectory.sol';\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\nimport {IJBMigratable} from './IJBMigratable.sol';\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\nimport {IJBProjects} from './IJBProjects.sol';\nimport {IJBSplitsStore} from './IJBSplitsStore.sol';\nimport {IJBTokenStore} from './IJBTokenStore.sol';\n\ninterface IJBController is IERC165 {\n event LaunchProject(uint256 configuration, uint256 projectId, string memo, address caller);\n\n event LaunchFundingCycles(uint256 configuration, uint256 projectId, string memo, address caller);\n\n event ReconfigureFundingCycles(\n uint256 configuration,\n uint256 projectId,\n string memo,\n address caller\n );\n\n event SetFundAccessConstraints(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n JBFundAccessConstraints constraints,\n address caller\n );\n\n event DistributeReservedTokens(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n address beneficiary,\n uint256 tokenCount,\n uint256 beneficiaryTokenCount,\n string memo,\n address caller\n );\n\n event DistributeToReservedTokenSplit(\n uint256 indexed projectId,\n uint256 indexed domain,\n uint256 indexed group,\n JBSplit split,\n uint256 tokenCount,\n address caller\n );\n\n event MintTokens(\n address indexed beneficiary,\n uint256 indexed projectId,\n uint256 tokenCount,\n uint256 beneficiaryTokenCount,\n string memo,\n uint256 reservedRate,\n address caller\n );\n\n event BurnTokens(\n address indexed holder,\n uint256 indexed projectId,\n uint256 tokenCount,\n string memo,\n address caller\n );\n\n event Migrate(uint256 indexed projectId, IJBMigratable to, address caller);\n\n event PrepMigration(uint256 indexed projectId, address from, address caller);\n\n function projects() external view returns (IJBProjects);\n\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\n\n function tokenStore() external view returns (IJBTokenStore);\n\n function splitsStore() external view returns (IJBSplitsStore);\n\n function directory() external view returns (IJBDirectory);\n\n function reservedTokenBalanceOf(\n uint256 projectId,\n uint256 reservedRate\n ) external view returns (uint256);\n\n function distributionLimitOf(\n uint256 projectId,\n uint256 configuration,\n IJBPaymentTerminal terminal,\n address token\n ) external view returns (uint256 distributionLimit, uint256 distributionLimitCurrency);\n\n function overflowAllowanceOf(\n uint256 projectId,\n uint256 configuration,\n IJBPaymentTerminal terminal,\n address token\n ) external view returns (uint256 overflowAllowance, uint256 overflowAllowanceCurrency);\n\n function totalOutstandingTokensOf(\n uint256 projectId,\n uint256 reservedRate\n ) external view returns (uint256);\n\n function getFundingCycleOf(\n uint256 projectId,\n uint256 configuration\n )\n external\n view\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata);\n\n function latestConfiguredFundingCycleOf(\n uint256 projectId\n )\n external\n view\n returns (JBFundingCycle memory, JBFundingCycleMetadata memory metadata, JBBallotState);\n\n function currentFundingCycleOf(\n uint256 projectId\n )\n external\n view\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata);\n\n function queuedFundingCycleOf(\n uint256 projectId\n )\n external\n view\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata);\n\n function launchProjectFor(\n address owner,\n JBProjectMetadata calldata projectMetadata,\n JBFundingCycleData calldata data,\n JBFundingCycleMetadata calldata metadata,\n uint256 mustStartAtOrAfter,\n JBGroupedSplits[] memory groupedSplits,\n JBFundAccessConstraints[] memory fundAccessConstraints,\n IJBPaymentTerminal[] memory terminals,\n string calldata memo\n ) external returns (uint256 projectId);\n\n function launchFundingCyclesFor(\n uint256 projectId,\n JBFundingCycleData calldata data,\n JBFundingCycleMetadata calldata metadata,\n uint256 mustStartAtOrAfter,\n JBGroupedSplits[] memory groupedSplits,\n JBFundAccessConstraints[] memory fundAccessConstraints,\n IJBPaymentTerminal[] memory terminals,\n string calldata memo\n ) external returns (uint256 configuration);\n\n function reconfigureFundingCyclesOf(\n uint256 projectId,\n JBFundingCycleData calldata data,\n JBFundingCycleMetadata calldata metadata,\n uint256 mustStartAtOrAfter,\n JBGroupedSplits[] memory groupedSplits,\n JBFundAccessConstraints[] memory fundAccessConstraints,\n string calldata memo\n ) external returns (uint256);\n\n function mintTokensOf(\n uint256 projectId,\n uint256 tokenCount,\n address beneficiary,\n string calldata memo,\n bool preferClaimedTokens,\n bool useReservedRate\n ) external returns (uint256 beneficiaryTokenCount);\n\n function burnTokensOf(\n address holder,\n uint256 projectId,\n uint256 tokenCount,\n string calldata memo,\n bool preferClaimedTokens\n ) external;\n\n function distributeReservedTokensOf(\n uint256 projectId,\n string memory memo\n ) external returns (uint256);\n\n function migrate(uint256 projectId, IJBMigratable to) external;\n}\n" + }, + "contracts/interfaces/IJBFundAccessConstraintsStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBFundAccessConstraints} from './../structs/JBFundAccessConstraints.sol';\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\n\ninterface IJBFundAccessConstraintsStore is IERC165 {\n event SetFundAccessConstraints(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed projectId,\n JBFundAccessConstraints constraints,\n address caller\n );\n\n function distributionLimitOf(\n uint256 projectId,\n uint256 configuration,\n IJBPaymentTerminal terminal,\n address token\n ) external view returns (uint256 distributionLimit, uint256 distributionLimitCurrency);\n\n function overflowAllowanceOf(\n uint256 projectId,\n uint256 configuration,\n IJBPaymentTerminal terminal,\n address token\n ) external view returns (uint256 overflowAllowance, uint256 overflowAllowanceCurrency);\n\n function setFor(\n uint256 projectId,\n uint256 configuration,\n JBFundAccessConstraints[] memory fundAccessConstaints\n ) external;\n}\n" + }, + "contracts/interfaces/IJBMigratable.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBMigratable {\n function prepForMigrationOf(uint256 projectId, address from) external;\n}\n" + }, + "contracts/interfaces/IJBSplitAllocator.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBSplitAllocationData} from '../structs/JBSplitAllocationData.sol';\n\n/// @title Split allocator\n/// @notice Provide a way to process a single split with extra logic\n/// @dev The contract address should be set as an allocator in the adequate split\ninterface IJBSplitAllocator is IERC165 {\n /// @notice This function is called by JBPaymentTerminal.distributePayoutOf(..), during the processing of the split including it\n /// @dev Critical business logic should be protected by an appropriate access control. The token and/or eth are optimistically transfered to the allocator for its logic.\n /// @param data the data passed by the terminal, as a JBSplitAllocationData struct:\n function allocate(JBSplitAllocationData calldata data) external payable;\n}\n" + }, + "contracts/interfaces/IJBSplitsStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBGroupedSplits} from './../structs/JBGroupedSplits.sol';\nimport {JBSplit} from './../structs/JBSplit.sol';\nimport {IJBDirectory} from './IJBDirectory.sol';\nimport {IJBProjects} from './IJBProjects.sol';\n\ninterface IJBSplitsStore {\n event SetSplit(\n uint256 indexed projectId,\n uint256 indexed domain,\n uint256 indexed group,\n JBSplit split,\n address caller\n );\n\n function projects() external view returns (IJBProjects);\n\n function directory() external view returns (IJBDirectory);\n\n function splitsOf(\n uint256 projectId,\n uint256 domain,\n uint256 group\n ) external view returns (JBSplit[] memory);\n\n function set(uint256 projectId, uint256 domain, JBGroupedSplits[] memory groupedSplits) external;\n}\n" + }, + "contracts/libraries/JBSplitsGroups.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nlibrary JBSplitsGroups {\n uint256 public constant ETH_PAYOUT = 1;\n uint256 public constant RESERVED_TOKENS = 2;\n}\n" + }, + "contracts/structs/JBSplitAllocationData.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBSplit} from './JBSplit.sol';\n\n/// @custom:member token The token being sent to the split allocator.\n/// @custom:member amount The amount being sent to the split allocator, as a fixed point number.\n/// @custom:member decimals The number of decimals in the amount.\n/// @custom:member projectId The project to which the split belongs.\n/// @custom:member group The group to which the split belongs.\n/// @custom:member split The split that caused the allocation.\nstruct JBSplitAllocationData {\n address token;\n uint256 amount;\n uint256 decimals;\n uint256 projectId;\n uint256 group;\n JBSplit split;\n}\n" + }, + "contracts/structs/JBFundAccessConstraints.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\n\n/// @custom:member terminal The terminal within which the distribution limit and the overflow allowance applies.\n/// @custom:member token The token for which the fund access constraints apply.\n/// @custom:member distributionLimit The amount of the distribution limit, as a fixed point number with the same number of decimals as the terminal within which the limit applies.\n/// @custom:member distributionLimitCurrency The currency of the distribution limit.\n/// @custom:member overflowAllowance The amount of the allowance, as a fixed point number with the same number of decimals as the terminal within which the allowance applies.\n/// @custom:member overflowAllowanceCurrency The currency of the overflow allowance.\nstruct JBFundAccessConstraints {\n IJBPaymentTerminal terminal;\n address token;\n uint256 distributionLimit;\n uint256 distributionLimitCurrency;\n uint256 overflowAllowance;\n uint256 overflowAllowanceCurrency;\n}\n" + }, + "contracts/structs/JBGroupedSplits.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBSplit} from './JBSplit.sol';\n\n/// @custom:member group The group indentifier.\n/// @custom:member splits The splits to associate with the group.\nstruct JBGroupedSplits {\n uint256 group;\n JBSplit[] splits;\n}\n" + }, + "contracts/structs/JBSplit.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBSplitAllocator} from './../interfaces/IJBSplitAllocator.sol';\n\n/// @custom:member preferClaimed A flag that only has effect if a projectId is also specified, and the project has a token contract attached. If so, this flag indicates if the tokens that result from making a payment to the project should be delivered claimed into the beneficiary's wallet, or unclaimed to save gas.\n/// @custom:member preferAddToBalance A flag indicating if a distribution to a project should prefer triggering it's addToBalance function instead of its pay function.\n/// @custom:member percent The percent of the whole group that this split occupies. This number is out of `JBConstants.SPLITS_TOTAL_PERCENT`.\n/// @custom:member projectId The ID of a project. If an allocator is not set but a projectId is set, funds will be sent to the protocol treasury belonging to the project who's ID is specified. Resulting tokens will be routed to the beneficiary with the claimed token preference respected.\n/// @custom:member beneficiary An address. The role the of the beneficary depends on whether or not projectId is specified, and whether or not an allocator is specified. If allocator is set, the beneficiary will be forwarded to the allocator for it to use. If allocator is not set but projectId is set, the beneficiary is the address to which the project's tokens will be sent that result from a payment to it. If neither allocator or projectId are set, the beneficiary is where the funds from the split will be sent.\n/// @custom:member lockedUntil Specifies if the split should be unchangeable until the specified time, with the exception of extending the locked period.\n/// @custom:member allocator If an allocator is specified, funds will be sent to the allocator contract along with all properties of this split.\nstruct JBSplit {\n bool preferClaimed;\n bool preferAddToBalance;\n uint256 percent;\n uint256 projectId;\n address payable beneficiary;\n uint256 lockedUntil;\n IJBSplitAllocator allocator;\n}\n" + }, + "prb-math/contracts/PRBMath.sol": { + "content": "// SPDX-License-Identifier: Unlicense\npragma solidity >=0.8.4;\n\n/// @notice Emitted when the result overflows uint256.\nerror PRBMath__MulDivFixedPointOverflow(uint256 prod1);\n\n/// @notice Emitted when the result overflows uint256.\nerror PRBMath__MulDivOverflow(uint256 prod1, uint256 denominator);\n\n/// @notice Emitted when one of the inputs is type(int256).min.\nerror PRBMath__MulDivSignedInputTooSmall();\n\n/// @notice Emitted when the intermediary absolute result overflows int256.\nerror PRBMath__MulDivSignedOverflow(uint256 rAbs);\n\n/// @notice Emitted when the input is MIN_SD59x18.\nerror PRBMathSD59x18__AbsInputTooSmall();\n\n/// @notice Emitted when ceiling a number overflows SD59x18.\nerror PRBMathSD59x18__CeilOverflow(int256 x);\n\n/// @notice Emitted when one of the inputs is MIN_SD59x18.\nerror PRBMathSD59x18__DivInputTooSmall();\n\n/// @notice Emitted when one of the intermediary unsigned results overflows SD59x18.\nerror PRBMathSD59x18__DivOverflow(uint256 rAbs);\n\n/// @notice Emitted when the input is greater than 133.084258667509499441.\nerror PRBMathSD59x18__ExpInputTooBig(int256 x);\n\n/// @notice Emitted when the input is greater than 192.\nerror PRBMathSD59x18__Exp2InputTooBig(int256 x);\n\n/// @notice Emitted when flooring a number underflows SD59x18.\nerror PRBMathSD59x18__FloorUnderflow(int256 x);\n\n/// @notice Emitted when converting a basic integer to the fixed-point format overflows SD59x18.\nerror PRBMathSD59x18__FromIntOverflow(int256 x);\n\n/// @notice Emitted when converting a basic integer to the fixed-point format underflows SD59x18.\nerror PRBMathSD59x18__FromIntUnderflow(int256 x);\n\n/// @notice Emitted when the product of the inputs is negative.\nerror PRBMathSD59x18__GmNegativeProduct(int256 x, int256 y);\n\n/// @notice Emitted when multiplying the inputs overflows SD59x18.\nerror PRBMathSD59x18__GmOverflow(int256 x, int256 y);\n\n/// @notice Emitted when the input is less than or equal to zero.\nerror PRBMathSD59x18__LogInputTooSmall(int256 x);\n\n/// @notice Emitted when one of the inputs is MIN_SD59x18.\nerror PRBMathSD59x18__MulInputTooSmall();\n\n/// @notice Emitted when the intermediary absolute result overflows SD59x18.\nerror PRBMathSD59x18__MulOverflow(uint256 rAbs);\n\n/// @notice Emitted when the intermediary absolute result overflows SD59x18.\nerror PRBMathSD59x18__PowuOverflow(uint256 rAbs);\n\n/// @notice Emitted when the input is negative.\nerror PRBMathSD59x18__SqrtNegativeInput(int256 x);\n\n/// @notice Emitted when the calculating the square root overflows SD59x18.\nerror PRBMathSD59x18__SqrtOverflow(int256 x);\n\n/// @notice Emitted when addition overflows UD60x18.\nerror PRBMathUD60x18__AddOverflow(uint256 x, uint256 y);\n\n/// @notice Emitted when ceiling a number overflows UD60x18.\nerror PRBMathUD60x18__CeilOverflow(uint256 x);\n\n/// @notice Emitted when the input is greater than 133.084258667509499441.\nerror PRBMathUD60x18__ExpInputTooBig(uint256 x);\n\n/// @notice Emitted when the input is greater than 192.\nerror PRBMathUD60x18__Exp2InputTooBig(uint256 x);\n\n/// @notice Emitted when converting a basic integer to the fixed-point format format overflows UD60x18.\nerror PRBMathUD60x18__FromUintOverflow(uint256 x);\n\n/// @notice Emitted when multiplying the inputs overflows UD60x18.\nerror PRBMathUD60x18__GmOverflow(uint256 x, uint256 y);\n\n/// @notice Emitted when the input is less than 1.\nerror PRBMathUD60x18__LogInputTooSmall(uint256 x);\n\n/// @notice Emitted when the calculating the square root overflows UD60x18.\nerror PRBMathUD60x18__SqrtOverflow(uint256 x);\n\n/// @notice Emitted when subtraction underflows UD60x18.\nerror PRBMathUD60x18__SubUnderflow(uint256 x, uint256 y);\n\n/// @dev Common mathematical functions used in both PRBMathSD59x18 and PRBMathUD60x18. Note that this shared library\n/// does not always assume the signed 59.18-decimal fixed-point or the unsigned 60.18-decimal fixed-point\n/// representation. When it does not, it is explicitly mentioned in the NatSpec documentation.\nlibrary PRBMath {\n /// STRUCTS ///\n\n struct SD59x18 {\n int256 value;\n }\n\n struct UD60x18 {\n uint256 value;\n }\n\n /// STORAGE ///\n\n /// @dev How many trailing decimals can be represented.\n uint256 internal constant SCALE = 1e18;\n\n /// @dev Largest power of two divisor of SCALE.\n uint256 internal constant SCALE_LPOTD = 262144;\n\n /// @dev SCALE inverted mod 2^256.\n uint256 internal constant SCALE_INVERSE =\n 78156646155174841979727994598816262306175212592076161876661_508869554232690281;\n\n /// FUNCTIONS ///\n\n /// @notice Calculates the binary exponent of x using the binary fraction method.\n /// @dev Has to use 192.64-bit fixed-point numbers.\n /// See https://ethereum.stackexchange.com/a/96594/24693.\n /// @param x The exponent as an unsigned 192.64-bit fixed-point number.\n /// @return result The result as an unsigned 60.18-decimal fixed-point number.\n function exp2(uint256 x) internal pure returns (uint256 result) {\n unchecked {\n // Start from 0.5 in the 192.64-bit fixed-point format.\n result = 0x800000000000000000000000000000000000000000000000;\n\n // Multiply the result by root(2, 2^-i) when the bit at position i is 1. None of the intermediary results overflows\n // because the initial result is 2^191 and all magic factors are less than 2^65.\n if (x & 0x8000000000000000 > 0) {\n result = (result * 0x16A09E667F3BCC909) >> 64;\n }\n if (x & 0x4000000000000000 > 0) {\n result = (result * 0x1306FE0A31B7152DF) >> 64;\n }\n if (x & 0x2000000000000000 > 0) {\n result = (result * 0x1172B83C7D517ADCE) >> 64;\n }\n if (x & 0x1000000000000000 > 0) {\n result = (result * 0x10B5586CF9890F62A) >> 64;\n }\n if (x & 0x800000000000000 > 0) {\n result = (result * 0x1059B0D31585743AE) >> 64;\n }\n if (x & 0x400000000000000 > 0) {\n result = (result * 0x102C9A3E778060EE7) >> 64;\n }\n if (x & 0x200000000000000 > 0) {\n result = (result * 0x10163DA9FB33356D8) >> 64;\n }\n if (x & 0x100000000000000 > 0) {\n result = (result * 0x100B1AFA5ABCBED61) >> 64;\n }\n if (x & 0x80000000000000 > 0) {\n result = (result * 0x10058C86DA1C09EA2) >> 64;\n }\n if (x & 0x40000000000000 > 0) {\n result = (result * 0x1002C605E2E8CEC50) >> 64;\n }\n if (x & 0x20000000000000 > 0) {\n result = (result * 0x100162F3904051FA1) >> 64;\n }\n if (x & 0x10000000000000 > 0) {\n result = (result * 0x1000B175EFFDC76BA) >> 64;\n }\n if (x & 0x8000000000000 > 0) {\n result = (result * 0x100058BA01FB9F96D) >> 64;\n }\n if (x & 0x4000000000000 > 0) {\n result = (result * 0x10002C5CC37DA9492) >> 64;\n }\n if (x & 0x2000000000000 > 0) {\n result = (result * 0x1000162E525EE0547) >> 64;\n }\n if (x & 0x1000000000000 > 0) {\n result = (result * 0x10000B17255775C04) >> 64;\n }\n if (x & 0x800000000000 > 0) {\n result = (result * 0x1000058B91B5BC9AE) >> 64;\n }\n if (x & 0x400000000000 > 0) {\n result = (result * 0x100002C5C89D5EC6D) >> 64;\n }\n if (x & 0x200000000000 > 0) {\n result = (result * 0x10000162E43F4F831) >> 64;\n }\n if (x & 0x100000000000 > 0) {\n result = (result * 0x100000B1721BCFC9A) >> 64;\n }\n if (x & 0x80000000000 > 0) {\n result = (result * 0x10000058B90CF1E6E) >> 64;\n }\n if (x & 0x40000000000 > 0) {\n result = (result * 0x1000002C5C863B73F) >> 64;\n }\n if (x & 0x20000000000 > 0) {\n result = (result * 0x100000162E430E5A2) >> 64;\n }\n if (x & 0x10000000000 > 0) {\n result = (result * 0x1000000B172183551) >> 64;\n }\n if (x & 0x8000000000 > 0) {\n result = (result * 0x100000058B90C0B49) >> 64;\n }\n if (x & 0x4000000000 > 0) {\n result = (result * 0x10000002C5C8601CC) >> 64;\n }\n if (x & 0x2000000000 > 0) {\n result = (result * 0x1000000162E42FFF0) >> 64;\n }\n if (x & 0x1000000000 > 0) {\n result = (result * 0x10000000B17217FBB) >> 64;\n }\n if (x & 0x800000000 > 0) {\n result = (result * 0x1000000058B90BFCE) >> 64;\n }\n if (x & 0x400000000 > 0) {\n result = (result * 0x100000002C5C85FE3) >> 64;\n }\n if (x & 0x200000000 > 0) {\n result = (result * 0x10000000162E42FF1) >> 64;\n }\n if (x & 0x100000000 > 0) {\n result = (result * 0x100000000B17217F8) >> 64;\n }\n if (x & 0x80000000 > 0) {\n result = (result * 0x10000000058B90BFC) >> 64;\n }\n if (x & 0x40000000 > 0) {\n result = (result * 0x1000000002C5C85FE) >> 64;\n }\n if (x & 0x20000000 > 0) {\n result = (result * 0x100000000162E42FF) >> 64;\n }\n if (x & 0x10000000 > 0) {\n result = (result * 0x1000000000B17217F) >> 64;\n }\n if (x & 0x8000000 > 0) {\n result = (result * 0x100000000058B90C0) >> 64;\n }\n if (x & 0x4000000 > 0) {\n result = (result * 0x10000000002C5C860) >> 64;\n }\n if (x & 0x2000000 > 0) {\n result = (result * 0x1000000000162E430) >> 64;\n }\n if (x & 0x1000000 > 0) {\n result = (result * 0x10000000000B17218) >> 64;\n }\n if (x & 0x800000 > 0) {\n result = (result * 0x1000000000058B90C) >> 64;\n }\n if (x & 0x400000 > 0) {\n result = (result * 0x100000000002C5C86) >> 64;\n }\n if (x & 0x200000 > 0) {\n result = (result * 0x10000000000162E43) >> 64;\n }\n if (x & 0x100000 > 0) {\n result = (result * 0x100000000000B1721) >> 64;\n }\n if (x & 0x80000 > 0) {\n result = (result * 0x10000000000058B91) >> 64;\n }\n if (x & 0x40000 > 0) {\n result = (result * 0x1000000000002C5C8) >> 64;\n }\n if (x & 0x20000 > 0) {\n result = (result * 0x100000000000162E4) >> 64;\n }\n if (x & 0x10000 > 0) {\n result = (result * 0x1000000000000B172) >> 64;\n }\n if (x & 0x8000 > 0) {\n result = (result * 0x100000000000058B9) >> 64;\n }\n if (x & 0x4000 > 0) {\n result = (result * 0x10000000000002C5D) >> 64;\n }\n if (x & 0x2000 > 0) {\n result = (result * 0x1000000000000162E) >> 64;\n }\n if (x & 0x1000 > 0) {\n result = (result * 0x10000000000000B17) >> 64;\n }\n if (x & 0x800 > 0) {\n result = (result * 0x1000000000000058C) >> 64;\n }\n if (x & 0x400 > 0) {\n result = (result * 0x100000000000002C6) >> 64;\n }\n if (x & 0x200 > 0) {\n result = (result * 0x10000000000000163) >> 64;\n }\n if (x & 0x100 > 0) {\n result = (result * 0x100000000000000B1) >> 64;\n }\n if (x & 0x80 > 0) {\n result = (result * 0x10000000000000059) >> 64;\n }\n if (x & 0x40 > 0) {\n result = (result * 0x1000000000000002C) >> 64;\n }\n if (x & 0x20 > 0) {\n result = (result * 0x10000000000000016) >> 64;\n }\n if (x & 0x10 > 0) {\n result = (result * 0x1000000000000000B) >> 64;\n }\n if (x & 0x8 > 0) {\n result = (result * 0x10000000000000006) >> 64;\n }\n if (x & 0x4 > 0) {\n result = (result * 0x10000000000000003) >> 64;\n }\n if (x & 0x2 > 0) {\n result = (result * 0x10000000000000001) >> 64;\n }\n if (x & 0x1 > 0) {\n result = (result * 0x10000000000000001) >> 64;\n }\n\n // We're doing two things at the same time:\n //\n // 1. Multiply the result by 2^n + 1, where \"2^n\" is the integer part and the one is added to account for\n // the fact that we initially set the result to 0.5. This is accomplished by subtracting from 191\n // rather than 192.\n // 2. Convert the result to the unsigned 60.18-decimal fixed-point format.\n //\n // This works because 2^(191-ip) = 2^ip / 2^191, where \"ip\" is the integer part \"2^n\".\n result *= SCALE;\n result >>= (191 - (x >> 64));\n }\n }\n\n /// @notice Finds the zero-based index of the first one in the binary representation of x.\n /// @dev See the note on msb in the \"Find First Set\" Wikipedia article https://en.wikipedia.org/wiki/Find_first_set\n /// @param x The uint256 number for which to find the index of the most significant bit.\n /// @return msb The index of the most significant bit as an uint256.\n function mostSignificantBit(uint256 x) internal pure returns (uint256 msb) {\n if (x >= 2**128) {\n x >>= 128;\n msb += 128;\n }\n if (x >= 2**64) {\n x >>= 64;\n msb += 64;\n }\n if (x >= 2**32) {\n x >>= 32;\n msb += 32;\n }\n if (x >= 2**16) {\n x >>= 16;\n msb += 16;\n }\n if (x >= 2**8) {\n x >>= 8;\n msb += 8;\n }\n if (x >= 2**4) {\n x >>= 4;\n msb += 4;\n }\n if (x >= 2**2) {\n x >>= 2;\n msb += 2;\n }\n if (x >= 2**1) {\n // No need to shift x any more.\n msb += 1;\n }\n }\n\n /// @notice Calculates floor(x*y÷denominator) with full precision.\n ///\n /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv.\n ///\n /// Requirements:\n /// - The denominator cannot be zero.\n /// - The result must fit within uint256.\n ///\n /// Caveats:\n /// - This function does not work with fixed-point numbers.\n ///\n /// @param x The multiplicand as an uint256.\n /// @param y The multiplier as an uint256.\n /// @param denominator The divisor as an uint256.\n /// @return result The result as an uint256.\n function mulDiv(\n uint256 x,\n uint256 y,\n uint256 denominator\n ) internal pure returns (uint256 result) {\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n // variables such that product = prod1 * 2^256 + prod0.\n uint256 prod0; // Least significant 256 bits of the product\n uint256 prod1; // Most significant 256 bits of the product\n assembly {\n let mm := mulmod(x, y, not(0))\n prod0 := mul(x, y)\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n }\n\n // Handle non-overflow cases, 256 by 256 division.\n if (prod1 == 0) {\n unchecked {\n result = prod0 / denominator;\n }\n return result;\n }\n\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\n if (prod1 >= denominator) {\n revert PRBMath__MulDivOverflow(prod1, denominator);\n }\n\n ///////////////////////////////////////////////\n // 512 by 256 division.\n ///////////////////////////////////////////////\n\n // Make division exact by subtracting the remainder from [prod1 prod0].\n uint256 remainder;\n assembly {\n // Compute remainder using mulmod.\n remainder := mulmod(x, y, denominator)\n\n // Subtract 256 bit number from 512 bit number.\n prod1 := sub(prod1, gt(remainder, prod0))\n prod0 := sub(prod0, remainder)\n }\n\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\n // See https://cs.stackexchange.com/q/138556/92363.\n unchecked {\n // Does not overflow because the denominator cannot be zero at this stage in the function.\n uint256 lpotdod = denominator & (~denominator + 1);\n assembly {\n // Divide denominator by lpotdod.\n denominator := div(denominator, lpotdod)\n\n // Divide [prod1 prod0] by lpotdod.\n prod0 := div(prod0, lpotdod)\n\n // Flip lpotdod such that it is 2^256 / lpotdod. If lpotdod is zero, then it becomes one.\n lpotdod := add(div(sub(0, lpotdod), lpotdod), 1)\n }\n\n // Shift in bits from prod1 into prod0.\n prod0 |= prod1 * lpotdod;\n\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\n // four bits. That is, denominator * inv = 1 mod 2^4.\n uint256 inverse = (3 * denominator) ^ 2;\n\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\n // in modular arithmetic, doubling the correct bits in each step.\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\n\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\n // is no longer required.\n result = prod0 * inverse;\n return result;\n }\n }\n\n /// @notice Calculates floor(x*y÷1e18) with full precision.\n ///\n /// @dev Variant of \"mulDiv\" with constant folding, i.e. in which the denominator is always 1e18. Before returning the\n /// final result, we add 1 if (x * y) % SCALE >= HALF_SCALE. Without this, 6.6e-19 would be truncated to 0 instead of\n /// being rounded to 1e-18. See \"Listing 6\" and text above it at https://accu.org/index.php/journals/1717.\n ///\n /// Requirements:\n /// - The result must fit within uint256.\n ///\n /// Caveats:\n /// - The body is purposely left uncommented; see the NatSpec comments in \"PRBMath.mulDiv\" to understand how this works.\n /// - It is assumed that the result can never be type(uint256).max when x and y solve the following two equations:\n /// 1. x * y = type(uint256).max * SCALE\n /// 2. (x * y) % SCALE >= SCALE / 2\n ///\n /// @param x The multiplicand as an unsigned 60.18-decimal fixed-point number.\n /// @param y The multiplier as an unsigned 60.18-decimal fixed-point number.\n /// @return result The result as an unsigned 60.18-decimal fixed-point number.\n function mulDivFixedPoint(uint256 x, uint256 y) internal pure returns (uint256 result) {\n uint256 prod0;\n uint256 prod1;\n assembly {\n let mm := mulmod(x, y, not(0))\n prod0 := mul(x, y)\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n }\n\n if (prod1 >= SCALE) {\n revert PRBMath__MulDivFixedPointOverflow(prod1);\n }\n\n uint256 remainder;\n uint256 roundUpUnit;\n assembly {\n remainder := mulmod(x, y, SCALE)\n roundUpUnit := gt(remainder, 499999999999999999)\n }\n\n if (prod1 == 0) {\n unchecked {\n result = (prod0 / SCALE) + roundUpUnit;\n return result;\n }\n }\n\n assembly {\n result := add(\n mul(\n or(\n div(sub(prod0, remainder), SCALE_LPOTD),\n mul(sub(prod1, gt(remainder, prod0)), add(div(sub(0, SCALE_LPOTD), SCALE_LPOTD), 1))\n ),\n SCALE_INVERSE\n ),\n roundUpUnit\n )\n }\n }\n\n /// @notice Calculates floor(x*y÷denominator) with full precision.\n ///\n /// @dev An extension of \"mulDiv\" for signed numbers. Works by computing the signs and the absolute values separately.\n ///\n /// Requirements:\n /// - None of the inputs can be type(int256).min.\n /// - The result must fit within int256.\n ///\n /// @param x The multiplicand as an int256.\n /// @param y The multiplier as an int256.\n /// @param denominator The divisor as an int256.\n /// @return result The result as an int256.\n function mulDivSigned(\n int256 x,\n int256 y,\n int256 denominator\n ) internal pure returns (int256 result) {\n if (x == type(int256).min || y == type(int256).min || denominator == type(int256).min) {\n revert PRBMath__MulDivSignedInputTooSmall();\n }\n\n // Get hold of the absolute values of x, y and the denominator.\n uint256 ax;\n uint256 ay;\n uint256 ad;\n unchecked {\n ax = x < 0 ? uint256(-x) : uint256(x);\n ay = y < 0 ? uint256(-y) : uint256(y);\n ad = denominator < 0 ? uint256(-denominator) : uint256(denominator);\n }\n\n // Compute the absolute value of (x*y)÷denominator. The result must fit within int256.\n uint256 rAbs = mulDiv(ax, ay, ad);\n if (rAbs > uint256(type(int256).max)) {\n revert PRBMath__MulDivSignedOverflow(rAbs);\n }\n\n // Get the signs of x, y and the denominator.\n uint256 sx;\n uint256 sy;\n uint256 sd;\n assembly {\n sx := sgt(x, sub(0, 1))\n sy := sgt(y, sub(0, 1))\n sd := sgt(denominator, sub(0, 1))\n }\n\n // XOR over sx, sy and sd. This is checking whether there are one or three negative signs in the inputs.\n // If yes, the result should be negative.\n result = sx ^ sy ^ sd == 0 ? -int256(rAbs) : int256(rAbs);\n }\n\n /// @notice Calculates the square root of x, rounding down.\n /// @dev Uses the Babylonian method https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method.\n ///\n /// Caveats:\n /// - This function does not work with fixed-point numbers.\n ///\n /// @param x The uint256 number for which to calculate the square root.\n /// @return result The result as an uint256.\n function sqrt(uint256 x) internal pure returns (uint256 result) {\n if (x == 0) {\n return 0;\n }\n\n // Set the initial guess to the closest power of two that is higher than x.\n uint256 xAux = uint256(x);\n result = 1;\n if (xAux >= 0x100000000000000000000000000000000) {\n xAux >>= 128;\n result <<= 64;\n }\n if (xAux >= 0x10000000000000000) {\n xAux >>= 64;\n result <<= 32;\n }\n if (xAux >= 0x100000000) {\n xAux >>= 32;\n result <<= 16;\n }\n if (xAux >= 0x10000) {\n xAux >>= 16;\n result <<= 8;\n }\n if (xAux >= 0x100) {\n xAux >>= 8;\n result <<= 4;\n }\n if (xAux >= 0x10) {\n xAux >>= 4;\n result <<= 2;\n }\n if (xAux >= 0x8) {\n result <<= 1;\n }\n\n // The operations can never overflow because the result is max 2^127 when it enters this block.\n unchecked {\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1; // Seven iterations should be enough\n uint256 roundedDownResult = x / result;\n return result >= roundedDownResult ? roundedDownResult : result;\n }\n }\n}\n" + }, + "contracts/JBSplitsStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {JBOperatable} from './abstract/JBOperatable.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {IJBSplitAllocator} from './interfaces/IJBSplitAllocator.sol';\nimport {JBConstants} from './libraries/JBConstants.sol';\nimport {JBOperations} from './libraries/JBOperations.sol';\nimport {JBGroupedSplits} from './structs/JBGroupedSplits.sol';\nimport {JBSplit} from './structs/JBSplit.sol';\n\n/// @notice Stores splits for each project.\ncontract JBSplitsStore is JBOperatable, IJBSplitsStore {\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error INVALID_LOCKED_UNTIL();\n error INVALID_PROJECT_ID();\n error INVALID_SPLIT_PERCENT();\n error INVALID_TOTAL_PERCENT();\n error PREVIOUS_LOCKED_SPLITS_NOT_INCLUDED();\n\n //*********************************************************************//\n // --------------------- private stored properties ------------------- //\n //*********************************************************************//\n\n /// @notice The number of splits currently set for each project ID's configurations.\n /// @custom:param _projectId The ID of the project to get the split count for.\n /// @custom:param _domain An identifier within which the returned splits should be considered active.\n /// @custom:param _group The identifying group of the splits.\n mapping(uint256 => mapping(uint256 => mapping(uint256 => uint256))) private _splitCountOf;\n\n /// @notice Packed data of splits for each project ID's configurations.\n /// @custom:param _projectId The ID of the project to get packed splits data for.\n /// @custom:param _domain An identifier within which the returned splits should be considered active.\n /// @custom:param _group The identifying group of the splits.\n /// @custom:param _index The indexed order that the split was set at.\n mapping(uint256 => mapping(uint256 => mapping(uint256 => mapping(uint256 => uint256))))\n private _packedSplitParts1Of;\n\n /// @notice More packed data of splits for each project ID's configurations.\n /// @dev This packed data is often 0.\n /// @custom:param _projectId The ID of the project to get packed splits data for.\n /// @custom:param _domain An identifier within which the returned splits should be considered active.\n /// @custom:param _group The identifying group of the splits.\n /// @custom:param _index The indexed order that the split was set at.\n mapping(uint256 => mapping(uint256 => mapping(uint256 => mapping(uint256 => uint256))))\n private _packedSplitParts2Of;\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice Mints ERC-721's that represent project ownership and transfers.\n IJBProjects public immutable override projects;\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Get all splits for the specified project ID, within the specified domain, for the specified group.\n /// @param _projectId The ID of the project to get splits for.\n /// @param _domain An identifier within which the returned splits should be considered active.\n /// @param _group The identifying group of the splits.\n /// @return An array of all splits for the project.\n function splitsOf(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group\n ) external view override returns (JBSplit[] memory) {\n return _getStructsFor(_projectId, _domain, _group);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n constructor(\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory\n ) JBOperatable(_operatorStore) {\n projects = _projects;\n directory = _directory;\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Sets a project's splits.\n /// @dev Only the owner or operator of a project, or the current controller contract of the project, can set its splits.\n /// @dev The new splits must include any currently set splits that are locked.\n /// @param _projectId The ID of the project for which splits are being added.\n /// @param _domain An identifier within which the splits should be considered active.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n function set(\n uint256 _projectId,\n uint256 _domain,\n JBGroupedSplits[] calldata _groupedSplits\n )\n external\n override\n requirePermissionAllowingOverride(\n projects.ownerOf(_projectId),\n _projectId,\n JBOperations.SET_SPLITS,\n address(directory.controllerOf(_projectId)) == msg.sender\n )\n {\n // Push array length in stack\n uint256 _groupedSplitsLength = _groupedSplits.length;\n\n // Set each grouped splits.\n for (uint256 _i; _i < _groupedSplitsLength; ) {\n // Get a reference to the grouped split being iterated on.\n JBGroupedSplits memory _groupedSplit = _groupedSplits[_i];\n\n // Set the splits for the group.\n _set(_projectId, _domain, _groupedSplit.group, _groupedSplit.splits);\n\n unchecked {\n ++_i;\n }\n }\n }\n\n //*********************************************************************//\n // --------------------- private helper functions -------------------- //\n //*********************************************************************//\n\n /// @notice Sets a project's splits.\n /// @dev The new splits must include any currently set splits that are locked.\n /// @param _projectId The ID of the project for which splits are being added.\n /// @param _domain An identifier within which the splits should be considered active.\n /// @param _group An identifier between of splits being set. All splits within this _group must add up to within 100%.\n /// @param _splits The splits to set.\n function _set(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group,\n JBSplit[] memory _splits\n ) internal {\n // Get a reference to the project's current splits.\n JBSplit[] memory _currentSplits = _getStructsFor(_projectId, _domain, _group);\n\n // Keep a reference to the number of splits.\n uint256 _currentSplitsLength = _currentSplits.length;\n\n // Check to see if all locked splits are included.\n for (uint256 _i; _i < _currentSplitsLength; ) {\n // If not locked, continue.\n if (\n block.timestamp < _currentSplits[_i].lockedUntil &&\n !_includesLocked(_splits, _currentSplits[_i])\n ) revert PREVIOUS_LOCKED_SPLITS_NOT_INCLUDED();\n\n unchecked {\n ++_i;\n }\n }\n\n // Add up all the percents to make sure they cumulatively are under 100%.\n uint256 _percentTotal;\n\n // Keep a reference to the number of splits.\n uint256 _splitsLength = _splits.length;\n\n for (uint256 _i; _i < _splitsLength; ) {\n // The percent should be greater than 0.\n if (_splits[_i].percent == 0) revert INVALID_SPLIT_PERCENT();\n\n // ProjectId should be within a uint56\n if (_splits[_i].projectId > type(uint56).max) revert INVALID_PROJECT_ID();\n\n // Add to the total percents.\n _percentTotal = _percentTotal + _splits[_i].percent;\n\n // Validate the total does not exceed the expected value.\n if (_percentTotal > JBConstants.SPLITS_TOTAL_PERCENT) revert INVALID_TOTAL_PERCENT();\n\n uint256 _packedSplitParts1;\n\n // prefer claimed in bit 0.\n if (_splits[_i].preferClaimed) _packedSplitParts1 = 1;\n // prefer add to balance in bit 1.\n if (_splits[_i].preferAddToBalance) _packedSplitParts1 |= 1 << 1;\n // percent in bits 2-33.\n _packedSplitParts1 |= _splits[_i].percent << 2;\n // projectId in bits 32-89.\n _packedSplitParts1 |= _splits[_i].projectId << 34;\n // beneficiary in bits 90-249.\n _packedSplitParts1 |= uint256(uint160(address(_splits[_i].beneficiary))) << 90;\n\n // Store the first split part.\n _packedSplitParts1Of[_projectId][_domain][_group][_i] = _packedSplitParts1;\n\n // If there's data to store in the second packed split part, pack and store.\n if (_splits[_i].lockedUntil > 0 || _splits[_i].allocator != IJBSplitAllocator(address(0))) {\n // Locked until should be within a uint48\n if (_splits[_i].lockedUntil > type(uint48).max) revert INVALID_LOCKED_UNTIL();\n\n // lockedUntil in bits 0-47.\n uint256 _packedSplitParts2 = uint48(_splits[_i].lockedUntil);\n // allocator in bits 48-207.\n _packedSplitParts2 |= uint256(uint160(address(_splits[_i].allocator))) << 48;\n\n // Store the second split part.\n _packedSplitParts2Of[_projectId][_domain][_group][_i] = _packedSplitParts2;\n\n // Otherwise if there's a value stored in the indexed position, delete it.\n } else if (_packedSplitParts2Of[_projectId][_domain][_group][_i] > 0)\n delete _packedSplitParts2Of[_projectId][_domain][_group][_i];\n\n emit SetSplit(_projectId, _domain, _group, _splits[_i], msg.sender);\n\n unchecked {\n ++_i;\n }\n }\n\n // Set the new length of the splits.\n _splitCountOf[_projectId][_domain][_group] = _splitsLength;\n }\n\n /// @notice A flag indiciating if the provided splits array includes the locked split.\n /// @param _splits The array of splits to check within.\n /// @param _lockedSplit The locked split.\n /// @return A flag indicating if the `_lockedSplit` is contained in the `_splits`.\n function _includesLocked(\n JBSplit[] memory _splits,\n JBSplit memory _lockedSplit\n ) private pure returns (bool) {\n // Keep a reference to the number of splits.\n uint256 _numberOfSplits = _splits.length;\n\n for (uint256 _i; _i < _numberOfSplits; ) {\n // Check for sameness.\n if (\n _splits[_i].percent == _lockedSplit.percent &&\n _splits[_i].beneficiary == _lockedSplit.beneficiary &&\n _splits[_i].allocator == _lockedSplit.allocator &&\n _splits[_i].projectId == _lockedSplit.projectId &&\n _splits[_i].preferClaimed == _lockedSplit.preferClaimed &&\n _splits[_i].preferAddToBalance == _lockedSplit.preferAddToBalance &&\n // Allow lock extention.\n _splits[_i].lockedUntil >= _lockedSplit.lockedUntil\n ) return true;\n\n unchecked {\n ++_i;\n }\n }\n\n return false;\n }\n\n /// @notice Unpack splits' packed stored values into easy-to-work-with split structs.\n /// @param _projectId The ID of the project to which the split belongs.\n /// @param _domain The identifier within which the returned splits should be considered active.\n /// @param _group The identifying group of the splits.\n /// @return splits The split structs.\n function _getStructsFor(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group\n ) private view returns (JBSplit[] memory) {\n // Get a reference to the number of splits that need to be added to the returned array.\n uint256 _splitCount = _splitCountOf[_projectId][_domain][_group];\n\n // Initialize an array to be returned that has the set length.\n JBSplit[] memory _splits = new JBSplit[](_splitCount);\n\n // Loop through each split and unpack the values into structs.\n for (uint256 _i; _i < _splitCount; ) {\n // Get a reference to the fist packed data.\n uint256 _packedSplitPart1 = _packedSplitParts1Of[_projectId][_domain][_group][_i];\n\n // Populate the split struct.\n JBSplit memory _split;\n\n // prefer claimed in bit 0.\n _split.preferClaimed = _packedSplitPart1 & 1 == 1;\n // prefer add to balance in bit 1.\n _split.preferAddToBalance = (_packedSplitPart1 >> 1) & 1 == 1;\n // percent in bits 2-33.\n _split.percent = uint256(uint32(_packedSplitPart1 >> 2));\n // projectId in bits 32-89.\n _split.projectId = uint256(uint56(_packedSplitPart1 >> 34));\n // beneficiary in bits 90-249.\n _split.beneficiary = payable(address(uint160(_packedSplitPart1 >> 90)));\n\n // Get a reference to the second packed data.\n uint256 _packedSplitPart2 = _packedSplitParts2Of[_projectId][_domain][_group][_i];\n\n // If there's anything in it, unpack.\n if (_packedSplitPart2 > 0) {\n // lockedUntil in bits 0-47.\n _split.lockedUntil = uint256(uint48(_packedSplitPart2));\n // allocator in bits 48-207.\n _split.allocator = IJBSplitAllocator(address(uint160(_packedSplitPart2 >> 48)));\n }\n\n // Add the split to the value being returned.\n _splits[_i] = _split;\n\n unchecked {\n ++_i;\n }\n }\n\n return _splits;\n }\n}\n" + }, + "contracts/JBETHERC20SplitsPayerDeployer.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Clones} from '@openzeppelin/contracts/proxy/Clones.sol';\nimport {IJBETHERC20SplitsPayerDeployer} from './interfaces/IJBETHERC20SplitsPayerDeployer.sol';\nimport {IJBSplitsPayer} from './interfaces/IJBSplitsPayer.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {JBSplit} from './structs/JBSplit.sol';\nimport {JBGroupedSplits} from './structs/JBGroupedSplits.sol';\nimport {JBETHERC20SplitsPayer} from './JBETHERC20SplitsPayer.sol';\n\n/// @notice Deploys splits payer contracts.\ncontract JBETHERC20SplitsPayerDeployer is IJBETHERC20SplitsPayerDeployer {\n //*********************************************************************//\n // --------------- public immutable stored properties ---------------- //\n //*********************************************************************//\n\n /// @notice The implementation contract on which Clones will be based.\n address immutable implementation;\n\n /// @notice The contract that stores splits for each project.\n IJBSplitsStore immutable splitsStore;\n\n //*********************************************************************//\n // ---------------------------- constructor -------------------------- //\n //*********************************************************************//\n\n /// @param _splitsStore The contract that stores splits for each project.\n constructor(IJBSplitsStore _splitsStore) {\n implementation = address(new JBETHERC20SplitsPayer(_splitsStore));\n splitsStore = _splitsStore;\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Allows anyone to deploy a new splits payer contract.\n /// @dev This contract must have Operator permissions over the SET_SPLITS permission of the specified `_defaultSplitsProjectId`.\n /// @param _defaultSplitsProjectId The ID of project for which the default splits are stored.\n /// @param _defaultSplits The splits to payout when this contract receives direct payments.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _defaultProjectId The ID of the project whose treasury should be forwarded the splits payer contract's received payment leftovers after distributing to the default splits group.\n /// @param _defaultBeneficiary The address that'll receive the project's tokens when the splits payer receives payments.\n /// @param _defaultPreferClaimedTokens A flag indicating whether issued tokens from the splits payer's received payments should be automatically claimed into the beneficiary's wallet.\n /// @param _defaultMemo The memo that'll be forwarded with the splits payer's received payments.\n /// @param _defaultMetadata The metadata that'll be forwarded with the splits payer's received payments.\n /// @param _defaultPreferAddToBalance A flag indicating if received payments should call the `pay` function or the `addToBalance` function of a project.\n /// @param _owner The address that will own the splits payer.\n /// @return splitsPayer The splits payer contract.\n function deploySplitsPayerWithSplits(\n uint256 _defaultSplitsProjectId,\n JBSplit[] memory _defaultSplits,\n IJBSplitsStore _splitsStore,\n uint256 _defaultProjectId,\n address payable _defaultBeneficiary,\n bool _defaultPreferClaimedTokens,\n string memory _defaultMemo,\n bytes memory _defaultMetadata,\n bool _defaultPreferAddToBalance,\n address _owner\n ) external override returns (IJBSplitsPayer splitsPayer) {\n // Use this contract's address as the domain.\n uint256 _domain = uint256(uint160(address(this)));\n\n // Create the random hash using data unique to this instance that'll be used as the storage domain.\n uint256 _group = uint256(keccak256(abi.encodePacked(msg.sender, block.number)));\n\n // Set the splits in the store.\n JBGroupedSplits[] memory _groupedSplits;\n _groupedSplits = new JBGroupedSplits[](1);\n _groupedSplits[0] = JBGroupedSplits(_group, _defaultSplits);\n _splitsStore.set(_defaultSplitsProjectId, _domain, _groupedSplits);\n\n return\n deploySplitsPayer(\n _defaultSplitsProjectId,\n _domain,\n _group,\n _defaultProjectId,\n _defaultBeneficiary,\n _defaultPreferClaimedTokens,\n _defaultMemo,\n _defaultMetadata,\n _defaultPreferAddToBalance,\n _owner\n );\n }\n\n //*********************************************************************//\n // ---------------------- public transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Allows anyone to deploy a new splits payer contract.\n /// @param _defaultSplitsProjectId The ID of project for which the default splits are stored.\n /// @param _defaultSplitsDomain The splits domain to payout when this contract receives direct payments.\n /// @param _defaultSplitsGroup The splits group to payout when this contract receives direct payments.\n /// @param _defaultProjectId The ID of the project whose treasury should be forwarded the splits payer contract's received payment leftovers after distributing to the default splits group.\n /// @param _defaultBeneficiary The address that'll receive the project's tokens when the splits payer receives payments.\n /// @param _defaultPreferClaimedTokens A flag indicating whether issued tokens from the splits payer's received payments should be automatically claimed into the beneficiary's wallet.\n /// @param _defaultMemo The memo that'll be forwarded with the splits payer's received payments.\n /// @param _defaultMetadata The metadata that'll be forwarded with the splits payer's received payments.\n /// @param _defaultPreferAddToBalance A flag indicating if received payments should call the `pay` function or the `addToBalance` function of a project.\n /// @param _owner The address that will own the splits payer.\n /// @return splitsPayer The splits payer contract.\n function deploySplitsPayer(\n uint256 _defaultSplitsProjectId,\n uint256 _defaultSplitsDomain,\n uint256 _defaultSplitsGroup,\n uint256 _defaultProjectId,\n address payable _defaultBeneficiary,\n bool _defaultPreferClaimedTokens,\n string memory _defaultMemo,\n bytes memory _defaultMetadata,\n bool _defaultPreferAddToBalance,\n address _owner\n ) public override returns (IJBSplitsPayer splitsPayer) {\n // Deploy the splits payer.\n splitsPayer = IJBSplitsPayer(payable(Clones.clone(implementation)));\n\n splitsPayer.initialize(\n _defaultSplitsProjectId,\n _defaultSplitsDomain,\n _defaultSplitsGroup,\n _defaultProjectId,\n _defaultBeneficiary,\n _defaultPreferClaimedTokens,\n _defaultMemo,\n _defaultMetadata,\n _defaultPreferAddToBalance,\n _owner\n );\n\n emit DeploySplitsPayer(\n splitsPayer,\n _defaultSplitsProjectId,\n _defaultSplitsDomain,\n _defaultSplitsGroup,\n splitsStore,\n _defaultProjectId,\n _defaultBeneficiary,\n _defaultPreferClaimedTokens,\n _defaultMemo,\n _defaultMetadata,\n _defaultPreferAddToBalance,\n _owner,\n msg.sender\n );\n }\n}\n" + }, + "@openzeppelin/contracts/proxy/Clones.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (proxy/Clones.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for\n * deploying minimal proxy contracts, also known as \"clones\".\n *\n * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies\n * > a minimal bytecode implementation that delegates all calls to a known, fixed address.\n *\n * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`\n * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the\n * deterministic method.\n *\n * _Available since v3.4._\n */\nlibrary Clones {\n /**\n * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.\n *\n * This function uses the create opcode, which should never revert.\n */\n function clone(address implementation) internal returns (address instance) {\n assembly {\n let ptr := mload(0x40)\n mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)\n mstore(add(ptr, 0x14), shl(0x60, implementation))\n mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)\n instance := create(0, ptr, 0x37)\n }\n require(instance != address(0), \"ERC1167: create failed\");\n }\n\n /**\n * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.\n *\n * This function uses the create2 opcode and a `salt` to deterministically deploy\n * the clone. Using the same `implementation` and `salt` multiple time will revert, since\n * the clones cannot be deployed twice at the same address.\n */\n function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {\n assembly {\n let ptr := mload(0x40)\n mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)\n mstore(add(ptr, 0x14), shl(0x60, implementation))\n mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)\n instance := create2(0, ptr, 0x37, salt)\n }\n require(instance != address(0), \"ERC1167: create2 failed\");\n }\n\n /**\n * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.\n */\n function predictDeterministicAddress(\n address implementation,\n bytes32 salt,\n address deployer\n ) internal pure returns (address predicted) {\n assembly {\n let ptr := mload(0x40)\n mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)\n mstore(add(ptr, 0x14), shl(0x60, implementation))\n mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf3ff00000000000000000000000000000000)\n mstore(add(ptr, 0x38), shl(0x60, deployer))\n mstore(add(ptr, 0x4c), salt)\n mstore(add(ptr, 0x6c), keccak256(ptr, 0x37))\n predicted := keccak256(add(ptr, 0x37), 0x55)\n }\n }\n\n /**\n * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.\n */\n function predictDeterministicAddress(address implementation, bytes32 salt)\n internal\n view\n returns (address predicted)\n {\n return predictDeterministicAddress(implementation, salt, address(this));\n }\n}\n" + }, + "contracts/interfaces/IJBETHERC20SplitsPayerDeployer.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBSplitsPayer} from './IJBSplitsPayer.sol';\nimport {IJBSplitsStore} from './IJBSplitsStore.sol';\nimport {JBSplit} from './../structs/JBSplit.sol';\n\ninterface IJBETHERC20SplitsPayerDeployer {\n event DeploySplitsPayer(\n IJBSplitsPayer indexed splitsPayer,\n uint256 defaultSplitsProjectId,\n uint256 defaultSplitsDomain,\n uint256 defaultSplitsGroup,\n IJBSplitsStore splitsStore,\n uint256 defaultProjectId,\n address defaultBeneficiary,\n bool defaultPreferClaimedTokens,\n string defaultMemo,\n bytes defaultMetadata,\n bool preferAddToBalance,\n address owner,\n address caller\n );\n\n function deploySplitsPayer(\n uint256 defaultSplitsProjectId,\n uint256 defaultSplitsDomain,\n uint256 defaultSplitsGroup,\n uint256 defaultProjectId,\n address payable defaultBeneficiary,\n bool defaultPreferClaimedTokens,\n string calldata defaultMemo,\n bytes calldata defaultMetadata,\n bool preferAddToBalance,\n address owner\n ) external returns (IJBSplitsPayer splitsPayer);\n\n function deploySplitsPayerWithSplits(\n uint256 defaultSplitsProjectId,\n JBSplit[] memory defaultSplits,\n IJBSplitsStore splitsStore,\n uint256 defaultProjectId,\n address payable defaultBeneficiary,\n bool defaultPreferClaimedTokens,\n string memory defaultMemo,\n bytes memory defaultMetadata,\n bool defaultPreferAddToBalance,\n address owner\n ) external returns (IJBSplitsPayer splitsPayer);\n}\n" + }, + "contracts/interfaces/IJBSplitsPayer.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBSplit} from './../structs/JBSplit.sol';\nimport {JBGroupedSplits} from './../structs/JBGroupedSplits.sol';\nimport {IJBSplitsStore} from './IJBSplitsStore.sol';\n\ninterface IJBSplitsPayer is IERC165 {\n event SetDefaultSplitsReference(\n uint256 indexed projectId,\n uint256 indexed domain,\n uint256 indexed group,\n address caller\n );\n event Pay(\n uint256 indexed projectId,\n address beneficiary,\n address token,\n uint256 amount,\n uint256 decimals,\n uint256 leftoverAmount,\n uint256 minReturnedTokens,\n bool preferClaimedTokens,\n string memo,\n bytes metadata,\n address caller\n );\n\n event AddToBalance(\n uint256 indexed projectId,\n address beneficiary,\n address token,\n uint256 amount,\n uint256 decimals,\n uint256 leftoverAmount,\n string memo,\n bytes metadata,\n address caller\n );\n\n event DistributeToSplitGroup(\n uint256 indexed projectId,\n uint256 indexed domain,\n uint256 indexed group,\n address caller\n );\n\n event DistributeToSplit(\n JBSplit split,\n uint256 amount,\n address defaultBeneficiary,\n address caller\n );\n\n function defaultSplitsProjectId() external view returns (uint256);\n\n function defaultSplitsDomain() external view returns (uint256);\n\n function defaultSplitsGroup() external view returns (uint256);\n\n function splitsStore() external view returns (IJBSplitsStore);\n\n function initialize(\n uint256 defaultSplitsProjectId,\n uint256 defaultSplitsDomain,\n uint256 defaultSplitsGroup,\n uint256 defaultProjectId,\n address payable defaultBeneficiary,\n bool defaultPreferClaimedTokens,\n string memory defaultMemo,\n bytes memory defaultMetadata,\n bool preferAddToBalance,\n address owner\n ) external;\n\n function setDefaultSplitsReference(uint256 projectId, uint256 domain, uint256 group) external;\n\n function setDefaultSplits(\n uint256 projectId,\n uint256 domain,\n uint256 group,\n JBGroupedSplits[] memory splitsGroup\n ) external;\n}\n" + }, + "contracts/JBETHERC20SplitsPayer.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {ReentrancyGuard} from '@openzeppelin/contracts/security/ReentrancyGuard.sol';\nimport {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';\nimport {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';\nimport {Address} from '@openzeppelin/contracts/utils/Address.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {IJBSplitsPayer} from './interfaces/IJBSplitsPayer.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {JBConstants} from './libraries/JBConstants.sol';\nimport {JBETHERC20ProjectPayer} from './JBETHERC20ProjectPayer.sol';\nimport {IJBSplitAllocator} from './interfaces/IJBSplitAllocator.sol';\nimport {JBTokens} from './libraries/JBTokens.sol';\nimport {JBGroupedSplits} from './structs/JBGroupedSplits.sol';\nimport {JBSplit} from './structs/JBSplit.sol';\nimport {JBSplitAllocationData} from './structs/JBSplitAllocationData.sol';\n\n/// @notice Sends ETH or ERC20's to a group of splits as it receives direct payments or has its functions called.\n/// @dev Inherit from this contract or borrow from its logic to forward ETH or ERC20's to a group of splits from within other contracts.\ncontract JBETHERC20SplitsPayer is JBETHERC20ProjectPayer, ReentrancyGuard, IJBSplitsPayer {\n using SafeERC20 for IERC20;\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice The contract that stores splits for each project.\n IJBSplitsStore public immutable override splitsStore;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The ID of project for which the default splits are stored.\n uint256 public override defaultSplitsProjectId;\n\n /// @notice The domain within which the default splits are stored.\n uint256 public override defaultSplitsDomain;\n\n /// @notice The group within which the default splits are stored.\n uint256 public override defaultSplitsGroup;\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if this contract adheres to the specified interface.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(JBETHERC20ProjectPayer, IERC165) returns (bool) {\n return\n _interfaceId == type(IJBSplitsPayer).interfaceId || super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _splitsStore A contract that stores splits for each project.\n constructor(IJBSplitsStore _splitsStore) JBETHERC20ProjectPayer(_splitsStore.directory()) {\n splitsStore = _splitsStore;\n }\n\n /// @dev The re-initialize check is done in the inherited paroject payer\n /// @param _defaultSplitsProjectId The ID of project for which the default splits are stored.\n /// @param _defaultSplitsDomain The splits domain to payout when this contract receives direct payments.\n /// @param _defaultSplitsGroup The splits group to payout when this contract receives direct payments.\n /// @param _defaultProjectId The ID of the project whose treasury should be forwarded the splits payer contract's received payment leftovers after distributing to the default splits group.\n /// @param _defaultBeneficiary The address that'll receive the project's tokens.\n /// @param _defaultPreferClaimedTokens A flag indicating whether issued tokens should be automatically claimed into the beneficiary's wallet.\n /// @param _defaultMemo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _defaultMetadata Bytes to send along to the project's data source and delegate, if provided.\n /// @param _preferAddToBalance A flag indicating if received payments should call the `pay` function or the `addToBalance` function of a project.\n /// @param _owner The address that will own the contract.\n function initialize(\n uint256 _defaultSplitsProjectId,\n uint256 _defaultSplitsDomain,\n uint256 _defaultSplitsGroup,\n uint256 _defaultProjectId,\n address payable _defaultBeneficiary,\n bool _defaultPreferClaimedTokens,\n string memory _defaultMemo,\n bytes memory _defaultMetadata,\n bool _preferAddToBalance,\n address _owner\n ) external override {\n super.initialize(\n _defaultProjectId,\n _defaultBeneficiary,\n _defaultPreferClaimedTokens,\n _defaultMemo,\n _defaultMetadata,\n _preferAddToBalance,\n _owner\n );\n\n defaultSplitsProjectId = _defaultSplitsProjectId;\n defaultSplitsDomain = _defaultSplitsDomain;\n defaultSplitsGroup = _defaultSplitsGroup;\n }\n\n //*********************************************************************//\n // ------------------------- default receive ------------------------- //\n //*********************************************************************//\n\n /// @notice Received funds are paid to the default split group using the stored default properties.\n /// @dev This function is called automatically when the contract receives an ETH payment.\n receive() external payable virtual override nonReentrant {\n // Pay the splits and get a reference to the amount leftover.\n uint256 _leftoverAmount = _payToSplits(\n defaultSplitsProjectId,\n defaultSplitsDomain,\n defaultSplitsGroup,\n JBTokens.ETH,\n address(this).balance,\n 18, // decimals.\n defaultBeneficiary != address(0) ? defaultBeneficiary : tx.origin\n );\n\n // If there is no leftover amount, nothing left to pay.\n if (_leftoverAmount == 0) return;\n\n // If there's a default project ID, try to pay it.\n if (defaultProjectId != 0)\n if (defaultPreferAddToBalance)\n // Pay the project by adding to its balance if prefered.\n _addToBalanceOf(\n defaultProjectId,\n JBTokens.ETH,\n _leftoverAmount,\n 18, // decimals.\n defaultMemo,\n defaultMetadata\n );\n // Otherwise, issue a payment to the project.\n else\n _pay(\n defaultProjectId,\n JBTokens.ETH,\n _leftoverAmount,\n 18, // decimals.\n defaultBeneficiary != address(0) ? defaultBeneficiary : tx.origin,\n 0, // min returned tokens.\n defaultPreferClaimedTokens,\n defaultMemo,\n defaultMetadata\n );\n // If no project was specified, send the funds directly to the beneficiary or the tx.origin.\n else\n Address.sendValue(\n defaultBeneficiary != address(0) ? payable(defaultBeneficiary) : payable(tx.origin),\n _leftoverAmount\n );\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Sets the splits in the splits store that payments this contract receives will be split between.\n /// @param _projectId The ID of project for which the default splits are stored.\n /// @param _domain The domain within which the default splits are stored.\n /// @param _group The group within which the default splits are stored.\n /// @param _groupedSplits The split groups to set.\n function setDefaultSplits(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group,\n JBGroupedSplits[] memory _groupedSplits\n ) external virtual override onlyOwner {\n // Set the splits in the store.\n splitsStore.set(_projectId, _domain, _groupedSplits);\n\n // Set the splits reference.\n setDefaultSplitsReference(_projectId, _domain, _group);\n }\n\n //*********************************************************************//\n // ----------------------- public transactions ----------------------- //\n //*********************************************************************//\n\n /// @notice Sets the location of the splits that payments this contract receives will be split between.\n /// @param _projectId The ID of project for which the default splits are stored.\n /// @param _domain The domain within which the default splits are stored.\n /// @param _group The group within which the default splits are stored.\n function setDefaultSplitsReference(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group\n ) public virtual override onlyOwner {\n // Set the default splits project ID if it's changing.\n if (_projectId != defaultSplitsProjectId) defaultSplitsProjectId = _projectId;\n\n // Set the default splits domain if it's changing.\n if (_domain != defaultSplitsDomain) defaultSplitsDomain = _domain;\n\n // Set the default splits group if it's changing.\n if (_group != defaultSplitsGroup) defaultSplitsGroup = _group;\n\n emit SetDefaultSplitsReference(_projectId, _domain, _group, msg.sender);\n }\n\n /// @notice Make a payment to the specified project after first splitting the amount among the stored default splits.\n /// @param _projectId The ID of the project that is being paid after.\n /// @param _token The token being paid in.\n /// @param _amount The amount of tokens being paid, as a fixed point number. If the token is ETH, this is ignored and msg.value is used in its place.\n /// @param _decimals The number of decimals in the `_amount` fixed point number. If the token is ETH, this is ignored and 18 is used in its place, which corresponds to the amount of decimals expected in msg.value.\n /// @param _beneficiary The address who will receive tokens from the payment made with leftover funds.\n /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with 18 decimals.\n /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\n /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n function pay(\n uint256 _projectId,\n address _token,\n uint256 _amount,\n uint256 _decimals,\n address _beneficiary,\n uint256 _minReturnedTokens,\n bool _preferClaimedTokens,\n string calldata _memo,\n bytes calldata _metadata\n ) public payable virtual override nonReentrant {\n // ETH shouldn't be sent if the token isn't ETH.\n if (address(_token) != JBTokens.ETH) {\n if (msg.value > 0) revert NO_MSG_VALUE_ALLOWED();\n\n // Get a reference to the balance before receiving tokens.\n uint256 _balanceBefore = IERC20(_token).balanceOf(address(this));\n\n // Transfer tokens to this contract from the msg sender.\n IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount);\n\n // The amount should reflect the change in balance.\n _amount = IERC20(_token).balanceOf(address(this)) - _balanceBefore;\n } else {\n // If ETH is being paid, set the amount to the message value, and decimals to 18.\n _amount = msg.value;\n _decimals = 18;\n }\n\n // Pay the splits and get a reference to the amount leftover.\n uint256 _leftoverAmount = _payToSplits(\n defaultSplitsProjectId,\n defaultSplitsDomain,\n defaultSplitsGroup,\n _token,\n _amount,\n _decimals,\n defaultBeneficiary != address(0) ? defaultBeneficiary : tx.origin\n );\n\n // Pay any leftover amount.\n if (_leftoverAmount > 0) {\n // If there's a default project ID, try to pay it.\n if (_projectId != 0) {\n _pay(\n _projectId,\n _token,\n _leftoverAmount,\n _decimals,\n _beneficiary != address(0) ? _beneficiary : defaultBeneficiary != address(0)\n ? defaultBeneficiary\n : tx.origin,\n _minReturnedTokens,\n _preferClaimedTokens,\n _memo,\n _metadata\n );\n }\n // If no project was specified, send the funds directly to the beneficiary or the tx.origin.\n else {\n // Transfer the ETH.\n if (_token == JBTokens.ETH)\n Address.sendValue(\n // If there's a beneficiary, send the funds directly to the beneficiary. Otherwise send to the tx.origin.\n _beneficiary != address(0) ? payable(_beneficiary) : defaultBeneficiary != address(0)\n ? defaultBeneficiary\n : payable(tx.origin),\n _leftoverAmount\n );\n // Or, transfer the ERC20.\n else\n IERC20(_token).safeTransfer(\n // If there's a beneficiary, send the funds directly to the beneficiary. Otherwise send to the tx.origin.\n _beneficiary != address(0) ? _beneficiary : defaultBeneficiary != address(0)\n ? defaultBeneficiary\n : tx.origin,\n _leftoverAmount\n );\n }\n }\n\n emit Pay(\n _projectId,\n _beneficiary != address(0) ? _beneficiary : defaultBeneficiary != address(0)\n ? defaultBeneficiary\n : tx.origin,\n _token,\n _amount,\n _decimals,\n _leftoverAmount,\n _minReturnedTokens,\n _preferClaimedTokens,\n _memo,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Add to the balance of the specified project after first splitting the amount among the stored default splits.\n /// @param _projectId The ID of the project that is being paid after.\n /// @param _token The token being paid in.\n /// @param _amount The amount of tokens being paid, as a fixed point number. If the token is ETH, this is ignored and msg.value is used in its place.\n /// @param _decimals The number of decimals in the `_amount` fixed point number. If the token is ETH, this is ignored and 18 is used in its place, which corresponds to the amount of decimals expected in msg.value.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the terminal.\n function addToBalanceOf(\n uint256 _projectId,\n address _token,\n uint256 _amount,\n uint256 _decimals,\n string calldata _memo,\n bytes calldata _metadata\n ) public payable virtual override nonReentrant {\n // ETH shouldn't be sent if this terminal's token isn't ETH.\n if (address(_token) != JBTokens.ETH) {\n if (msg.value > 0) revert NO_MSG_VALUE_ALLOWED();\n\n // Get a reference to the balance before receiving tokens.\n uint256 _balanceBefore = IERC20(_token).balanceOf(address(this));\n\n // Transfer tokens to this contract from the msg sender.\n IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount);\n\n // The amount should reflect the change in balance.\n _amount = IERC20(_token).balanceOf(address(this)) - _balanceBefore;\n } else {\n // If ETH is being paid, set the amount to the message value, and decimals to 18.\n _amount = msg.value;\n _decimals = 18;\n }\n\n // Pay the splits and get a reference to the amount leftover.\n uint256 _leftoverAmount = _payToSplits(\n defaultSplitsProjectId,\n defaultSplitsDomain,\n defaultSplitsGroup,\n _token,\n _amount,\n _decimals,\n defaultBeneficiary != address(0) ? defaultBeneficiary : tx.origin\n );\n\n // Distribute any leftover amount.\n if (_leftoverAmount > 0) {\n // If there's a default project ID, try to add to its balance.\n if (_projectId != 0)\n // Add to the project's balance.\n _addToBalanceOf(_projectId, _token, _leftoverAmount, _decimals, _memo, _metadata);\n\n // Otherwise, send a payment to the beneficiary.\n else {\n // Transfer the ETH.\n if (_token == JBTokens.ETH)\n Address.sendValue(\n // If there's a default beneficiary, send the funds directly to the beneficiary. Otherwise send to the tx.origin.\n defaultBeneficiary != address(0) ? defaultBeneficiary : payable(tx.origin),\n _leftoverAmount\n );\n // Or, transfer the ERC20.\n else\n IERC20(_token).safeTransfer(\n // If there's a default beneficiary, send the funds directly to the beneficiary. Otherwise send to the tx.origin.\n defaultBeneficiary != address(0) ? defaultBeneficiary : tx.origin,\n _leftoverAmount\n );\n }\n }\n\n emit AddToBalance(\n _projectId,\n defaultBeneficiary != address(0) ? defaultBeneficiary : tx.origin,\n _token,\n _amount,\n _decimals,\n _leftoverAmount,\n _memo,\n _metadata,\n msg.sender\n );\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Split an amount between all splits.\n /// @param _splitsProjectId The ID of the project to which the splits belong.\n /// @param _splitsDomain The splits domain to which the group belongs.\n /// @param _splitsGroup The splits group to pay.\n /// @param _token The token the amonut being split is in.\n /// @param _amount The amount of tokens being split, as a fixed point number. If the `_token` is ETH, this is ignored and msg.value is used in its place.\n /// @param _decimals The number of decimals in the `_amount` fixed point number.\n /// @param _defaultBeneficiary The address that will benefit from any non-specified beneficiaries in splits.\n /// @return leftoverAmount The amount leftover after all splits were paid.\n function _payToSplits(\n uint256 _splitsProjectId,\n uint256 _splitsDomain,\n uint256 _splitsGroup,\n address _token,\n uint256 _amount,\n uint256 _decimals,\n address _defaultBeneficiary\n ) internal virtual returns (uint256 leftoverAmount) {\n // Pay the splits.\n leftoverAmount = _payTo(\n splitsStore.splitsOf(_splitsProjectId, _splitsDomain, _splitsGroup),\n _token,\n _amount,\n _decimals,\n _defaultBeneficiary\n );\n emit DistributeToSplitGroup(_splitsProjectId, _splitsDomain, _splitsGroup, msg.sender);\n }\n\n /// @notice Split an amount between all splits.\n /// @param _splits The splits.\n /// @param _token The token the amonut being split is in.\n /// @param _amount The amount of tokens being split, as a fixed point number. If the `_token` is ETH, this is ignored and msg.value is used in its place.\n /// @param _decimals The number of decimals in the `_amount` fixed point number.\n /// @param _defaultBeneficiary The address that will benefit from any non-specified beneficiaries in splits.\n /// @return leftoverAmount The amount leftover after all splits were paid.\n function _payTo(\n JBSplit[] memory _splits,\n address _token,\n uint256 _amount,\n uint256 _decimals,\n address _defaultBeneficiary\n ) internal virtual returns (uint256 leftoverAmount) {\n // Set the leftover amount to the initial balance.\n leftoverAmount = _amount;\n\n // Settle between all splits.\n for (uint256 i; i < _splits.length; ) {\n // Get a reference to the split being iterated on.\n JBSplit memory _split = _splits[i];\n\n // The amount to send towards the split.\n uint256 _splitAmount = PRBMath.mulDiv(\n _amount,\n _split.percent,\n JBConstants.SPLITS_TOTAL_PERCENT\n );\n\n if (_splitAmount > 0) {\n // Transfer tokens to the split.\n // If there's an allocator set, transfer to its `allocate` function.\n if (_split.allocator != IJBSplitAllocator(address(0))) {\n // Create the data to send to the allocator.\n JBSplitAllocationData memory _data = JBSplitAllocationData(\n _token,\n _splitAmount,\n _decimals,\n defaultProjectId,\n 0,\n _split\n );\n\n // Approve the `_amount` of tokens for the split allocator to transfer tokens from this contract.\n if (_token != JBTokens.ETH)\n IERC20(_token).safeApprove(address(_split.allocator), _splitAmount);\n\n // If the token is ETH, send it in msg.value.\n uint256 _payableValue = _token == JBTokens.ETH ? _splitAmount : 0;\n\n // Trigger the allocator's `allocate` function.\n _split.allocator.allocate{value: _payableValue}(_data);\n\n // Otherwise, if a project is specified, make a payment to it.\n } else if (_split.projectId != 0) {\n if (_split.preferAddToBalance)\n _addToBalanceOf(\n _split.projectId,\n _token,\n _splitAmount,\n _decimals,\n defaultMemo,\n defaultMetadata\n );\n else\n _pay(\n _split.projectId,\n _token,\n _splitAmount,\n _decimals,\n _split.beneficiary != address(0) ? _split.beneficiary : _defaultBeneficiary,\n 0,\n _split.preferClaimed,\n defaultMemo,\n defaultMetadata\n );\n } else {\n // Transfer the ETH.\n if (_token == JBTokens.ETH)\n Address.sendValue(\n // Get a reference to the address receiving the tokens. If there's a beneficiary, send the funds directly to the beneficiary. Otherwise send to _defaultBeneficiary.\n _split.beneficiary != address(0) ? _split.beneficiary : payable(_defaultBeneficiary),\n _splitAmount\n );\n // Or, transfer the ERC20.\n else {\n IERC20(_token).safeTransfer(\n // Get a reference to the address receiving the tokens. If there's a beneficiary, send the funds directly to the beneficiary. Otherwise send to _defaultBeneficiary.\n _split.beneficiary != address(0) ? _split.beneficiary : _defaultBeneficiary,\n _splitAmount\n );\n }\n }\n\n // Subtract from the amount to be sent to the beneficiary.\n leftoverAmount = leftoverAmount - _splitAmount;\n }\n\n emit DistributeToSplit(_split, _splitAmount, _defaultBeneficiary, msg.sender);\n\n unchecked {\n ++i;\n }\n }\n }\n}\n" + }, + "@openzeppelin/contracts/security/ReentrancyGuard.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuard {\n // Booleans are more expensive than uint256 or any type that takes up a full\n // word because each write operation emits an extra SLOAD to first read the\n // slot's contents, replace the bits taken up by the boolean, and then write\n // back. This is the compiler's defense against contract upgrades and\n // pointer aliasing, and it cannot be disabled.\n\n // The values being non-zero value makes deployment a bit more expensive,\n // but in exchange the refund on every call to nonReentrant will be lower in\n // amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to\n // increase the likelihood of the full refund coming into effect.\n uint256 private constant _NOT_ENTERED = 1;\n uint256 private constant _ENTERED = 2;\n\n uint256 private _status;\n\n constructor() {\n _status = _NOT_ENTERED;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a `nonReentrant` function from another `nonReentrant`\n * function is not supported. It is possible to prevent this from happening\n * by making the `nonReentrant` function external, and making it call a\n * `private` function that does the actual work.\n */\n modifier nonReentrant() {\n // On the first call to nonReentrant, _notEntered will be true\n require(_status != _ENTERED, \"ReentrancyGuard: reentrant call\");\n\n // Any calls to nonReentrant after this point will fail\n _status = _ENTERED;\n\n _;\n\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _status = _NOT_ENTERED;\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length > 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Address.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n *\n * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCall(target, data, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n require(isContract(target), \"Address: call to non-contract\");\n\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n require(isContract(target), \"Address: static call to non-contract\");\n\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(isContract(target), \"Address: delegate call to non-contract\");\n\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n }\n}\n" + }, + "contracts/JBETHERC20ProjectPayer.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';\nimport {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';\nimport {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';\nimport {ERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBProjectPayer} from './interfaces/IJBProjectPayer.sol';\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\nimport {JBTokens} from './libraries/JBTokens.sol';\n\n/// @notice Sends ETH or ERC20's to a project treasury as it receives direct payments or has it's functions called.\n/// @dev Inherit from this contract or borrow from its logic to forward ETH or ERC20's to project treasuries from within other contracts.\ncontract JBETHERC20ProjectPayer is Ownable, ERC165, IJBProjectPayer {\n using SafeERC20 for IERC20;\n\n //*********************************************************************//\n // -------------------------- custom errors -------------------------- //\n //*********************************************************************//\n error INCORRECT_DECIMAL_AMOUNT();\n error ALREADY_INITIALIZED();\n error NO_MSG_VALUE_ALLOWED();\n error TERMINAL_NOT_FOUND();\n\n //*********************************************************************//\n // ------------------- public immutable properties ------------------- //\n //*********************************************************************//\n\n /// @notice A contract storing directories of terminals and controllers for each project.\n IJBDirectory public immutable override directory;\n\n /// @notice The deployer associated with this implementation. Used to rule out double initialization.\n address public immutable override projectPayerDeployer;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The ID of the project that should be used to forward this contract's received payments.\n uint256 public override defaultProjectId;\n\n /// @notice The beneficiary that should be used in the payment made when this contract receives payments.\n address payable public override defaultBeneficiary;\n\n /// @notice A flag indicating whether issued tokens should be automatically claimed into the beneficiary's wallet. Leaving tokens unclaimed saves gas.\n bool public override defaultPreferClaimedTokens;\n\n /// @notice The memo that should be used in the payment made when this contract receives payments.\n string public override defaultMemo;\n\n /// @notice The metadata that should be used in the payment made when this contract receives payments.\n bytes public override defaultMetadata;\n\n /// @notice A flag indicating if received payments should call the `pay` function or the `addToBalance` function of a project.\n bool public override defaultPreferAddToBalance;\n\n //*********************************************************************//\n // ------------------------- public views ---------------------------- //\n //*********************************************************************//\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if the provided interface ID is supported.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(ERC165, IERC165) returns (bool) {\n return\n _interfaceId == type(IJBProjectPayer).interfaceId || super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // -------------------------- constructors --------------------------- //\n //*********************************************************************//\n\n /// @dev This is the constructor of the implementation. The directory is shared between project payers and is immutable. If a new JBDirectory is needed, a new JBProjectPayerDeployer should be deployed.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n constructor(IJBDirectory _directory) {\n directory = _directory;\n projectPayerDeployer = msg.sender;\n }\n\n /// @param _defaultProjectId The ID of the project whose treasury should be forwarded this contract's received payments.\n /// @param _defaultBeneficiary The address that'll receive the project's tokens.\n /// @param _defaultPreferClaimedTokens A flag indicating whether issued tokens should be automatically claimed into the beneficiary's wallet.\n /// @param _defaultMemo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _defaultMetadata Bytes to send along to the project's data source and delegate, if provided.\n /// @param _defaultPreferAddToBalance A flag indicating if received payments should call the `pay` function or the `addToBalance` function of a project.\n /// @param _owner The address that will own the contract.\n function initialize(\n uint256 _defaultProjectId,\n address payable _defaultBeneficiary,\n bool _defaultPreferClaimedTokens,\n string memory _defaultMemo,\n bytes memory _defaultMetadata,\n bool _defaultPreferAddToBalance,\n address _owner\n ) public {\n if (msg.sender != projectPayerDeployer) revert ALREADY_INITIALIZED();\n\n defaultProjectId = _defaultProjectId;\n defaultBeneficiary = _defaultBeneficiary;\n defaultPreferClaimedTokens = _defaultPreferClaimedTokens;\n defaultMemo = _defaultMemo;\n defaultMetadata = _defaultMetadata;\n defaultPreferAddToBalance = _defaultPreferAddToBalance;\n _transferOwnership(_owner);\n }\n\n //*********************************************************************//\n // ------------------------- default receive ------------------------- //\n //*********************************************************************//\n\n /// @notice Received funds are paid to the default project ID using the stored default properties.\n /// @dev Use the `addToBalance` function if there's a preference to do so. Otherwise use `pay`.\n /// @dev This function is called automatically when the contract receives an ETH payment.\n receive() external payable virtual override {\n if (defaultPreferAddToBalance)\n _addToBalanceOf(\n defaultProjectId,\n JBTokens.ETH,\n address(this).balance,\n 18, // balance is a fixed point number with 18 decimals.\n defaultMemo,\n defaultMetadata\n );\n else\n _pay(\n defaultProjectId,\n JBTokens.ETH,\n address(this).balance,\n 18, // balance is a fixed point number with 18 decimals.\n defaultBeneficiary == address(0) ? tx.origin : defaultBeneficiary,\n 0, // Can't determine expectation of returned tokens ahead of time.\n defaultPreferClaimedTokens,\n defaultMemo,\n defaultMetadata\n );\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Sets the default values that determine how to interact with a protocol treasury when this contract receives ETH directly.\n /// @param _projectId The ID of the project whose treasury should be forwarded this contract's received payments.\n /// @param _beneficiary The address that'll receive the project's tokens.\n /// @param _preferClaimedTokens A flag indicating whether issued tokens should be automatically claimed into the beneficiary's wallet.\n /// @param _memo The memo that'll be used.\n /// @param _metadata The metadata that'll be sent.\n /// @param _defaultPreferAddToBalance A flag indicating if received payments should call the `pay` function or the `addToBalance` function of a project.\n function setDefaultValues(\n uint256 _projectId,\n address payable _beneficiary,\n bool _preferClaimedTokens,\n string memory _memo,\n bytes memory _metadata,\n bool _defaultPreferAddToBalance\n ) external virtual override onlyOwner {\n // Set the default project ID if it has changed.\n if (_projectId != defaultProjectId) defaultProjectId = _projectId;\n\n // Set the default beneficiary if it has changed.\n if (_beneficiary != defaultBeneficiary) defaultBeneficiary = _beneficiary;\n\n // Set the default claimed token preference if it has changed.\n if (_preferClaimedTokens != defaultPreferClaimedTokens)\n defaultPreferClaimedTokens = _preferClaimedTokens;\n\n // Set the default memo if it has changed.\n if (keccak256(abi.encodePacked(_memo)) != keccak256(abi.encodePacked(defaultMemo)))\n defaultMemo = _memo;\n\n // Set the default metadata if it has changed.\n if (keccak256(abi.encodePacked(_metadata)) != keccak256(abi.encodePacked(defaultMetadata)))\n defaultMetadata = _metadata;\n\n // Set the add to balance preference if it has changed.\n if (_defaultPreferAddToBalance != defaultPreferAddToBalance)\n defaultPreferAddToBalance = _defaultPreferAddToBalance;\n\n emit SetDefaultValues(\n _projectId,\n _beneficiary,\n _preferClaimedTokens,\n _memo,\n _metadata,\n _defaultPreferAddToBalance,\n msg.sender\n );\n }\n\n //*********************************************************************//\n // ----------------------- public transactions ----------------------- //\n //*********************************************************************//\n\n /// @notice Make a payment to the specified project.\n /// @param _projectId The ID of the project that is being paid.\n /// @param _token The token being paid in.\n /// @param _amount The amount of tokens being paid, as a fixed point number. If the token is ETH, this is ignored and msg.value is used in its place.\n /// @param _decimals The number of decimals in the `_amount` fixed point number. If the token is ETH, this is ignored and 18 is used in its place, which corresponds to the amount of decimals expected in msg.value.\n /// @param _beneficiary The address who will receive tokens from the payment.\n /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with 18 decimals.\n /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\n /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n function pay(\n uint256 _projectId,\n address _token,\n uint256 _amount,\n uint256 _decimals,\n address _beneficiary,\n uint256 _minReturnedTokens,\n bool _preferClaimedTokens,\n string calldata _memo,\n bytes calldata _metadata\n ) public payable virtual override {\n // ETH shouldn't be sent if the token isn't ETH.\n if (address(_token) != JBTokens.ETH) {\n if (msg.value > 0) revert NO_MSG_VALUE_ALLOWED();\n\n // Get a reference to the balance before receiving tokens.\n uint256 _balanceBefore = IERC20(_token).balanceOf(address(this));\n\n // Transfer tokens to this contract from the msg sender.\n IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount);\n\n // The amount should reflect the change in balance.\n _amount = IERC20(_token).balanceOf(address(this)) - _balanceBefore;\n } else {\n // If ETH is being paid, set the amount to the message value, and decimals to 18.\n _amount = msg.value;\n _decimals = 18;\n }\n\n _pay(\n _projectId,\n _token,\n _amount,\n _decimals,\n _beneficiary,\n _minReturnedTokens,\n _preferClaimedTokens,\n _memo,\n _metadata\n );\n }\n\n /// @notice Add to the balance of the specified project.\n /// @param _projectId The ID of the project that is being paid.\n /// @param _token The token being paid in.\n /// @param _amount The amount of tokens being paid, as a fixed point number. If the token is ETH, this is ignored and msg.value is used in its place.\n /// @param _decimals The number of decimals in the `_amount` fixed point number. If the token is ETH, this is ignored and 18 is used in its place, which corresponds to the amount of decimals expected in msg.value.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the terminal.\n function addToBalanceOf(\n uint256 _projectId,\n address _token,\n uint256 _amount,\n uint256 _decimals,\n string calldata _memo,\n bytes calldata _metadata\n ) public payable virtual override {\n // ETH shouldn't be sent if the token isn't ETH.\n if (address(_token) != JBTokens.ETH) {\n if (msg.value > 0) revert NO_MSG_VALUE_ALLOWED();\n\n // Get a reference to the balance before receiving tokens.\n uint256 _balanceBefore = IERC20(_token).balanceOf(address(this));\n\n // Transfer tokens to this contract from the msg sender.\n IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount);\n\n // The amount should reflect the change in balance.\n _amount = IERC20(_token).balanceOf(address(this)) - _balanceBefore;\n } else {\n // If ETH is being paid, set the amount to the message value, and decimals to 18.\n _amount = msg.value;\n _decimals = 18;\n }\n\n _addToBalanceOf(_projectId, _token, _amount, _decimals, _memo, _metadata);\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Make a payment to the specified project.\n /// @param _projectId The ID of the project that is being paid.\n /// @param _token The token being paid in.\n /// @param _amount The amount of tokens being paid, as a fixed point number.\n /// @param _decimals The number of decimals in the `_amount` fixed point number.\n /// @param _beneficiary The address who will receive tokens from the payment.\n /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with 18 decimals.\n /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\n /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _metadata Bytes to send along to the data source and delegate, if provided.\n function _pay(\n uint256 _projectId,\n address _token,\n uint256 _amount,\n uint256 _decimals,\n address _beneficiary,\n uint256 _minReturnedTokens,\n bool _preferClaimedTokens,\n string memory _memo,\n bytes memory _metadata\n ) internal virtual {\n // Find the terminal for the specified project.\n IJBPaymentTerminal _terminal = directory.primaryTerminalOf(_projectId, _token);\n\n // There must be a terminal.\n if (_terminal == IJBPaymentTerminal(address(0))) revert TERMINAL_NOT_FOUND();\n\n // The amount's decimals must match the terminal's expected decimals.\n if (_terminal.decimalsForToken(_token) != _decimals) revert INCORRECT_DECIMAL_AMOUNT();\n\n // Approve the `_amount` of tokens from the destination terminal to transfer tokens from this contract.\n if (_token != JBTokens.ETH) IERC20(_token).safeApprove(address(_terminal), _amount);\n\n // If the token is ETH, send it in msg.value.\n uint256 _payableValue = _token == JBTokens.ETH ? _amount : 0;\n\n // Send funds to the terminal.\n // If the token is ETH, send it in msg.value.\n _terminal.pay{value: _payableValue}(\n _projectId,\n _amount, // ignored if the token is JBTokens.ETH.\n _token,\n _beneficiary != address(0) ? _beneficiary : defaultBeneficiary != address(0)\n ? defaultBeneficiary\n : tx.origin,\n _minReturnedTokens,\n _preferClaimedTokens,\n _memo,\n _metadata\n );\n }\n\n /// @notice Add to the balance of the specified project.\n /// @param _projectId The ID of the project that is being paid.\n /// @param _token The token being paid in.\n /// @param _amount The amount of tokens being paid, as a fixed point number. If the token is ETH, this is ignored and msg.value is used in its place.\n /// @param _decimals The number of decimals in the `_amount` fixed point number. If the token is ETH, this is ignored and 18 is used in its place, which corresponds to the amount of decimals expected in msg.value.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the terminal.\n function _addToBalanceOf(\n uint256 _projectId,\n address _token,\n uint256 _amount,\n uint256 _decimals,\n string memory _memo,\n bytes memory _metadata\n ) internal virtual {\n // Find the terminal for the specified project.\n IJBPaymentTerminal _terminal = directory.primaryTerminalOf(_projectId, _token);\n\n // There must be a terminal.\n if (_terminal == IJBPaymentTerminal(address(0))) revert TERMINAL_NOT_FOUND();\n\n // The amount's decimals must match the terminal's expected decimals.\n if (_terminal.decimalsForToken(_token) != _decimals) revert INCORRECT_DECIMAL_AMOUNT();\n\n // Approve the `_amount` of tokens from the destination terminal to transfer tokens from this contract.\n if (_token != JBTokens.ETH) IERC20(_token).safeApprove(address(_terminal), _amount);\n\n // If the token is ETH, send it in msg.value.\n uint256 _payableValue = _token == JBTokens.ETH ? _amount : 0;\n\n // Add to balance so tokens don't get issued.\n _terminal.addToBalanceOf{value: _payableValue}(_projectId, _amount, _token, _memo, _metadata);\n }\n}\n" + }, + "contracts/libraries/JBTokens.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nlibrary JBTokens {\n /// @notice The ETH token address in Juicebox is represented by 0x000000000000000000000000000000000000EEEe.\n address public constant ETH = address(0x000000000000000000000000000000000000EEEe);\n}\n" + }, + "contracts/interfaces/IJBProjectPayer.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {IJBDirectory} from './IJBDirectory.sol';\n\ninterface IJBProjectPayer is IERC165 {\n event SetDefaultValues(\n uint256 indexed projectId,\n address indexed beneficiary,\n bool preferClaimedTokens,\n string memo,\n bytes metadata,\n bool preferAddToBalance,\n address caller\n );\n\n function directory() external view returns (IJBDirectory);\n\n function projectPayerDeployer() external view returns (address);\n\n function defaultProjectId() external view returns (uint256);\n\n function defaultBeneficiary() external view returns (address payable);\n\n function defaultPreferClaimedTokens() external view returns (bool);\n\n function defaultMemo() external view returns (string memory);\n\n function defaultMetadata() external view returns (bytes memory);\n\n function defaultPreferAddToBalance() external view returns (bool);\n\n function initialize(\n uint256 defaultProjectId,\n address payable defaultBeneficiary,\n bool defaultPreferClaimedTokens,\n string memory defaultMemo,\n bytes memory defaultMetadata,\n bool defaultPreferAddToBalance,\n address owner\n ) external;\n\n function setDefaultValues(\n uint256 projectId,\n address payable beneficiary,\n bool preferClaimedTokens,\n string memory memo,\n bytes memory metadata,\n bool defaultPreferAddToBalance\n ) external;\n\n function pay(\n uint256 projectId,\n address token,\n uint256 amount,\n uint256 decimals,\n address beneficiary,\n uint256 minReturnedTokens,\n bool preferClaimedTokens,\n string memory memo,\n bytes memory metadata\n ) external payable;\n\n function addToBalanceOf(\n uint256 projectId,\n address token,\n uint256 amount,\n uint256 decimals,\n string memory memo,\n bytes memory metadata\n ) external payable;\n\n receive() external payable;\n}\n" + }, + "contracts/JBController3_0_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {ERC165, IERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {SafeCast} from '@openzeppelin/contracts/utils/math/SafeCast.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {JBOperatable} from './abstract/JBOperatable.sol';\nimport {JBBallotState} from './enums/JBBallotState.sol';\nimport {IJBController3_0_1} from './interfaces/IJBController3_0_1.sol';\nimport {IJBController} from './interfaces/IJBController.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol';\nimport {IJBMigratable} from './interfaces/IJBMigratable.sol';\nimport {IJBOperatable} from './interfaces/IJBOperatable.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {IJBSplitAllocator} from './interfaces/IJBSplitAllocator.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {IJBTokenStore} from './interfaces/IJBTokenStore.sol';\nimport {JBConstants} from './libraries/JBConstants.sol';\nimport {JBFundingCycleMetadataResolver} from './libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBOperations} from './libraries/JBOperations.sol';\nimport {JBSplitsGroups} from './libraries/JBSplitsGroups.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\nimport {JBSplitAllocationData} from './structs/JBSplitAllocationData.sol';\nimport {JBFundAccessConstraints} from './structs/JBFundAccessConstraints.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\nimport {JBFundingCycleData} from './structs/JBFundingCycleData.sol';\nimport {JBFundingCycleMetadata} from './structs/JBFundingCycleMetadata.sol';\nimport {JBGroupedSplits} from './structs/JBGroupedSplits.sol';\nimport {JBProjectMetadata} from './structs/JBProjectMetadata.sol';\nimport {JBSplit} from './structs/JBSplit.sol';\n\n/// @notice Stitches together funding cycles and project tokens, making sure all activity is accounted for and correct.\n/// @dev This Controller manages a project's reserved tokens explicitly instead of through a passive tracker property.\n/// @dev It is backwards compatible with the original IJBController, and exposes convenience view methods as part of IJBController3_1 for clearer queries.\ncontract JBController3_0_1 is\n JBOperatable,\n ERC165,\n IJBController,\n IJBController3_0_1,\n IJBMigratable\n{\n // A library that parses the packed funding cycle metadata into a more friendly format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error BURN_PAUSED_AND_SENDER_NOT_VALID_TERMINAL_DELEGATE();\n error FUNDING_CYCLE_ALREADY_LAUNCHED();\n error INVALID_BALLOT_REDEMPTION_RATE();\n error INVALID_DISTRIBUTION_LIMIT();\n error INVALID_DISTRIBUTION_LIMIT_CURRENCY();\n error INVALID_OVERFLOW_ALLOWANCE();\n error INVALID_OVERFLOW_ALLOWANCE_CURRENCY();\n error INVALID_REDEMPTION_RATE();\n error INVALID_RESERVED_RATE();\n error MIGRATION_NOT_ALLOWED();\n error MINT_NOT_ALLOWED_AND_NOT_TERMINAL_DELEGATE();\n error NO_BURNABLE_TOKENS();\n error NOT_CURRENT_CONTROLLER();\n error ZERO_TOKENS_TO_MINT();\n\n //*********************************************************************//\n // --------------------- internal stored properties ------------------ //\n //*********************************************************************//\n\n /// @notice Data regarding the distribution limit of a project during a configuration.\n /// @dev bits 0-231: The amount of token that a project can distribute per funding cycle.\n /// @dev bits 232-255: The currency of amount that a project can distribute.\n /// @custom:param _projectId The ID of the project to get the packed distribution limit data of.\n /// @custom:param _configuration The configuration during which the packed distribution limit data applies.\n /// @custom:param _terminal The terminal from which distributions are being limited.\n /// @custom:param _token The token for which distributions are being limited.\n mapping(uint256 => mapping(uint256 => mapping(IJBPaymentTerminal => mapping(address => uint256))))\n internal _packedDistributionLimitDataOf;\n\n /// @notice Data regarding the overflow allowance of a project during a configuration.\n /// @dev bits 0-231: The amount of overflow that a project is allowed to tap into on-demand throughout the configuration.\n /// @dev bits 232-255: The currency of the amount of overflow that a project is allowed to tap.\n /// @custom:param _projectId The ID of the project to get the packed overflow allowance data of.\n /// @custom:param _configuration The configuration during which the packed overflow allowance data applies.\n /// @custom:param _terminal The terminal managing the overflow.\n /// @custom:param _token The token for which overflow is being allowed.\n mapping(uint256 => mapping(uint256 => mapping(IJBPaymentTerminal => mapping(address => uint256))))\n internal _packedOverflowAllowanceDataOf;\n\n /// @notice The current undistributed reserved token balance of.\n /// @custom:param _projectId The ID of the project to get a reserved token balance of.\n mapping(uint256 => uint256) internal _reservedTokenBalanceOf;\n\n //*********************************************************************//\n // --------------- public immutable stored properties ---------------- //\n //*********************************************************************//\n\n /// @notice Mints ERC-721's that represent project ownership.\n IJBProjects public immutable override projects;\n\n /// @notice The contract storing all funding cycle configurations.\n IJBFundingCycleStore public immutable override fundingCycleStore;\n\n /// @notice The contract that manages token minting and burning.\n IJBTokenStore public immutable override tokenStore;\n\n /// @notice The contract that stores splits for each project.\n IJBSplitsStore public immutable override splitsStore;\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice The amount of token that a project can distribute per funding cycle, and the currency it's in terms of.\n /// @dev The number of decimals in the returned fixed point amount is the same as that of the specified terminal.\n /// @param _projectId The ID of the project to get the distribution limit of.\n /// @param _configuration The configuration during which the distribution limit applies.\n /// @param _terminal The terminal from which distributions are being limited.\n /// @param _token The token for which the distribution limit applies.\n /// @return The distribution limit, as a fixed point number with the same number of decimals as the provided terminal.\n /// @return The currency of the distribution limit.\n function distributionLimitOf(\n uint256 _projectId,\n uint256 _configuration,\n IJBPaymentTerminal _terminal,\n address _token\n ) external view override returns (uint256, uint256) {\n // Get a reference to the packed data.\n uint256 _data = _packedDistributionLimitDataOf[_projectId][_configuration][_terminal][_token];\n\n // The limit is in bits 0-231. The currency is in bits 232-255.\n return (uint256(uint232(_data)), _data >> 232);\n }\n\n /// @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.\n /// @dev The number of decimals in the returned fixed point amount is the same as that of the specified terminal.\n /// @param _projectId The ID of the project to get the overflow allowance of.\n /// @param _configuration The configuration of the during which the allowance applies.\n /// @param _terminal The terminal managing the overflow.\n /// @param _token The token for which the overflow allowance applies.\n /// @return The overflow allowance, as a fixed point number with the same number of decimals as the provided terminal.\n /// @return The currency of the overflow allowance.\n function overflowAllowanceOf(\n uint256 _projectId,\n uint256 _configuration,\n IJBPaymentTerminal _terminal,\n address _token\n ) external view override returns (uint256, uint256) {\n // Get a reference to the packed data.\n uint256 _data = _packedOverflowAllowanceDataOf[_projectId][_configuration][_terminal][_token];\n\n // The allowance is in bits 0-231. The currency is in bits 232-255.\n return (uint256(uint232(_data)), _data >> 232);\n }\n\n /// @notice A project's funding cycle for the specified configuration along with its metadata.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The funding cycle.\n /// @return metadata The funding cycle's metadata.\n function getFundingCycleOf(\n uint256 _projectId,\n uint256 _configuration\n )\n external\n view\n override\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata)\n {\n fundingCycle = fundingCycleStore.get(_projectId, _configuration);\n metadata = fundingCycle.expandMetadata();\n }\n\n /// @notice A project's latest configured funding cycle along with its metadata and the ballot state of the configuration.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The latest configured funding cycle.\n /// @return metadata The latest configured funding cycle's metadata.\n /// @return ballotState The state of the configuration.\n function latestConfiguredFundingCycleOf(\n uint256 _projectId\n )\n external\n view\n override\n returns (\n JBFundingCycle memory fundingCycle,\n JBFundingCycleMetadata memory metadata,\n JBBallotState ballotState\n )\n {\n (fundingCycle, ballotState) = fundingCycleStore.latestConfiguredOf(_projectId);\n metadata = fundingCycle.expandMetadata();\n }\n\n /// @notice A project's current funding cycle along with its metadata.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The current funding cycle.\n /// @return metadata The current funding cycle's metadata.\n function currentFundingCycleOf(\n uint256 _projectId\n )\n external\n view\n override\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata)\n {\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n metadata = fundingCycle.expandMetadata();\n }\n\n /// @notice A project's queued funding cycle along with its metadata.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The queued funding cycle.\n /// @return metadata The queued funding cycle's metadata.\n function queuedFundingCycleOf(\n uint256 _projectId\n )\n external\n view\n override\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata)\n {\n fundingCycle = fundingCycleStore.queuedOf(_projectId);\n metadata = fundingCycle.expandMetadata();\n }\n\n /// @notice\tGets the amount of reserved tokens that a project has available to distribute.\n /// @param _projectId The ID of the project to get a reserved token balance of.\n /// @return The current amount of reserved tokens.\n function reservedTokenBalanceOf(uint256 _projectId) external view override returns (uint256) {\n return _reservedTokenBalanceOf[_projectId];\n }\n\n /// @notice\tGets the amount of reserved tokens that a project has available to distribute.\n /// @dev This is just for IJBController backwards compatibility.\n /// @param _projectId The ID of the project to get a reserved token balance of.\n /// @param _reservedRate The reserved rate to use when making the calculation.\n /// @return The current amount of reserved tokens.\n function reservedTokenBalanceOf(\n uint256 _projectId,\n uint256 _reservedRate\n ) external view override returns (uint256) {\n _reservedRate;\n return _reservedTokenBalanceOf[_projectId];\n }\n\n /// @notice\tGets the current total amount of outstanding tokens for a project, given a reserved rate.\n /// @dev This is just for IJBController backwards compatibility.\n /// @param _projectId The ID of the project to get total outstanding tokens of.\n /// @param _reservedRate The reserved rate to use when making the calculation.\n /// @return The current total amount of outstanding tokens for the project.\n function totalOutstandingTokensOf(\n uint256 _projectId,\n uint256 _reservedRate\n ) external view override returns (uint256) {\n _reservedRate;\n // Add the reserved tokens to the total supply.\n return totalOutstandingTokensOf(_projectId);\n }\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice Gets the current total amount of outstanding tokens for a project.\n /// @param _projectId The ID of the project to get total outstanding tokens of.\n /// @return The current total amount of outstanding tokens for the project.\n function totalOutstandingTokensOf(uint256 _projectId) public view override returns (uint256) {\n // Add the reserved tokens to the total supply.\n return tokenStore.totalSupplyOf(_projectId) + _reservedTokenBalanceOf[_projectId];\n }\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if the provided interface ID is supported.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(ERC165, IERC165) returns (bool) {\n return\n _interfaceId == type(IJBController3_0_1).interfaceId ||\n _interfaceId == type(IJBMigratable).interfaceId ||\n _interfaceId == type(IJBOperatable).interfaceId ||\n super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // ---------------------------- constructor -------------------------- //\n //*********************************************************************//\n\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _fundingCycleStore A contract storing all funding cycle configurations.\n /// @param _tokenStore A contract that manages token minting and burning.\n /// @param _splitsStore A contract that stores splits for each project.\n constructor(\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBFundingCycleStore _fundingCycleStore,\n IJBTokenStore _tokenStore,\n IJBSplitsStore _splitsStore\n ) JBOperatable(_operatorStore) {\n projects = _projects;\n directory = _directory;\n fundingCycleStore = _fundingCycleStore;\n tokenStore = _tokenStore;\n splitsStore = _splitsStore;\n }\n\n //*********************************************************************//\n // --------------------- external transactions ----------------------- //\n //*********************************************************************//\n\n /// @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.\n /// @dev Each operation within this transaction can be done in sequence separately.\n /// @dev Anyone can deploy a project on an owner's behalf.\n /// @param _owner The address to set as the owner of the project. The project ERC-721 will be owned by this address.\n /// @param _projectMetadata Metadata to associate with the project within a particular domain. This can be updated any time by the owner of the project.\n /// @param _data Data that defines the project's first funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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`.\n /// @param _terminals Payment terminals to add for the project.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return projectId The ID of the project.\n function launchProjectFor(\n address _owner,\n JBProjectMetadata calldata _projectMetadata,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] calldata _groupedSplits,\n JBFundAccessConstraints[] calldata _fundAccessConstraints,\n IJBPaymentTerminal[] memory _terminals,\n string memory _memo\n ) external virtual override returns (uint256 projectId) {\n // Keep a reference to the directory.\n IJBDirectory _directory = directory;\n\n // Mint the project into the wallet of the owner.\n projectId = projects.createFor(_owner, _projectMetadata);\n\n // Set this contract as the project's controller in the directory.\n _directory.setControllerOf(projectId, address(this));\n\n // Configure the first funding cycle.\n uint256 _configuration = _configure(\n projectId,\n _data,\n _metadata,\n _mustStartAtOrAfter,\n _groupedSplits,\n _fundAccessConstraints\n );\n\n // Add the provided terminals to the list of terminals.\n if (_terminals.length > 0) _directory.setTerminalsOf(projectId, _terminals);\n\n emit LaunchProject(_configuration, projectId, _memo, msg.sender);\n }\n\n /// @notice Creates a funding cycle for an already existing project ERC-721.\n /// @dev Each operation within this transaction can be done in sequence separately.\n /// @dev Only a project owner or operator can launch its funding cycles.\n /// @param _projectId The ID of the project to launch funding cycles for.\n /// @param _data Data that defines the project's first funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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`.\n /// @param _terminals Payment terminals to add for the project.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return configuration The configuration of the funding cycle that was successfully created.\n function launchFundingCyclesFor(\n uint256 _projectId,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] calldata _groupedSplits,\n JBFundAccessConstraints[] memory _fundAccessConstraints,\n IJBPaymentTerminal[] memory _terminals,\n string memory _memo\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.RECONFIGURE)\n returns (uint256 configuration)\n {\n // If there is a previous configuration, reconfigureFundingCyclesOf should be called instead\n if (fundingCycleStore.latestConfigurationOf(_projectId) > 0)\n revert FUNDING_CYCLE_ALREADY_LAUNCHED();\n\n // Set this contract as the project's controller in the directory.\n directory.setControllerOf(_projectId, address(this));\n\n // Configure the first funding cycle.\n configuration = _configure(\n _projectId,\n _data,\n _metadata,\n _mustStartAtOrAfter,\n _groupedSplits,\n _fundAccessConstraints\n );\n\n // Add the provided terminals to the list of terminals.\n if (_terminals.length > 0) directory.setTerminalsOf(_projectId, _terminals);\n\n emit LaunchFundingCycles(configuration, _projectId, _memo, msg.sender);\n }\n\n /// @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.\n /// @dev Only a project's owner or a designated operator can configure its funding cycles.\n /// @param _projectId The ID of the project whose funding cycles are being reconfigured.\n /// @param _data Data that defines the funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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`.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return configuration The configuration of the funding cycle that was successfully reconfigured.\n function reconfigureFundingCyclesOf(\n uint256 _projectId,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] calldata _groupedSplits,\n JBFundAccessConstraints[] calldata _fundAccessConstraints,\n string calldata _memo\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.RECONFIGURE)\n returns (uint256 configuration)\n {\n // Configure the next funding cycle.\n configuration = _configure(\n _projectId,\n _data,\n _metadata,\n _mustStartAtOrAfter,\n _groupedSplits,\n _fundAccessConstraints\n );\n\n emit ReconfigureFundingCycles(configuration, _projectId, _memo, msg.sender);\n }\n\n /// @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.\n /// @dev Only a project's owner, a designated operator, one of its terminals, or the current data source can mint its tokens.\n /// @param _projectId The ID of the project to which the tokens being minted belong.\n /// @param _tokenCount The amount of tokens to mint in total, counting however many should be reserved.\n /// @param _beneficiary The account that the tokens are being minted for.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _preferClaimedTokens A flag indicating whether a project's attached token contract should be minted if they have been issued.\n /// @param _useReservedRate Whether to use the current funding cycle's reserved rate in the mint calculation.\n /// @return beneficiaryTokenCount The amount of tokens minted for the beneficiary.\n function mintTokensOf(\n uint256 _projectId,\n uint256 _tokenCount,\n address _beneficiary,\n string calldata _memo,\n bool _preferClaimedTokens,\n bool _useReservedRate\n ) external virtual override returns (uint256 beneficiaryTokenCount) {\n // There should be tokens to mint.\n if (_tokenCount == 0) revert ZERO_TOKENS_TO_MINT();\n\n // Define variables that will be needed outside scoped section below.\n // Keep a reference to the reserved rate to use\n uint256 _reservedRate;\n\n // Scoped section prevents stack too deep. `_fundingCycle` only used within scope.\n {\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Minting limited to: project owner, authorized callers, project terminal and current funding cycle data source\n _requirePermissionAllowingOverride(\n projects.ownerOf(_projectId),\n _projectId,\n JBOperations.MINT,\n directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender)) ||\n msg.sender == address(_fundingCycle.dataSource())\n );\n\n // If the message sender is not a terminal or a datasource, the current funding cycle must allow minting.\n if (\n !_fundingCycle.mintingAllowed() &&\n !directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender)) &&\n msg.sender != address(_fundingCycle.dataSource())\n ) revert MINT_NOT_ALLOWED_AND_NOT_TERMINAL_DELEGATE();\n\n // Determine the reserved rate to use.\n _reservedRate = _useReservedRate ? _fundingCycle.reservedRate() : 0;\n\n // Override the claimed token preference with the funding cycle value.\n _preferClaimedTokens = _preferClaimedTokens == true\n ? _preferClaimedTokens\n : _fundingCycle.preferClaimedTokenOverride();\n }\n\n if (_reservedRate != JBConstants.MAX_RESERVED_RATE) {\n // The unreserved token count that will be minted for the beneficiary.\n beneficiaryTokenCount = PRBMath.mulDiv(\n _tokenCount,\n JBConstants.MAX_RESERVED_RATE - _reservedRate,\n JBConstants.MAX_RESERVED_RATE\n );\n\n // Mint the tokens.\n tokenStore.mintFor(_beneficiary, _projectId, beneficiaryTokenCount, _preferClaimedTokens);\n }\n\n // Add reserved tokens if needed\n if (_reservedRate > 0)\n _reservedTokenBalanceOf[_projectId] += _tokenCount - beneficiaryTokenCount;\n\n emit MintTokens(\n _beneficiary,\n _projectId,\n _tokenCount,\n beneficiaryTokenCount,\n _memo,\n _reservedRate,\n msg.sender\n );\n }\n\n /// @notice Burns a token holder's supply.\n /// @dev Only a token's holder, a designated operator, or a project's terminal can burn it.\n /// @param _holder The account that is having its tokens burned.\n /// @param _projectId The ID of the project to which the tokens being burned belong.\n /// @param _tokenCount The number of tokens to burn.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _preferClaimedTokens A flag indicating whether a project's attached token contract should be burned first if they have been issued.\n function burnTokensOf(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n string calldata _memo,\n bool _preferClaimedTokens\n )\n external\n virtual\n override\n requirePermissionAllowingOverride(\n _holder,\n _projectId,\n JBOperations.BURN,\n directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender))\n )\n {\n // There should be tokens to burn\n if (_tokenCount == 0) revert NO_BURNABLE_TOKENS();\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // If the message sender is a terminal, the current funding cycle must not be paused.\n if (\n _fundingCycle.burnPaused() &&\n !directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender))\n ) revert BURN_PAUSED_AND_SENDER_NOT_VALID_TERMINAL_DELEGATE();\n\n // Burn the tokens.\n tokenStore.burnFrom(_holder, _projectId, _tokenCount, _preferClaimedTokens);\n\n emit BurnTokens(_holder, _projectId, _tokenCount, _memo, msg.sender);\n }\n\n /// @notice Distributes all outstanding reserved tokens for a project.\n /// @param _projectId The ID of the project to which the reserved tokens belong.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return The amount of minted reserved tokens.\n function distributeReservedTokensOf(\n uint256 _projectId,\n string calldata _memo\n ) external virtual override returns (uint256) {\n return _distributeReservedTokensOf(_projectId, _memo);\n }\n\n /// @notice Allows other controllers to signal to this one that a migration is expected for the specified project.\n /// @dev This controller should not yet be the project's controller.\n /// @param _projectId The ID of the project that will be migrated to this controller.\n /// @param _from The controller being migrated from.\n function prepForMigrationOf(uint256 _projectId, address _from) external virtual override {\n _projectId; // Prevents unused var compiler and natspec complaints.\n _from; // Prevents unused var compiler and natspec complaints.\n }\n\n /// @notice Allows a project to migrate from this controller to another.\n /// @dev Only a project's owner or a designated operator can migrate it.\n /// @param _projectId The ID of the project that will be migrated from this controller.\n /// @param _to The controller to which the project is migrating.\n function migrate(\n uint256 _projectId,\n IJBMigratable _to\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.MIGRATE_CONTROLLER)\n {\n // Keep a reference to the directory.\n IJBDirectory _directory = directory;\n\n // This controller must be the project's current controller.\n if (_directory.controllerOf(_projectId) != address(this)) revert NOT_CURRENT_CONTROLLER();\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Migration must be allowed.\n if (!_fundingCycle.controllerMigrationAllowed()) revert MIGRATION_NOT_ALLOWED();\n\n // All reserved tokens must be minted before migrating.\n if (_reservedTokenBalanceOf[_projectId] != 0) _distributeReservedTokensOf(_projectId, '');\n\n // Make sure the new controller is prepped for the migration.\n _to.prepForMigrationOf(_projectId, address(this));\n\n // Set the new controller.\n _directory.setControllerOf(_projectId, address(_to));\n\n emit Migrate(_projectId, _to, msg.sender);\n }\n\n //*********************************************************************//\n // ------------------------ internal functions ----------------------- //\n //*********************************************************************//\n\n /// @notice Distributes all outstanding reserved tokens for a project.\n /// @param _projectId The ID of the project to which the reserved tokens belong.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return tokenCount The amount of minted reserved tokens.\n function _distributeReservedTokensOf(\n uint256 _projectId,\n string memory _memo\n ) internal returns (uint256 tokenCount) {\n // Keep a reference to the token store.\n IJBTokenStore _tokenStore = tokenStore;\n\n // Get the current funding cycle to read the reserved rate from.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Get a reference to the number of tokens that need to be minted.\n tokenCount = _reservedTokenBalanceOf[_projectId];\n\n // Reset the reserved token balance\n _reservedTokenBalanceOf[_projectId] = 0;\n\n // Get a reference to the project owner.\n address _owner = projects.ownerOf(_projectId);\n\n // Distribute tokens to splits and get a reference to the leftover amount to mint after all splits have gotten their share.\n uint256 _leftoverTokenCount = tokenCount == 0\n ? 0\n : _distributeToReservedTokenSplitsOf(\n _projectId,\n _fundingCycle.configuration,\n JBSplitsGroups.RESERVED_TOKENS,\n tokenCount\n );\n\n // Mint any leftover tokens to the project owner.\n if (_leftoverTokenCount > 0)\n _tokenStore.mintFor(_owner, _projectId, _leftoverTokenCount, false);\n\n emit DistributeReservedTokens(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _owner,\n tokenCount,\n _leftoverTokenCount,\n _memo,\n msg.sender\n );\n }\n\n /// @notice Distribute tokens to the splits according to the specified funding cycle configuration.\n /// @param _projectId The ID of the project for which reserved token splits are being distributed.\n /// @param _domain The domain of the splits to distribute the reserved tokens between.\n /// @param _group The group of the splits to distribute the reserved tokens between.\n /// @param _amount The total amount of tokens to mint.\n /// @return leftoverAmount If the splits percents dont add up to 100%, the leftover amount is returned.\n function _distributeToReservedTokenSplitsOf(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group,\n uint256 _amount\n ) internal returns (uint256 leftoverAmount) {\n // Keep a reference to the token store.\n IJBTokenStore _tokenStore = tokenStore;\n\n // Set the leftover amount to the initial amount.\n leftoverAmount = _amount;\n\n // Get a reference to the project's reserved token splits.\n JBSplit[] memory _splits = splitsStore.splitsOf(_projectId, _domain, _group);\n\n //Transfer between all splits.\n for (uint256 _i; _i < _splits.length; ) {\n // Get a reference to the split being iterated on.\n JBSplit memory _split = _splits[_i];\n\n // The amount to send towards the split.\n uint256 _tokenCount = PRBMath.mulDiv(\n _amount,\n _split.percent,\n JBConstants.SPLITS_TOTAL_PERCENT\n );\n\n // Mints tokens for the split if needed.\n if (_tokenCount > 0) {\n _tokenStore.mintFor(\n // If an allocator is set in the splits, set it as the beneficiary.\n // Otherwise if a projectId is set in the split, set the project's owner as the beneficiary.\n // If the split has a beneficiary send to the split's beneficiary. Otherwise send to the msg.sender.\n _split.allocator != IJBSplitAllocator(address(0))\n ? address(_split.allocator)\n : _split.projectId != 0\n ? projects.ownerOf(_split.projectId)\n : _split.beneficiary != address(0)\n ? _split.beneficiary\n : msg.sender,\n _projectId,\n _tokenCount,\n _split.preferClaimed\n );\n\n // If there's an allocator set, trigger its `allocate` function.\n if (_split.allocator != IJBSplitAllocator(address(0)))\n _split.allocator.allocate(\n JBSplitAllocationData(\n address(_tokenStore.tokenOf(_projectId)),\n _tokenCount,\n 18,\n _projectId,\n _group,\n _split\n )\n );\n\n // Subtract from the amount to be sent to the beneficiary.\n leftoverAmount = leftoverAmount - _tokenCount;\n }\n\n emit DistributeToReservedTokenSplit(\n _projectId,\n _domain,\n _group,\n _split,\n _tokenCount,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n\n /// @notice Configures a funding cycle and stores information pertinent to the configuration.\n /// @param _projectId The ID of the project whose funding cycles are being reconfigured.\n /// @param _data Data that defines the funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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.\n /// @return configuration The configuration of the funding cycle that was successfully reconfigured.\n function _configure(\n uint256 _projectId,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] memory _groupedSplits,\n JBFundAccessConstraints[] memory _fundAccessConstraints\n ) internal returns (uint256) {\n // Make sure the provided reserved rate is valid.\n if (_metadata.reservedRate > JBConstants.MAX_RESERVED_RATE) revert INVALID_RESERVED_RATE();\n\n // Make sure the provided redemption rate is valid.\n if (_metadata.redemptionRate > JBConstants.MAX_REDEMPTION_RATE)\n revert INVALID_REDEMPTION_RATE();\n\n // Make sure the provided ballot redemption rate is valid.\n if (_metadata.ballotRedemptionRate > JBConstants.MAX_REDEMPTION_RATE)\n revert INVALID_BALLOT_REDEMPTION_RATE();\n\n // Configure the funding cycle's properties.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.configureFor(\n _projectId,\n _data,\n JBFundingCycleMetadataResolver.packFundingCycleMetadata(_metadata),\n _mustStartAtOrAfter\n );\n\n // Set splits for the group.\n splitsStore.set(_projectId, _fundingCycle.configuration, _groupedSplits);\n\n // Set distribution limits if there are any.\n for (uint256 _i; _i < _fundAccessConstraints.length; ) {\n JBFundAccessConstraints memory _constraints = _fundAccessConstraints[_i];\n\n // If distribution limit value is larger than 232 bits, revert.\n if (_constraints.distributionLimit > type(uint232).max) revert INVALID_DISTRIBUTION_LIMIT();\n\n // If distribution limit currency value is larger than 24 bits, revert.\n if (_constraints.distributionLimitCurrency > type(uint24).max)\n revert INVALID_DISTRIBUTION_LIMIT_CURRENCY();\n\n // If overflow allowance value is larger than 232 bits, revert.\n if (_constraints.overflowAllowance > type(uint232).max) revert INVALID_OVERFLOW_ALLOWANCE();\n\n // If overflow allowance currency value is larger than 24 bits, revert.\n if (_constraints.overflowAllowanceCurrency > type(uint24).max)\n revert INVALID_OVERFLOW_ALLOWANCE_CURRENCY();\n\n // Set the distribution limit if there is one.\n if (_constraints.distributionLimit > 0)\n _packedDistributionLimitDataOf[_projectId][_fundingCycle.configuration][\n _constraints.terminal\n ][_constraints.token] =\n _constraints.distributionLimit |\n (_constraints.distributionLimitCurrency << 232);\n\n // Set the overflow allowance if there is one.\n if (_constraints.overflowAllowance > 0)\n _packedOverflowAllowanceDataOf[_projectId][_fundingCycle.configuration][\n _constraints.terminal\n ][_constraints.token] =\n _constraints.overflowAllowance |\n (_constraints.overflowAllowanceCurrency << 232);\n\n emit SetFundAccessConstraints(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _constraints,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n\n return _fundingCycle.configuration;\n }\n}\n" + }, + "contracts/JBProjects.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';\nimport {ERC721Votes, ERC721, EIP712} from '@openzeppelin/contracts/token/ERC721/extensions/draft-ERC721Votes.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBOperatable} from './abstract/JBOperatable.sol';\nimport {IJBOperatable} from './interfaces/IJBOperatable.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {IJBTokenUriResolver} from './interfaces/IJBTokenUriResolver.sol';\nimport {JBOperations} from './libraries/JBOperations.sol';\nimport {JBProjectMetadata} from './structs/JBProjectMetadata.sol';\n\n/// @notice Stores project ownership and metadata.\n/// @dev Projects are represented as ERC-721's.\ncontract JBProjects is JBOperatable, ERC721Votes, Ownable, IJBProjects {\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The number of projects that have been created using this contract.\n /// @dev The count is incremented with each new project created.\n /// @dev The resulting ERC-721 token ID for each project is the newly incremented count value.\n uint256 public override count = 0;\n\n /// @notice The metadata for each project, which can be used across several domains.\n /// @custom:param _projectId The ID of the project to which the metadata belongs.\n /// @custom:param _domain The domain within which the metadata applies. Applications can use the domain namespace as they wish.\n mapping(uint256 => mapping(uint256 => string)) public override metadataContentOf;\n\n /// @notice The contract resolving each project ID to its ERC721 URI.\n IJBTokenUriResolver public override tokenUriResolver;\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice Returns the URI where the ERC-721 standard JSON of a project is hosted.\n /// @param _projectId The ID of the project to get a URI of.\n /// @return The token URI to use for the provided `_projectId`.\n function tokenURI(uint256 _projectId) public view override returns (string memory) {\n // Keep a reference to the resolver.\n IJBTokenUriResolver _tokenUriResolver = tokenUriResolver;\n\n // If there's no resolver, there's no URI.\n if (_tokenUriResolver == IJBTokenUriResolver(address(0))) return '';\n\n // Return the resolved URI.\n return _tokenUriResolver.getUri(_projectId);\n }\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if the provided interface ID is supported.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(IERC165, ERC721) returns (bool) {\n return\n _interfaceId == type(IJBProjects).interfaceId ||\n _interfaceId == type(IJBOperatable).interfaceId ||\n super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _operatorStore A contract storing operator assignments.\n constructor(\n IJBOperatorStore _operatorStore\n )\n ERC721('Juicebox Projects', 'JUICEBOX')\n EIP712('Juicebox Projects', '1')\n JBOperatable(_operatorStore)\n // solhint-disable-next-line no-empty-blocks\n {\n\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Create a new project for the specified owner, which mints an NFT (ERC-721) into their wallet.\n /// @dev Anyone can create a project on an owner's behalf.\n /// @param _owner The address that will be the owner of the project.\n /// @param _metadata A struct containing metadata content about the project, and domain within which the metadata applies.\n /// @return projectId The token ID of the newly created project.\n function createFor(\n address _owner,\n JBProjectMetadata calldata _metadata\n ) external override returns (uint256 projectId) {\n // Increment the count, which will be used as the ID.\n projectId = ++count;\n\n // Mint the project.\n _safeMint(_owner, projectId);\n\n // Set the metadata if one was provided.\n if (bytes(_metadata.content).length > 0)\n metadataContentOf[projectId][_metadata.domain] = _metadata.content;\n\n emit Create(projectId, _owner, _metadata, msg.sender);\n }\n\n /// @notice Allows a project owner to set the project's metadata content for a particular domain namespace.\n /// @dev Only a project's owner or operator can set its metadata.\n /// @dev Applications can use the domain namespace as they wish.\n /// @param _projectId The ID of the project who's metadata is being changed.\n /// @param _metadata A struct containing metadata content, and domain within which the metadata applies.\n function setMetadataOf(\n uint256 _projectId,\n JBProjectMetadata calldata _metadata\n )\n external\n override\n requirePermission(ownerOf(_projectId), _projectId, JBOperations.SET_METADATA)\n {\n // Set the project's new metadata content within the specified domain.\n metadataContentOf[_projectId][_metadata.domain] = _metadata.content;\n\n emit SetMetadata(_projectId, _metadata, msg.sender);\n }\n\n /// @notice Sets the address of the resolver used to retrieve the tokenURI of projects.\n /// @param _newResolver The address of the new resolver.\n function setTokenUriResolver(IJBTokenUriResolver _newResolver) external override onlyOwner {\n // Store the new resolver.\n tokenUriResolver = _newResolver;\n\n emit SetTokenUriResolver(_newResolver, msg.sender);\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC721/extensions/draft-ERC721Votes.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (token/ERC721/extensions/draft-ERC721Votes.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../ERC721.sol\";\nimport \"../../../governance/utils/Votes.sol\";\n\n/**\n * @dev Extension of ERC721 to support voting and delegation as implemented by {Votes}, where each individual NFT counts\n * as 1 vote unit.\n *\n * Tokens do not count as votes until they are delegated, because votes must be tracked which incurs an additional cost\n * on every transfer. Token holders can either delegate to a trusted representative who will decide how to make use of\n * the votes in governance decisions, or they can delegate to themselves to be their own representative.\n *\n * _Available since v4.5._\n */\nabstract contract ERC721Votes is ERC721, Votes {\n /**\n * @dev Adjusts votes when tokens are transferred.\n *\n * Emits a {Votes-DelegateVotesChanged} event.\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 tokenId\n ) internal virtual override {\n _transferVotingUnits(from, to, 1);\n super._afterTokenTransfer(from, to, tokenId);\n }\n\n /**\n * @dev Returns the balance of `account`.\n */\n function _getVotingUnits(address account) internal virtual override returns (uint256) {\n return balanceOf(account);\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC721/ERC721.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (token/ERC721/ERC721.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC721.sol\";\nimport \"./IERC721Receiver.sol\";\nimport \"./extensions/IERC721Metadata.sol\";\nimport \"../../utils/Address.sol\";\nimport \"../../utils/Context.sol\";\nimport \"../../utils/Strings.sol\";\nimport \"../../utils/introspection/ERC165.sol\";\n\n/**\n * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including\n * the Metadata extension, but not including the Enumerable extension, which is available separately as\n * {ERC721Enumerable}.\n */\ncontract ERC721 is Context, ERC165, IERC721, IERC721Metadata {\n using Address for address;\n using Strings for uint256;\n\n // Token name\n string private _name;\n\n // Token symbol\n string private _symbol;\n\n // Mapping from token ID to owner address\n mapping(uint256 => address) private _owners;\n\n // Mapping owner address to token count\n mapping(address => uint256) private _balances;\n\n // Mapping from token ID to approved address\n mapping(uint256 => address) private _tokenApprovals;\n\n // Mapping from owner to operator approvals\n mapping(address => mapping(address => bool)) private _operatorApprovals;\n\n /**\n * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {\n return\n interfaceId == type(IERC721).interfaceId ||\n interfaceId == type(IERC721Metadata).interfaceId ||\n super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev See {IERC721-balanceOf}.\n */\n function balanceOf(address owner) public view virtual override returns (uint256) {\n require(owner != address(0), \"ERC721: balance query for the zero address\");\n return _balances[owner];\n }\n\n /**\n * @dev See {IERC721-ownerOf}.\n */\n function ownerOf(uint256 tokenId) public view virtual override returns (address) {\n address owner = _owners[tokenId];\n require(owner != address(0), \"ERC721: owner query for nonexistent token\");\n return owner;\n }\n\n /**\n * @dev See {IERC721Metadata-name}.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev See {IERC721Metadata-symbol}.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev See {IERC721Metadata-tokenURI}.\n */\n function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {\n require(_exists(tokenId), \"ERC721Metadata: URI query for nonexistent token\");\n\n string memory baseURI = _baseURI();\n return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : \"\";\n }\n\n /**\n * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each\n * token will be the concatenation of the `baseURI` and the `tokenId`. Empty\n * by default, can be overriden in child contracts.\n */\n function _baseURI() internal view virtual returns (string memory) {\n return \"\";\n }\n\n /**\n * @dev See {IERC721-approve}.\n */\n function approve(address to, uint256 tokenId) public virtual override {\n address owner = ERC721.ownerOf(tokenId);\n require(to != owner, \"ERC721: approval to current owner\");\n\n require(\n _msgSender() == owner || isApprovedForAll(owner, _msgSender()),\n \"ERC721: approve caller is not owner nor approved for all\"\n );\n\n _approve(to, tokenId);\n }\n\n /**\n * @dev See {IERC721-getApproved}.\n */\n function getApproved(uint256 tokenId) public view virtual override returns (address) {\n require(_exists(tokenId), \"ERC721: approved query for nonexistent token\");\n\n return _tokenApprovals[tokenId];\n }\n\n /**\n * @dev See {IERC721-setApprovalForAll}.\n */\n function setApprovalForAll(address operator, bool approved) public virtual override {\n _setApprovalForAll(_msgSender(), operator, approved);\n }\n\n /**\n * @dev See {IERC721-isApprovedForAll}.\n */\n function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {\n return _operatorApprovals[owner][operator];\n }\n\n /**\n * @dev See {IERC721-transferFrom}.\n */\n function transferFrom(\n address from,\n address to,\n uint256 tokenId\n ) public virtual override {\n //solhint-disable-next-line max-line-length\n require(_isApprovedOrOwner(_msgSender(), tokenId), \"ERC721: transfer caller is not owner nor approved\");\n\n _transfer(from, to, tokenId);\n }\n\n /**\n * @dev See {IERC721-safeTransferFrom}.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId\n ) public virtual override {\n safeTransferFrom(from, to, tokenId, \"\");\n }\n\n /**\n * @dev See {IERC721-safeTransferFrom}.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId,\n bytes memory _data\n ) public virtual override {\n require(_isApprovedOrOwner(_msgSender(), tokenId), \"ERC721: transfer caller is not owner nor approved\");\n _safeTransfer(from, to, tokenId, _data);\n }\n\n /**\n * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\n * are aware of the ERC721 protocol to prevent tokens from being forever locked.\n *\n * `_data` is additional data, it has no specified format and it is sent in call to `to`.\n *\n * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.\n * implement alternative mechanisms to perform token transfer, such as signature-based.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must exist and be owned by `from`.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function _safeTransfer(\n address from,\n address to,\n uint256 tokenId,\n bytes memory _data\n ) internal virtual {\n _transfer(from, to, tokenId);\n require(_checkOnERC721Received(from, to, tokenId, _data), \"ERC721: transfer to non ERC721Receiver implementer\");\n }\n\n /**\n * @dev Returns whether `tokenId` exists.\n *\n * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.\n *\n * Tokens start existing when they are minted (`_mint`),\n * and stop existing when they are burned (`_burn`).\n */\n function _exists(uint256 tokenId) internal view virtual returns (bool) {\n return _owners[tokenId] != address(0);\n }\n\n /**\n * @dev Returns whether `spender` is allowed to manage `tokenId`.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n */\n function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {\n require(_exists(tokenId), \"ERC721: operator query for nonexistent token\");\n address owner = ERC721.ownerOf(tokenId);\n return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));\n }\n\n /**\n * @dev Safely mints `tokenId` and transfers it to `to`.\n *\n * Requirements:\n *\n * - `tokenId` must not exist.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function _safeMint(address to, uint256 tokenId) internal virtual {\n _safeMint(to, tokenId, \"\");\n }\n\n /**\n * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is\n * forwarded in {IERC721Receiver-onERC721Received} to contract recipients.\n */\n function _safeMint(\n address to,\n uint256 tokenId,\n bytes memory _data\n ) internal virtual {\n _mint(to, tokenId);\n require(\n _checkOnERC721Received(address(0), to, tokenId, _data),\n \"ERC721: transfer to non ERC721Receiver implementer\"\n );\n }\n\n /**\n * @dev Mints `tokenId` and transfers it to `to`.\n *\n * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible\n *\n * Requirements:\n *\n * - `tokenId` must not exist.\n * - `to` cannot be the zero address.\n *\n * Emits a {Transfer} event.\n */\n function _mint(address to, uint256 tokenId) internal virtual {\n require(to != address(0), \"ERC721: mint to the zero address\");\n require(!_exists(tokenId), \"ERC721: token already minted\");\n\n _beforeTokenTransfer(address(0), to, tokenId);\n\n _balances[to] += 1;\n _owners[tokenId] = to;\n\n emit Transfer(address(0), to, tokenId);\n\n _afterTokenTransfer(address(0), to, tokenId);\n }\n\n /**\n * @dev Destroys `tokenId`.\n * The approval is cleared when the token is burned.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n *\n * Emits a {Transfer} event.\n */\n function _burn(uint256 tokenId) internal virtual {\n address owner = ERC721.ownerOf(tokenId);\n\n _beforeTokenTransfer(owner, address(0), tokenId);\n\n // Clear approvals\n _approve(address(0), tokenId);\n\n _balances[owner] -= 1;\n delete _owners[tokenId];\n\n emit Transfer(owner, address(0), tokenId);\n\n _afterTokenTransfer(owner, address(0), tokenId);\n }\n\n /**\n * @dev Transfers `tokenId` from `from` to `to`.\n * As opposed to {transferFrom}, this imposes no restrictions on msg.sender.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - `tokenId` token must be owned by `from`.\n *\n * Emits a {Transfer} event.\n */\n function _transfer(\n address from,\n address to,\n uint256 tokenId\n ) internal virtual {\n require(ERC721.ownerOf(tokenId) == from, \"ERC721: transfer from incorrect owner\");\n require(to != address(0), \"ERC721: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, tokenId);\n\n // Clear approvals from the previous owner\n _approve(address(0), tokenId);\n\n _balances[from] -= 1;\n _balances[to] += 1;\n _owners[tokenId] = to;\n\n emit Transfer(from, to, tokenId);\n\n _afterTokenTransfer(from, to, tokenId);\n }\n\n /**\n * @dev Approve `to` to operate on `tokenId`\n *\n * Emits a {Approval} event.\n */\n function _approve(address to, uint256 tokenId) internal virtual {\n _tokenApprovals[tokenId] = to;\n emit Approval(ERC721.ownerOf(tokenId), to, tokenId);\n }\n\n /**\n * @dev Approve `operator` to operate on all of `owner` tokens\n *\n * Emits a {ApprovalForAll} event.\n */\n function _setApprovalForAll(\n address owner,\n address operator,\n bool approved\n ) internal virtual {\n require(owner != operator, \"ERC721: approve to caller\");\n _operatorApprovals[owner][operator] = approved;\n emit ApprovalForAll(owner, operator, approved);\n }\n\n /**\n * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.\n * The call is not executed if the target address is not a contract.\n *\n * @param from address representing the previous owner of the given token ID\n * @param to target address that will receive the tokens\n * @param tokenId uint256 ID of the token to be transferred\n * @param _data bytes optional data to send along with the call\n * @return bool whether the call correctly returned the expected magic value\n */\n function _checkOnERC721Received(\n address from,\n address to,\n uint256 tokenId,\n bytes memory _data\n ) private returns (bool) {\n if (to.isContract()) {\n try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) {\n return retval == IERC721Receiver.onERC721Received.selector;\n } catch (bytes memory reason) {\n if (reason.length == 0) {\n revert(\"ERC721: transfer to non ERC721Receiver implementer\");\n } else {\n assembly {\n revert(add(32, reason), mload(reason))\n }\n }\n }\n } else {\n return true;\n }\n }\n\n /**\n * @dev Hook that is called before any token transfer. This includes minting\n * and burning.\n *\n * Calling conditions:\n *\n * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be\n * transferred to `to`.\n * - When `from` is zero, `tokenId` will be minted for `to`.\n * - When `to` is zero, ``from``'s `tokenId` will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 tokenId\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 tokenId\n ) internal virtual {}\n}\n" + }, + "@openzeppelin/contracts/governance/utils/Votes.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (governance/utils/Votes.sol)\npragma solidity ^0.8.0;\n\nimport \"../../utils/Context.sol\";\nimport \"../../utils/Counters.sol\";\nimport \"../../utils/Checkpoints.sol\";\nimport \"../../utils/cryptography/draft-EIP712.sol\";\nimport \"./IVotes.sol\";\n\n/**\n * @dev This is a base abstract contract that tracks voting units, which are a measure of voting power that can be\n * transferred, and provides a system of vote delegation, where an account can delegate its voting units to a sort of\n * \"representative\" that will pool delegated voting units from different accounts and can then use it to vote in\n * decisions. In fact, voting units _must_ be delegated in order to count as actual votes, and an account has to\n * delegate those votes to itself if it wishes to participate in decisions and does not have a trusted representative.\n *\n * This contract is often combined with a token contract such that voting units correspond to token units. For an\n * example, see {ERC721Votes}.\n *\n * The full history of delegate votes is tracked on-chain so that governance protocols can consider votes as distributed\n * at a particular block number to protect against flash loans and double voting. The opt-in delegate system makes the\n * cost of this history tracking optional.\n *\n * When using this module the derived contract must implement {_getVotingUnits} (for example, make it return\n * {ERC721-balanceOf}), and can use {_transferVotingUnits} to track a change in the distribution of those units (in the\n * previous example, it would be included in {ERC721-_beforeTokenTransfer}).\n *\n * _Available since v4.5._\n */\nabstract contract Votes is IVotes, Context, EIP712 {\n using Checkpoints for Checkpoints.History;\n using Counters for Counters.Counter;\n\n bytes32 private constant _DELEGATION_TYPEHASH =\n keccak256(\"Delegation(address delegatee,uint256 nonce,uint256 expiry)\");\n\n mapping(address => address) private _delegation;\n mapping(address => Checkpoints.History) private _delegateCheckpoints;\n Checkpoints.History private _totalCheckpoints;\n\n mapping(address => Counters.Counter) private _nonces;\n\n /**\n * @dev Returns the current amount of votes that `account` has.\n */\n function getVotes(address account) public view virtual override returns (uint256) {\n return _delegateCheckpoints[account].latest();\n }\n\n /**\n * @dev Returns the amount of votes that `account` had at the end of a past block (`blockNumber`).\n *\n * Requirements:\n *\n * - `blockNumber` must have been already mined\n */\n function getPastVotes(address account, uint256 blockNumber) public view virtual override returns (uint256) {\n return _delegateCheckpoints[account].getAtBlock(blockNumber);\n }\n\n /**\n * @dev Returns the total supply of votes available at the end of a past block (`blockNumber`).\n *\n * NOTE: This value is the sum of all available votes, which is not necessarily the sum of all delegated votes.\n * Votes that have not been delegated are still part of total supply, even though they would not participate in a\n * vote.\n *\n * Requirements:\n *\n * - `blockNumber` must have been already mined\n */\n function getPastTotalSupply(uint256 blockNumber) public view virtual override returns (uint256) {\n require(blockNumber < block.number, \"Votes: block not yet mined\");\n return _totalCheckpoints.getAtBlock(blockNumber);\n }\n\n /**\n * @dev Returns the current total supply of votes.\n */\n function _getTotalSupply() internal view virtual returns (uint256) {\n return _totalCheckpoints.latest();\n }\n\n /**\n * @dev Returns the delegate that `account` has chosen.\n */\n function delegates(address account) public view virtual override returns (address) {\n return _delegation[account];\n }\n\n /**\n * @dev Delegates votes from the sender to `delegatee`.\n */\n function delegate(address delegatee) public virtual override {\n address account = _msgSender();\n _delegate(account, delegatee);\n }\n\n /**\n * @dev Delegates votes from signer to `delegatee`.\n */\n function delegateBySig(\n address delegatee,\n uint256 nonce,\n uint256 expiry,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) public virtual override {\n require(block.timestamp <= expiry, \"Votes: signature expired\");\n address signer = ECDSA.recover(\n _hashTypedDataV4(keccak256(abi.encode(_DELEGATION_TYPEHASH, delegatee, nonce, expiry))),\n v,\n r,\n s\n );\n require(nonce == _useNonce(signer), \"Votes: invalid nonce\");\n _delegate(signer, delegatee);\n }\n\n /**\n * @dev Delegate all of `account`'s voting units to `delegatee`.\n *\n * Emits events {DelegateChanged} and {DelegateVotesChanged}.\n */\n function _delegate(address account, address delegatee) internal virtual {\n address oldDelegate = delegates(account);\n _delegation[account] = delegatee;\n\n emit DelegateChanged(account, oldDelegate, delegatee);\n _moveDelegateVotes(oldDelegate, delegatee, _getVotingUnits(account));\n }\n\n /**\n * @dev Transfers, mints, or burns voting units. To register a mint, `from` should be zero. To register a burn, `to`\n * should be zero. Total supply of voting units will be adjusted with mints and burns.\n */\n function _transferVotingUnits(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n if (from == address(0)) {\n _totalCheckpoints.push(_add, amount);\n }\n if (to == address(0)) {\n _totalCheckpoints.push(_subtract, amount);\n }\n _moveDelegateVotes(delegates(from), delegates(to), amount);\n }\n\n /**\n * @dev Moves delegated votes from one delegate to another.\n */\n function _moveDelegateVotes(\n address from,\n address to,\n uint256 amount\n ) private {\n if (from != to && amount > 0) {\n if (from != address(0)) {\n (uint256 oldValue, uint256 newValue) = _delegateCheckpoints[from].push(_subtract, amount);\n emit DelegateVotesChanged(from, oldValue, newValue);\n }\n if (to != address(0)) {\n (uint256 oldValue, uint256 newValue) = _delegateCheckpoints[to].push(_add, amount);\n emit DelegateVotesChanged(to, oldValue, newValue);\n }\n }\n }\n\n function _add(uint256 a, uint256 b) private pure returns (uint256) {\n return a + b;\n }\n\n function _subtract(uint256 a, uint256 b) private pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Consumes a nonce.\n *\n * Returns the current value and increments nonce.\n */\n function _useNonce(address owner) internal virtual returns (uint256 current) {\n Counters.Counter storage nonce = _nonces[owner];\n current = nonce.current();\n nonce.increment();\n }\n\n /**\n * @dev Returns an address nonce.\n */\n function nonces(address owner) public view virtual returns (uint256) {\n return _nonces[owner].current();\n }\n\n /**\n * @dev Returns the contract's {EIP712} domain separator.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32) {\n return _domainSeparatorV4();\n }\n\n /**\n * @dev Must return the voting units held by an account.\n */\n function _getVotingUnits(address) internal virtual returns (uint256);\n}\n" + }, + "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721Receiver.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @title ERC721 token receiver interface\n * @dev Interface for any contract that wants to support safeTransfers\n * from ERC721 asset contracts.\n */\ninterface IERC721Receiver {\n /**\n * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}\n * by `operator` from `from`, this function is called.\n *\n * It must return its Solidity selector to confirm the token transfer.\n * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.\n *\n * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`.\n */\n function onERC721Received(\n address operator,\n address from,\n uint256 tokenId,\n bytes calldata data\n ) external returns (bytes4);\n}\n" + }, + "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC721.sol\";\n\n/**\n * @title ERC-721 Non-Fungible Token Standard, optional metadata extension\n * @dev See https://eips.ethereum.org/EIPS/eip-721\n */\ninterface IERC721Metadata is IERC721 {\n /**\n * @dev Returns the token collection name.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the token collection symbol.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.\n */\n function tokenURI(uint256 tokenId) external view returns (string memory);\n}\n" + }, + "@openzeppelin/contracts/utils/Checkpoints.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (utils/Checkpoints.sol)\npragma solidity ^0.8.0;\n\nimport \"./math/Math.sol\";\nimport \"./math/SafeCast.sol\";\n\n/**\n * @dev This library defines the `History` struct, for checkpointing values as they change at different points in\n * time, and later looking up past values by block number. See {Votes} as an example.\n *\n * To create a history of checkpoints define a variable type `Checkpoints.History` in your contract, and store a new\n * checkpoint for the current transaction block using the {push} function.\n *\n * _Available since v4.5._\n */\nlibrary Checkpoints {\n struct Checkpoint {\n uint32 _blockNumber;\n uint224 _value;\n }\n\n struct History {\n Checkpoint[] _checkpoints;\n }\n\n /**\n * @dev Returns the value in the latest checkpoint, or zero if there are no checkpoints.\n */\n function latest(History storage self) internal view returns (uint256) {\n uint256 pos = self._checkpoints.length;\n return pos == 0 ? 0 : self._checkpoints[pos - 1]._value;\n }\n\n /**\n * @dev Returns the value at a given block number. If a checkpoint is not available at that block, the closest one\n * before it is returned, or zero otherwise.\n */\n function getAtBlock(History storage self, uint256 blockNumber) internal view returns (uint256) {\n require(blockNumber < block.number, \"Checkpoints: block not yet mined\");\n\n uint256 high = self._checkpoints.length;\n uint256 low = 0;\n while (low < high) {\n uint256 mid = Math.average(low, high);\n if (self._checkpoints[mid]._blockNumber > blockNumber) {\n high = mid;\n } else {\n low = mid + 1;\n }\n }\n return high == 0 ? 0 : self._checkpoints[high - 1]._value;\n }\n\n /**\n * @dev Pushes a value onto a History so that it is stored as the checkpoint for the current block.\n *\n * Returns previous value and new value.\n */\n function push(History storage self, uint256 value) internal returns (uint256, uint256) {\n uint256 pos = self._checkpoints.length;\n uint256 old = latest(self);\n if (pos > 0 && self._checkpoints[pos - 1]._blockNumber == block.number) {\n self._checkpoints[pos - 1]._value = SafeCast.toUint224(value);\n } else {\n self._checkpoints.push(\n Checkpoint({_blockNumber: SafeCast.toUint32(block.number), _value: SafeCast.toUint224(value)})\n );\n }\n return (old, value);\n }\n\n /**\n * @dev Pushes a value onto a History, by updating the latest value using binary operation `op`. The new value will\n * be set to `op(latest, delta)`.\n *\n * Returns previous value and new value.\n */\n function push(\n History storage self,\n function(uint256, uint256) view returns (uint256) op,\n uint256 delta\n ) internal returns (uint256, uint256) {\n return push(self, op(latest(self), delta));\n }\n}\n" + }, + "contracts/JBDirectory.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';\nimport {JBOperatable} from './abstract/JBOperatable.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {JBFundingCycleMetadataResolver} from './libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBOperations} from './libraries/JBOperations.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\n\n/// @notice Keeps a reference of which terminal contracts each project is currently accepting funds through, and which controller contract is managing each project's tokens and funding cycles.\ncontract JBDirectory is JBOperatable, Ownable, IJBDirectory {\n // A library that parses the packed funding cycle metadata into a friendlier format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error DUPLICATE_TERMINALS();\n error INVALID_PROJECT_ID_IN_DIRECTORY();\n error SET_CONTROLLER_NOT_ALLOWED();\n error SET_TERMINALS_NOT_ALLOWED();\n error TOKEN_NOT_ACCEPTED();\n\n //*********************************************************************//\n // --------------------- private stored properties ------------------- //\n //*********************************************************************//\n\n /// @notice For each project ID, the terminals that are currently managing its funds.\n /// @custom:member _projectId The ID of the project to get terminals of.\n mapping(uint256 => IJBPaymentTerminal[]) private _terminalsOf;\n\n /// @notice The project's primary terminal for a token.\n /// @custom:member _projectId The ID of the project to get the primary terminal of.\n /// @custom:member _token The token to get the project's primary terminal of.\n mapping(uint256 => mapping(address => IJBPaymentTerminal)) private _primaryTerminalOf;\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice Mints ERC-721's that represent project ownership and transfers.\n IJBProjects public immutable override projects;\n\n /// @notice The contract storing all funding cycle configurations.\n IJBFundingCycleStore public immutable override fundingCycleStore;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice For each project ID, the controller that manages how terminals interact with tokens and funding cycles.\n /// @custom:member _projectId The ID of the project to get the controller of.\n mapping(uint256 => address) public override controllerOf;\n\n /// @notice Addresses that can set a project's first controller on their behalf. These addresses/contracts have been vetted and verified by this contract's owner.\n /// @custom:param _address The address that is either allowed or not.\n mapping(address => bool) public override isAllowedToSetFirstController;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice For each project ID, the terminals that are currently managing its funds.\n /// @param _projectId The ID of the project to get terminals of.\n /// @return An array of terminal addresses.\n function terminalsOf(uint256 _projectId)\n external\n view\n override\n returns (IJBPaymentTerminal[] memory)\n {\n return _terminalsOf[_projectId];\n }\n\n /// @notice The primary terminal that is managing funds for a project for a specified token.\n /// @dev The zero address is returned if a terminal isn't found for the specified token.\n /// @param _projectId The ID of the project to get a terminal for.\n /// @param _token The token the terminal accepts.\n /// @return The primary terminal for the project for the specified token.\n function primaryTerminalOf(uint256 _projectId, address _token)\n external\n view\n override\n returns (IJBPaymentTerminal)\n {\n // Keep a reference to the primary terminal for the provided project ID and token.\n IJBPaymentTerminal _primaryTerminal = _primaryTerminalOf[_projectId][_token];\n\n // If a primary terminal for the token was specifically set and it's one of the project's terminals, return it.\n if (\n _primaryTerminal != IJBPaymentTerminal(address(0)) &&\n isTerminalOf(_projectId, _primaryTerminal)\n ) return _primaryTerminal;\n\n // Keep a reference to the number of terminals the project has.\n uint256 _numberOfTerminals = _terminalsOf[_projectId].length;\n\n // Return the first terminal which accepts the specified token.\n for (uint256 _i; _i < _numberOfTerminals; ) {\n // Keep a reference to the terminal being iterated on.\n IJBPaymentTerminal _terminal = _terminalsOf[_projectId][_i];\n\n // If the terminal accepts the specified token, return it.\n if (_terminal.acceptsToken(_token, _projectId)) return _terminal;\n\n unchecked {\n ++_i;\n }\n }\n\n // Not found.\n return IJBPaymentTerminal(address(0));\n }\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice Whether or not a specified terminal is a terminal of the specified project.\n /// @param _projectId The ID of the project to check within.\n /// @param _terminal The address of the terminal to check for.\n /// @return A flag indicating whether or not the specified terminal is a terminal of the specified project.\n function isTerminalOf(uint256 _projectId, IJBPaymentTerminal _terminal)\n public\n view\n override\n returns (bool)\n {\n // Keep a reference to the number of terminals the project has.\n uint256 _numberOfTerminals = _terminalsOf[_projectId].length;\n\n // Loop through and return true if the terminal is contained.\n for (uint256 _i; _i < _numberOfTerminals; ) {\n // If the terminal being iterated on matches the provided terminal, return true.\n if (_terminalsOf[_projectId][_i] == _terminal) return true;\n\n unchecked {\n ++_i;\n }\n }\n\n // Otherwise, return false.\n return false;\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _fundingCycleStore A contract storing all funding cycle configurations.\n /// @param _owner The address that will own the contract.\n constructor(\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBFundingCycleStore _fundingCycleStore,\n address _owner\n ) JBOperatable(_operatorStore) {\n projects = _projects;\n fundingCycleStore = _fundingCycleStore;\n\n _transferOwnership(_owner);\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Update the controller that manages how terminals interact with the ecosystem.\n /// @dev A controller can be set if:\n /// @dev - the message sender is the project owner or an operator having the correct authorization.\n /// @dev - the message sender is the project's current controller.\n /// @dev - or, an allowedlisted address is setting a controller for a project that doesn't already have a controller.\n /// @param _projectId The ID of the project to set a new controller for.\n /// @param _controller The new controller to set.\n function setControllerOf(uint256 _projectId, address _controller)\n external\n override\n requirePermissionAllowingOverride(\n projects.ownerOf(_projectId),\n _projectId,\n JBOperations.SET_CONTROLLER,\n (msg.sender == address(controllerOf[_projectId]) ||\n (isAllowedToSetFirstController[msg.sender] && controllerOf[_projectId] == address(0)))\n )\n {\n // The project must exist.\n if (projects.count() < _projectId) revert INVALID_PROJECT_ID_IN_DIRECTORY();\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Setting controller is allowed if called from the current controller, or if the project doesn't have a current controller, or if the project's funding cycle allows setting the controller. Revert otherwise.\n if (\n msg.sender != address(controllerOf[_projectId]) &&\n controllerOf[_projectId] != address(0) &&\n !_fundingCycle.global().allowSetController\n ) revert SET_CONTROLLER_NOT_ALLOWED();\n\n // Set the new controller.\n controllerOf[_projectId] = _controller;\n\n emit SetController(_projectId, _controller, msg.sender);\n }\n\n /// @notice Set a project's terminals.\n /// @dev Only a project owner, an operator, or its controller can set its terminals.\n /// @param _projectId The ID of the project having terminals set.\n /// @param _terminals The terminal to set.\n function setTerminalsOf(uint256 _projectId, IJBPaymentTerminal[] calldata _terminals)\n external\n override\n requirePermissionAllowingOverride(\n projects.ownerOf(_projectId),\n _projectId,\n JBOperations.SET_TERMINALS,\n msg.sender == address(controllerOf[_projectId])\n )\n {\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Setting terminals must be allowed if not called from the current controller.\n if (\n msg.sender != address(controllerOf[_projectId]) && !_fundingCycle.global().allowSetTerminals\n ) revert SET_TERMINALS_NOT_ALLOWED();\n\n // Set the stored terminals for the project.\n _terminalsOf[_projectId] = _terminals;\n\n // Make sure duplicates were not added.\n if (_terminals.length > 1) {\n for (uint256 _i; _i < _terminals.length; ) {\n for (uint256 _j = _i + 1; _j < _terminals.length; ) {\n if (_terminals[_i] == _terminals[_j]) revert DUPLICATE_TERMINALS();\n\n unchecked {\n ++_j;\n }\n }\n\n unchecked {\n ++_i;\n }\n }\n }\n emit SetTerminals(_projectId, _terminals, msg.sender);\n }\n\n /// @notice Project's can set which terminal should be their primary for a particular token. \n /// @dev This is useful in case a project has several terminals connected for a particular token.\n /// @dev The terminal will be set as the primary terminal where ecosystem contracts should route tokens.\n /// @dev If setting a newly added terminal and the funding cycle doesn't allow new terminals, the caller must be the current controller.\n /// @param _projectId The ID of the project for which a primary token is being set.\n /// @param _token The token to set the primary terminal of.\n /// @param _terminal The terminal to make primary.\n function setPrimaryTerminalOf(\n uint256 _projectId,\n address _token,\n IJBPaymentTerminal _terminal\n )\n external\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.SET_PRIMARY_TERMINAL)\n {\n // Can't set the primary terminal for a token if it doesn't accept the token.\n if (!_terminal.acceptsToken(_token, _projectId)) revert TOKEN_NOT_ACCEPTED();\n\n // Add the terminal to the project if it hasn't been already.\n _addTerminalIfNeeded(_projectId, _terminal);\n\n // Store the terminal as the primary for the particular token.\n _primaryTerminalOf[_projectId][_token] = _terminal;\n\n emit SetPrimaryTerminal(_projectId, _token, _terminal, msg.sender);\n }\n\n /// @notice Set a contract to the list of trusted addresses that can set a first controller for any project.\t\n /// @dev The owner can add addresses which are allowed to change projects' first controllers. \n /// @dev These addresses are known and vetted controllers as well as contracts designed to launch new projects. \n /// @dev A project can set its own controller without it being on the allow list.\n /// @dev If you would like an address/contract allowlisted, please reach out to the contract owner.\n /// @param _address The address to allow or revoke allowance from.\n /// @param _flag Whether allowance is being added or revoked.\n function setIsAllowedToSetFirstController(address _address, bool _flag)\n external\n override\n onlyOwner\n {\n // Set the flag in the allowlist.\n isAllowedToSetFirstController[_address] = _flag;\n\n emit SetIsAllowedToSetFirstController(_address, _flag, msg.sender);\n }\n\n //*********************************************************************//\n // --------------------- private helper functions -------------------- //\n //*********************************************************************//\n\n /// @notice Add a terminal to a project's list of terminals if it hasn't been already.\n /// @param _projectId The ID of the project having a terminal added.\n /// @param _terminal The terminal to add.\n function _addTerminalIfNeeded(uint256 _projectId, IJBPaymentTerminal _terminal) private {\n // Check that the terminal has not already been added.\n if (isTerminalOf(_projectId, _terminal)) return;\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Setting terminals must be allowed if not called from the current controller.\n if (\n msg.sender != address(controllerOf[_projectId]) && !_fundingCycle.global().allowSetTerminals\n ) revert SET_TERMINALS_NOT_ALLOWED();\n\n // Add the new terminal.\n _terminalsOf[_projectId].push(_terminal);\n\n emit AddTerminal(_projectId, _terminal, msg.sender);\n }\n}\n" + }, + "contracts/JBSingleTokenPaymentTerminalStore3_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {ReentrancyGuard} from '@openzeppelin/contracts/security/ReentrancyGuard.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {JBBallotState} from './enums/JBBallotState.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBController3_1} from './interfaces/IJBController3_1.sol';\nimport {IJBFundingCycleDataSource} from './interfaces/IJBFundingCycleDataSource.sol';\nimport {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol';\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\nimport {IJBSingleTokenPaymentTerminal} from './interfaces/IJBSingleTokenPaymentTerminal.sol';\nimport {IJBSingleTokenPaymentTerminalStore} from './interfaces/IJBSingleTokenPaymentTerminalStore.sol';\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\nimport {JBConstants} from './libraries/JBConstants.sol';\nimport {JBCurrencies} from './libraries/JBCurrencies.sol';\nimport {JBFixedPointNumber} from './libraries/JBFixedPointNumber.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\nimport {JBFundingCycleMetadataResolver} from './libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBPayDelegateAllocation} from './structs/JBPayDelegateAllocation.sol';\nimport {JBPayParamsData} from './structs/JBPayParamsData.sol';\nimport {JBRedeemParamsData} from './structs/JBRedeemParamsData.sol';\nimport {JBRedemptionDelegateAllocation} from './structs/JBRedemptionDelegateAllocation.sol';\nimport {JBTokenAmount} from './structs/JBTokenAmount.sol';\n\n/// @notice Manages all bookkeeping for inflows and outflows of funds from any ISingleTokenPaymentTerminal.\n/// @dev This Store expects a project's controller to be an IJBController3_1. This is the only difference between this version and the original.\ncontract JBSingleTokenPaymentTerminalStore3_1 is\n ReentrancyGuard,\n IJBSingleTokenPaymentTerminalStore\n{\n // A library that parses the packed funding cycle metadata into a friendlier format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error INVALID_AMOUNT_TO_SEND_DELEGATE();\n error CURRENCY_MISMATCH();\n error DISTRIBUTION_AMOUNT_LIMIT_REACHED();\n error FUNDING_CYCLE_PAYMENT_PAUSED();\n error FUNDING_CYCLE_DISTRIBUTION_PAUSED();\n error FUNDING_CYCLE_REDEEM_PAUSED();\n error INADEQUATE_CONTROLLER_ALLOWANCE();\n error INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n error INSUFFICIENT_TOKENS();\n error INVALID_FUNDING_CYCLE();\n error PAYMENT_TERMINAL_MIGRATION_NOT_ALLOWED();\n\n //*********************************************************************//\n // -------------------------- private constants ---------------------- //\n //*********************************************************************//\n\n /// @notice Ensures a maximum number of decimal points of persisted fidelity on mulDiv operations of fixed point numbers.\n uint256 private constant _MAX_FIXED_POINT_FIDELITY = 18;\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n /// @notice The contract storing all funding cycle configurations.\n IJBFundingCycleStore public immutable override fundingCycleStore;\n\n /// @notice The contract that exposes price feeds.\n IJBPrices public immutable override prices;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The amount of tokens that each project has for each terminal, in terms of the terminal's token.\n /// @dev The used distribution limit is represented as a fixed point number with the same amount of decimals as its relative terminal.\n /// @custom:param _terminal The terminal to which the balance applies.\n /// @custom:param _projectId The ID of the project to get the balance of.\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => uint256)) public override balanceOf;\n\n /// @notice The amount of funds that a project has distributed from its limit during the current funding cycle for each terminal, in terms of the distribution limit's currency.\n /// @dev Increases as projects use their preconfigured distribution limits.\n /// @dev The used distribution limit is represented as a fixed point number with the same amount of decimals as its relative terminal.\n /// @custom:param _terminal The terminal to which the used distribution limit applies.\n /// @custom:param _projectId The ID of the project to get the used distribution limit of.\n /// @custom:param _fundingCycleNumber The number of the funding cycle during which the distribution limit was used.\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => mapping(uint256 => uint256)))\n public\n override usedDistributionLimitOf;\n\n /// @notice The amount of funds that a project has used from its allowance during the current funding cycle configuration for each terminal, in terms of the overflow allowance's currency.\n /// @dev Increases as projects use their allowance.\n /// @dev The used allowance is represented as a fixed point number with the same amount of decimals as its relative terminal.\n /// @custom:param _terminal The terminal to which the overflow allowance applies.\n /// @custom:param _projectId The ID of the project to get the used overflow allowance of.\n /// @custom:param _configuration The configuration of the during which the allowance was used.\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => mapping(uint256 => uint256)))\n public\n override usedOverflowAllowanceOf;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Gets the current overflowed amount in a terminal for a specified project.\n /// @dev The current overflow is represented as a fixed point number with the same amount of decimals as the specified terminal.\n /// @param _terminal The terminal for which the overflow is being calculated.\n /// @param _projectId The ID of the project to get overflow for.\n /// @return The current amount of overflow that project has in the specified terminal.\n function currentOverflowOf(\n IJBSingleTokenPaymentTerminal _terminal,\n uint256 _projectId\n ) external view override returns (uint256) {\n // Return the overflow during the project's current funding cycle.\n return\n _overflowDuring(\n _terminal,\n _projectId,\n fundingCycleStore.currentOf(_projectId),\n _terminal.currency()\n );\n }\n\n /// @notice Gets the current overflowed amount for a specified project across all terminals.\n /// @param _projectId The ID of the project to get total overflow for.\n /// @param _decimals The number of decimals that the fixed point overflow should include.\n /// @param _currency The currency that the total overflow should be in terms of.\n /// @return The current total amount of overflow that project has across all terminals.\n function currentTotalOverflowOf(\n uint256 _projectId,\n uint256 _decimals,\n uint256 _currency\n ) external view override returns (uint256) {\n return _currentTotalOverflowOf(_projectId, _decimals, _currency);\n }\n\n /// @notice The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the total token supply and overflow in the ecosystem.\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\n /// @dev The current reclaimable overflow is returned in terms of the specified terminal's currency.\n /// @dev The reclaimable overflow is represented as a fixed point number with the same amount of decimals as the specified terminal.\n /// @param _terminal The terminal from which the reclaimable amount would come.\n /// @param _projectId The ID of the project to get the reclaimable overflow amount for.\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _useTotalOverflow A flag indicating whether the overflow used in the calculation should be summed from all of the project's terminals. If false, overflow should be limited to the amount in the specified `_terminal`.\n /// @return The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_terminal`.\n function currentReclaimableOverflowOf(\n IJBSingleTokenPaymentTerminal _terminal,\n uint256 _projectId,\n uint256 _tokenCount,\n bool _useTotalOverflow\n ) external view override returns (uint256) {\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Get the amount of current overflow.\n // Use the project's total overflow across all of its terminals if the flag species specifies so. Otherwise, use the overflow local to the specified terminal.\n uint256 _currentOverflow = _useTotalOverflow\n ? _currentTotalOverflowOf(_projectId, _terminal.decimals(), _terminal.currency())\n : _overflowDuring(_terminal, _projectId, _fundingCycle, _terminal.currency());\n\n // If there's no overflow, there's no reclaimable overflow.\n if (_currentOverflow == 0) return 0;\n\n // Get the number of outstanding tokens the project has.\n uint256 _totalSupply = IJBController3_1(directory.controllerOf(_projectId))\n .totalOutstandingTokensOf(_projectId);\n\n // Can't redeem more tokens that is in the supply.\n if (_tokenCount > _totalSupply) return 0;\n\n // Return the reclaimable overflow amount.\n return\n _reclaimableOverflowDuring(\n _projectId,\n _fundingCycle,\n _tokenCount,\n _totalSupply,\n _currentOverflow\n );\n }\n\n /// @notice The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the specified total token supply and overflow amounts.\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\n /// @param _projectId The ID of the project to get the reclaimable overflow amount for.\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _totalSupply The total number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _overflow The amount of overflow to make the calculation with, as a fixed point number.\n /// @return The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_overflow`.\n function currentReclaimableOverflowOf(\n uint256 _projectId,\n uint256 _tokenCount,\n uint256 _totalSupply,\n uint256 _overflow\n ) external view override returns (uint256) {\n // If there's no overflow, there's no reclaimable overflow.\n if (_overflow == 0) return 0;\n\n // Can't redeem more tokens that is in the supply.\n if (_tokenCount > _totalSupply) return 0;\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Return the reclaimable overflow amount.\n return\n _reclaimableOverflowDuring(_projectId, _fundingCycle, _tokenCount, _totalSupply, _overflow);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _fundingCycleStore A contract storing all funding cycle configurations.\n /// @param _prices A contract that exposes price feeds.\n constructor(IJBDirectory _directory, IJBFundingCycleStore _fundingCycleStore, IJBPrices _prices) {\n directory = _directory;\n fundingCycleStore = _fundingCycleStore;\n prices = _prices;\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Records newly contributed tokens to a project.\n /// @dev Mints the project's tokens according to values provided by a configured data source. If no data source is configured, mints tokens proportional to the amount of the contribution.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.sender's tokens.\n /// @param _payer The original address that sent the payment to the terminal.\n /// @param _amount The amount of tokens being paid. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\n /// @param _projectId The ID of the project being paid.\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _beneficiary The specified address that should be the beneficiary of anything that results from the payment.\n /// @param _memo A memo to pass along to the emitted event, and passed along to the funding cycle's data source.\n /// @param _metadata Bytes to send along to the data source, if one is provided.\n /// @return fundingCycle The project's funding cycle during which payment was made.\n /// @return tokenCount The number of project tokens that were minted, as a fixed point number with 18 decimals.\n /// @return delegateAllocations The amount to send to delegates instead of adding to the local balance.\n /// @return memo A memo that should be passed along to the emitted event.\n function recordPaymentFrom(\n address _payer,\n JBTokenAmount calldata _amount,\n uint256 _projectId,\n uint256 _baseWeightCurrency,\n address _beneficiary,\n string calldata _memo,\n bytes memory _metadata\n )\n external\n override\n nonReentrant\n returns (\n JBFundingCycle memory fundingCycle,\n uint256 tokenCount,\n JBPayDelegateAllocation[] memory delegateAllocations,\n string memory memo\n )\n {\n // Get a reference to the current funding cycle for the project.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // The project must have a funding cycle configured.\n if (fundingCycle.number == 0) revert INVALID_FUNDING_CYCLE();\n\n // Must not be paused.\n if (fundingCycle.payPaused()) revert FUNDING_CYCLE_PAYMENT_PAUSED();\n\n // The weight according to which new token supply is to be minted, as a fixed point number with 18 decimals.\n uint256 _weight;\n\n // If the funding cycle has configured a data source, use it to derive a weight and memo.\n if (fundingCycle.useDataSourceForPay() && fundingCycle.dataSource() != address(0)) {\n // Create the params that'll be sent to the data source.\n JBPayParamsData memory _data = JBPayParamsData(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _payer,\n _amount,\n _projectId,\n fundingCycle.configuration,\n _beneficiary,\n fundingCycle.weight,\n fundingCycle.reservedRate(),\n _memo,\n _metadata\n );\n (_weight, memo, delegateAllocations) = IJBFundingCycleDataSource(fundingCycle.dataSource())\n .payParams(_data);\n }\n // Otherwise use the funding cycle's weight\n else {\n _weight = fundingCycle.weight;\n memo = _memo;\n }\n\n // Scoped section prevents stack too deep. `_balanceDiff` only used within scope.\n {\n // Keep a reference to the amount that should be added to the project's balance.\n uint256 _balanceDiff = _amount.value;\n\n // Validate all delegated amounts. This needs to be done before returning the delegate allocations to ensure valid delegated amounts.\n if (delegateAllocations.length != 0) {\n for (uint256 _i; _i < delegateAllocations.length; ) {\n // Get a reference to the amount to be delegated.\n uint256 _delegatedAmount = delegateAllocations[_i].amount;\n\n // Validate if non-zero.\n if (_delegatedAmount != 0) {\n // Can't delegate more than was paid.\n if (_delegatedAmount > _balanceDiff) revert INVALID_AMOUNT_TO_SEND_DELEGATE();\n\n // Decrement the total amount being added to the balance.\n _balanceDiff = _balanceDiff - _delegatedAmount;\n }\n\n unchecked {\n ++_i;\n }\n }\n }\n\n // If there's no amount being recorded, there's nothing left to do.\n if (_amount.value == 0) return (fundingCycle, 0, delegateAllocations, memo);\n\n // Add the correct balance difference to the token balance of the project.\n if (_balanceDiff != 0)\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] +\n _balanceDiff;\n }\n\n // If there's no weight, token count must be 0 so there's nothing left to do.\n if (_weight == 0) return (fundingCycle, 0, delegateAllocations, memo);\n\n // Get a reference to the number of decimals in the amount. (prevents stack too deep).\n uint256 _decimals = _amount.decimals;\n\n // If the terminal should base its weight on a different currency from the terminal's currency, determine the factor.\n // The weight is always a fixed point mumber with 18 decimals. To ensure this, the ratio should use the same number of decimals as the `_amount`.\n uint256 _weightRatio = _amount.currency == _baseWeightCurrency\n ? 10 ** _decimals\n : prices.priceFor(_amount.currency, _baseWeightCurrency, _decimals);\n\n // Find the number of tokens to mint, as a fixed point number with as many decimals as `weight` has.\n tokenCount = PRBMath.mulDiv(_amount.value, _weight, _weightRatio);\n }\n\n /// @notice Records newly redeemed tokens of a project.\n /// @dev Redeems the project's tokens according to values provided by a configured data source. If no data source is configured, redeems tokens along a redemption bonding curve that is a function of the number of tokens being burned.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.senders tokens.\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the data source, if one is provided.\n /// @return fundingCycle The funding cycle during which the redemption was made.\n /// @return reclaimAmount The amount of terminal tokens reclaimed, as a fixed point number with 18 decimals.\n /// @return delegateAllocations The amount to send to delegates instead of sending to the beneficiary.\n /// @return memo A memo that should be passed along to the emitted event.\n function recordRedemptionFor(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n string memory _memo,\n bytes memory _metadata\n )\n external\n override\n nonReentrant\n returns (\n JBFundingCycle memory fundingCycle,\n uint256 reclaimAmount,\n JBRedemptionDelegateAllocation[] memory delegateAllocations,\n string memory memo\n )\n {\n // Get a reference to the project's current funding cycle.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // The current funding cycle must not be paused.\n if (fundingCycle.redeemPaused()) revert FUNDING_CYCLE_REDEEM_PAUSED();\n\n // Scoped section prevents stack too deep. `_reclaimedTokenAmount`, `_currentOverflow`, and `_totalSupply` only used within scope.\n {\n // Get a reference to the reclaimed token amount struct, the current overflow, and the total token supply.\n JBTokenAmount memory _reclaimedTokenAmount;\n uint256 _currentOverflow;\n uint256 _totalSupply;\n\n // Another scoped section prevents stack too deep. `_token`, `_decimals`, and `_currency` only used within scope.\n {\n // Get a reference to the terminal's tokens.\n address _token = IJBSingleTokenPaymentTerminal(msg.sender).token();\n\n // Get a reference to the terminal's decimals.\n uint256 _decimals = IJBSingleTokenPaymentTerminal(msg.sender).decimals();\n\n // Get areference to the terminal's currency.\n uint256 _currency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\n\n // Get the amount of current overflow.\n // Use the local overflow if the funding cycle specifies that it should be used. Otherwise, use the project's total overflow across all of its terminals.\n _currentOverflow = fundingCycle.useTotalOverflowForRedemptions()\n ? _currentTotalOverflowOf(_projectId, _decimals, _currency)\n : _overflowDuring(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _projectId,\n fundingCycle,\n _currency\n );\n\n // Get the number of outstanding tokens the project has.\n _totalSupply = IJBController3_1(directory.controllerOf(_projectId))\n .totalOutstandingTokensOf(_projectId);\n\n // Can't redeem more tokens that is in the supply.\n if (_tokenCount > _totalSupply) revert INSUFFICIENT_TOKENS();\n\n if (_currentOverflow != 0)\n // Calculate reclaim amount using the current overflow amount.\n reclaimAmount = _reclaimableOverflowDuring(\n _projectId,\n fundingCycle,\n _tokenCount,\n _totalSupply,\n _currentOverflow\n );\n\n _reclaimedTokenAmount = JBTokenAmount(_token, reclaimAmount, _decimals, _currency);\n }\n\n // If the funding cycle has configured a data source, use it to derive a claim amount and memo.\n if (fundingCycle.useDataSourceForRedeem() && fundingCycle.dataSource() != address(0)) {\n // Yet another scoped section prevents stack too deep. `_state` only used within scope.\n {\n // Get a reference to the ballot state.\n JBBallotState _state = fundingCycleStore.currentBallotStateOf(_projectId);\n\n // Create the params that'll be sent to the data source.\n JBRedeemParamsData memory _data = JBRedeemParamsData(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _holder,\n _projectId,\n fundingCycle.configuration,\n _tokenCount,\n _totalSupply,\n _currentOverflow,\n _reclaimedTokenAmount,\n fundingCycle.useTotalOverflowForRedemptions(),\n _state == JBBallotState.Active\n ? fundingCycle.ballotRedemptionRate()\n : fundingCycle.redemptionRate(),\n _memo,\n _metadata\n );\n (reclaimAmount, memo, delegateAllocations) = IJBFundingCycleDataSource(\n fundingCycle.dataSource()\n ).redeemParams(_data);\n }\n } else {\n memo = _memo;\n }\n }\n\n // Keep a reference to the amount that should be subtracted from the project's balance.\n uint256 _balanceDiff = reclaimAmount;\n\n if (delegateAllocations.length != 0) {\n // Validate all delegated amounts.\n for (uint256 _i; _i < delegateAllocations.length; ) {\n // Get a reference to the amount to be delegated.\n uint256 _delegatedAmount = delegateAllocations[_i].amount;\n\n // Validate if non-zero.\n if (_delegatedAmount != 0)\n // Increment the total amount being subtracted from the balance.\n _balanceDiff = _balanceDiff + _delegatedAmount;\n\n unchecked {\n ++_i;\n }\n }\n }\n\n // The amount being reclaimed must be within the project's balance.\n if (_balanceDiff > balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId])\n revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n\n // Remove the reclaimed funds from the project's balance.\n if (_balanceDiff != 0) {\n unchecked {\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\n _balanceDiff;\n }\n }\n }\n\n /// @notice Records newly distributed funds for a project.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\n /// @param _projectId The ID of the project that is having funds distributed.\n /// @param _amount The amount to use from the distribution limit, as a fixed point number.\n /// @param _currency The currency of the `_amount`. This must match the project's current funding cycle's currency.\n /// @return fundingCycle The funding cycle during which the distribution was made.\n /// @return distributedAmount The amount of terminal tokens distributed, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordDistributionFor(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency\n )\n external\n override\n nonReentrant\n returns (JBFundingCycle memory fundingCycle, uint256 distributedAmount)\n {\n // Get a reference to the project's current funding cycle.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // The funding cycle must not be configured to have distributions paused.\n if (fundingCycle.distributionsPaused()) revert FUNDING_CYCLE_DISTRIBUTION_PAUSED();\n\n // The new total amount that has been distributed during this funding cycle.\n uint256 _newUsedDistributionLimitOf = usedDistributionLimitOf[\n IJBSingleTokenPaymentTerminal(msg.sender)\n ][_projectId][fundingCycle.number] + _amount;\n\n // Amount must be within what is still distributable.\n (uint256 _distributionLimitOf, uint256 _distributionLimitCurrencyOf) = IJBController3_1(\n directory.controllerOf(_projectId)\n ).fundAccessConstraintsStore().distributionLimitOf(\n _projectId,\n fundingCycle.configuration,\n IJBSingleTokenPaymentTerminal(msg.sender),\n IJBSingleTokenPaymentTerminal(msg.sender).token()\n );\n\n // Make sure the new used amount is within the distribution limit.\n if (_newUsedDistributionLimitOf > _distributionLimitOf || _distributionLimitOf == 0)\n revert DISTRIBUTION_AMOUNT_LIMIT_REACHED();\n\n // Make sure the currencies match.\n if (_currency != _distributionLimitCurrencyOf) revert CURRENCY_MISMATCH();\n\n // Get a reference to the terminal's currency.\n uint256 _balanceCurrency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\n\n // Convert the amount to the balance's currency.\n distributedAmount = (_currency == _balanceCurrency)\n ? _amount\n : PRBMath.mulDiv(\n _amount,\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\n prices.priceFor(_currency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\n );\n\n // The amount being distributed must be available.\n if (distributedAmount > balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId])\n revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n\n // Store the new amount.\n usedDistributionLimitOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId][\n fundingCycle.number\n ] = _newUsedDistributionLimitOf;\n\n // Removed the distributed funds from the project's token balance.\n unchecked {\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\n distributedAmount;\n }\n }\n\n /// @notice Records newly used allowance funds of a project.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\n /// @param _projectId The ID of the project to use the allowance of.\n /// @param _amount The amount to use from the allowance, as a fixed point number.\n /// @param _currency The currency of the `_amount`. Must match the currency of the overflow allowance.\n /// @return fundingCycle The funding cycle during which the overflow allowance is being used.\n /// @return usedAmount The amount of terminal tokens used, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordUsedAllowanceOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency\n )\n external\n override\n nonReentrant\n returns (JBFundingCycle memory fundingCycle, uint256 usedAmount)\n {\n // Get a reference to the project's current funding cycle.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Get a reference to the new used overflow allowance for this funding cycle configuration.\n uint256 _newUsedOverflowAllowanceOf = usedOverflowAllowanceOf[\n IJBSingleTokenPaymentTerminal(msg.sender)\n ][_projectId][fundingCycle.configuration] + _amount;\n\n // There must be sufficient allowance available.\n (uint256 _overflowAllowanceOf, uint256 _overflowAllowanceCurrency) = IJBController3_1(\n directory.controllerOf(_projectId)\n ).fundAccessConstraintsStore().overflowAllowanceOf(\n _projectId,\n fundingCycle.configuration,\n IJBSingleTokenPaymentTerminal(msg.sender),\n IJBSingleTokenPaymentTerminal(msg.sender).token()\n );\n\n // Make sure the new used amount is within the allowance.\n if (_newUsedOverflowAllowanceOf > _overflowAllowanceOf || _overflowAllowanceOf == 0)\n revert INADEQUATE_CONTROLLER_ALLOWANCE();\n\n // Make sure the currencies match.\n if (_currency != _overflowAllowanceCurrency) revert CURRENCY_MISMATCH();\n\n // Get a reference to the terminal's currency.\n uint256 _balanceCurrency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\n\n // Convert the amount to this store's terminal's token.\n usedAmount = (_currency == _balanceCurrency)\n ? _amount\n : PRBMath.mulDiv(\n _amount,\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\n prices.priceFor(_currency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\n );\n\n // The amount being distributed must be available in the overflow.\n if (\n usedAmount >\n _overflowDuring(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _projectId,\n fundingCycle,\n _balanceCurrency\n )\n ) revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n\n // Store the incremented value.\n usedOverflowAllowanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId][\n fundingCycle.configuration\n ] = _newUsedOverflowAllowanceOf;\n\n // Update the project's balance.\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\n usedAmount;\n }\n\n /// @notice Records newly added funds for the project.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\n /// @param _projectId The ID of the project to which the funds being added belong.\n /// @param _amount The amount of terminal tokens added, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordAddedBalanceFor(uint256 _projectId, uint256 _amount) external override {\n // Increment the balance.\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] +\n _amount;\n }\n\n /// @notice Records the migration of funds from this store.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount returned is in terms of the msg.senders tokens.\n /// @param _projectId The ID of the project being migrated.\n /// @return balance The project's migrated balance, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordMigration(\n uint256 _projectId\n ) external override nonReentrant returns (uint256 balance) {\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n // Migration must be allowed.\n if (!_fundingCycle.terminalMigrationAllowed()) revert PAYMENT_TERMINAL_MIGRATION_NOT_ALLOWED();\n\n // Return the current balance.\n balance = balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId];\n\n // Set the balance to 0.\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] = 0;\n }\n\n //*********************************************************************//\n // --------------------- private helper functions -------------------- //\n //*********************************************************************//\n\n /// @notice The amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens when measured from the specified.\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\n /// @param _projectId The ID of the project to get the reclaimable overflow amount for.\n /// @param _fundingCycle The funding cycle during which reclaimable overflow is being calculated.\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _totalSupply The total supply of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _overflow The amount of overflow to make the calculation with.\n /// @return The amount of overflowed tokens that can be reclaimed.\n function _reclaimableOverflowDuring(\n uint256 _projectId,\n JBFundingCycle memory _fundingCycle,\n uint256 _tokenCount,\n uint256 _totalSupply,\n uint256 _overflow\n ) private view returns (uint256) {\n // If the amount being redeemed is the total supply, return the rest of the overflow.\n if (_tokenCount == _totalSupply) return _overflow;\n\n // Use the ballot redemption rate if the queued cycle is pending approval according to the previous funding cycle's ballot.\n uint256 _redemptionRate = fundingCycleStore.currentBallotStateOf(_projectId) ==\n JBBallotState.Active\n ? _fundingCycle.ballotRedemptionRate()\n : _fundingCycle.redemptionRate();\n\n // If the redemption rate is 0, nothing is claimable.\n if (_redemptionRate == 0) return 0;\n\n // Get a reference to the linear proportion.\n uint256 _base = PRBMath.mulDiv(_overflow, _tokenCount, _totalSupply);\n\n // These conditions are all part of the same curve. Edge conditions are separated because fewer operation are necessary.\n if (_redemptionRate == JBConstants.MAX_REDEMPTION_RATE) return _base;\n\n return\n PRBMath.mulDiv(\n _base,\n _redemptionRate +\n PRBMath.mulDiv(\n _tokenCount,\n JBConstants.MAX_REDEMPTION_RATE - _redemptionRate,\n _totalSupply\n ),\n JBConstants.MAX_REDEMPTION_RATE\n );\n }\n\n /// @notice Gets the amount that is overflowing when measured from the specified funding cycle.\n /// @dev This amount changes as the value of the balance changes in relation to the currency being used to measure the distribution limit.\n /// @param _terminal The terminal for which the overflow is being calculated.\n /// @param _fundingCycle The ID of the funding cycle to base the overflow on.\n /// @param _balanceCurrency The currency that the stored balance is expected to be in terms of.\n /// @return overflow The overflow of funds, as a fixed point number with 18 decimals.\n function _overflowDuring(\n IJBSingleTokenPaymentTerminal _terminal,\n uint256 _projectId,\n JBFundingCycle memory _fundingCycle,\n uint256 _balanceCurrency\n ) private view returns (uint256) {\n // Get the current balance of the project.\n uint256 _balanceOf = balanceOf[_terminal][_projectId];\n\n // If there's no balance, there's no overflow.\n if (_balanceOf == 0) return 0;\n\n // Get a reference to the distribution limit during the funding cycle.\n (uint256 _distributionLimit, uint256 _distributionLimitCurrency) = IJBController3_1(\n directory.controllerOf(_projectId)\n ).fundAccessConstraintsStore().distributionLimitOf(\n _projectId,\n _fundingCycle.configuration,\n _terminal,\n _terminal.token()\n );\n\n // Get a reference to the amount still distributable during the funding cycle.\n uint256 _distributionLimitRemaining = _distributionLimit -\n usedDistributionLimitOf[_terminal][_projectId][_fundingCycle.number];\n\n // Convert the _distributionRemaining to be in terms of the provided currency.\n if (_distributionLimitRemaining != 0 && _distributionLimitCurrency != _balanceCurrency)\n _distributionLimitRemaining = PRBMath.mulDiv(\n _distributionLimitRemaining,\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\n prices.priceFor(_distributionLimitCurrency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\n );\n\n // Overflow is the balance of this project minus the amount that can still be distributed.\n unchecked {\n return\n _balanceOf > _distributionLimitRemaining ? _balanceOf - _distributionLimitRemaining : 0;\n }\n }\n\n /// @notice Gets the amount that is currently overflowing across all of a project's terminals.\n /// @dev This amount changes as the value of the balances changes in relation to the currency being used to measure the project's distribution limits.\n /// @param _projectId The ID of the project to get the total overflow for.\n /// @param _decimals The number of decimals that the fixed point overflow should include.\n /// @param _currency The currency that the overflow should be in terms of.\n /// @return overflow The total overflow of a project's funds.\n function _currentTotalOverflowOf(\n uint256 _projectId,\n uint256 _decimals,\n uint256 _currency\n ) private view returns (uint256) {\n // Get a reference to the project's terminals.\n IJBPaymentTerminal[] memory _terminals = directory.terminalsOf(_projectId);\n\n // Keep a reference to the ETH overflow across all terminals, as a fixed point number with 18 decimals.\n uint256 _ethOverflow;\n\n // Add the current ETH overflow for each terminal.\n for (uint256 _i; _i < _terminals.length; ) {\n _ethOverflow = _ethOverflow + _terminals[_i].currentEthOverflowOf(_projectId);\n unchecked {\n ++_i;\n }\n }\n\n // Convert the ETH overflow to the specified currency if needed, maintaining a fixed point number with 18 decimals.\n uint256 _totalOverflow18Decimal = _currency == JBCurrencies.ETH\n ? _ethOverflow\n : PRBMath.mulDiv(_ethOverflow, 10 ** 18, prices.priceFor(JBCurrencies.ETH, _currency, 18));\n\n // Adjust the decimals of the fixed point number if needed to match the target decimals.\n return\n (_decimals == 18)\n ? _totalOverflow18Decimal\n : JBFixedPointNumber.adjustDecimals(_totalOverflow18Decimal, 18, _decimals);\n }\n}\n" + }, + "contracts/interfaces/IJBFundingCycleDataSource.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBPayDelegateAllocation} from './../structs/JBPayDelegateAllocation.sol';\nimport {JBPayParamsData} from './../structs/JBPayParamsData.sol';\nimport {JBRedeemParamsData} from './../structs/JBRedeemParamsData.sol';\nimport {JBRedemptionDelegateAllocation} from './../structs/JBRedemptionDelegateAllocation.sol';\n\n/// @title Datasource\n/// @notice The datasource is called by JBPayoutRedemptionPaymentTerminals on pay and redemption, and provide an extra layer of logic to use a custom weight, a custom memo and/or a pay/redeem delegate\ninterface IJBFundingCycleDataSource is IERC165 {\n /// @notice The datasource implementation for JBPaymentTerminal.pay(..)\n /// @param data the data passed to the data source in terminal.pay(..), as a JBPayParamsData struct:\n /// @return weight the weight to use to override the funding cycle weight\n /// @return memo the memo to override the pay(..) memo\n /// @return delegateAllocations The amount to send to delegates instead of adding to the local balance.\n function payParams(\n JBPayParamsData calldata data\n )\n external\n returns (\n uint256 weight,\n string memory memo,\n JBPayDelegateAllocation[] memory delegateAllocations\n );\n\n /// @notice The datasource implementation for JBPaymentTerminal.redeemTokensOf(..)\n /// @param data the data passed to the data source in terminal.redeemTokensOf(..), as a JBRedeemParamsData struct:\n /// @return reclaimAmount The amount to claim, overriding the terminal logic.\n /// @return memo The memo to override the redeemTokensOf(..) memo.\n /// @return delegateAllocations The amount to send to delegates instead of adding to the beneficiary.\n function redeemParams(\n JBRedeemParamsData calldata data\n )\n external\n returns (\n uint256 reclaimAmount,\n string memory memo,\n JBRedemptionDelegateAllocation[] memory delegateAllocations\n );\n}\n" + }, + "contracts/interfaces/IJBSingleTokenPaymentTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\n\ninterface IJBSingleTokenPaymentTerminal is IJBPaymentTerminal {\n function token() external view returns (address);\n\n function currency() external view returns (uint256);\n\n function decimals() external view returns (uint256);\n}\n" + }, + "contracts/interfaces/IJBSingleTokenPaymentTerminalStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\nimport {JBPayDelegateAllocation} from './../structs/JBPayDelegateAllocation.sol';\nimport {JBRedemptionDelegateAllocation} from './../structs/JBRedemptionDelegateAllocation.sol';\nimport {JBTokenAmount} from './../structs/JBTokenAmount.sol';\nimport {IJBDirectory} from './IJBDirectory.sol';\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\nimport {IJBPrices} from './IJBPrices.sol';\nimport {IJBSingleTokenPaymentTerminal} from './IJBSingleTokenPaymentTerminal.sol';\n\ninterface IJBSingleTokenPaymentTerminalStore {\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\n\n function directory() external view returns (IJBDirectory);\n\n function prices() external view returns (IJBPrices);\n\n function balanceOf(\n IJBSingleTokenPaymentTerminal terminal,\n uint256 projectId\n ) external view returns (uint256);\n\n function usedDistributionLimitOf(\n IJBSingleTokenPaymentTerminal terminal,\n uint256 projectId,\n uint256 fundingCycleNumber\n ) external view returns (uint256);\n\n function usedOverflowAllowanceOf(\n IJBSingleTokenPaymentTerminal terminal,\n uint256 projectId,\n uint256 fundingCycleConfiguration\n ) external view returns (uint256);\n\n function currentOverflowOf(\n IJBSingleTokenPaymentTerminal terminal,\n uint256 projectId\n ) external view returns (uint256);\n\n function currentTotalOverflowOf(\n uint256 projectId,\n uint256 decimals,\n uint256 currency\n ) external view returns (uint256);\n\n function currentReclaimableOverflowOf(\n IJBSingleTokenPaymentTerminal terminal,\n uint256 projectId,\n uint256 tokenCount,\n bool useTotalOverflow\n ) external view returns (uint256);\n\n function currentReclaimableOverflowOf(\n uint256 projectId,\n uint256 tokenCount,\n uint256 totalSupply,\n uint256 overflow\n ) external view returns (uint256);\n\n function recordPaymentFrom(\n address payer,\n JBTokenAmount memory amount,\n uint256 projectId,\n uint256 baseWeightCurrency,\n address beneficiary,\n string calldata inputMemo,\n bytes calldata metadata\n )\n external\n returns (\n JBFundingCycle memory fundingCycle,\n uint256 tokenCount,\n JBPayDelegateAllocation[] memory delegateAllocations,\n string memory outputMemo\n );\n\n function recordRedemptionFor(\n address holder,\n uint256 projectId,\n uint256 tokenCount,\n string calldata inputMemo,\n bytes calldata metadata\n )\n external\n returns (\n JBFundingCycle memory fundingCycle,\n uint256 reclaimAmount,\n JBRedemptionDelegateAllocation[] memory delegateAllocations,\n string memory outputMemo\n );\n\n function recordDistributionFor(\n uint256 projectId,\n uint256 amount,\n uint256 currency\n ) external returns (JBFundingCycle memory fundingCycle, uint256 distributedAmount);\n\n function recordUsedAllowanceOf(\n uint256 projectId,\n uint256 amount,\n uint256 currency\n ) external returns (JBFundingCycle memory fundingCycle, uint256 withdrawnAmount);\n\n function recordAddedBalanceFor(uint256 projectId, uint256 amount) external;\n\n function recordMigration(uint256 projectId) external returns (uint256 balance);\n}\n" + }, + "contracts/interfaces/IJBPrices.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBPriceFeed} from './IJBPriceFeed.sol';\n\ninterface IJBPrices {\n event AddFeed(uint256 indexed currency, uint256 indexed base, IJBPriceFeed feed);\n\n function feedFor(uint256 currency, uint256 base) external view returns (IJBPriceFeed);\n\n function priceFor(\n uint256 currency,\n uint256 base,\n uint256 decimals\n ) external view returns (uint256);\n\n function addFeedFor(uint256 currency, uint256 base, IJBPriceFeed priceFeed) external;\n}\n" + }, + "contracts/libraries/JBCurrencies.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nlibrary JBCurrencies {\n uint256 public constant ETH = 1;\n uint256 public constant USD = 2;\n}\n" + }, + "contracts/libraries/JBFixedPointNumber.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nlibrary JBFixedPointNumber {\n function adjustDecimals(\n uint256 _value,\n uint256 _decimals,\n uint256 _targetDecimals\n ) internal pure returns (uint256) {\n // If decimals need adjusting, multiply or divide the price by the decimal adjuster to get the normalized result.\n if (_targetDecimals == _decimals) return _value;\n else if (_targetDecimals > _decimals) return _value * 10**(_targetDecimals - _decimals);\n else return _value / 10**(_decimals - _targetDecimals);\n }\n}\n" + }, + "contracts/structs/JBPayDelegateAllocation.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBPayDelegate} from '../interfaces/IJBPayDelegate.sol';\n\n/// @custom:member delegate A delegate contract to use for subsequent calls.\n/// @custom:member amount The amount to send to the delegate.\nstruct JBPayDelegateAllocation {\n IJBPayDelegate delegate;\n uint256 amount;\n}\n" + }, + "contracts/structs/JBPayParamsData.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\nimport {JBTokenAmount} from './JBTokenAmount.sol';\n\n/// @custom:member terminal The terminal that is facilitating the payment.\n/// @custom:member payer The address from which the payment originated.\n/// @custom:member amount The amount of the payment. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\n/// @custom:member projectId The ID of the project being paid.\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the payment is being made.\n/// @custom:member beneficiary The specified address that should be the beneficiary of anything that results from the payment.\n/// @custom:member weight The weight of the funding cycle during which the payment is being made.\n/// @custom:member reservedRate The reserved rate of the funding cycle during which the payment is being made.\n/// @custom:member memo The memo that was sent alongside the payment.\n/// @custom:member metadata Extra data provided by the payer.\nstruct JBPayParamsData {\n IJBPaymentTerminal terminal;\n address payer;\n JBTokenAmount amount;\n uint256 projectId;\n uint256 currentFundingCycleConfiguration;\n address beneficiary;\n uint256 weight;\n uint256 reservedRate;\n string memo;\n bytes metadata;\n}\n" + }, + "contracts/structs/JBRedeemParamsData.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\nimport {JBTokenAmount} from './JBTokenAmount.sol';\n\n/// @custom:member terminal The terminal that is facilitating the redemption.\n/// @custom:member holder The holder of the tokens being redeemed.\n/// @custom:member projectId The ID of the project whos tokens are being redeemed.\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the redemption is being made.\n/// @custom:member tokenCount The proposed number of tokens being redeemed, as a fixed point number with 18 decimals.\n/// @custom:member totalSupply The total supply of tokens used in the calculation, as a fixed point number with 18 decimals.\n/// @custom:member overflow The amount of overflow used in the reclaim amount calculation.\n/// @custom:member reclaimAmount The amount that should be reclaimed by the redeemer using the protocol's standard bonding curve redemption formula. Includes the token being reclaimed, the reclaim value, the number of decimals included, and the currency of the reclaim amount.\n/// @custom:member useTotalOverflow If overflow across all of a project's terminals is being used when making redemptions.\n/// @custom:member redemptionRate The redemption rate of the funding cycle during which the redemption is being made.\n/// @custom:member memo The proposed memo that is being emitted alongside the redemption.\n/// @custom:member metadata Extra data provided by the redeemer.\nstruct JBRedeemParamsData {\n IJBPaymentTerminal terminal;\n address holder;\n uint256 projectId;\n uint256 currentFundingCycleConfiguration;\n uint256 tokenCount;\n uint256 totalSupply;\n uint256 overflow;\n JBTokenAmount reclaimAmount;\n bool useTotalOverflow;\n uint256 redemptionRate;\n string memo;\n bytes metadata;\n}\n" + }, + "contracts/structs/JBRedemptionDelegateAllocation.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBRedemptionDelegate} from '../interfaces/IJBRedemptionDelegate.sol';\n\n/// @custom:member delegate A delegate contract to use for subsequent calls.\n/// @custom:member amount The amount to send to the delegate.\nstruct JBRedemptionDelegateAllocation {\n IJBRedemptionDelegate delegate;\n uint256 amount;\n}\n" + }, + "contracts/structs/JBTokenAmount.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @custom:member token The token the payment was made in.\n/// @custom:member value The amount of tokens that was paid, as a fixed point number.\n/// @custom:member decimals The number of decimals included in the value fixed point number.\n/// @custom:member currency The expected currency of the value.\nstruct JBTokenAmount {\n address token;\n uint256 value;\n uint256 decimals;\n uint256 currency;\n}\n" + }, + "contracts/interfaces/IJBPayDelegate.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBDidPayData} from './../structs/JBDidPayData.sol';\n\n/// @title Pay delegate\n/// @notice Delegate called after JBTerminal.pay(..) logic completion (if passed by the funding cycle datasource)\ninterface IJBPayDelegate is IERC165 {\n /// @notice This function is called by JBPaymentTerminal.pay(..), after the execution of its logic\n /// @dev Critical business logic should be protected by an appropriate access control\n /// @param data the data passed by the terminal, as a JBDidPayData struct:\n function didPay(JBDidPayData calldata data) external payable;\n}\n" + }, + "contracts/structs/JBDidPayData.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBTokenAmount} from './JBTokenAmount.sol';\n\n/// @custom:member payer The address from which the payment originated.\n/// @custom:member projectId The ID of the project for which the payment was made.\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the payment is being made.\n/// @custom:member amount The amount of the payment. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\n/// @custom:member forwardedAmount The amount of the payment that is being sent to the delegate. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\n/// @custom:member projectTokenCount The number of project tokens minted for the beneficiary.\n/// @custom:member beneficiary The address to which the tokens were minted.\n/// @custom:member preferClaimedTokens A flag indicating whether the request prefered to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract.\n/// @custom:member memo The memo that is being emitted alongside the payment.\n/// @custom:member metadata Extra data to send to the delegate.\nstruct JBDidPayData {\n address payer;\n uint256 projectId;\n uint256 currentFundingCycleConfiguration;\n JBTokenAmount amount;\n JBTokenAmount forwardedAmount;\n uint256 projectTokenCount;\n address beneficiary;\n bool preferClaimedTokens;\n string memo;\n bytes metadata;\n}\n" + }, + "contracts/interfaces/IJBRedemptionDelegate.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBDidRedeemData} from './../structs/JBDidRedeemData.sol';\n\n/// @title Redemption delegate\n/// @notice Delegate called after JBTerminal.redeemTokensOf(..) logic completion (if passed by the funding cycle datasource)\ninterface IJBRedemptionDelegate is IERC165 {\n /// @notice This function is called by JBPaymentTerminal.redeemTokensOf(..), after the execution of its logic\n /// @dev Critical business logic should be protected by an appropriate access control\n /// @param data the data passed by the terminal, as a JBDidRedeemData struct:\n function didRedeem(JBDidRedeemData calldata data) external payable;\n}\n" + }, + "contracts/structs/JBDidRedeemData.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBTokenAmount} from './JBTokenAmount.sol';\n\n/// @custom:member holder The holder of the tokens being redeemed.\n/// @custom:member projectId The ID of the project with which the redeemed tokens are associated.\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the redemption is being made.\n/// @custom:member projectTokenCount The number of project tokens being redeemed.\n/// @custom:member reclaimedAmount The amount reclaimed from the treasury. Includes the token being reclaimed, the value, the number of decimals included, and the currency of the amount.\n/// @custom:member forwardedAmount The amount of the payment that is being sent to the delegate. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\n/// @custom:member beneficiary The address to which the reclaimed amount will be sent.\n/// @custom:member memo The memo that is being emitted alongside the redemption.\n/// @custom:member metadata Extra data to send to the delegate.\nstruct JBDidRedeemData {\n address holder;\n uint256 projectId;\n uint256 currentFundingCycleConfiguration;\n uint256 projectTokenCount;\n JBTokenAmount reclaimedAmount;\n JBTokenAmount forwardedAmount;\n address payable beneficiary;\n string memo;\n bytes metadata;\n}\n" + }, + "contracts/interfaces/IJBPriceFeed.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBPriceFeed {\n function currentPrice(uint256 targetDecimals) external view returns (uint256);\n}\n" + }, + "contracts/JBSingleTokenPaymentTerminalStore3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {ReentrancyGuard} from '@openzeppelin/contracts/security/ReentrancyGuard.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {JBBallotState} from './enums/JBBallotState.sol';\nimport {IJBController3_1} from './interfaces/IJBController3_1.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBFundingCycleDataSource3_1_1} from './interfaces/IJBFundingCycleDataSource3_1_1.sol';\nimport {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol';\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\nimport {IJBSingleTokenPaymentTerminal} from './interfaces/IJBSingleTokenPaymentTerminal.sol';\nimport {IJBSingleTokenPaymentTerminalStore3_1_1} from './interfaces/IJBSingleTokenPaymentTerminalStore3_1_1.sol';\nimport {JBConstants} from './libraries/JBConstants.sol';\nimport {JBCurrencies} from './libraries/JBCurrencies.sol';\nimport {JBFixedPointNumber} from './libraries/JBFixedPointNumber.sol';\nimport {JBFundingCycleMetadataResolver} from './libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\nimport {JBPayDelegateAllocation3_1_1} from './structs/JBPayDelegateAllocation3_1_1.sol';\nimport {JBPayParamsData} from './structs/JBPayParamsData.sol';\nimport {JBRedeemParamsData} from './structs/JBRedeemParamsData.sol';\nimport {JBRedemptionDelegateAllocation3_1_1} from './structs/JBRedemptionDelegateAllocation3_1_1.sol';\nimport {JBTokenAmount} from './structs/JBTokenAmount.sol';\n\n/// @notice Manages all bookkeeping for inflows and outflows of funds from any ISingleTokenPaymentTerminal.\n/// @dev This Store expects a project's controller to be an IJBController3_1.\ncontract JBSingleTokenPaymentTerminalStore3_1_1 is\n ReentrancyGuard,\n IJBSingleTokenPaymentTerminalStore3_1_1\n{\n // A library that parses the packed funding cycle metadata into a friendlier format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error INVALID_AMOUNT_TO_SEND_DELEGATE();\n error CURRENCY_MISMATCH();\n error DISTRIBUTION_AMOUNT_LIMIT_REACHED();\n error FUNDING_CYCLE_PAYMENT_PAUSED();\n error FUNDING_CYCLE_DISTRIBUTION_PAUSED();\n error FUNDING_CYCLE_REDEEM_PAUSED();\n error INADEQUATE_CONTROLLER_ALLOWANCE();\n error INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n error INSUFFICIENT_TOKENS();\n error INVALID_FUNDING_CYCLE();\n error PAYMENT_TERMINAL_MIGRATION_NOT_ALLOWED();\n\n //*********************************************************************//\n // -------------------------- private constants ---------------------- //\n //*********************************************************************//\n\n /// @notice Ensures a maximum number of decimal points of persisted fidelity on mulDiv operations of fixed point numbers.\n uint256 private constant _MAX_FIXED_POINT_FIDELITY = 18;\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n /// @notice The contract storing all funding cycle configurations.\n IJBFundingCycleStore public immutable override fundingCycleStore;\n\n /// @notice The contract that exposes price feeds.\n IJBPrices public immutable override prices;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The amount of tokens that each project has for each terminal, in terms of the terminal's token.\n /// @dev The balance is represented as a fixed point number with the same amount of decimals as its relative terminal.\n /// @custom:param _terminal The terminal to which the balance applies.\n /// @custom:param _projectId The ID of the project to get the balance of.\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => uint256)) public override balanceOf;\n\n /// @notice The amount of funds that a project has distributed from its limit during the current funding cycle for each terminal, in terms of the distribution limit's currency.\n /// @dev Increases as projects use their preconfigured distribution limits.\n /// @dev The used distribution limit is represented as a fixed point number with the same amount of decimals as its relative terminal.\n /// @custom:param _terminal The terminal to which the used distribution limit applies.\n /// @custom:param _projectId The ID of the project to get the used distribution limit of.\n /// @custom:param _fundingCycleNumber The number of the funding cycle during which the distribution limit was used.\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => mapping(uint256 => uint256)))\n public\n override usedDistributionLimitOf;\n\n /// @notice The amount of funds that a project has used from its allowance during the current funding cycle configuration for each terminal, in terms of the overflow allowance's currency.\n /// @dev Increases as projects use their allowance.\n /// @dev The used allowance is represented as a fixed point number with the same amount of decimals as its relative terminal.\n /// @custom:param _terminal The terminal to which the overflow allowance applies.\n /// @custom:param _projectId The ID of the project to get the used overflow allowance of.\n /// @custom:param _configuration The configuration of the during which the allowance was used.\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => mapping(uint256 => uint256)))\n public\n override usedOverflowAllowanceOf;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Gets the current overflowed amount in a terminal for a specified project.\n /// @dev The current overflow is represented as a fixed point number with the same amount of decimals as the specified terminal.\n /// @param _terminal The terminal for which the overflow is being calculated.\n /// @param _projectId The ID of the project to get overflow for.\n /// @return The current amount of overflow that project has in the specified terminal.\n function currentOverflowOf(\n IJBSingleTokenPaymentTerminal _terminal,\n uint256 _projectId\n ) external view override returns (uint256) {\n // Return the overflow during the project's current funding cycle.\n return\n _overflowDuring(\n _terminal,\n _projectId,\n fundingCycleStore.currentOf(_projectId),\n _terminal.currency()\n );\n }\n\n /// @notice Gets the current overflowed amount for a specified project across all terminals.\n /// @param _projectId The ID of the project to get total overflow for.\n /// @param _decimals The number of decimals that the fixed point overflow should include.\n /// @param _currency The currency that the total overflow should be in terms of.\n /// @return The current total amount of overflow that project has across all terminals.\n function currentTotalOverflowOf(\n uint256 _projectId,\n uint256 _decimals,\n uint256 _currency\n ) external view override returns (uint256) {\n return _currentTotalOverflowOf(_projectId, _decimals, _currency);\n }\n\n /// @notice The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the total token supply and overflow in the ecosystem.\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\n /// @dev The current reclaimable overflow is returned in terms of the specified terminal's currency.\n /// @dev The reclaimable overflow is represented as a fixed point number with the same amount of decimals as the specified terminal.\n /// @param _terminal The terminal from which the reclaimable amount would come.\n /// @param _projectId The ID of the project to get the reclaimable overflow amount for.\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _useTotalOverflow A flag indicating whether the overflow used in the calculation should be summed from all of the project's terminals. If false, overflow should be limited to the amount in the specified `_terminal`.\n /// @return The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_terminal`.\n function currentReclaimableOverflowOf(\n IJBSingleTokenPaymentTerminal _terminal,\n uint256 _projectId,\n uint256 _tokenCount,\n bool _useTotalOverflow\n ) external view override returns (uint256) {\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Get the amount of current overflow.\n // Use the project's total overflow across all of its terminals if the flag species specifies so. Otherwise, use the overflow local to the specified terminal.\n uint256 _currentOverflow = _useTotalOverflow\n ? _currentTotalOverflowOf(_projectId, _terminal.decimals(), _terminal.currency())\n : _overflowDuring(_terminal, _projectId, _fundingCycle, _terminal.currency());\n\n // If there's no overflow, there's no reclaimable overflow.\n if (_currentOverflow == 0) return 0;\n\n // Get the number of outstanding tokens the project has.\n uint256 _totalSupply = IJBController3_1(directory.controllerOf(_projectId))\n .totalOutstandingTokensOf(_projectId);\n\n // Can't redeem more tokens that is in the supply.\n if (_tokenCount > _totalSupply) return 0;\n\n // Return the reclaimable overflow amount.\n return\n _reclaimableOverflowDuring(\n _projectId,\n _fundingCycle,\n _tokenCount,\n _totalSupply,\n _currentOverflow\n );\n }\n\n /// @notice The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the specified total token supply and overflow amounts.\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\n /// @param _projectId The ID of the project to get the reclaimable overflow amount for.\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _totalSupply The total number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _overflow The amount of overflow to make the calculation with, as a fixed point number.\n /// @return The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_overflow`.\n function currentReclaimableOverflowOf(\n uint256 _projectId,\n uint256 _tokenCount,\n uint256 _totalSupply,\n uint256 _overflow\n ) external view override returns (uint256) {\n // If there's no overflow, there's no reclaimable overflow.\n if (_overflow == 0) return 0;\n\n // Can't redeem more tokens that is in the supply.\n if (_tokenCount > _totalSupply) return 0;\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Return the reclaimable overflow amount.\n return\n _reclaimableOverflowDuring(_projectId, _fundingCycle, _tokenCount, _totalSupply, _overflow);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _fundingCycleStore A contract storing all funding cycle configurations.\n /// @param _prices A contract that exposes price feeds.\n constructor(IJBDirectory _directory, IJBFundingCycleStore _fundingCycleStore, IJBPrices _prices) {\n directory = _directory;\n fundingCycleStore = _fundingCycleStore;\n prices = _prices;\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Records newly contributed tokens to a project.\n /// @dev Mints the project's tokens according to values provided by a configured data source. If no data source is configured, mints tokens proportional to the amount of the contribution.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.sender's tokens.\n /// @param _payer The original address that sent the payment to the terminal.\n /// @param _amount The amount of tokens being paid. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\n /// @param _projectId The ID of the project being paid.\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _beneficiary The specified address that should be the beneficiary of anything that results from the payment.\n /// @param _memo A memo to pass along to the emitted event, and passed along to the funding cycle's data source.\n /// @param _metadata Bytes to send along to the data source, if one is provided.\n /// @return fundingCycle The project's funding cycle during which payment was made.\n /// @return tokenCount The number of project tokens that were minted, as a fixed point number with 18 decimals.\n /// @return delegateAllocations The amount to send to delegates instead of adding to the local balance.\n /// @return memo A memo that should be passed along to the emitted event.\n function recordPaymentFrom(\n address _payer,\n JBTokenAmount calldata _amount,\n uint256 _projectId,\n uint256 _baseWeightCurrency,\n address _beneficiary,\n string calldata _memo,\n bytes memory _metadata\n )\n external\n override\n nonReentrant\n returns (\n JBFundingCycle memory fundingCycle,\n uint256 tokenCount,\n JBPayDelegateAllocation3_1_1[] memory delegateAllocations,\n string memory memo\n )\n {\n // Get a reference to the current funding cycle for the project.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // The project must have a funding cycle configured.\n if (fundingCycle.number == 0) revert INVALID_FUNDING_CYCLE();\n\n // Must not be paused.\n if (fundingCycle.payPaused()) revert FUNDING_CYCLE_PAYMENT_PAUSED();\n\n // The weight according to which new token supply is to be minted, as a fixed point number with 18 decimals.\n uint256 _weight;\n\n // If the funding cycle has configured a data source, use it to derive a weight and memo.\n if (fundingCycle.useDataSourceForPay() && fundingCycle.dataSource() != address(0)) {\n // Create the params that'll be sent to the data source.\n JBPayParamsData memory _data = JBPayParamsData(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _payer,\n _amount,\n _projectId,\n fundingCycle.configuration,\n _beneficiary,\n fundingCycle.weight,\n fundingCycle.reservedRate(),\n _memo,\n _metadata\n );\n (_weight, memo, delegateAllocations) = IJBFundingCycleDataSource3_1_1(\n fundingCycle.dataSource()\n ).payParams(_data);\n }\n // Otherwise use the funding cycle's weight\n else {\n _weight = fundingCycle.weight;\n memo = _memo;\n }\n\n // Scoped section prevents stack too deep. `_balanceDiff` only used within scope.\n {\n // Keep a reference to the amount that should be added to the project's balance.\n uint256 _balanceDiff = _amount.value;\n\n // Validate all delegated amounts. This needs to be done before returning the delegate allocations to ensure valid delegated amounts.\n if (delegateAllocations.length != 0) {\n for (uint256 _i; _i < delegateAllocations.length; ) {\n // Get a reference to the amount to be delegated.\n uint256 _delegatedAmount = delegateAllocations[_i].amount;\n\n // Validate if non-zero.\n if (_delegatedAmount != 0) {\n // Can't delegate more than was paid.\n if (_delegatedAmount > _balanceDiff) revert INVALID_AMOUNT_TO_SEND_DELEGATE();\n\n // Decrement the total amount being added to the balance.\n _balanceDiff = _balanceDiff - _delegatedAmount;\n }\n\n unchecked {\n ++_i;\n }\n }\n }\n\n // If there's no amount being recorded, there's nothing left to do.\n if (_amount.value == 0) return (fundingCycle, 0, delegateAllocations, memo);\n\n // Add the correct balance difference to the token balance of the project.\n if (_balanceDiff != 0)\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] +\n _balanceDiff;\n }\n\n // If there's no weight, token count must be 0 so there's nothing left to do.\n if (_weight == 0) return (fundingCycle, 0, delegateAllocations, memo);\n\n // Get a reference to the number of decimals in the amount. (prevents stack too deep).\n uint256 _decimals = _amount.decimals;\n\n // If the terminal should base its weight on a different currency from the terminal's currency, determine the factor.\n // The weight is always a fixed point mumber with 18 decimals. To ensure this, the ratio should use the same number of decimals as the `_amount`.\n uint256 _weightRatio = _amount.currency == _baseWeightCurrency\n ? 10 ** _decimals\n : prices.priceFor(_amount.currency, _baseWeightCurrency, _decimals);\n\n // Find the number of tokens to mint, as a fixed point number with as many decimals as `weight` has.\n tokenCount = PRBMath.mulDiv(_amount.value, _weight, _weightRatio);\n }\n\n /// @notice Records newly redeemed tokens of a project.\n /// @dev Redeems the project's tokens according to values provided by a configured data source. If no data source is configured, redeems tokens along a redemption bonding curve that is a function of the number of tokens being burned.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.senders tokens.\n /// @param _holder The account that is having its tokens redeemed.\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\n /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the data source, if one is provided.\n /// @return fundingCycle The funding cycle during which the redemption was made.\n /// @return reclaimAmount The amount of terminal tokens reclaimed, as a fixed point number with 18 decimals.\n /// @return delegateAllocations The amount to send to delegates instead of sending to the beneficiary.\n /// @return memo A memo that should be passed along to the emitted event.\n function recordRedemptionFor(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n string memory _memo,\n bytes memory _metadata\n )\n external\n override\n nonReentrant\n returns (\n JBFundingCycle memory fundingCycle,\n uint256 reclaimAmount,\n JBRedemptionDelegateAllocation3_1_1[] memory delegateAllocations,\n string memory memo\n )\n {\n // Get a reference to the project's current funding cycle.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // The current funding cycle must not be paused.\n if (fundingCycle.redeemPaused()) revert FUNDING_CYCLE_REDEEM_PAUSED();\n\n // Scoped section prevents stack too deep. `_reclaimedTokenAmount`, `_currentOverflow`, and `_totalSupply` only used within scope.\n {\n // Get a reference to the reclaimed token amount struct, the current overflow, and the total token supply.\n JBTokenAmount memory _reclaimedTokenAmount;\n uint256 _currentOverflow;\n uint256 _totalSupply;\n\n // Another scoped section prevents stack too deep. `_token`, `_decimals`, and `_currency` only used within scope.\n {\n // Get a reference to the terminal's tokens.\n address _token = IJBSingleTokenPaymentTerminal(msg.sender).token();\n\n // Get a reference to the terminal's decimals.\n uint256 _decimals = IJBSingleTokenPaymentTerminal(msg.sender).decimals();\n\n // Get areference to the terminal's currency.\n uint256 _currency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\n\n // Get the amount of current overflow.\n // Use the local overflow if the funding cycle specifies that it should be used. Otherwise, use the project's total overflow across all of its terminals.\n _currentOverflow = fundingCycle.useTotalOverflowForRedemptions()\n ? _currentTotalOverflowOf(_projectId, _decimals, _currency)\n : _overflowDuring(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _projectId,\n fundingCycle,\n _currency\n );\n\n // Get the number of outstanding tokens the project has.\n _totalSupply = IJBController3_1(directory.controllerOf(_projectId))\n .totalOutstandingTokensOf(_projectId);\n\n // Can't redeem more tokens that is in the supply.\n if (_tokenCount > _totalSupply) revert INSUFFICIENT_TOKENS();\n\n if (_currentOverflow != 0)\n // Calculate reclaim amount using the current overflow amount.\n reclaimAmount = _reclaimableOverflowDuring(\n _projectId,\n fundingCycle,\n _tokenCount,\n _totalSupply,\n _currentOverflow\n );\n\n _reclaimedTokenAmount = JBTokenAmount(_token, reclaimAmount, _decimals, _currency);\n }\n\n // If the funding cycle has configured a data source, use it to derive a claim amount and memo.\n if (fundingCycle.useDataSourceForRedeem() && fundingCycle.dataSource() != address(0)) {\n // Yet another scoped section prevents stack too deep. `_state` only used within scope.\n {\n // Get a reference to the ballot state.\n JBBallotState _state = fundingCycleStore.currentBallotStateOf(_projectId);\n\n // Create the params that'll be sent to the data source.\n JBRedeemParamsData memory _data = JBRedeemParamsData(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _holder,\n _projectId,\n fundingCycle.configuration,\n _tokenCount,\n _totalSupply,\n _currentOverflow,\n _reclaimedTokenAmount,\n fundingCycle.useTotalOverflowForRedemptions(),\n _state == JBBallotState.Active\n ? fundingCycle.ballotRedemptionRate()\n : fundingCycle.redemptionRate(),\n _memo,\n _metadata\n );\n (reclaimAmount, memo, delegateAllocations) = IJBFundingCycleDataSource3_1_1(\n fundingCycle.dataSource()\n ).redeemParams(_data);\n }\n } else {\n memo = _memo;\n }\n }\n\n // Keep a reference to the amount that should be subtracted from the project's balance.\n uint256 _balanceDiff = reclaimAmount;\n\n if (delegateAllocations.length != 0) {\n // Validate all delegated amounts.\n for (uint256 _i; _i < delegateAllocations.length; ) {\n // Get a reference to the amount to be delegated.\n uint256 _delegatedAmount = delegateAllocations[_i].amount;\n\n // Validate if non-zero.\n if (_delegatedAmount != 0)\n // Increment the total amount being subtracted from the balance.\n _balanceDiff = _balanceDiff + _delegatedAmount;\n\n unchecked {\n ++_i;\n }\n }\n }\n\n // The amount being reclaimed must be within the project's balance.\n if (_balanceDiff > balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId])\n revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n\n // Remove the reclaimed funds from the project's balance.\n if (_balanceDiff != 0) {\n unchecked {\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\n _balanceDiff;\n }\n }\n }\n\n /// @notice Records newly distributed funds for a project.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\n /// @param _projectId The ID of the project that is having funds distributed.\n /// @param _amount The amount to use from the distribution limit, as a fixed point number.\n /// @param _currency The currency of the `_amount`. This must match the project's current funding cycle's currency.\n /// @return fundingCycle The funding cycle during which the distribution was made.\n /// @return distributedAmount The amount of terminal tokens distributed, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordDistributionFor(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency\n )\n external\n override\n nonReentrant\n returns (JBFundingCycle memory fundingCycle, uint256 distributedAmount)\n {\n // Get a reference to the project's current funding cycle.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // The funding cycle must not be configured to have distributions paused.\n if (fundingCycle.distributionsPaused()) revert FUNDING_CYCLE_DISTRIBUTION_PAUSED();\n\n // The new total amount that has been distributed during this funding cycle.\n uint256 _newUsedDistributionLimitOf = usedDistributionLimitOf[\n IJBSingleTokenPaymentTerminal(msg.sender)\n ][_projectId][fundingCycle.number] + _amount;\n\n // Amount must be within what is still distributable.\n (uint256 _distributionLimitOf, uint256 _distributionLimitCurrencyOf) = IJBController3_1(\n directory.controllerOf(_projectId)\n ).fundAccessConstraintsStore().distributionLimitOf(\n _projectId,\n fundingCycle.configuration,\n IJBSingleTokenPaymentTerminal(msg.sender),\n IJBSingleTokenPaymentTerminal(msg.sender).token()\n );\n\n // Make sure the new used amount is within the distribution limit.\n if (_newUsedDistributionLimitOf > _distributionLimitOf || _distributionLimitOf == 0)\n revert DISTRIBUTION_AMOUNT_LIMIT_REACHED();\n\n // Make sure the currencies match.\n if (_currency != _distributionLimitCurrencyOf) revert CURRENCY_MISMATCH();\n\n // Get a reference to the terminal's currency.\n uint256 _balanceCurrency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\n\n // Convert the amount to the balance's currency.\n distributedAmount = (_currency == _balanceCurrency)\n ? _amount\n : PRBMath.mulDiv(\n _amount,\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\n prices.priceFor(_currency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\n );\n\n // The amount being distributed must be available.\n if (distributedAmount > balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId])\n revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n\n // Store the new amount.\n usedDistributionLimitOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId][\n fundingCycle.number\n ] = _newUsedDistributionLimitOf;\n\n // Removed the distributed funds from the project's token balance.\n unchecked {\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\n distributedAmount;\n }\n }\n\n /// @notice Records newly used allowance funds of a project.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\n /// @param _projectId The ID of the project to use the allowance of.\n /// @param _amount The amount to use from the allowance, as a fixed point number.\n /// @param _currency The currency of the `_amount`. Must match the currency of the overflow allowance.\n /// @return fundingCycle The funding cycle during which the overflow allowance is being used.\n /// @return usedAmount The amount of terminal tokens used, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordUsedAllowanceOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency\n )\n external\n override\n nonReentrant\n returns (JBFundingCycle memory fundingCycle, uint256 usedAmount)\n {\n // Get a reference to the project's current funding cycle.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Get a reference to the new used overflow allowance for this funding cycle configuration.\n uint256 _newUsedOverflowAllowanceOf = usedOverflowAllowanceOf[\n IJBSingleTokenPaymentTerminal(msg.sender)\n ][_projectId][fundingCycle.configuration] + _amount;\n\n // There must be sufficient allowance available.\n (uint256 _overflowAllowanceOf, uint256 _overflowAllowanceCurrency) = IJBController3_1(\n directory.controllerOf(_projectId)\n ).fundAccessConstraintsStore().overflowAllowanceOf(\n _projectId,\n fundingCycle.configuration,\n IJBSingleTokenPaymentTerminal(msg.sender),\n IJBSingleTokenPaymentTerminal(msg.sender).token()\n );\n\n // Make sure the new used amount is within the allowance.\n if (_newUsedOverflowAllowanceOf > _overflowAllowanceOf || _overflowAllowanceOf == 0)\n revert INADEQUATE_CONTROLLER_ALLOWANCE();\n\n // Make sure the currencies match.\n if (_currency != _overflowAllowanceCurrency) revert CURRENCY_MISMATCH();\n\n // Get a reference to the terminal's currency.\n uint256 _balanceCurrency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\n\n // Convert the amount to this store's terminal's token.\n usedAmount = (_currency == _balanceCurrency)\n ? _amount\n : PRBMath.mulDiv(\n _amount,\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\n prices.priceFor(_currency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\n );\n\n // The amount being distributed must be available in the overflow.\n if (\n usedAmount >\n _overflowDuring(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _projectId,\n fundingCycle,\n _balanceCurrency\n )\n ) revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n\n // Store the incremented value.\n usedOverflowAllowanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId][\n fundingCycle.configuration\n ] = _newUsedOverflowAllowanceOf;\n\n // Update the project's balance.\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\n usedAmount;\n }\n\n /// @notice Records newly added funds for the project.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\n /// @param _projectId The ID of the project to which the funds being added belong.\n /// @param _amount The amount of terminal tokens added, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordAddedBalanceFor(uint256 _projectId, uint256 _amount) external override {\n // Increment the balance.\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] +\n _amount;\n }\n\n /// @notice Records the migration of funds from this store.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount returned is in terms of the msg.senders tokens.\n /// @param _projectId The ID of the project being migrated.\n /// @return balance The project's migrated balance, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordMigration(\n uint256 _projectId\n ) external override nonReentrant returns (uint256 balance) {\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Migration must be allowed.\n if (!_fundingCycle.terminalMigrationAllowed()) revert PAYMENT_TERMINAL_MIGRATION_NOT_ALLOWED();\n\n // Return the current balance.\n balance = balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId];\n\n // Set the balance to 0.\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] = 0;\n }\n\n //*********************************************************************//\n // --------------------- private helper functions -------------------- //\n //*********************************************************************//\n\n /// @notice The amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens when measured from the specified.\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\n /// @param _projectId The ID of the project to get the reclaimable overflow amount for.\n /// @param _fundingCycle The funding cycle during which reclaimable overflow is being calculated.\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _totalSupply The total supply of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _overflow The amount of overflow to make the calculation with.\n /// @return The amount of overflowed tokens that can be reclaimed.\n function _reclaimableOverflowDuring(\n uint256 _projectId,\n JBFundingCycle memory _fundingCycle,\n uint256 _tokenCount,\n uint256 _totalSupply,\n uint256 _overflow\n ) private view returns (uint256) {\n // If the amount being redeemed is the total supply, return the rest of the overflow.\n if (_tokenCount == _totalSupply) return _overflow;\n\n // Use the ballot redemption rate if the queued cycle is pending approval according to the previous funding cycle's ballot.\n uint256 _redemptionRate = fundingCycleStore.currentBallotStateOf(_projectId) ==\n JBBallotState.Active\n ? _fundingCycle.ballotRedemptionRate()\n : _fundingCycle.redemptionRate();\n\n // If the redemption rate is 0, nothing is claimable.\n if (_redemptionRate == 0) return 0;\n\n // Get a reference to the linear proportion.\n uint256 _base = PRBMath.mulDiv(_overflow, _tokenCount, _totalSupply);\n\n // These conditions are all part of the same curve. Edge conditions are separated because fewer operation are necessary.\n if (_redemptionRate == JBConstants.MAX_REDEMPTION_RATE) return _base;\n\n return\n PRBMath.mulDiv(\n _base,\n _redemptionRate +\n PRBMath.mulDiv(\n _tokenCount,\n JBConstants.MAX_REDEMPTION_RATE - _redemptionRate,\n _totalSupply\n ),\n JBConstants.MAX_REDEMPTION_RATE\n );\n }\n\n /// @notice Gets the amount that is overflowing when measured from the specified funding cycle.\n /// @dev This amount changes as the value of the balance changes in relation to the currency being used to measure the distribution limit.\n /// @param _terminal The terminal for which the overflow is being calculated.\n /// @param _projectId The ID of the project to get overflow for.\n /// @param _fundingCycle The ID of the funding cycle to base the overflow on.\n /// @param _balanceCurrency The currency that the stored balance is expected to be in terms of.\n /// @return overflow The overflow of funds, as a fixed point number with 18 decimals.\n function _overflowDuring(\n IJBSingleTokenPaymentTerminal _terminal,\n uint256 _projectId,\n JBFundingCycle memory _fundingCycle,\n uint256 _balanceCurrency\n ) private view returns (uint256) {\n // Get the current balance of the project.\n uint256 _balanceOf = balanceOf[_terminal][_projectId];\n\n // If there's no balance, there's no overflow.\n if (_balanceOf == 0) return 0;\n\n // Get a reference to the distribution limit during the funding cycle.\n (uint256 _distributionLimit, uint256 _distributionLimitCurrency) = IJBController3_1(\n directory.controllerOf(_projectId)\n ).fundAccessConstraintsStore().distributionLimitOf(\n _projectId,\n _fundingCycle.configuration,\n _terminal,\n _terminal.token()\n );\n\n // Get a reference to the amount still distributable during the funding cycle.\n uint256 _distributionLimitRemaining = _distributionLimit -\n usedDistributionLimitOf[_terminal][_projectId][_fundingCycle.number];\n\n // Convert the _distributionRemaining to be in terms of the provided currency.\n if (_distributionLimitRemaining != 0 && _distributionLimitCurrency != _balanceCurrency)\n _distributionLimitRemaining = PRBMath.mulDiv(\n _distributionLimitRemaining,\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\n prices.priceFor(_distributionLimitCurrency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\n );\n\n // Overflow is the balance of this project minus the amount that can still be distributed.\n unchecked {\n return\n _balanceOf > _distributionLimitRemaining ? _balanceOf - _distributionLimitRemaining : 0;\n }\n }\n\n /// @notice Gets the amount that is currently overflowing across all of a project's terminals.\n /// @dev This amount changes as the value of the balances changes in relation to the currency being used to measure the project's distribution limits.\n /// @param _projectId The ID of the project to get the total overflow for.\n /// @param _decimals The number of decimals that the fixed point overflow should include.\n /// @param _currency The currency that the overflow should be in terms of.\n /// @return overflow The total overflow of a project's funds.\n function _currentTotalOverflowOf(\n uint256 _projectId,\n uint256 _decimals,\n uint256 _currency\n ) private view returns (uint256) {\n // Get a reference to the project's terminals.\n IJBPaymentTerminal[] memory _terminals = directory.terminalsOf(_projectId);\n\n // Keep a reference to the ETH overflow across all terminals, as a fixed point number with 18 decimals.\n uint256 _ethOverflow;\n\n // Add the current ETH overflow for each terminal.\n for (uint256 _i; _i < _terminals.length; ) {\n _ethOverflow = _ethOverflow + _terminals[_i].currentEthOverflowOf(_projectId);\n unchecked {\n ++_i;\n }\n }\n\n // Convert the ETH overflow to the specified currency if needed, maintaining a fixed point number with 18 decimals.\n uint256 _totalOverflow18Decimal = _currency == JBCurrencies.ETH\n ? _ethOverflow\n : PRBMath.mulDiv(_ethOverflow, 10 ** 18, prices.priceFor(JBCurrencies.ETH, _currency, 18));\n\n // Adjust the decimals of the fixed point number if needed to match the target decimals.\n return\n (_decimals == 18)\n ? _totalOverflow18Decimal\n : JBFixedPointNumber.adjustDecimals(_totalOverflow18Decimal, 18, _decimals);\n }\n}\n" + }, + "contracts/interfaces/IJBFundingCycleDataSource3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBPayDelegateAllocation3_1_1} from './../structs/JBPayDelegateAllocation3_1_1.sol';\nimport {JBPayParamsData} from './../structs/JBPayParamsData.sol';\nimport {JBRedeemParamsData} from './../structs/JBRedeemParamsData.sol';\nimport {JBRedemptionDelegateAllocation3_1_1} from './../structs/JBRedemptionDelegateAllocation3_1_1.sol';\n\n/// @title Datasource\n/// @notice The datasource is called by JBPayoutRedemptionPaymentTerminals on pay and redemption, and provide an extra layer of logic to use a custom weight, a custom memo and/or a pay/redeem delegate\ninterface IJBFundingCycleDataSource3_1_1 is IERC165 {\n /// @notice The datasource implementation for JBPaymentTerminal.pay(..)\n /// @param data the data passed to the data source in terminal.pay(..), as a JBPayParamsData struct:\n /// @return weight the weight to use to override the funding cycle weight\n /// @return memo the memo to override the pay(..) memo\n /// @return delegateAllocations The amount to send to delegates instead of adding to the local balance.\n function payParams(\n JBPayParamsData calldata data\n )\n external\n returns (\n uint256 weight,\n string memory memo,\n JBPayDelegateAllocation3_1_1[] memory delegateAllocations\n );\n\n /// @notice The datasource implementation for JBPaymentTerminal.redeemTokensOf(..)\n /// @param data the data passed to the data source in terminal.redeemTokensOf(..), as a JBRedeemParamsData struct:\n /// @return reclaimAmount The amount to claim, overriding the terminal logic.\n /// @return memo The memo to override the redeemTokensOf(..) memo.\n /// @return delegateAllocations The amount to send to delegates instead of adding to the beneficiary.\n function redeemParams(\n JBRedeemParamsData calldata data\n )\n external\n returns (\n uint256 reclaimAmount,\n string memory memo,\n JBRedemptionDelegateAllocation3_1_1[] memory delegateAllocations\n );\n}\n" + }, + "contracts/interfaces/IJBSingleTokenPaymentTerminalStore3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\nimport {JBPayDelegateAllocation3_1_1} from './../structs/JBPayDelegateAllocation3_1_1.sol';\nimport {JBRedemptionDelegateAllocation3_1_1} from './../structs/JBRedemptionDelegateAllocation3_1_1.sol';\nimport {JBTokenAmount} from './../structs/JBTokenAmount.sol';\nimport {IJBDirectory} from './IJBDirectory.sol';\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\nimport {IJBPrices} from './IJBPrices.sol';\nimport {IJBSingleTokenPaymentTerminal} from './IJBSingleTokenPaymentTerminal.sol';\n\ninterface IJBSingleTokenPaymentTerminalStore3_1_1 {\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\n\n function directory() external view returns (IJBDirectory);\n\n function prices() external view returns (IJBPrices);\n\n function balanceOf(\n IJBSingleTokenPaymentTerminal terminal,\n uint256 projectId\n ) external view returns (uint256);\n\n function usedDistributionLimitOf(\n IJBSingleTokenPaymentTerminal terminal,\n uint256 projectId,\n uint256 fundingCycleNumber\n ) external view returns (uint256);\n\n function usedOverflowAllowanceOf(\n IJBSingleTokenPaymentTerminal terminal,\n uint256 projectId,\n uint256 fundingCycleConfiguration\n ) external view returns (uint256);\n\n function currentOverflowOf(\n IJBSingleTokenPaymentTerminal terminal,\n uint256 projectId\n ) external view returns (uint256);\n\n function currentTotalOverflowOf(\n uint256 projectId,\n uint256 decimals,\n uint256 currency\n ) external view returns (uint256);\n\n function currentReclaimableOverflowOf(\n IJBSingleTokenPaymentTerminal terminal,\n uint256 projectId,\n uint256 tokenCount,\n bool useTotalOverflow\n ) external view returns (uint256);\n\n function currentReclaimableOverflowOf(\n uint256 projectId,\n uint256 tokenCount,\n uint256 totalSupply,\n uint256 overflow\n ) external view returns (uint256);\n\n function recordPaymentFrom(\n address payer,\n JBTokenAmount memory amount,\n uint256 projectId,\n uint256 baseWeightCurrency,\n address beneficiary,\n string calldata inputMemo,\n bytes calldata metadata\n )\n external\n returns (\n JBFundingCycle memory fundingCycle,\n uint256 tokenCount,\n JBPayDelegateAllocation3_1_1[] memory delegateAllocations,\n string memory outputMemo\n );\n\n function recordRedemptionFor(\n address holder,\n uint256 projectId,\n uint256 tokenCount,\n string calldata inputMemo,\n bytes calldata metadata\n )\n external\n returns (\n JBFundingCycle memory fundingCycle,\n uint256 reclaimAmount,\n JBRedemptionDelegateAllocation3_1_1[] memory delegateAllocations,\n string memory outputMemo\n );\n\n function recordDistributionFor(\n uint256 projectId,\n uint256 amount,\n uint256 currency\n ) external returns (JBFundingCycle memory fundingCycle, uint256 distributedAmount);\n\n function recordUsedAllowanceOf(\n uint256 projectId,\n uint256 amount,\n uint256 currency\n ) external returns (JBFundingCycle memory fundingCycle, uint256 withdrawnAmount);\n\n function recordAddedBalanceFor(uint256 projectId, uint256 amount) external;\n\n function recordMigration(uint256 projectId) external returns (uint256 balance);\n}\n" + }, + "contracts/structs/JBPayDelegateAllocation3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBPayDelegate3_1_1} from '../interfaces/IJBPayDelegate3_1_1.sol';\n\n/// @custom:member delegate A delegate contract to use for subsequent calls.\n/// @custom:member amount The amount to send to the delegate.\n/// @custom:member metadata Metadata to pass the delegate.\nstruct JBPayDelegateAllocation3_1_1 {\n IJBPayDelegate3_1_1 delegate;\n uint256 amount;\n bytes metadata;\n}\n" + }, + "contracts/structs/JBRedemptionDelegateAllocation3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBRedemptionDelegate3_1_1} from '../interfaces/IJBRedemptionDelegate3_1_1.sol';\n\n/// @custom:member delegate A delegate contract to use for subsequent calls.\n/// @custom:member amount The amount to send to the delegate.\n/// @custom:member metadata Metadata to pass the delegate.\nstruct JBRedemptionDelegateAllocation3_1_1 {\n IJBRedemptionDelegate3_1_1 delegate;\n uint256 amount;\n bytes metadata;\n}\n" + }, + "contracts/interfaces/IJBPayDelegate3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBDidPayData3_1_1} from './../structs/JBDidPayData3_1_1.sol';\n\n/// @title Pay delegate\n/// @notice Delegate called after JBTerminal.pay(..) logic completion (if passed by the funding cycle datasource)\ninterface IJBPayDelegate3_1_1 is IERC165 {\n /// @notice This function is called by JBPaymentTerminal.pay(..), after the execution of its logic\n /// @dev Critical business logic should be protected by an appropriate access control\n /// @param data the data passed by the terminal, as a JBDidPayData3_1_1 struct:\n function didPay(JBDidPayData3_1_1 calldata data) external payable;\n}\n" + }, + "contracts/structs/JBDidPayData3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBTokenAmount} from './JBTokenAmount.sol';\n\n/// @custom:member payer The address from which the payment originated.\n/// @custom:member projectId The ID of the project for which the payment was made.\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the payment is being made.\n/// @custom:member amount The amount of the payment. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\n/// @custom:member forwardedAmount The amount of the payment that is being sent to the delegate. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\n/// @custom:member projectTokenCount The number of project tokens minted for the beneficiary.\n/// @custom:member beneficiary The address to which the tokens were minted.\n/// @custom:member preferClaimedTokens A flag indicating whether the request prefered to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract.\n/// @custom:member memo The memo that is being emitted alongside the payment.\n/// @custom:member dataSourceMetadata Extra data to send to the delegate sent by the data source.\n/// @custom:member payerMetadata Extra data to send to the delegate sent by the payer.\nstruct JBDidPayData3_1_1 {\n address payer;\n uint256 projectId;\n uint256 currentFundingCycleConfiguration;\n JBTokenAmount amount;\n JBTokenAmount forwardedAmount;\n uint256 projectTokenCount;\n address beneficiary;\n bool preferClaimedTokens;\n string memo;\n bytes dataSourceMetadata;\n bytes payerMetadata;\n}\n" + }, + "contracts/interfaces/IJBRedemptionDelegate3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBDidRedeemData3_1_1} from './../structs/JBDidRedeemData3_1_1.sol';\n\n/// @title Redemption delegate\n/// @notice Delegate called after JBTerminal.redeemTokensOf(..) logic completion (if passed by the funding cycle datasource)\ninterface IJBRedemptionDelegate3_1_1 is IERC165 {\n /// @notice This function is called by JBPaymentTerminal.redeemTokensOf(..), after the execution of its logic\n /// @dev Critical business logic should be protected by an appropriate access control\n /// @param data the data passed by the terminal, as a JBDidRedeemData struct:\n function didRedeem(JBDidRedeemData3_1_1 calldata data) external payable;\n}\n" + }, + "contracts/structs/JBDidRedeemData3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBTokenAmount} from './JBTokenAmount.sol';\n\n/// @custom:member holder The holder of the tokens being redeemed.\n/// @custom:member projectId The ID of the project with which the redeemed tokens are associated.\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the redemption is being made.\n/// @custom:member projectTokenCount The number of project tokens being redeemed.\n/// @custom:member reclaimedAmount The amount reclaimed from the treasury. Includes the token being reclaimed, the value, the number of decimals included, and the currency of the amount.\n/// @custom:member forwardedAmount The amount of the payment that is being sent to the delegate. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\n/// @custom:member beneficiary The address to which the reclaimed amount will be sent.\n/// @custom:member memo The memo that is being emitted alongside the redemption.\n/// @custom:member dataSourceMetadata Extra data to send to the delegate sent by the data source.\n/// @custom:member redeemerMetadata Extra data to send to the delegate sent by the redeemer.\nstruct JBDidRedeemData3_1_1 {\n address holder;\n uint256 projectId;\n uint256 currentFundingCycleConfiguration;\n uint256 projectTokenCount;\n JBTokenAmount reclaimedAmount;\n JBTokenAmount forwardedAmount;\n address payable beneficiary;\n string memo;\n bytes dataSourceMetadata;\n bytes redeemerMetadata;\n}\n" + }, + "contracts/JBSingleTokenPaymentTerminalStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {ReentrancyGuard} from '@openzeppelin/contracts/security/ReentrancyGuard.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {JBBallotState} from './enums/JBBallotState.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBController} from './interfaces/IJBController.sol';\nimport {IJBFundingCycleDataSource} from './interfaces/IJBFundingCycleDataSource.sol';\nimport {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol';\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\nimport {IJBSingleTokenPaymentTerminal} from './interfaces/IJBSingleTokenPaymentTerminal.sol';\nimport {IJBSingleTokenPaymentTerminalStore} from './interfaces/IJBSingleTokenPaymentTerminalStore.sol';\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\nimport {JBConstants} from './libraries/JBConstants.sol';\nimport {JBCurrencies} from './libraries/JBCurrencies.sol';\nimport {JBFixedPointNumber} from './libraries/JBFixedPointNumber.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\nimport {JBFundingCycleMetadataResolver} from './libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBPayDelegateAllocation} from './structs/JBPayDelegateAllocation.sol';\nimport {JBPayParamsData} from './structs/JBPayParamsData.sol';\nimport {JBRedeemParamsData} from './structs/JBRedeemParamsData.sol';\nimport {JBRedemptionDelegateAllocation} from './structs/JBRedemptionDelegateAllocation.sol';\nimport {JBTokenAmount} from './structs/JBTokenAmount.sol';\n\n/// @notice Manages all bookkeeping for inflows and outflows of funds from any ISingleTokenPaymentTerminal.\ncontract JBSingleTokenPaymentTerminalStore is ReentrancyGuard, IJBSingleTokenPaymentTerminalStore {\n // A library that parses the packed funding cycle metadata into a friendlier format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error INVALID_AMOUNT_TO_SEND_DELEGATE();\n error CURRENCY_MISMATCH();\n error DISTRIBUTION_AMOUNT_LIMIT_REACHED();\n error FUNDING_CYCLE_PAYMENT_PAUSED();\n error FUNDING_CYCLE_DISTRIBUTION_PAUSED();\n error FUNDING_CYCLE_REDEEM_PAUSED();\n error INADEQUATE_CONTROLLER_ALLOWANCE();\n error INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n error INSUFFICIENT_TOKENS();\n error INVALID_FUNDING_CYCLE();\n error PAYMENT_TERMINAL_MIGRATION_NOT_ALLOWED();\n\n //*********************************************************************//\n // -------------------------- private constants ---------------------- //\n //*********************************************************************//\n\n /// @notice Ensures a maximum number of decimal points of persisted fidelity on mulDiv operations of fixed point numbers.\n uint256 private constant _MAX_FIXED_POINT_FIDELITY = 18;\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n /// @notice The contract storing all funding cycle configurations.\n IJBFundingCycleStore public immutable override fundingCycleStore;\n\n /// @notice The contract that exposes price feeds.\n IJBPrices public immutable override prices;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The amount of tokens that each project has for each terminal, in terms of the terminal's token.\n /// @dev The used distribution limit is represented as a fixed point number with the same amount of decimals as its relative terminal.\n /// @custom:param _terminal The terminal to which the balance applies.\n /// @custom:param _projectId The ID of the project to get the balance of.\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => uint256)) public override balanceOf;\n\n /// @notice The amount of funds that a project has distributed from its limit during the current funding cycle for each terminal, in terms of the distribution limit's currency.\n /// @dev Increases as projects use their preconfigured distribution limits.\n /// @dev The used distribution limit is represented as a fixed point number with the same amount of decimals as its relative terminal.\n /// @custom:param _terminal The terminal to which the used distribution limit applies.\n /// @custom:param _projectId The ID of the project to get the used distribution limit of.\n /// @custom:param _fundingCycleNumber The number of the funding cycle during which the distribution limit was used.\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => mapping(uint256 => uint256)))\n public\n override usedDistributionLimitOf;\n\n /// @notice The amount of funds that a project has used from its allowance during the current funding cycle configuration for each terminal, in terms of the overflow allowance's currency.\n /// @dev Increases as projects use their allowance.\n /// @dev The used allowance is represented as a fixed point number with the same amount of decimals as its relative terminal.\n /// @custom:param _terminal The terminal to which the overflow allowance applies.\n /// @custom:param _projectId The ID of the project to get the used overflow allowance of.\n /// @custom:param _configuration The configuration of the during which the allowance was used.\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => mapping(uint256 => uint256)))\n public\n override usedOverflowAllowanceOf;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Gets the current overflowed amount in a terminal for a specified project.\n /// @dev The current overflow is represented as a fixed point number with the same amount of decimals as the specified terminal.\n /// @param _terminal The terminal for which the overflow is being calculated.\n /// @param _projectId The ID of the project to get overflow for.\n /// @return The current amount of overflow that project has in the specified terminal.\n function currentOverflowOf(\n IJBSingleTokenPaymentTerminal _terminal,\n uint256 _projectId\n ) external view override returns (uint256) {\n // Return the overflow during the project's current funding cycle.\n return\n _overflowDuring(\n _terminal,\n _projectId,\n fundingCycleStore.currentOf(_projectId),\n _terminal.currency()\n );\n }\n\n /// @notice Gets the current overflowed amount for a specified project across all terminals.\n /// @param _projectId The ID of the project to get total overflow for.\n /// @param _decimals The number of decimals that the fixed point overflow should include.\n /// @param _currency The currency that the total overflow should be in terms of.\n /// @return The current total amount of overflow that project has across all terminals.\n function currentTotalOverflowOf(\n uint256 _projectId,\n uint256 _decimals,\n uint256 _currency\n ) external view override returns (uint256) {\n return _currentTotalOverflowOf(_projectId, _decimals, _currency);\n }\n\n /// @notice The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the total token supply and overflow in the ecosystem.\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\n /// @dev The current reclaimable overflow is returned in terms of the specified terminal's currency.\n /// @dev The reclaimable overflow is represented as a fixed point number with the same amount of decimals as the specified terminal.\n /// @param _terminal The terminal from which the reclaimable amount would come.\n /// @param _projectId The ID of the project to get the reclaimable overflow amount for.\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _useTotalOverflow A flag indicating whether the overflow used in the calculation should be summed from all of the project's terminals. If false, overflow should be limited to the amount in the specified `_terminal`.\n /// @return The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_terminal`.\n function currentReclaimableOverflowOf(\n IJBSingleTokenPaymentTerminal _terminal,\n uint256 _projectId,\n uint256 _tokenCount,\n bool _useTotalOverflow\n ) external view override returns (uint256) {\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Get the amount of current overflow.\n // Use the project's total overflow across all of its terminals if the flag species specifies so. Otherwise, use the overflow local to the specified terminal.\n uint256 _currentOverflow = _useTotalOverflow\n ? _currentTotalOverflowOf(_projectId, _terminal.decimals(), _terminal.currency())\n : _overflowDuring(_terminal, _projectId, _fundingCycle, _terminal.currency());\n\n // If there's no overflow, there's no reclaimable overflow.\n if (_currentOverflow == 0) return 0;\n\n // Get the number of outstanding tokens the project has.\n uint256 _totalSupply = IJBController(directory.controllerOf(_projectId))\n .totalOutstandingTokensOf(_projectId, _fundingCycle.reservedRate());\n\n // Can't redeem more tokens that is in the supply.\n if (_tokenCount > _totalSupply) return 0;\n\n // Return the reclaimable overflow amount.\n return\n _reclaimableOverflowDuring(\n _projectId,\n _fundingCycle,\n _tokenCount,\n _totalSupply,\n _currentOverflow\n );\n }\n\n /// @notice The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the specified total token supply and overflow amounts.\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\n /// @param _projectId The ID of the project for which the reclaimable overflow applies.\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _totalSupply The total number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _overflow The amount of overflow to make the calculation with, as a fixed point number.\n /// @return The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_overflow`.\n function currentReclaimableOverflowOf(\n uint256 _projectId,\n uint256 _tokenCount,\n uint256 _totalSupply,\n uint256 _overflow\n ) external view override returns (uint256) {\n // If there's no overflow, there's no reclaimable overflow.\n if (_overflow == 0) return 0;\n\n // Can't redeem more tokens that is in the supply.\n if (_tokenCount > _totalSupply) return 0;\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Return the reclaimable overflow amount.\n return\n _reclaimableOverflowDuring(_projectId, _fundingCycle, _tokenCount, _totalSupply, _overflow);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _fundingCycleStore A contract storing all funding cycle configurations.\n /// @param _prices A contract that exposes price feeds.\n constructor(IJBDirectory _directory, IJBFundingCycleStore _fundingCycleStore, IJBPrices _prices) {\n directory = _directory;\n fundingCycleStore = _fundingCycleStore;\n prices = _prices;\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Records newly contributed tokens to a project.\n /// @dev Mints the project's tokens according to values provided by a configured data source. If no data source is configured, mints tokens proportional to the amount of the contribution.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.sender's tokens.\n /// @param _payer The original address that sent the payment to the terminal.\n /// @param _amount The amount of tokens being paid. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\n /// @param _projectId The ID of the project being paid.\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _beneficiary The specified address that should be the beneficiary of anything that results from the payment.\n /// @param _memo A memo to pass along to the emitted event, and passed along to the funding cycle's data source.\n /// @param _metadata Bytes to send along to the data source, if one is provided.\n /// @return fundingCycle The project's funding cycle during which payment was made.\n /// @return tokenCount The number of project tokens that were minted, as a fixed point number with 18 decimals.\n /// @return delegateAllocations The amount to send to delegates instead of adding to the local balance.\n /// @return memo A memo that should be passed along to the emitted event.\n function recordPaymentFrom(\n address _payer,\n JBTokenAmount calldata _amount,\n uint256 _projectId,\n uint256 _baseWeightCurrency,\n address _beneficiary,\n string calldata _memo,\n bytes memory _metadata\n )\n external\n override\n nonReentrant\n returns (\n JBFundingCycle memory fundingCycle,\n uint256 tokenCount,\n JBPayDelegateAllocation[] memory delegateAllocations,\n string memory memo\n )\n {\n // Get a reference to the current funding cycle for the project.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // The project must have a funding cycle configured.\n if (fundingCycle.number == 0) revert INVALID_FUNDING_CYCLE();\n\n // Must not be paused.\n if (fundingCycle.payPaused()) revert FUNDING_CYCLE_PAYMENT_PAUSED();\n\n // The weight according to which new token supply is to be minted, as a fixed point number with 18 decimals.\n uint256 _weight;\n\n // If the funding cycle has configured a data source, use it to derive a weight and memo.\n if (fundingCycle.useDataSourceForPay() && fundingCycle.dataSource() != address(0)) {\n // Create the params that'll be sent to the data source.\n JBPayParamsData memory _data = JBPayParamsData(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _payer,\n _amount,\n _projectId,\n fundingCycle.configuration,\n _beneficiary,\n fundingCycle.weight,\n fundingCycle.reservedRate(),\n _memo,\n _metadata\n );\n (_weight, memo, delegateAllocations) = IJBFundingCycleDataSource(fundingCycle.dataSource())\n .payParams(_data);\n }\n // Otherwise use the funding cycle's weight\n else {\n _weight = fundingCycle.weight;\n memo = _memo;\n }\n\n // Scoped section prevents stack too deep. `_balanceDiff` only used within scope.\n {\n // Keep a reference to the amount that should be added to the project's balance.\n uint256 _balanceDiff = _amount.value;\n\n // Validate all delegated amounts. This needs to be done before returning the delegate allocations to ensure valid delegated amounts.\n if (delegateAllocations.length != 0) {\n for (uint256 _i; _i < delegateAllocations.length; ) {\n // Get a reference to the amount to be delegated.\n uint256 _delegatedAmount = delegateAllocations[_i].amount;\n\n // Validate if non-zero.\n if (_delegatedAmount != 0) {\n // Can't delegate more than was paid.\n if (_delegatedAmount > _balanceDiff) revert INVALID_AMOUNT_TO_SEND_DELEGATE();\n\n // Decrement the total amount being added to the balance.\n _balanceDiff = _balanceDiff - _delegatedAmount;\n }\n\n unchecked {\n ++_i;\n }\n }\n }\n\n // If there's no amount being recorded, there's nothing left to do.\n if (_amount.value == 0) return (fundingCycle, 0, delegateAllocations, memo);\n\n // Add the correct balance difference to the token balance of the project.\n if (_balanceDiff != 0)\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] +\n _balanceDiff;\n }\n\n // If there's no weight, token count must be 0 so there's nothing left to do.\n if (_weight == 0) return (fundingCycle, 0, delegateAllocations, memo);\n\n // Get a reference to the number of decimals in the amount. (prevents stack too deep).\n uint256 _decimals = _amount.decimals;\n\n // If the terminal should base its weight on a different currency from the terminal's currency, determine the factor.\n // The weight is always a fixed point mumber with 18 decimals. To ensure this, the ratio should use the same number of decimals as the `_amount`.\n uint256 _weightRatio = _amount.currency == _baseWeightCurrency\n ? 10 ** _decimals\n : prices.priceFor(_amount.currency, _baseWeightCurrency, _decimals);\n\n // Find the number of tokens to mint, as a fixed point number with as many decimals as `weight` has.\n tokenCount = PRBMath.mulDiv(_amount.value, _weight, _weightRatio);\n }\n\n /// @notice Records newly redeemed tokens of a project.\n /// @dev Redeems the project's tokens according to values provided by a configured data source. If no data source is configured, redeems tokens along a redemption bonding curve that is a function of the number of tokens being burned.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.senders tokens.\n /// @param _holder The account that is having its tokens redeemed.\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\n /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the data source, if one is provided.\n /// @return fundingCycle The funding cycle during which the redemption was made.\n /// @return reclaimAmount The amount of terminal tokens reclaimed, as a fixed point number with 18 decimals.\n /// @return delegateAllocations The amount to send to delegates instead of sending to the beneficiary.\n /// @return memo A memo that should be passed along to the emitted event.\n function recordRedemptionFor(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n string memory _memo,\n bytes memory _metadata\n )\n external\n override\n nonReentrant\n returns (\n JBFundingCycle memory fundingCycle,\n uint256 reclaimAmount,\n JBRedemptionDelegateAllocation[] memory delegateAllocations,\n string memory memo\n )\n {\n // Get a reference to the project's current funding cycle.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // The current funding cycle must not be paused.\n if (fundingCycle.redeemPaused()) revert FUNDING_CYCLE_REDEEM_PAUSED();\n\n // Scoped section prevents stack too deep. `_reclaimedTokenAmount`, `_currentOverflow`, and `_totalSupply` only used within scope.\n {\n // Get a reference to the reclaimed token amount struct, the current overflow, and the total token supply.\n JBTokenAmount memory _reclaimedTokenAmount;\n uint256 _currentOverflow;\n uint256 _totalSupply;\n\n // Another scoped section prevents stack too deep. `_token`, `_decimals`, and `_currency` only used within scope.\n {\n // Get a reference to the terminal's tokens.\n address _token = IJBSingleTokenPaymentTerminal(msg.sender).token();\n\n // Get a reference to the terminal's decimals.\n uint256 _decimals = IJBSingleTokenPaymentTerminal(msg.sender).decimals();\n\n // Get areference to the terminal's currency.\n uint256 _currency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\n\n // Get the amount of current overflow.\n // Use the local overflow if the funding cycle specifies that it should be used. Otherwise, use the project's total overflow across all of its terminals.\n _currentOverflow = fundingCycle.useTotalOverflowForRedemptions()\n ? _currentTotalOverflowOf(_projectId, _decimals, _currency)\n : _overflowDuring(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _projectId,\n fundingCycle,\n _currency\n );\n\n // Get the number of outstanding tokens the project has.\n _totalSupply = IJBController(directory.controllerOf(_projectId)).totalOutstandingTokensOf(\n _projectId,\n fundingCycle.reservedRate()\n );\n\n // Can't redeem more tokens that is in the supply.\n if (_tokenCount > _totalSupply) revert INSUFFICIENT_TOKENS();\n\n if (_currentOverflow != 0)\n // Calculate reclaim amount using the current overflow amount.\n reclaimAmount = _reclaimableOverflowDuring(\n _projectId,\n fundingCycle,\n _tokenCount,\n _totalSupply,\n _currentOverflow\n );\n\n _reclaimedTokenAmount = JBTokenAmount(_token, reclaimAmount, _decimals, _currency);\n }\n\n // If the funding cycle has configured a data source, use it to derive a claim amount and memo.\n if (fundingCycle.useDataSourceForRedeem() && fundingCycle.dataSource() != address(0)) {\n // Yet another scoped section prevents stack too deep. `_state` only used within scope.\n {\n // Get a reference to the ballot state.\n JBBallotState _state = fundingCycleStore.currentBallotStateOf(_projectId);\n\n // Create the params that'll be sent to the data source.\n JBRedeemParamsData memory _data = JBRedeemParamsData(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _holder,\n _projectId,\n fundingCycle.configuration,\n _tokenCount,\n _totalSupply,\n _currentOverflow,\n _reclaimedTokenAmount,\n fundingCycle.useTotalOverflowForRedemptions(),\n _state == JBBallotState.Active\n ? fundingCycle.ballotRedemptionRate()\n : fundingCycle.redemptionRate(),\n _memo,\n _metadata\n );\n (reclaimAmount, memo, delegateAllocations) = IJBFundingCycleDataSource(\n fundingCycle.dataSource()\n ).redeemParams(_data);\n }\n } else {\n memo = _memo;\n }\n }\n\n // Keep a reference to the amount that should be subtracted from the project's balance.\n uint256 _balanceDiff = reclaimAmount;\n\n if (delegateAllocations.length != 0) {\n // Validate all delegated amounts.\n for (uint256 _i; _i < delegateAllocations.length; ) {\n // Get a reference to the amount to be delegated.\n uint256 _delegatedAmount = delegateAllocations[_i].amount;\n\n // Validate if non-zero.\n if (_delegatedAmount != 0)\n // Increment the total amount being subtracted from the balance.\n _balanceDiff = _balanceDiff + _delegatedAmount;\n\n unchecked {\n ++_i;\n }\n }\n }\n\n // The amount being reclaimed must be within the project's balance.\n if (_balanceDiff > balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId])\n revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n\n // Remove the reclaimed funds from the project's balance.\n if (_balanceDiff != 0) {\n unchecked {\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\n _balanceDiff;\n }\n }\n }\n\n /// @notice Records newly distributed funds for a project.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\n /// @param _projectId The ID of the project that is having funds distributed.\n /// @param _amount The amount to use from the distribution limit, as a fixed point number.\n /// @param _currency The currency of the `_amount`. This must match the project's current funding cycle's currency.\n /// @return fundingCycle The funding cycle during which the distribution was made.\n /// @return distributedAmount The amount of terminal tokens distributed, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordDistributionFor(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency\n )\n external\n override\n nonReentrant\n returns (JBFundingCycle memory fundingCycle, uint256 distributedAmount)\n {\n // Get a reference to the project's current funding cycle.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // The funding cycle must not be configured to have distributions paused.\n if (fundingCycle.distributionsPaused()) revert FUNDING_CYCLE_DISTRIBUTION_PAUSED();\n\n // The new total amount that has been distributed during this funding cycle.\n uint256 _newUsedDistributionLimitOf = usedDistributionLimitOf[\n IJBSingleTokenPaymentTerminal(msg.sender)\n ][_projectId][fundingCycle.number] + _amount;\n\n // Amount must be within what is still distributable.\n (uint256 _distributionLimitOf, uint256 _distributionLimitCurrencyOf) = IJBController(\n directory.controllerOf(_projectId)\n ).distributionLimitOf(\n _projectId,\n fundingCycle.configuration,\n IJBSingleTokenPaymentTerminal(msg.sender),\n IJBSingleTokenPaymentTerminal(msg.sender).token()\n );\n\n // Make sure the new used amount is within the distribution limit.\n if (_newUsedDistributionLimitOf > _distributionLimitOf || _distributionLimitOf == 0)\n revert DISTRIBUTION_AMOUNT_LIMIT_REACHED();\n\n // Make sure the currencies match.\n if (_currency != _distributionLimitCurrencyOf) revert CURRENCY_MISMATCH();\n\n // Get a reference to the terminal's currency.\n uint256 _balanceCurrency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\n\n // Convert the amount to the balance's currency.\n distributedAmount = (_currency == _balanceCurrency)\n ? _amount\n : PRBMath.mulDiv(\n _amount,\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\n prices.priceFor(_currency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\n );\n\n // The amount being distributed must be available.\n if (distributedAmount > balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId])\n revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n\n // Store the new amount.\n usedDistributionLimitOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId][\n fundingCycle.number\n ] = _newUsedDistributionLimitOf;\n\n // Removed the distributed funds from the project's token balance.\n unchecked {\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\n distributedAmount;\n }\n }\n\n /// @notice Records newly used allowance funds of a project.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\n /// @param _projectId The ID of the project to use the allowance of.\n /// @param _amount The amount to use from the allowance, as a fixed point number.\n /// @param _currency The currency of the `_amount`. Must match the currency of the overflow allowance.\n /// @return fundingCycle The funding cycle during which the overflow allowance is being used.\n /// @return usedAmount The amount of terminal tokens used, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordUsedAllowanceOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency\n )\n external\n override\n nonReentrant\n returns (JBFundingCycle memory fundingCycle, uint256 usedAmount)\n {\n // Get a reference to the project's current funding cycle.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Get a reference to the new used overflow allowance for this funding cycle configuration.\n uint256 _newUsedOverflowAllowanceOf = usedOverflowAllowanceOf[\n IJBSingleTokenPaymentTerminal(msg.sender)\n ][_projectId][fundingCycle.configuration] + _amount;\n\n // There must be sufficient allowance available.\n (uint256 _overflowAllowanceOf, uint256 _overflowAllowanceCurrency) = IJBController(\n directory.controllerOf(_projectId)\n ).overflowAllowanceOf(\n _projectId,\n fundingCycle.configuration,\n IJBSingleTokenPaymentTerminal(msg.sender),\n IJBSingleTokenPaymentTerminal(msg.sender).token()\n );\n\n // Make sure the new used amount is within the allowance.\n if (_newUsedOverflowAllowanceOf > _overflowAllowanceOf || _overflowAllowanceOf == 0)\n revert INADEQUATE_CONTROLLER_ALLOWANCE();\n\n // Make sure the currencies match.\n if (_currency != _overflowAllowanceCurrency) revert CURRENCY_MISMATCH();\n\n // Get a reference to the terminal's currency.\n uint256 _balanceCurrency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\n\n // Convert the amount to this store's terminal's token.\n usedAmount = (_currency == _balanceCurrency)\n ? _amount\n : PRBMath.mulDiv(\n _amount,\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\n prices.priceFor(_currency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\n );\n\n // The amount being distributed must be available in the overflow.\n if (\n usedAmount >\n _overflowDuring(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _projectId,\n fundingCycle,\n _balanceCurrency\n )\n ) revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n\n // Store the incremented value.\n usedOverflowAllowanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId][\n fundingCycle.configuration\n ] = _newUsedOverflowAllowanceOf;\n\n // Update the project's balance.\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\n usedAmount;\n }\n\n /// @notice Records newly added funds for the project.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\n /// @param _projectId The ID of the project to which the funds being added belong.\n /// @param _amount The amount of terminal tokens added, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordAddedBalanceFor(uint256 _projectId, uint256 _amount) external override {\n // Increment the balance.\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] +\n _amount;\n }\n\n /// @notice Records the migration of funds from this store.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount returned is in terms of the msg.senders tokens.\n /// @param _projectId The ID of the project being migrated.\n /// @return balance The project's migrated balance, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordMigration(\n uint256 _projectId\n ) external override nonReentrant returns (uint256 balance) {\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Migration must be allowed.\n if (!_fundingCycle.terminalMigrationAllowed()) revert PAYMENT_TERMINAL_MIGRATION_NOT_ALLOWED();\n\n // Return the current balance.\n balance = balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId];\n\n // Set the balance to 0.\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] = 0;\n }\n\n //*********************************************************************//\n // --------------------- private helper functions -------------------- //\n //*********************************************************************//\n\n /// @notice The amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens when measured from the specified.\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\n /// @param _projectId The ID of the project to get the reclaimable overflow amount for.\n /// @param _fundingCycle The funding cycle during which reclaimable overflow is being calculated.\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _totalSupply The total supply of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _overflow The amount of overflow to make the calculation with.\n /// @return The amount of overflowed tokens that can be reclaimed.\n function _reclaimableOverflowDuring(\n uint256 _projectId,\n JBFundingCycle memory _fundingCycle,\n uint256 _tokenCount,\n uint256 _totalSupply,\n uint256 _overflow\n ) private view returns (uint256) {\n // If the amount being redeemed is the total supply, return the rest of the overflow.\n if (_tokenCount == _totalSupply) return _overflow;\n\n // Use the ballot redemption rate if the queued cycle is pending approval according to the previous funding cycle's ballot.\n uint256 _redemptionRate = fundingCycleStore.currentBallotStateOf(_projectId) ==\n JBBallotState.Active\n ? _fundingCycle.ballotRedemptionRate()\n : _fundingCycle.redemptionRate();\n\n // If the redemption rate is 0, nothing is claimable.\n if (_redemptionRate == 0) return 0;\n\n // Get a reference to the linear proportion.\n uint256 _base = PRBMath.mulDiv(_overflow, _tokenCount, _totalSupply);\n\n // These conditions are all part of the same curve. Edge conditions are separated because fewer operation are necessary.\n if (_redemptionRate == JBConstants.MAX_REDEMPTION_RATE) return _base;\n\n return\n PRBMath.mulDiv(\n _base,\n _redemptionRate +\n PRBMath.mulDiv(\n _tokenCount,\n JBConstants.MAX_REDEMPTION_RATE - _redemptionRate,\n _totalSupply\n ),\n JBConstants.MAX_REDEMPTION_RATE\n );\n }\n\n /// @notice Gets the amount that is overflowing when measured from the specified funding cycle.\n /// @dev This amount changes as the value of the balance changes in relation to the currency being used to measure the distribution limit.\n /// @param _terminal The terminal for which the overflow is being calculated.\n /// @param _projectId The ID of the project to get overflow for.\n /// @param _fundingCycle The ID of the funding cycle to base the overflow on.\n /// @param _balanceCurrency The currency that the stored balance is expected to be in terms of.\n /// @return overflow The overflow of funds, as a fixed point number with 18 decimals.\n function _overflowDuring(\n IJBSingleTokenPaymentTerminal _terminal,\n uint256 _projectId,\n JBFundingCycle memory _fundingCycle,\n uint256 _balanceCurrency\n ) private view returns (uint256) {\n // Get the current balance of the project.\n uint256 _balanceOf = balanceOf[_terminal][_projectId];\n\n // If there's no balance, there's no overflow.\n if (_balanceOf == 0) return 0;\n\n // Get a reference to the distribution limit during the funding cycle.\n (uint256 _distributionLimit, uint256 _distributionLimitCurrency) = IJBController(\n directory.controllerOf(_projectId)\n ).distributionLimitOf(_projectId, _fundingCycle.configuration, _terminal, _terminal.token());\n\n // Get a reference to the amount still distributable during the funding cycle.\n uint256 _distributionLimitRemaining = _distributionLimit -\n usedDistributionLimitOf[_terminal][_projectId][_fundingCycle.number];\n\n // Convert the _distributionRemaining to be in terms of the provided currency.\n if (_distributionLimitRemaining != 0 && _distributionLimitCurrency != _balanceCurrency)\n _distributionLimitRemaining = PRBMath.mulDiv(\n _distributionLimitRemaining,\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\n prices.priceFor(_distributionLimitCurrency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\n );\n\n // Overflow is the balance of this project minus the amount that can still be distributed.\n unchecked {\n return\n _balanceOf > _distributionLimitRemaining ? _balanceOf - _distributionLimitRemaining : 0;\n }\n }\n\n /// @notice Gets the amount that is currently overflowing across all of a project's terminals.\n /// @dev This amount changes as the value of the balances changes in relation to the currency being used to measure the project's distribution limits.\n /// @param _projectId The ID of the project to get the total overflow for.\n /// @param _decimals The number of decimals that the fixed point overflow should include.\n /// @param _currency The currency that the overflow should be in terms of.\n /// @return overflow The total overflow of a project's funds.\n function _currentTotalOverflowOf(\n uint256 _projectId,\n uint256 _decimals,\n uint256 _currency\n ) private view returns (uint256) {\n // Get a reference to the project's terminals.\n IJBPaymentTerminal[] memory _terminals = directory.terminalsOf(_projectId);\n\n // Keep a reference to the ETH overflow across all terminals, as a fixed point number with 18 decimals.\n uint256 _ethOverflow;\n\n // Add the current ETH overflow for each terminal.\n for (uint256 _i; _i < _terminals.length; ) {\n _ethOverflow = _ethOverflow + _terminals[_i].currentEthOverflowOf(_projectId);\n unchecked {\n ++_i;\n }\n }\n\n // Convert the ETH overflow to the specified currency if needed, maintaining a fixed point number with 18 decimals.\n uint256 _totalOverflow18Decimal = _currency == JBCurrencies.ETH\n ? _ethOverflow\n : PRBMath.mulDiv(_ethOverflow, 10 ** 18, prices.priceFor(JBCurrencies.ETH, _currency, 18));\n\n // Adjust the decimals of the fixed point number if needed to match the target decimals.\n return\n (_decimals == 18)\n ? _totalOverflow18Decimal\n : JBFixedPointNumber.adjustDecimals(_totalOverflow18Decimal, 18, _decimals);\n }\n}\n" + }, + "contracts/JBMigrationOperator.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {IJBController} from './interfaces/IJBController.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBMigratable} from './interfaces/IJBMigratable.sol';\nimport {IJBPayoutRedemptionPaymentTerminal} from './interfaces/IJBPayoutRedemptionPaymentTerminal.sol';\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\n\n/// @notice Allows projects to migrate their controller & terminal to 3.1 version\ncontract JBMigrationOperator {\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error UNAUTHORIZED();\n\n //*********************************************************************//\n // --------------- public immutable stored properties ---------------- //\n //*********************************************************************//\n\n /// @notice directory instance which keeps a track of which controller is linked to which project.\n IJBDirectory public immutable directory;\n\n /// @notice The NFT granting ownership to a Juicebox project\n IJBProjects public immutable projects;\n\n //*********************************************************************//\n // ---------------------------- constructor -------------------------- //\n //*********************************************************************//\n\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n constructor(IJBDirectory _directory) {\n directory = _directory;\n projects = IJBProjects(_directory.projects());\n }\n\n //*********************************************************************//\n // --------------------- external transactions ----------------------- //\n //*********************************************************************//\n\n /// @notice Allows project owners to migrate the controller & terminal linked to their project to the latest version.\n /// @param _projectId The project id whose controller & terminal are to be migrated\n /// @param _newController Controller 3.1 address to migrate to.\n /// @param _newJbTerminal Terminal 3.1 address to migrate to.\n /// @param _oldJbTerminal Old terminal address to migrate from.\n function migrate(\n uint256 _projectId,\n IJBMigratable _newController,\n IJBPaymentTerminal _newJbTerminal,\n IJBPayoutRedemptionPaymentTerminal _oldJbTerminal\n ) external {\n // Only allow the project owner to migrate\n if (projects.ownerOf(_projectId) != msg.sender) revert UNAUTHORIZED();\n\n // controller migration\n address _oldController = directory.controllerOf(_projectId);\n\n // assuming the project owner has reconfigured the funding cycle with allowControllerMigration\n IJBController(_oldController).migrate(_projectId, _newController);\n\n // terminal migration\n IJBPaymentTerminal[] memory _newTerminals = new IJBPaymentTerminal[](1);\n _newTerminals[0] = IJBPaymentTerminal(address(_newJbTerminal));\n\n // assuming the project owner has reconfigured the funding cycle with allowTerminalMigration & global.allowSetTerminals\n directory.setTerminalsOf(_projectId, _newTerminals);\n _oldJbTerminal.migrate(_projectId, _newJbTerminal);\n }\n}\n" + }, + "contracts/interfaces/IJBPayoutRedemptionPaymentTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBFee} from './../structs/JBFee.sol';\nimport {IJBAllowanceTerminal} from './IJBAllowanceTerminal.sol';\nimport {IJBDirectory} from './IJBDirectory.sol';\nimport {IJBPayDelegate} from './IJBPayDelegate.sol';\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\nimport {IJBPayoutTerminal} from './IJBPayoutTerminal.sol';\nimport {IJBPrices} from './IJBPrices.sol';\nimport {IJBProjects} from './IJBProjects.sol';\nimport {IJBRedemptionDelegate} from './IJBRedemptionDelegate.sol';\nimport {IJBRedemptionTerminal} from './IJBRedemptionTerminal.sol';\nimport {IJBSplitsStore} from './IJBSplitsStore.sol';\nimport {JBDidPayData} from './../structs/JBDidPayData.sol';\nimport {JBDidRedeemData} from './../structs/JBDidRedeemData.sol';\nimport {JBSplit} from './../structs/JBSplit.sol';\n\ninterface IJBPayoutRedemptionPaymentTerminal is\n IJBPaymentTerminal,\n IJBPayoutTerminal,\n IJBAllowanceTerminal,\n IJBRedemptionTerminal\n{\n event AddToBalance(\n uint256 indexed projectId,\n uint256 amount,\n uint256 refundedFees,\n string memo,\n bytes metadata,\n address caller\n );\n\n event Migrate(\n uint256 indexed projectId,\n IJBPaymentTerminal indexed to,\n uint256 amount,\n address caller\n );\n\n event DistributePayouts(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n address beneficiary,\n uint256 amount,\n uint256 distributedAmount,\n uint256 fee,\n uint256 beneficiaryDistributionAmount,\n string memo,\n address caller\n );\n\n event UseAllowance(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n address beneficiary,\n uint256 amount,\n uint256 distributedAmount,\n uint256 netDistributedamount,\n string memo,\n address caller\n );\n\n event HoldFee(\n uint256 indexed projectId,\n uint256 indexed amount,\n uint256 indexed fee,\n uint256 feeDiscount,\n address beneficiary,\n address caller\n );\n\n event ProcessFee(\n uint256 indexed projectId,\n uint256 indexed amount,\n bool indexed wasHeld,\n address beneficiary,\n address caller\n );\n\n event RefundHeldFees(\n uint256 indexed projectId,\n uint256 indexed amount,\n uint256 indexed refundedFees,\n uint256 leftoverAmount,\n address caller\n );\n\n event Pay(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n address payer,\n address beneficiary,\n uint256 amount,\n uint256 beneficiaryTokenCount,\n string memo,\n bytes metadata,\n address caller\n );\n\n event DelegateDidPay(\n IJBPayDelegate indexed delegate,\n JBDidPayData data,\n uint256 delegatedAmount,\n address caller\n );\n\n event RedeemTokens(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n address holder,\n address beneficiary,\n uint256 tokenCount,\n uint256 reclaimedAmount,\n string memo,\n bytes metadata,\n address caller\n );\n\n event DelegateDidRedeem(\n IJBRedemptionDelegate indexed delegate,\n JBDidRedeemData data,\n uint256 delegatedAmount,\n address caller\n );\n\n event DistributeToPayoutSplit(\n uint256 indexed projectId,\n uint256 indexed domain,\n uint256 indexed group,\n JBSplit split,\n uint256 amount,\n address caller\n );\n\n event SetFee(uint256 fee, address caller);\n\n event SetFeeGauge(address indexed feeGauge, address caller);\n\n event SetFeelessAddress(address indexed addrs, bool indexed flag, address caller);\n\n function projects() external view returns (IJBProjects);\n\n function splitsStore() external view returns (IJBSplitsStore);\n\n function directory() external view returns (IJBDirectory);\n\n function prices() external view returns (IJBPrices);\n\n function store() external view returns (address);\n\n function baseWeightCurrency() external view returns (uint256);\n\n function payoutSplitsGroup() external view returns (uint256);\n\n function heldFeesOf(uint256 projectId) external view returns (JBFee[] memory);\n\n function fee() external view returns (uint256);\n\n function feeGauge() external view returns (address);\n\n function isFeelessAddress(address account) external view returns (bool);\n\n function migrate(uint256 projectId, IJBPaymentTerminal _to) external returns (uint256 balance);\n\n function processFees(uint256 projectId) external;\n\n function setFee(uint256 fee) external;\n\n function setFeeGauge(address feeGauge) external;\n\n function setFeelessAddress(address account, bool flag) external;\n}\n" + }, + "contracts/structs/JBFee.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @custom:member amount The total amount the fee was taken from, as a fixed point number with the same number of decimals as the terminal in which this struct was created.\n/// @custom:member fee The percent of the fee, out of MAX_FEE.\n/// @custom:member feeDiscount The discount of the fee.\n/// @custom:member beneficiary The address that will receive the tokens that are minted as a result of the fee payment.\nstruct JBFee {\n uint256 amount;\n uint32 fee;\n uint32 feeDiscount;\n address beneficiary;\n}\n" + }, + "contracts/interfaces/IJBAllowanceTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBAllowanceTerminal {\n function useAllowanceOf(\n uint256 projectId,\n uint256 amount,\n uint256 currency,\n address token,\n uint256 minReturnedTokens,\n address payable beneficiary,\n string calldata memo\n ) external returns (uint256 netDistributedAmount);\n}\n" + }, + "contracts/interfaces/IJBPayoutTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBPayoutTerminal {\n function distributePayoutsOf(\n uint256 projectId,\n uint256 amount,\n uint256 currency,\n address token,\n uint256 minReturnedTokens,\n string calldata memo\n ) external returns (uint256 netLeftoverDistributionAmount);\n}\n" + }, + "contracts/interfaces/IJBRedemptionTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBRedemptionTerminal {\n function redeemTokensOf(\n address holder,\n uint256 projectId,\n uint256 tokenCount,\n address token,\n uint256 minReturnedTokens,\n address payable beneficiary,\n string calldata memo,\n bytes calldata metadata\n ) external returns (uint256 reclaimAmount);\n}\n" + }, + "contracts/JBETHPaymentTerminal3_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Address} from '@openzeppelin/contracts/utils/Address.sol';\nimport {JBPayoutRedemptionPaymentTerminal3_1} from './abstract/JBPayoutRedemptionPaymentTerminal3_1.sol';\nimport {JBSplitsGroups} from './libraries/JBSplitsGroups.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {JBCurrencies} from './libraries/JBCurrencies.sol';\nimport {JBTokens} from './libraries/JBTokens.sol';\n\n/// @notice Manages all inflows and outflows of ETH funds into the protocol ecosystem.\ncontract JBETHPaymentTerminal3_1 is JBPayoutRedemptionPaymentTerminal3_1 {\n //*********************************************************************//\n // -------------------------- internal views ------------------------- //\n //*********************************************************************//\n\n /// @notice Checks the balance of tokens in this contract.\n /// @return The contract's balance, as a fixed point number with the same amount of decimals as this terminal.\n function _balance() internal view override returns (uint256) {\n return address(this).balance;\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _prices A contract that exposes price feeds.\n /// @param _store A contract that stores the terminal's data.\n /// @param _owner The address that will own this contract.\n constructor(\n uint256 _baseWeightCurrency,\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBSplitsStore _splitsStore,\n IJBPrices _prices,\n address _store,\n address _owner\n )\n JBPayoutRedemptionPaymentTerminal3_1(\n JBTokens.ETH,\n 18, // 18 decimals.\n JBCurrencies.ETH,\n _baseWeightCurrency,\n JBSplitsGroups.ETH_PAYOUT,\n _operatorStore,\n _projects,\n _directory,\n _splitsStore,\n _prices,\n _store,\n _owner\n )\n // solhint-disable-next-line no-empty-blocks\n {\n\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Transfers tokens.\n /// @param _from The address from which the transfer should originate.\n /// @param _to The address to which the transfer should go.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _transferFrom(address _from, address payable _to, uint256 _amount) internal override {\n _from; // Prevents unused var compiler and natspec complaints.\n\n Address.sendValue(_to, _amount);\n }\n}\n" + }, + "contracts/abstract/JBPayoutRedemptionPaymentTerminal3_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {ERC165Checker} from '@openzeppelin/contracts/utils/introspection/ERC165Checker.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {IJBAllowanceTerminal3_1} from './../interfaces/IJBAllowanceTerminal3_1.sol';\nimport {IJBController} from './../interfaces/IJBController.sol';\nimport {IJBDirectory} from './../interfaces/IJBDirectory.sol';\nimport {IJBFeeGauge} from './../interfaces/IJBFeeGauge.sol';\nimport {IJBPayoutRedemptionPaymentTerminal3_1} from './../interfaces/IJBPayoutRedemptionPaymentTerminal3_1.sol';\nimport {IJBSplitAllocator} from './../interfaces/IJBSplitAllocator.sol';\nimport {IJBOperatable} from './../interfaces/IJBOperatable.sol';\nimport {IJBOperatorStore} from './../interfaces/IJBOperatorStore.sol';\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\nimport {IJBPayoutTerminal3_1} from './../interfaces/IJBPayoutTerminal3_1.sol';\nimport {IJBPrices} from './../interfaces/IJBPrices.sol';\nimport {IJBProjects} from './../interfaces/IJBProjects.sol';\nimport {IJBRedemptionTerminal} from './../interfaces/IJBRedemptionTerminal.sol';\nimport {IJBSingleTokenPaymentTerminalStore} from './../interfaces/IJBSingleTokenPaymentTerminalStore.sol';\nimport {IJBSplitsStore} from './../interfaces/IJBSplitsStore.sol';\nimport {JBConstants} from './../libraries/JBConstants.sol';\nimport {JBCurrencies} from './../libraries/JBCurrencies.sol';\nimport {JBFixedPointNumber} from './../libraries/JBFixedPointNumber.sol';\nimport {JBFundingCycleMetadataResolver} from './../libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBOperations} from './../libraries/JBOperations.sol';\nimport {JBTokens} from './../libraries/JBTokens.sol';\nimport {JBDidPayData} from './../structs/JBDidPayData.sol';\nimport {JBDidRedeemData} from './../structs/JBDidRedeemData.sol';\nimport {JBFee} from './../structs/JBFee.sol';\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\nimport {JBPayDelegateAllocation} from './../structs/JBPayDelegateAllocation.sol';\nimport {JBTokenAmount} from './../structs/JBTokenAmount.sol';\nimport {JBRedemptionDelegateAllocation} from './../structs/JBRedemptionDelegateAllocation.sol';\nimport {JBSplit} from './../structs/JBSplit.sol';\nimport {JBSplitAllocationData} from './../structs/JBSplitAllocationData.sol';\nimport {JBOperatable} from './JBOperatable.sol';\nimport {JBSingleTokenPaymentTerminal} from './JBSingleTokenPaymentTerminal.sol';\n\n/// @notice Generic terminal managing all inflows and outflows of funds into the protocol ecosystem.\nabstract contract JBPayoutRedemptionPaymentTerminal3_1 is\n JBSingleTokenPaymentTerminal,\n JBOperatable,\n Ownable,\n IJBPayoutRedemptionPaymentTerminal3_1\n{\n // A library that parses the packed funding cycle metadata into a friendlier format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error FEE_TOO_HIGH();\n error INADEQUATE_DISTRIBUTION_AMOUNT();\n error INADEQUATE_RECLAIM_AMOUNT();\n error INADEQUATE_TOKEN_COUNT();\n error NO_MSG_VALUE_ALLOWED();\n error PAY_TO_ZERO_ADDRESS();\n error PROJECT_TERMINAL_MISMATCH();\n error REDEEM_TO_ZERO_ADDRESS();\n error TERMINAL_IN_SPLIT_ZERO_ADDRESS();\n error TERMINAL_TOKENS_INCOMPATIBLE();\n\n //*********************************************************************//\n // ---------------------------- modifiers ---------------------------- //\n //*********************************************************************//\n\n /// @notice A modifier that verifies this terminal is a terminal of provided project ID.\n modifier isTerminalOf(uint256 _projectId) {\n if (!directory.isTerminalOf(_projectId, this)) revert PROJECT_TERMINAL_MISMATCH();\n _;\n }\n\n //*********************************************************************//\n // --------------------- internal stored constants ------------------- //\n //*********************************************************************//\n\n /// @notice Maximum fee that can be set for a funding cycle configuration.\n /// @dev Out of MAX_FEE (50_000_000 / 1_000_000_000).\n uint256 internal constant _FEE_CAP = 50_000_000;\n\n /// @notice The fee beneficiary project ID is 1, as it should be the first project launched during the deployment process.\n uint256 internal constant _FEE_BENEFICIARY_PROJECT_ID = 1;\n\n //*********************************************************************//\n // --------------------- internal stored properties ------------------ //\n //*********************************************************************//\n\n /// @notice Fees that are being held to be processed later.\n /// @custom:param _projectId The ID of the project for which fees are being held.\n mapping(uint256 => JBFee[]) internal _heldFeesOf;\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice Mints ERC-721's that represent project ownership and transfers.\n IJBProjects public immutable override projects;\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n /// @notice The contract that stores splits for each project.\n IJBSplitsStore public immutable override splitsStore;\n\n /// @notice The contract that exposes price feeds.\n IJBPrices public immutable override prices;\n\n /// @notice The contract that stores and manages the terminal's data.\n address public immutable override store;\n\n /// @notice The currency to base token issuance on.\n /// @dev If this differs from `currency`, there must be a price feed available to convert `currency` to `baseWeightCurrency`.\n uint256 public immutable override baseWeightCurrency;\n\n /// @notice The group that payout splits coming from this terminal are identified by.\n uint256 public immutable override payoutSplitsGroup;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The platform fee percent.\n /// @dev Out of MAX_FEE (25_000_000 / 1_000_000_000)\n uint256 public override fee = 25_000_000; // 2.5%\n\n /// @notice The data source that returns a discount to apply to a project's fee.\n address public override feeGauge;\n\n /// @notice Addresses that can be paid towards from this terminal without incurring a fee.\n /// @dev Only addresses that are considered to be contained within the ecosystem can be feeless. Funds sent outside the ecosystem may incur fees despite being stored as feeless.\n /// @custom:param _address The address that can be paid toward.\n mapping(address => bool) public override isFeelessAddress;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Gets the current overflowed amount in this terminal for a specified project, in terms of ETH.\n /// @dev The current overflow is represented as a fixed point number with 18 decimals.\n /// @param _projectId The ID of the project to get overflow for.\n /// @return The current amount of ETH overflow that project has in this terminal, as a fixed point number with 18 decimals.\n function currentEthOverflowOf(\n uint256 _projectId\n ) external view virtual override returns (uint256) {\n // Get this terminal's current overflow.\n uint256 _overflow = IJBSingleTokenPaymentTerminalStore(store).currentOverflowOf(\n this,\n _projectId\n );\n\n // Adjust the decimals of the fixed point number if needed to have 18 decimals.\n uint256 _adjustedOverflow = (decimals == 18)\n ? _overflow\n : JBFixedPointNumber.adjustDecimals(_overflow, decimals, 18);\n\n // Return the amount converted to ETH.\n return\n (currency == JBCurrencies.ETH)\n ? _adjustedOverflow\n : PRBMath.mulDiv(\n _adjustedOverflow,\n 10 ** decimals,\n prices.priceFor(currency, JBCurrencies.ETH, decimals)\n );\n }\n\n /// @notice The fees that are currently being held to be processed later for each project.\n /// @param _projectId The ID of the project for which fees are being held.\n /// @return An array of fees that are being held.\n function heldFeesOf(uint256 _projectId) external view override returns (JBFee[] memory) {\n return _heldFeesOf[_projectId];\n }\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if the provided interface ID is supported.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(JBSingleTokenPaymentTerminal, IERC165) returns (bool) {\n return\n _interfaceId == type(IJBPayoutRedemptionPaymentTerminal3_1).interfaceId ||\n _interfaceId == type(IJBPayoutTerminal3_1).interfaceId ||\n _interfaceId == type(IJBAllowanceTerminal3_1).interfaceId ||\n _interfaceId == type(IJBRedemptionTerminal).interfaceId ||\n _interfaceId == type(IJBOperatable).interfaceId ||\n super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // -------------------------- internal views ------------------------- //\n //*********************************************************************//\n\n /// @notice Checks the balance of tokens in this contract.\n /// @return The contract's balance.\n function _balance() internal view virtual returns (uint256);\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _decimals The number of decimals the token fixed point amounts are expected to have.\n /// @param _currency The currency that this terminal's token adheres to for price feeds.\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _payoutSplitsGroup The group that denotes payout splits from this terminal in the splits store.\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _prices A contract that exposes price feeds.\n /// @param _store A contract that stores the terminal's data.\n /// @param _owner The address that will own this contract.\n constructor(\n // payable constructor save the gas used to check msg.value==0\n address _token,\n uint256 _decimals,\n uint256 _currency,\n uint256 _baseWeightCurrency,\n uint256 _payoutSplitsGroup,\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBSplitsStore _splitsStore,\n IJBPrices _prices,\n address _store,\n address _owner\n )\n payable\n JBSingleTokenPaymentTerminal(_token, _decimals, _currency)\n JBOperatable(_operatorStore)\n {\n baseWeightCurrency = _baseWeightCurrency;\n payoutSplitsGroup = _payoutSplitsGroup;\n projects = _projects;\n directory = _directory;\n splitsStore = _splitsStore;\n prices = _prices;\n store = _store;\n\n transferOwnership(_owner);\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Contribute tokens to a project.\n /// @param _projectId The ID of the project being paid.\n /// @param _amount The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place.\n /// @param _token The token being paid. This terminal ignores this property since it only manages one token.\n /// @param _beneficiary The address to mint tokens for and pass along to the funding cycle's data source and delegate.\n /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\n /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals.\n function pay(\n uint256 _projectId,\n uint256 _amount,\n address _token,\n address _beneficiary,\n uint256 _minReturnedTokens,\n bool _preferClaimedTokens,\n string calldata _memo,\n bytes calldata _metadata\n ) external payable virtual override isTerminalOf(_projectId) returns (uint256) {\n _token; // Prevents unused var compiler and natspec complaints.\n\n // ETH shouldn't be sent if this terminal's token isn't ETH.\n if (token != JBTokens.ETH) {\n if (msg.value > 0) revert NO_MSG_VALUE_ALLOWED();\n\n // Get a reference to the balance before receiving tokens.\n uint256 _balanceBefore = _balance();\n\n // Transfer tokens to this terminal from the msg sender.\n _transferFrom(msg.sender, payable(address(this)), _amount);\n\n // The amount should reflect the change in balance.\n _amount = _balance() - _balanceBefore;\n }\n // If this terminal's token is ETH, override _amount with msg.value.\n else _amount = msg.value;\n\n return\n _pay(\n _amount,\n msg.sender,\n _projectId,\n _beneficiary,\n _minReturnedTokens,\n _preferClaimedTokens,\n _memo,\n _metadata\n );\n }\n\n /// @notice Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source.\n /// @dev Only a token holder or a designated operator can redeem its tokens.\n /// @param _holder The account to redeem tokens for.\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\n /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals.\n /// @param _token The token being reclaimed. This terminal ignores this property since it only manages one token.\n /// @param _minReturnedTokens The minimum amount of terminal tokens expected in return, as a fixed point number with the same amount of decimals as the terminal.\n /// @param _beneficiary The address to send the terminal tokens to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return reclaimAmount The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals.\n function redeemTokensOf(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n address _token,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo,\n bytes memory _metadata\n )\n external\n virtual\n override\n requirePermission(_holder, _projectId, JBOperations.REDEEM)\n returns (uint256 reclaimAmount)\n {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return\n _redeemTokensOf(\n _holder,\n _projectId,\n _tokenCount,\n _minReturnedTokens,\n _beneficiary,\n _memo,\n _metadata\n );\n }\n\n /// @notice Distributes payouts for a project with the distribution limit of its current funding cycle.\n /// @dev Payouts are sent to the preprogrammed splits. Any leftover is sent to the project's owner.\n /// @dev 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.\n /// @dev All funds distributed outside of this contract or any feeless terminals incure the protocol fee.\n /// @param _projectId The ID of the project having its payouts distributed.\n /// @param _amount The amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency.\n /// @param _token The token being distributed. This terminal ignores this property since it only manages one token.\n /// @param _minReturnedTokens 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.\n /// @param _metadata Bytes to send along to the emitted event, if provided.\n /// @return netLeftoverDistributionAmount The amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal.\n function distributePayoutsOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n address _token,\n uint256 _minReturnedTokens,\n bytes calldata _metadata\n ) external virtual override returns (uint256 netLeftoverDistributionAmount) {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return _distributePayoutsOf(_projectId, _amount, _currency, _minReturnedTokens, _metadata);\n }\n\n /// @notice Only a project's owner or a designated operator can use its allowance.\n /// @dev Incurs the protocol fee.\n /// @param _projectId The ID of the project to use the allowance of.\n /// @param _amount The amount of terminal tokens to use from this project's current allowance, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's overflow allowance currency.\n /// @param _token The token being distributed. This terminal ignores this property since it only manages one token.\n /// @param _minReturnedTokens The minimum number of tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with 18 decimals.\n /// @param _beneficiary The address to send the funds to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the emitted event, if provided.\n /// @return netDistributedAmount The amount of tokens that was distributed to the beneficiary, as a fixed point number with the same amount of decimals as the terminal.\n function useAllowanceOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n address _token,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo,\n bytes calldata _metadata\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.USE_ALLOWANCE)\n returns (uint256 netDistributedAmount)\n {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return\n _useAllowanceOf(\n _projectId,\n _amount,\n _currency,\n _minReturnedTokens,\n _beneficiary,\n _memo,\n _metadata\n );\n }\n\n /// @notice Allows a project owner to migrate its funds and operations to a new terminal that accepts the same token type.\n /// @dev Only a project's owner or a designated operator can migrate it.\n /// @param _projectId The ID of the project being migrated.\n /// @param _to The terminal contract that will gain the project's funds.\n /// @return balance The amount of funds that were migrated, as a fixed point number with the same amount of decimals as this terminal.\n function migrate(\n uint256 _projectId,\n IJBPaymentTerminal _to\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.MIGRATE_TERMINAL)\n returns (uint256 balance)\n {\n // The terminal being migrated to must accept the same token as this terminal.\n if (!_to.acceptsToken(token, _projectId)) revert TERMINAL_TOKENS_INCOMPATIBLE();\n\n // Record the migration in the store.\n balance = IJBSingleTokenPaymentTerminalStore(store).recordMigration(_projectId);\n\n // Transfer the balance if needed.\n if (balance > 0) {\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_to), balance);\n\n // If this terminal's token is ETH, send it in msg.value.\n uint256 _payableValue = token == JBTokens.ETH ? balance : 0;\n\n // Withdraw the balance to transfer to the new terminal;\n _to.addToBalanceOf{value: _payableValue}(_projectId, balance, token, '', bytes(''));\n }\n\n emit Migrate(_projectId, _to, balance, msg.sender);\n }\n\n /// @notice Receives funds belonging to the specified project.\n /// @param _projectId The ID of the project to which the funds received belong.\n /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\n /// @param _token The token being paid. This terminal ignores this property since it only manages one currency.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the emitted event.\n function addToBalanceOf(\n uint256 _projectId,\n uint256 _amount,\n address _token,\n string calldata _memo,\n bytes calldata _metadata\n ) external payable virtual override isTerminalOf(_projectId) {\n // Do not refund held fees by default.\n addToBalanceOf(_projectId, _amount, _token, false, _memo, _metadata);\n }\n\n /// @notice Process any fees that are being held for the project.\n /// @dev Only a project owner, an operator, or the contract's owner can process held fees.\n /// @param _projectId The ID of the project whos held fees should be processed.\n function processFees(\n uint256 _projectId\n )\n external\n virtual\n override\n requirePermissionAllowingOverride(\n projects.ownerOf(_projectId),\n _projectId,\n JBOperations.PROCESS_FEES,\n msg.sender == owner()\n )\n {\n // Get a reference to the project's held fees.\n JBFee[] memory _heldFees = _heldFeesOf[_projectId];\n\n // Delete the held fees.\n delete _heldFeesOf[_projectId];\n\n // Push array length in stack\n uint256 _heldFeeLength = _heldFees.length;\n\n // Process each fee.\n for (uint256 _i; _i < _heldFeeLength; ) {\n // Get the fee amount.\n uint256 _amount = _feeAmount(\n _heldFees[_i].amount,\n _heldFees[_i].fee,\n _heldFees[_i].feeDiscount\n );\n\n // Process the fee.\n _processFee(_amount, _heldFees[_i].beneficiary, _projectId);\n\n emit ProcessFee(_projectId, _amount, true, _heldFees[_i].beneficiary, msg.sender);\n\n unchecked {\n ++_i;\n }\n }\n }\n\n /// @notice Allows the fee to be updated.\n /// @dev Only the owner of this contract can change the fee.\n /// @param _fee The new fee, out of MAX_FEE.\n function setFee(uint256 _fee) external virtual override onlyOwner {\n // The provided fee must be within the max.\n if (_fee > _FEE_CAP) revert FEE_TOO_HIGH();\n\n // Store the new fee.\n fee = _fee;\n\n emit SetFee(_fee, msg.sender);\n }\n\n /// @notice Allows the fee gauge to be updated.\n /// @dev Only the owner of this contract can change the fee gauge.\n /// @param _feeGauge The new fee gauge.\n function setFeeGauge(address _feeGauge) external virtual override onlyOwner {\n // Store the new fee gauge.\n feeGauge = _feeGauge;\n\n emit SetFeeGauge(_feeGauge, msg.sender);\n }\n\n /// @notice Sets whether projects operating on this terminal can pay towards the specified address without incurring a fee.\n /// @param _address The address that can be paid towards while still bypassing fees.\n /// @param _flag A flag indicating whether the terminal should be feeless or not.\n function setFeelessAddress(address _address, bool _flag) external virtual override onlyOwner {\n // Set the flag value.\n isFeelessAddress[_address] = _flag;\n\n emit SetFeelessAddress(_address, _flag, msg.sender);\n }\n\n //*********************************************************************//\n // ----------------------- public transactions ----------------------- //\n //*********************************************************************//\n\n /// @notice Receives funds belonging to the specified project.\n /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\n /// @param _token The token being paid. This terminal ignores this property since it only manages one currency.\n /// @param _shouldRefundHeldFees A flag indicating if held fees should be refunded based on the amount being added.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the emitted event.\n function addToBalanceOf(\n uint256 _projectId,\n uint256 _amount,\n address _token,\n bool _shouldRefundHeldFees,\n string calldata _memo,\n bytes calldata _metadata\n ) public payable virtual override isTerminalOf(_projectId) {\n _token; // Prevents unused var compiler and natspec complaints.\n\n // If this terminal's token isn't ETH, make sure no msg.value was sent, then transfer the tokens in from msg.sender.\n if (token != JBTokens.ETH) {\n // Amount must be greater than 0.\n if (msg.value > 0) revert NO_MSG_VALUE_ALLOWED();\n\n // Get a reference to the balance before receiving tokens.\n uint256 _balanceBefore = _balance();\n\n // Transfer tokens to this terminal from the msg sender.\n _transferFrom(msg.sender, payable(address(this)), _amount);\n\n // The amount should reflect the change in balance.\n _amount = _balance() - _balanceBefore;\n }\n // If the terminal's token is ETH, override `_amount` with msg.value.\n else _amount = msg.value;\n\n // Add to balance.\n _addToBalanceOf(_projectId, _amount, _shouldRefundHeldFees, _memo, _metadata);\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Transfers tokens.\n /// @param _from The address from which the transfer should originate.\n /// @param _to The address to which the transfer should go.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _transferFrom(address _from, address payable _to, uint256 _amount) internal virtual {\n _from; // Prevents unused var compiler and natspec complaints.\n _to; // Prevents unused var compiler and natspec complaints.\n _amount; // Prevents unused var compiler and natspec complaints.\n }\n\n /// @notice Logic to be triggered before transferring tokens from this terminal.\n /// @param _to The address to which the transfer is going.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _beforeTransferTo(address _to, uint256 _amount) internal virtual {\n _to; // Prevents unused var compiler and natspec complaints.\n _amount; // Prevents unused var compiler and natspec complaints.\n }\n\n /// @notice Logic to be triggered if a transfer should be undone\n /// @param _to The address to which the transfer went.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _cancelTransferTo(address _to, uint256 _amount) internal virtual {\n _to; // Prevents unused var compiler and natspec complaints.\n _amount; // Prevents unused var compiler and natspec complaints.\n }\n\n /// @notice Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source.\n /// @dev Only a token holder or a designated operator can redeem its tokens.\n /// @param _holder The account to redeem tokens for.\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\n /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals.\n /// @param _minReturnedTokens The minimum amount of terminal tokens expected in return, as a fixed point number with the same amount of decimals as the terminal.\n /// @param _beneficiary The address to send the terminal tokens to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return reclaimAmount The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals.\n function _redeemTokensOf(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo,\n bytes memory _metadata\n ) internal returns (uint256 reclaimAmount) {\n // Can't send reclaimed funds to the zero address.\n if (_beneficiary == address(0)) revert REDEEM_TO_ZERO_ADDRESS();\n\n // Define variables that will be needed outside the scoped section below.\n // Keep a reference to the funding cycle during which the redemption is being made.\n JBFundingCycle memory _fundingCycle;\n\n // Scoped section prevents stack too deep. `_delegateAllocations` only used within scope.\n {\n JBRedemptionDelegateAllocation[] memory _delegateAllocations;\n\n // Record the redemption.\n (\n _fundingCycle,\n reclaimAmount,\n _delegateAllocations,\n _memo\n ) = IJBSingleTokenPaymentTerminalStore(store).recordRedemptionFor(\n _holder,\n _projectId,\n _tokenCount,\n _memo,\n _metadata\n );\n\n // The amount being reclaimed must be at least as much as was expected.\n if (reclaimAmount < _minReturnedTokens) revert INADEQUATE_RECLAIM_AMOUNT();\n\n // Burn the project tokens.\n if (_tokenCount > 0)\n IJBController(directory.controllerOf(_projectId)).burnTokensOf(\n _holder,\n _projectId,\n _tokenCount,\n '',\n false\n );\n\n // If delegate allocations were specified by the data source, fulfill them.\n if (_delegateAllocations.length != 0) {\n // Keep a reference to the token amount being forwarded to the delegate.\n JBTokenAmount memory _forwardedAmount = JBTokenAmount(token, 0, decimals, currency);\n\n JBDidRedeemData memory _data = JBDidRedeemData(\n _holder,\n _projectId,\n _fundingCycle.configuration,\n _tokenCount,\n JBTokenAmount(token, reclaimAmount, decimals, currency),\n _forwardedAmount,\n _beneficiary,\n _memo,\n _metadata\n );\n\n uint256 _numDelegates = _delegateAllocations.length;\n\n for (uint256 _i; _i < _numDelegates; ) {\n // Get a reference to the delegate being iterated on.\n JBRedemptionDelegateAllocation memory _delegateAllocation = _delegateAllocations[_i];\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_delegateAllocation.delegate), _delegateAllocation.amount);\n\n // Keep track of the msg.value to use in the delegate call\n uint256 _payableValue;\n\n // If this terminal's token is ETH, send it in msg.value.\n if (token == JBTokens.ETH) _payableValue = _delegateAllocation.amount;\n\n // Pass the correct token forwardedAmount to the delegate\n _data.forwardedAmount.value = _delegateAllocation.amount;\n\n _delegateAllocation.delegate.didRedeem{value: _payableValue}(_data);\n\n emit DelegateDidRedeem(\n _delegateAllocation.delegate,\n _data,\n _delegateAllocation.amount,\n msg.sender\n );\n unchecked {\n ++_i;\n }\n }\n }\n }\n\n // Send the reclaimed funds to the beneficiary.\n if (reclaimAmount > 0) _transferFrom(address(this), _beneficiary, reclaimAmount);\n\n emit RedeemTokens(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _holder,\n _beneficiary,\n _tokenCount,\n reclaimAmount,\n _memo,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Distributes payouts for a project with the distribution limit of its current funding cycle.\n /// @dev Payouts are sent to the preprogrammed splits. Any leftover is sent to the project's owner.\n /// @dev 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.\n /// @dev All funds distributed outside of this contract or any feeless terminals incure the protocol fee.\n /// @param _projectId The ID of the project having its payouts distributed.\n /// @param _amount The amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency.\n /// @param _minReturnedTokens 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.\n /// @param _metadata Bytes to send along to the emitted event, if provided.\n /// @return netLeftoverDistributionAmount The amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal.\n function _distributePayoutsOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n uint256 _minReturnedTokens,\n bytes calldata _metadata\n ) internal returns (uint256 netLeftoverDistributionAmount) {\n // Record the distribution.\n (\n JBFundingCycle memory _fundingCycle,\n uint256 _distributedAmount\n ) = IJBSingleTokenPaymentTerminalStore(store).recordDistributionFor(\n _projectId,\n _amount,\n _currency\n );\n\n // The amount being distributed must be at least as much as was expected.\n if (_distributedAmount < _minReturnedTokens) revert INADEQUATE_DISTRIBUTION_AMOUNT();\n\n // Get a reference to the project owner, which will receive tokens from paying the platform fee\n // and receive any extra distributable funds not allocated to payout splits.\n address payable _projectOwner = payable(projects.ownerOf(_projectId));\n\n // Define variables that will be needed outside the scoped section below.\n // Keep a reference to the fee amount that was paid.\n uint256 _fee;\n\n // Scoped section prevents stack too deep. `_feeDiscount`, `_feeEligibleDistributionAmount`, and `_leftoverDistributionAmount` only used within scope.\n {\n // Get the amount of discount that should be applied to any fees taken.\n // If the fee is zero, set the discount to 100% for convenience.\n uint256 _feeDiscount = fee == 0\n ? JBConstants.MAX_FEE_DISCOUNT\n : _currentFeeDiscount(_projectId);\n\n // The amount distributed that is eligible for incurring fees.\n uint256 _feeEligibleDistributionAmount;\n\n // The amount leftover after distributing to the splits.\n uint256 _leftoverDistributionAmount;\n\n // Payout to splits and get a reference to the leftover transfer amount after all splits have been paid.\n // Also get a reference to the amount that was distributed to splits from which fees should be taken.\n (_leftoverDistributionAmount, _feeEligibleDistributionAmount) = _distributeToPayoutSplitsOf(\n _projectId,\n _fundingCycle.configuration,\n payoutSplitsGroup,\n _distributedAmount,\n _feeDiscount\n );\n\n if (_feeDiscount != JBConstants.MAX_FEE_DISCOUNT) {\n // Leftover distribution amount is also eligible for a fee since the funds are going out of the ecosystem to _beneficiary.\n unchecked {\n _feeEligibleDistributionAmount += _leftoverDistributionAmount;\n }\n }\n\n // Take the fee.\n _fee = _feeEligibleDistributionAmount != 0\n ? _takeFeeFrom(\n _projectId,\n _fundingCycle,\n _feeEligibleDistributionAmount,\n _projectOwner,\n _feeDiscount\n )\n : 0;\n\n // Transfer any remaining balance to the project owner and update returned leftover accordingly.\n if (_leftoverDistributionAmount != 0) {\n // Subtract the fee from the net leftover amount.\n netLeftoverDistributionAmount =\n _leftoverDistributionAmount -\n _feeAmount(_leftoverDistributionAmount, fee, _feeDiscount);\n\n // Transfer the amount to the project owner.\n _transferFrom(address(this), _projectOwner, netLeftoverDistributionAmount);\n }\n }\n\n emit DistributePayouts(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _projectOwner,\n _amount,\n _distributedAmount,\n _fee,\n netLeftoverDistributionAmount,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Allows a project to send funds from its overflow up to the preconfigured allowance.\n /// @dev Only a project's owner or a designated operator can use its allowance.\n /// @dev Incurs the protocol fee.\n /// @param _projectId The ID of the project to use the allowance of.\n /// @param _amount The amount of terminal tokens to use from this project's current allowance, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's overflow allowance currency.\n /// @param _minReturnedTokens The minimum number of tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with 18 decimals.\n /// @param _beneficiary The address to send the funds to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the emitted event, if provided.\n /// @return netDistributedAmount The amount of tokens that was distributed to the beneficiary, as a fixed point number with the same amount of decimals as the terminal.\n function _useAllowanceOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo,\n bytes calldata _metadata\n ) internal returns (uint256 netDistributedAmount) {\n // Record the use of the allowance.\n (\n JBFundingCycle memory _fundingCycle,\n uint256 _distributedAmount\n ) = IJBSingleTokenPaymentTerminalStore(store).recordUsedAllowanceOf(\n _projectId,\n _amount,\n _currency\n );\n\n // The amount being withdrawn must be at least as much as was expected.\n if (_distributedAmount < _minReturnedTokens) revert INADEQUATE_DISTRIBUTION_AMOUNT();\n\n // Scoped section prevents stack too deep. `_fee`, `_projectOwner`, `_feeDiscount`, and `_netAmount` only used within scope.\n {\n // Keep a reference to the fee amount that was paid.\n uint256 _fee;\n\n // Get a reference to the project owner, which will receive tokens from paying the platform fee.\n address _projectOwner = projects.ownerOf(_projectId);\n\n // Get the amount of discount that should be applied to any fees taken.\n // 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.\n uint256 _feeDiscount = fee == 0 || isFeelessAddress[msg.sender]\n ? JBConstants.MAX_FEE_DISCOUNT\n : _currentFeeDiscount(_projectId);\n\n // Take a fee from the `_distributedAmount`, if needed.\n _fee = _feeDiscount == JBConstants.MAX_FEE_DISCOUNT\n ? 0\n : _takeFeeFrom(_projectId, _fundingCycle, _distributedAmount, _projectOwner, _feeDiscount);\n\n unchecked {\n // The net amount is the withdrawn amount without the fee.\n netDistributedAmount = _distributedAmount - _fee;\n }\n\n // Transfer any remaining balance to the beneficiary.\n if (netDistributedAmount > 0)\n _transferFrom(address(this), _beneficiary, netDistributedAmount);\n }\n\n emit UseAllowance(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _beneficiary,\n _amount,\n _distributedAmount,\n netDistributedAmount,\n _memo,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Pays out splits for a project's funding cycle configuration.\n /// @param _projectId The ID of the project for which payout splits are being distributed.\n /// @param _domain The domain of the splits to distribute the payout between.\n /// @param _group The group of the splits to distribute the payout between.\n /// @param _amount The total amount being distributed, as a fixed point number with the same number of decimals as this terminal.\n /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE.\n /// @return leftoverAmount If the leftover amount if the splits don't add up to 100%.\n /// @return feeEligibleDistributionAmount The total amount of distributions that are eligible to have fees taken from.\n function _distributeToPayoutSplitsOf(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group,\n uint256 _amount,\n uint256 _feeDiscount\n ) internal returns (uint256 leftoverAmount, uint256 feeEligibleDistributionAmount) {\n // Set the leftover amount to the initial amount.\n leftoverAmount = _amount;\n // The total percentage available to split\n uint256 leftoverPercentage = JBConstants.SPLITS_TOTAL_PERCENT;\n\n // Get a reference to the project's payout splits.\n JBSplit[] memory _splits = splitsStore.splitsOf(_projectId, _domain, _group);\n\n // Transfer between all splits.\n for (uint256 _i; _i < _splits.length; ) {\n // Get a reference to the split being iterated on.\n JBSplit memory _split = _splits[_i];\n\n // The amount to send towards the split.\n uint256 _payoutAmount = _split.percent == leftoverPercentage\n ? leftoverAmount\n : PRBMath.mulDiv(_amount, _split.percent, JBConstants.SPLITS_TOTAL_PERCENT);\n\n // Decrement the leftover percentage.\n leftoverPercentage -= _split.percent;\n\n // The payout amount substracting any applicable incurred fees.\n uint256 _netPayoutAmount = _distributeToPayoutSplit(\n _split,\n _projectId,\n _group,\n _payoutAmount,\n _feeDiscount\n );\n\n // If the split allocator is set as feeless, this distribution is not eligible for a fee.\n if (_netPayoutAmount != 0 && _netPayoutAmount != _payoutAmount)\n feeEligibleDistributionAmount += _payoutAmount;\n\n if (_payoutAmount > 0) {\n // Subtract from the amount to be sent to the beneficiary.\n unchecked {\n leftoverAmount = leftoverAmount - _payoutAmount;\n }\n }\n\n emit DistributeToPayoutSplit(\n _projectId,\n _domain,\n _group,\n _split,\n _payoutAmount,\n _netPayoutAmount,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n\n /// @notice Pays out a split for a project's funding cycle configuration.\n /// @param _split The split to distribute payouts to.\n /// @param _amount The total amount being distributed to the split, as a fixed point number with the same number of decimals as this terminal.\n /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE.\n /// @return netPayoutAmount The amount sent to the split after subtracting fees.\n function _distributeToPayoutSplit(\n JBSplit memory _split,\n uint256 _projectId,\n uint256 _group,\n uint256 _amount,\n uint256 _feeDiscount\n ) internal returns (uint256 netPayoutAmount) {\n // If there's an allocator set, transfer to its `allocate` function.\n if (_split.allocator != IJBSplitAllocator(address(0))) {\n // If the split allocator is set as feeless, this distribution is not eligible for a fee.\n if (\n _feeDiscount == JBConstants.MAX_FEE_DISCOUNT || isFeelessAddress[address(_split.allocator)]\n )\n netPayoutAmount = _amount;\n // This distribution is eligible for a fee since the funds are leaving this contract and the allocator isn't listed as feeless.\n else {\n unchecked {\n netPayoutAmount = _amount - _feeAmount(_amount, fee, _feeDiscount);\n }\n }\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_split.allocator), netPayoutAmount);\n\n // Create the data to send to the allocator.\n JBSplitAllocationData memory _data = JBSplitAllocationData(\n token,\n netPayoutAmount,\n decimals,\n _projectId,\n _group,\n _split\n );\n\n // Trigger the allocator's `allocate` function.\n uint256 _error;\n bytes memory _reason;\n\n if (\n ERC165Checker.supportsInterface(\n address(_split.allocator),\n type(IJBSplitAllocator).interfaceId\n )\n )\n // If this terminal's token is ETH, send it in msg.value.\n try\n _split.allocator.allocate{value: token == JBTokens.ETH ? netPayoutAmount : 0}(_data)\n {} catch (bytes memory reason) {\n _reason = reason;\n _error = 1;\n }\n else _error = 2;\n\n if (_error != 0) {\n // Trigger any inhereted post-transfer cancelation logic.\n _cancelTransferTo(address(_split.allocator), netPayoutAmount);\n\n // Set the net payout amount to 0 to signal the reversion.\n netPayoutAmount = 0;\n\n // Add undistributed amount back to project's balance.\n IJBSingleTokenPaymentTerminalStore(store).recordAddedBalanceFor(_projectId, _amount);\n\n emit PayoutReverted(\n _projectId,\n _split,\n _amount,\n _error == 1 ? _reason : abi.encode('IERC165 fail'),\n msg.sender\n );\n }\n\n // Otherwise, if a project is specified, make a payment to it.\n } else if (_split.projectId != 0) {\n // Get a reference to the Juicebox terminal being used.\n IJBPaymentTerminal _terminal = directory.primaryTerminalOf(_split.projectId, token);\n\n // The project must have a terminal to send funds to.\n if (_terminal == IJBPaymentTerminal(address(0))) revert TERMINAL_IN_SPLIT_ZERO_ADDRESS();\n\n // If the terminal is set as feeless, this distribution is not eligible for a fee.\n if (\n _terminal == this ||\n _feeDiscount == JBConstants.MAX_FEE_DISCOUNT ||\n isFeelessAddress[address(_terminal)]\n )\n netPayoutAmount = _amount;\n // This distribution is eligible for a fee since the funds are leaving this contract and the terminal isn't listed as feeless.\n else {\n unchecked {\n netPayoutAmount = _amount - _feeAmount(_amount, fee, _feeDiscount);\n }\n }\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_terminal), netPayoutAmount);\n\n // Send the projectId in the metadata.\n bytes memory _projectMetadata = new bytes(32);\n _projectMetadata = bytes(abi.encodePacked(_projectId));\n\n // Add to balance if prefered.\n if (_split.preferAddToBalance)\n try\n _terminal.addToBalanceOf{value: token == JBTokens.ETH ? netPayoutAmount : 0}(\n _split.projectId,\n netPayoutAmount,\n token,\n '',\n _projectMetadata\n )\n {} catch (bytes memory reason) {\n // Trigger any inhereted post-transfer cancelation logic.\n _cancelTransferTo(address(_terminal), netPayoutAmount);\n\n // Set the net payout amount to 0 to signal the reversion.\n netPayoutAmount = 0;\n\n // Add undistributed amount back to project's balance.\n IJBSingleTokenPaymentTerminalStore(store).recordAddedBalanceFor(_projectId, _amount);\n\n emit PayoutReverted(_projectId, _split, _amount, reason, msg.sender);\n }\n else\n try\n _terminal.pay{value: token == JBTokens.ETH ? netPayoutAmount : 0}(\n _split.projectId,\n netPayoutAmount,\n token,\n _split.beneficiary != address(0) ? _split.beneficiary : msg.sender,\n 0,\n _split.preferClaimed,\n '',\n _projectMetadata\n )\n {} catch (bytes memory reason) {\n // Trigger any inhereted post-transfer cancelation logic.\n _cancelTransferTo(address(_terminal), netPayoutAmount);\n\n // Set the net payout amount to 0 to signal the reversion.\n netPayoutAmount = 0;\n\n // Add undistributed amount back to project's balance.\n IJBSingleTokenPaymentTerminalStore(store).recordAddedBalanceFor(_projectId, _amount);\n\n emit PayoutReverted(_projectId, _split, _amount, reason, msg.sender);\n }\n } else {\n // Keep a reference to the beneficiary.\n address payable _beneficiary = _split.beneficiary != address(0)\n ? _split.beneficiary\n : payable(msg.sender);\n\n // If there's a full discount, this distribution is not eligible for a fee.\n // Don't enforce feeless address for the beneficiary since the funds are leaving the ecosystem.\n if (_feeDiscount == JBConstants.MAX_FEE_DISCOUNT)\n netPayoutAmount = _amount;\n // This distribution is eligible for a fee since the funds are leaving this contract and the beneficiary isn't listed as feeless.\n else {\n unchecked {\n netPayoutAmount = _amount - _feeAmount(_amount, fee, _feeDiscount);\n }\n }\n\n // If there's a beneficiary, send the funds directly to the beneficiary. Otherwise send to the msg.sender.\n _transferFrom(address(this), _beneficiary, netPayoutAmount);\n }\n }\n\n /// @notice Takes a fee into the platform's project, which has an id of _FEE_BENEFICIARY_PROJECT_ID.\n /// @param _projectId The ID of the project having fees taken from.\n /// @param _fundingCycle The funding cycle during which the fee is being taken.\n /// @param _amount The amount of the fee to take, as a floating point number with 18 decimals.\n /// @param _beneficiary The address to mint the platforms tokens for.\n /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE.\n /// @return feeAmount The amount of the fee taken.\n function _takeFeeFrom(\n uint256 _projectId,\n JBFundingCycle memory _fundingCycle,\n uint256 _amount,\n address _beneficiary,\n uint256 _feeDiscount\n ) internal returns (uint256 feeAmount) {\n feeAmount = _feeAmount(_amount, fee, _feeDiscount);\n\n if (_fundingCycle.shouldHoldFees()) {\n // Store the held fee.\n _heldFeesOf[_projectId].push(JBFee(_amount, uint32(fee), uint32(_feeDiscount), _beneficiary));\n\n emit HoldFee(_projectId, _amount, fee, _feeDiscount, _beneficiary, msg.sender);\n } else {\n // Process the fee.\n _processFee(feeAmount, _beneficiary, _projectId); // Take the fee.\n\n emit ProcessFee(_projectId, feeAmount, false, _beneficiary, msg.sender);\n }\n }\n\n /// @notice Process a fee of the specified amount.\n /// @param _amount The fee amount, as a floating point number with 18 decimals.\n /// @param _beneficiary The address to mint the platform's tokens for.\n /// @param _from The project ID the fee is being paid from.\n function _processFee(uint256 _amount, address _beneficiary, uint256 _from) internal {\n // Get the terminal for the protocol project.\n IJBPaymentTerminal _terminal = directory.primaryTerminalOf(_FEE_BENEFICIARY_PROJECT_ID, token);\n\n // If this terminal's token is ETH, send it in msg.value.\n uint256 _payableValue = token == JBTokens.ETH ? _amount : 0;\n\n // Send the projectId in the metadata.\n bytes memory _projectMetadata = new bytes(32);\n _projectMetadata = bytes(abi.encodePacked(_from));\n\n // Trigger any inherited pre-transfer logic if funds will be transferred.\n if (address(_terminal) != address(this)) _beforeTransferTo(address(_terminal), _amount);\n\n try\n // Send the fee.\n _terminal.pay{value: _payableValue}(\n _FEE_BENEFICIARY_PROJECT_ID,\n _amount,\n token,\n _beneficiary,\n 0,\n false,\n '',\n _projectMetadata\n )\n {} catch (bytes memory reason) {\n // Trigger any inhereted post-transfer cancelation logic if the pre-transfer logic was triggered.\n if (address(_terminal) != address(this)) _cancelTransferTo(address(_terminal), _amount);\n\n // Add fee amount back to project's balance.\n IJBSingleTokenPaymentTerminalStore(store).recordAddedBalanceFor(_from, _amount);\n\n emit FeeReverted(_from, _FEE_BENEFICIARY_PROJECT_ID, _amount, reason, msg.sender);\n }\n }\n\n /// @notice Contribute tokens to a project.\n /// @param _amount The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place.\n /// @param _payer The address making the payment.\n /// @param _projectId The ID of the project being paid.\n /// @param _beneficiary The address to mint tokens for and pass along to the funding cycle's data source and delegate.\n /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\n /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return beneficiaryTokenCount The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals.\n function _pay(\n uint256 _amount,\n address _payer,\n uint256 _projectId,\n address _beneficiary,\n uint256 _minReturnedTokens,\n bool _preferClaimedTokens,\n string memory _memo,\n bytes memory _metadata\n ) internal returns (uint256 beneficiaryTokenCount) {\n // Cant send tokens to the zero address.\n if (_beneficiary == address(0)) revert PAY_TO_ZERO_ADDRESS();\n\n // Define variables that will be needed outside the scoped section below.\n // Keep a reference to the funding cycle during which the payment is being made.\n JBFundingCycle memory _fundingCycle;\n\n // Scoped section prevents stack too deep. `_delegateAllocations` and `_tokenCount` only used within scope.\n {\n JBPayDelegateAllocation[] memory _delegateAllocations;\n uint256 _tokenCount;\n\n // Bundle the amount info into a JBTokenAmount struct.\n JBTokenAmount memory _bundledAmount = JBTokenAmount(token, _amount, decimals, currency);\n\n // Record the payment.\n (\n _fundingCycle,\n _tokenCount,\n _delegateAllocations,\n _memo\n ) = IJBSingleTokenPaymentTerminalStore(store).recordPaymentFrom(\n _payer,\n _bundledAmount,\n _projectId,\n baseWeightCurrency,\n _beneficiary,\n _memo,\n _metadata\n );\n\n // Mint the tokens if needed.\n if (_tokenCount > 0)\n // Set token count to be the number of tokens minted for the beneficiary instead of the total amount.\n beneficiaryTokenCount = IJBController(directory.controllerOf(_projectId)).mintTokensOf(\n _projectId,\n _tokenCount,\n _beneficiary,\n '',\n _preferClaimedTokens,\n true\n );\n\n // The token count for the beneficiary must be greater than or equal to the minimum expected.\n if (beneficiaryTokenCount < _minReturnedTokens) revert INADEQUATE_TOKEN_COUNT();\n\n // If delegate allocations were specified by the data source, fulfill them.\n if (_delegateAllocations.length != 0) {\n // Keep a reference to the token amount being forwarded to the delegate.\n JBTokenAmount memory _forwardedAmount = JBTokenAmount(token, _amount, decimals, currency);\n\n JBDidPayData memory _data = JBDidPayData(\n _payer,\n _projectId,\n _fundingCycle.configuration,\n _bundledAmount,\n _forwardedAmount,\n beneficiaryTokenCount,\n _beneficiary,\n _preferClaimedTokens,\n _memo,\n _metadata\n );\n\n // Get a reference to the number of delegates to allocate to.\n uint256 _numDelegates = _delegateAllocations.length;\n\n for (uint256 _i; _i < _numDelegates; ) {\n // Get a reference to the delegate being iterated on.\n JBPayDelegateAllocation memory _delegateAllocation = _delegateAllocations[_i];\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_delegateAllocation.delegate), _delegateAllocation.amount);\n\n // Keep track of the msg.value to use in the delegate call\n uint256 _payableValue;\n\n // If this terminal's token is ETH, send it in msg.value.\n if (token == JBTokens.ETH) _payableValue = _delegateAllocation.amount;\n\n // Pass the correct token forwardedAmount to the delegate\n _data.forwardedAmount.value = _delegateAllocation.amount;\n\n _delegateAllocation.delegate.didPay{value: _payableValue}(_data);\n\n emit DelegateDidPay(\n _delegateAllocation.delegate,\n _data,\n _delegateAllocation.amount,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n }\n\n emit Pay(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _payer,\n _beneficiary,\n _amount,\n beneficiaryTokenCount,\n _memo,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Receives funds belonging to the specified project.\n /// @param _projectId The ID of the project to which the funds received belong.\n /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\n /// @param _shouldRefundHeldFees A flag indicating if held fees should be refunded based on the amount being added.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the emitted event.\n function _addToBalanceOf(\n uint256 _projectId,\n uint256 _amount,\n bool _shouldRefundHeldFees,\n string memory _memo,\n bytes memory _metadata\n ) internal {\n // Refund any held fees to make sure the project doesn't pay double for funds going in and out of the protocol.\n uint256 _refundedFees = _shouldRefundHeldFees ? _refundHeldFees(_projectId, _amount) : 0;\n\n // Record the added funds with any refunded fees.\n IJBSingleTokenPaymentTerminalStore(store).recordAddedBalanceFor(\n _projectId,\n _amount + _refundedFees\n );\n\n emit AddToBalance(_projectId, _amount, _refundedFees, _memo, _metadata, msg.sender);\n }\n\n /// @notice Refund fees based on the specified amount.\n /// @param _projectId The project for which fees are being refunded.\n /// @param _amount The amount to base the refund on, as a fixed point number with the same amount of decimals as this terminal.\n /// @return refundedFees How much fees were refunded, as a fixed point number with the same number of decimals as this terminal\n function _refundHeldFees(\n uint256 _projectId,\n uint256 _amount\n ) internal returns (uint256 refundedFees) {\n // Get a reference to the project's held fees.\n JBFee[] memory _heldFees = _heldFeesOf[_projectId];\n\n // Delete the current held fees.\n delete _heldFeesOf[_projectId];\n\n // Get a reference to the leftover amount once all fees have been settled.\n uint256 leftoverAmount = _amount;\n\n // Push length in stack\n uint256 _heldFeesLength = _heldFees.length;\n\n // Process each fee.\n for (uint256 _i; _i < _heldFeesLength; ) {\n if (leftoverAmount == 0) _heldFeesOf[_projectId].push(_heldFees[_i]);\n else if (leftoverAmount >= _heldFees[_i].amount) {\n unchecked {\n leftoverAmount = leftoverAmount - _heldFees[_i].amount;\n refundedFees += _feeAmount(\n _heldFees[_i].amount,\n _heldFees[_i].fee,\n _heldFees[_i].feeDiscount\n );\n }\n } else {\n unchecked {\n _heldFeesOf[_projectId].push(\n JBFee(\n _heldFees[_i].amount - leftoverAmount,\n _heldFees[_i].fee,\n _heldFees[_i].feeDiscount,\n _heldFees[_i].beneficiary\n )\n );\n refundedFees += _feeAmount(leftoverAmount, _heldFees[_i].fee, _heldFees[_i].feeDiscount);\n }\n leftoverAmount = 0;\n }\n\n unchecked {\n ++_i;\n }\n }\n\n emit RefundHeldFees(_projectId, _amount, refundedFees, leftoverAmount, msg.sender);\n }\n\n /// @notice Returns the fee amount based on the provided amount for the specified project.\n /// @param _amount The amount that the fee is based on, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _fee The percentage of the fee, out of MAX_FEE.\n /// @param _feeDiscount The percentage discount that should be applied out of the max amount, out of MAX_FEE_DISCOUNT.\n /// @return The amount of the fee, as a fixed point number with the same amount of decimals as this terminal.\n function _feeAmount(\n uint256 _amount,\n uint256 _fee,\n uint256 _feeDiscount\n ) internal pure returns (uint256) {\n // Calculate the discounted fee.\n uint256 _discountedFee = _fee -\n PRBMath.mulDiv(_fee, _feeDiscount, JBConstants.MAX_FEE_DISCOUNT);\n\n // The amount of tokens from the `_amount` to pay as a fee.\n return\n _amount - PRBMath.mulDiv(_amount, JBConstants.MAX_FEE, _discountedFee + JBConstants.MAX_FEE);\n }\n\n /// @notice Get the fee discount from the fee gauge for the specified project.\n /// @param _projectId The ID of the project to get a fee discount for.\n /// @return feeDiscount The fee discount, which should be interpreted as a percentage out MAX_FEE_DISCOUNT.\n function _currentFeeDiscount(uint256 _projectId) internal view returns (uint256) {\n // Can't take a fee if the protocol project doesn't have a terminal that accepts the token.\n if (\n directory.primaryTerminalOf(_FEE_BENEFICIARY_PROJECT_ID, token) ==\n IJBPaymentTerminal(address(0))\n ) return JBConstants.MAX_FEE_DISCOUNT;\n\n // Get the fee discount.\n if (feeGauge != address(0))\n // If the guage reverts, keep the discount at 0.\n try IJBFeeGauge(feeGauge).currentDiscountFor(_projectId) returns (uint256 discount) {\n // If the fee discount is greater than the max, we ignore the return value\n if (discount <= JBConstants.MAX_FEE_DISCOUNT) return discount;\n } catch {\n return 0;\n }\n\n return 0;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165Checker.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC165.sol\";\n\n/**\n * @dev Library used to query support of an interface declared via {IERC165}.\n *\n * Note that these functions return the actual result of the query: they do not\n * `revert` if an interface is not supported. It is up to the caller to decide\n * what to do in these cases.\n */\nlibrary ERC165Checker {\n // As per the EIP-165 spec, no interface should ever match 0xffffffff\n bytes4 private constant _INTERFACE_ID_INVALID = 0xffffffff;\n\n /**\n * @dev Returns true if `account` supports the {IERC165} interface,\n */\n function supportsERC165(address account) internal view returns (bool) {\n // Any contract that implements ERC165 must explicitly indicate support of\n // InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid\n return\n _supportsERC165Interface(account, type(IERC165).interfaceId) &&\n !_supportsERC165Interface(account, _INTERFACE_ID_INVALID);\n }\n\n /**\n * @dev Returns true if `account` supports the interface defined by\n * `interfaceId`. Support for {IERC165} itself is queried automatically.\n *\n * See {IERC165-supportsInterface}.\n */\n function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) {\n // query support of both ERC165 as per the spec and support of _interfaceId\n return supportsERC165(account) && _supportsERC165Interface(account, interfaceId);\n }\n\n /**\n * @dev Returns a boolean array where each value corresponds to the\n * interfaces passed in and whether they're supported or not. This allows\n * you to batch check interfaces for a contract where your expectation\n * is that some interfaces may not be supported.\n *\n * See {IERC165-supportsInterface}.\n *\n * _Available since v3.4._\n */\n function getSupportedInterfaces(address account, bytes4[] memory interfaceIds)\n internal\n view\n returns (bool[] memory)\n {\n // an array of booleans corresponding to interfaceIds and whether they're supported or not\n bool[] memory interfaceIdsSupported = new bool[](interfaceIds.length);\n\n // query support of ERC165 itself\n if (supportsERC165(account)) {\n // query support of each interface in interfaceIds\n for (uint256 i = 0; i < interfaceIds.length; i++) {\n interfaceIdsSupported[i] = _supportsERC165Interface(account, interfaceIds[i]);\n }\n }\n\n return interfaceIdsSupported;\n }\n\n /**\n * @dev Returns true if `account` supports all the interfaces defined in\n * `interfaceIds`. Support for {IERC165} itself is queried automatically.\n *\n * Batch-querying can lead to gas savings by skipping repeated checks for\n * {IERC165} support.\n *\n * See {IERC165-supportsInterface}.\n */\n function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) {\n // query support of ERC165 itself\n if (!supportsERC165(account)) {\n return false;\n }\n\n // query support of each interface in _interfaceIds\n for (uint256 i = 0; i < interfaceIds.length; i++) {\n if (!_supportsERC165Interface(account, interfaceIds[i])) {\n return false;\n }\n }\n\n // all interfaces supported\n return true;\n }\n\n /**\n * @notice Query if a contract implements an interface, does not check ERC165 support\n * @param account The address of the contract to query for support of an interface\n * @param interfaceId The interface identifier, as specified in ERC-165\n * @return true if the contract at account indicates support of the interface with\n * identifier interfaceId, false otherwise\n * @dev Assumes that account contains a contract that supports ERC165, otherwise\n * the behavior of this method is undefined. This precondition can be checked\n * with {supportsERC165}.\n * Interface identification is specified in ERC-165.\n */\n function _supportsERC165Interface(address account, bytes4 interfaceId) private view returns (bool) {\n bytes memory encodedParams = abi.encodeWithSelector(IERC165.supportsInterface.selector, interfaceId);\n (bool success, bytes memory result) = account.staticcall{gas: 30000}(encodedParams);\n if (result.length < 32) return false;\n return success && abi.decode(result, (bool));\n }\n}\n" + }, + "contracts/interfaces/IJBAllowanceTerminal3_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBAllowanceTerminal3_1 {\n function useAllowanceOf(\n uint256 projectId,\n uint256 amount,\n uint256 currency,\n address token,\n uint256 minReturnedTokens,\n address payable beneficiary,\n string calldata memo,\n bytes calldata metadata\n ) external returns (uint256 netDistributedAmount);\n}\n" + }, + "contracts/interfaces/IJBFeeGauge.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBFeeGauge {\n function currentDiscountFor(uint256 projectId) external view returns (uint256);\n}\n" + }, + "contracts/interfaces/IJBPayoutRedemptionPaymentTerminal3_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBFee} from './../structs/JBFee.sol';\nimport {IJBAllowanceTerminal3_1} from './IJBAllowanceTerminal3_1.sol';\nimport {IJBDirectory} from './IJBDirectory.sol';\nimport {IJBFeeHoldingTerminal} from './IJBFeeHoldingTerminal.sol';\nimport {IJBPayDelegate} from './IJBPayDelegate.sol';\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\nimport {IJBPayoutTerminal3_1} from './IJBPayoutTerminal3_1.sol';\nimport {IJBPrices} from './IJBPrices.sol';\nimport {IJBProjects} from './IJBProjects.sol';\nimport {IJBRedemptionDelegate} from './IJBRedemptionDelegate.sol';\nimport {IJBRedemptionTerminal} from './IJBRedemptionTerminal.sol';\nimport {IJBSplitsStore} from './IJBSplitsStore.sol';\nimport {JBDidPayData} from './../structs/JBDidPayData.sol';\nimport {JBDidRedeemData} from './../structs/JBDidRedeemData.sol';\nimport {JBSplit} from './../structs/JBSplit.sol';\n\ninterface IJBPayoutRedemptionPaymentTerminal3_1 is\n IJBPaymentTerminal,\n IJBPayoutTerminal3_1,\n IJBAllowanceTerminal3_1,\n IJBRedemptionTerminal,\n IJBFeeHoldingTerminal\n{\n event AddToBalance(\n uint256 indexed projectId,\n uint256 amount,\n uint256 refundedFees,\n string memo,\n bytes metadata,\n address caller\n );\n\n event Migrate(\n uint256 indexed projectId,\n IJBPaymentTerminal indexed to,\n uint256 amount,\n address caller\n );\n\n event DistributePayouts(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n address beneficiary,\n uint256 amount,\n uint256 distributedAmount,\n uint256 fee,\n uint256 beneficiaryDistributionAmount,\n bytes metadata,\n address caller\n );\n\n event UseAllowance(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n address beneficiary,\n uint256 amount,\n uint256 distributedAmount,\n uint256 netDistributedamount,\n string memo,\n bytes metadata,\n address caller\n );\n\n event HoldFee(\n uint256 indexed projectId,\n uint256 indexed amount,\n uint256 indexed fee,\n uint256 feeDiscount,\n address beneficiary,\n address caller\n );\n\n event ProcessFee(\n uint256 indexed projectId,\n uint256 indexed amount,\n bool indexed wasHeld,\n address beneficiary,\n address caller\n );\n\n event RefundHeldFees(\n uint256 indexed projectId,\n uint256 indexed amount,\n uint256 indexed refundedFees,\n uint256 leftoverAmount,\n address caller\n );\n\n event Pay(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n address payer,\n address beneficiary,\n uint256 amount,\n uint256 beneficiaryTokenCount,\n string memo,\n bytes metadata,\n address caller\n );\n\n event DelegateDidPay(\n IJBPayDelegate indexed delegate,\n JBDidPayData data,\n uint256 delegatedAmount,\n address caller\n );\n\n event RedeemTokens(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n address holder,\n address beneficiary,\n uint256 tokenCount,\n uint256 reclaimedAmount,\n string memo,\n bytes metadata,\n address caller\n );\n\n event DelegateDidRedeem(\n IJBRedemptionDelegate indexed delegate,\n JBDidRedeemData data,\n uint256 delegatedAmount,\n address caller\n );\n\n event DistributeToPayoutSplit(\n uint256 indexed projectId,\n uint256 indexed domain,\n uint256 indexed group,\n JBSplit split,\n uint256 amount,\n uint256 netAmount,\n address caller\n );\n\n event SetFee(uint256 fee, address caller);\n\n event SetFeeGauge(address indexed feeGauge, address caller);\n\n event SetFeelessAddress(address indexed addrs, bool indexed flag, address caller);\n\n event PayoutReverted(\n uint256 indexed projectId,\n JBSplit split,\n uint256 amount,\n bytes reason,\n address caller\n );\n\n event FeeReverted(\n uint256 indexed projectId,\n uint256 indexed feeProjectId,\n uint256 amount,\n bytes reason,\n address caller\n );\n\n function projects() external view returns (IJBProjects);\n\n function splitsStore() external view returns (IJBSplitsStore);\n\n function directory() external view returns (IJBDirectory);\n\n function prices() external view returns (IJBPrices);\n\n function store() external view returns (address);\n\n function baseWeightCurrency() external view returns (uint256);\n\n function payoutSplitsGroup() external view returns (uint256);\n\n function heldFeesOf(uint256 projectId) external view returns (JBFee[] memory);\n\n function fee() external view returns (uint256);\n\n function feeGauge() external view returns (address);\n\n function isFeelessAddress(address account) external view returns (bool);\n\n function migrate(uint256 projectId, IJBPaymentTerminal to) external returns (uint256 balance);\n\n function processFees(uint256 projectId) external;\n\n function setFee(uint256 fee) external;\n\n function setFeeGauge(address feeGauge) external;\n\n function setFeelessAddress(address account, bool flag) external;\n}\n" + }, + "contracts/interfaces/IJBPayoutTerminal3_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBPayoutTerminal3_1 {\n function distributePayoutsOf(\n uint256 projectId,\n uint256 amount,\n uint256 currency,\n address token,\n uint256 minReturnedTokens,\n bytes calldata metadata\n ) external returns (uint256 netLeftoverDistributionAmount);\n}\n" + }, + "contracts/abstract/JBSingleTokenPaymentTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {ERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol';\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\nimport {IJBSingleTokenPaymentTerminal} from './../interfaces/IJBSingleTokenPaymentTerminal.sol';\n\n/// @notice Generic terminal managing all inflows of funds into the protocol ecosystem for one token.\nabstract contract JBSingleTokenPaymentTerminal is ERC165, IJBSingleTokenPaymentTerminal {\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice The token that this terminal accepts.\n address public immutable override token;\n\n /// @notice The number of decimals the token fixed point amounts are expected to have.\n uint256 public immutable override decimals;\n\n /// @notice The currency to use when resolving price feeds for this terminal.\n uint256 public immutable override currency;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice A flag indicating if this terminal accepts the specified token.\n /// @param _token The token to check if this terminal accepts or not.\n /// @param _projectId The project ID to check for token acceptance.\n /// @return The flag.\n function acceptsToken(address _token, uint256 _projectId) external view override returns (bool) {\n _projectId; // Prevents unused var compiler and natspec complaints.\n\n return _token == token;\n }\n\n /// @notice The decimals that should be used in fixed number accounting for the specified token.\n /// @param _token The token to check for the decimals of.\n /// @return The number of decimals for the token.\n function decimalsForToken(address _token) external view override returns (uint256) {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return decimals;\n }\n\n /// @notice The currency that should be used for the specified token.\n /// @param _token The token to check for the currency of.\n /// @return The currency index.\n function currencyForToken(address _token) external view override returns (uint256) {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return currency;\n }\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if the provided interface ID is supported.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(ERC165, IERC165) returns (bool) {\n return\n _interfaceId == type(IJBPaymentTerminal).interfaceId ||\n _interfaceId == type(IJBSingleTokenPaymentTerminal).interfaceId ||\n super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _token The token that this terminal manages.\n /// @param _decimals The number of decimals the token fixed point amounts are expected to have.\n /// @param _currency The currency that this terminal's token adheres to for price feeds.\n constructor(address _token, uint256 _decimals, uint256 _currency) {\n token = _token;\n decimals = _decimals;\n currency = _currency;\n }\n}\n" + }, + "contracts/interfaces/IJBFeeHoldingTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBFeeHoldingTerminal {\n function addToBalanceOf(\n uint256 projectId,\n uint256 amount,\n address token,\n bool shouldRefundHeldFees,\n string calldata memo,\n bytes calldata metadata\n ) external payable;\n}\n" + }, + "contracts/JBETHPaymentTerminal3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Address} from '@openzeppelin/contracts/utils/Address.sol';\nimport {JBPayoutRedemptionPaymentTerminal3_1_1} from './abstract/JBPayoutRedemptionPaymentTerminal3_1_1.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\nimport {JBCurrencies} from './libraries/JBCurrencies.sol';\nimport {JBSplitsGroups} from './libraries/JBSplitsGroups.sol';\nimport {JBTokens} from './libraries/JBTokens.sol';\n\n/// @notice Manages all inflows and outflows of ETH funds into the protocol ecosystem.\ncontract JBETHPaymentTerminal3_1_1 is JBPayoutRedemptionPaymentTerminal3_1_1 {\n //*********************************************************************//\n // -------------------------- internal views ------------------------- //\n //*********************************************************************//\n\n /// @notice Checks the balance of tokens in this contract.\n /// @return The contract's balance, as a fixed point number with the same amount of decimals as this terminal.\n function _balance() internal view override returns (uint256) {\n return address(this).balance;\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _prices A contract that exposes price feeds.\n /// @param _store A contract that stores the terminal's data.\n /// @param _owner The address that will own this contract.\n constructor(\n uint256 _baseWeightCurrency,\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBSplitsStore _splitsStore,\n IJBPrices _prices,\n address _store,\n address _owner\n )\n JBPayoutRedemptionPaymentTerminal3_1_1(\n JBTokens.ETH,\n 18, // 18 decimals.\n JBCurrencies.ETH,\n _baseWeightCurrency,\n JBSplitsGroups.ETH_PAYOUT,\n _operatorStore,\n _projects,\n _directory,\n _splitsStore,\n _prices,\n _store,\n _owner\n )\n // solhint-disable-next-line no-empty-blocks\n {\n\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Transfers tokens.\n /// @param _from The address from which the transfer should originate.\n /// @param _to The address to which the transfer should go.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _transferFrom(address _from, address payable _to, uint256 _amount) internal override {\n _from; // Prevents unused var compiler and natspec complaints.\n\n Address.sendValue(_to, _amount);\n }\n}\n" + }, + "contracts/abstract/JBPayoutRedemptionPaymentTerminal3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {ERC165Checker} from '@openzeppelin/contracts/utils/introspection/ERC165Checker.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {JBFeeType} from './../enums/JBFeeType.sol';\nimport {IJBAllowanceTerminal3_1} from './../interfaces/IJBAllowanceTerminal3_1.sol';\nimport {IJBController} from './../interfaces/IJBController.sol';\nimport {IJBDirectory} from './../interfaces/IJBDirectory.sol';\nimport {IJBPayoutRedemptionPaymentTerminal3_1} from './../interfaces/IJBPayoutRedemptionPaymentTerminal3_1.sol';\nimport {IJBPayoutRedemptionPaymentTerminal3_1_1} from './../interfaces/IJBPayoutRedemptionPaymentTerminal3_1_1.sol';\nimport {IJBSplitsStore} from './../interfaces/IJBSplitsStore.sol';\nimport {IJBFeeGauge3_1} from './../interfaces/IJBFeeGauge3_1.sol';\nimport {IJBOperatable} from './../interfaces/IJBOperatable.sol';\nimport {IJBOperatorStore} from './../interfaces/IJBOperatorStore.sol';\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\nimport {IJBPayoutTerminal3_1} from './../interfaces/IJBPayoutTerminal3_1.sol';\nimport {IJBPrices} from './../interfaces/IJBPrices.sol';\nimport {IJBProjects} from './../interfaces/IJBProjects.sol';\nimport {IJBRedemptionTerminal} from './../interfaces/IJBRedemptionTerminal.sol';\nimport {IJBSingleTokenPaymentTerminalStore3_1_1} from './../interfaces/IJBSingleTokenPaymentTerminalStore3_1_1.sol';\nimport {IJBSplitAllocator} from './../interfaces/IJBSplitAllocator.sol';\nimport {JBConstants} from './../libraries/JBConstants.sol';\nimport {JBCurrencies} from './../libraries/JBCurrencies.sol';\nimport {JBFixedPointNumber} from './../libraries/JBFixedPointNumber.sol';\nimport {JBFundingCycleMetadataResolver} from './../libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBOperations} from './../libraries/JBOperations.sol';\nimport {JBTokens} from './../libraries/JBTokens.sol';\nimport {JBDidRedeemData3_1_1} from './../structs/JBDidRedeemData3_1_1.sol';\nimport {JBDidPayData3_1_1} from './../structs/JBDidPayData3_1_1.sol';\nimport {JBFee} from './../structs/JBFee.sol';\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\nimport {JBPayDelegateAllocation3_1_1} from './../structs/JBPayDelegateAllocation3_1_1.sol';\nimport {JBRedemptionDelegateAllocation3_1_1} from './../structs/JBRedemptionDelegateAllocation3_1_1.sol';\nimport {JBSplit} from './../structs/JBSplit.sol';\nimport {JBSplitAllocationData} from './../structs/JBSplitAllocationData.sol';\nimport {JBTokenAmount} from './../structs/JBTokenAmount.sol';\nimport {JBOperatable} from './JBOperatable.sol';\nimport {JBSingleTokenPaymentTerminal} from './JBSingleTokenPaymentTerminal.sol';\n\n/// @notice Generic terminal managing all inflows and outflows of funds into the protocol ecosystem.\nabstract contract JBPayoutRedemptionPaymentTerminal3_1_1 is\n JBSingleTokenPaymentTerminal,\n JBOperatable,\n Ownable,\n IJBPayoutRedemptionPaymentTerminal3_1,\n IJBPayoutRedemptionPaymentTerminal3_1_1\n{\n // A library that parses the packed funding cycle metadata into a friendlier format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error FEE_TOO_HIGH();\n error INADEQUATE_DISTRIBUTION_AMOUNT();\n error INADEQUATE_RECLAIM_AMOUNT();\n error INADEQUATE_TOKEN_COUNT();\n error NO_MSG_VALUE_ALLOWED();\n error PAY_TO_ZERO_ADDRESS();\n error PROJECT_TERMINAL_MISMATCH();\n error REDEEM_TO_ZERO_ADDRESS();\n error TERMINAL_TOKENS_INCOMPATIBLE();\n\n //*********************************************************************//\n // --------------------- internal stored constants ------------------- //\n //*********************************************************************//\n\n /// @notice Maximum fee that can be set for a funding cycle configuration.\n /// @dev Out of MAX_FEE (50_000_000 / 1_000_000_000).\n uint256 internal constant _FEE_CAP = 50_000_000;\n\n /// @notice The fee beneficiary project ID is 1, as it should be the first project launched during the deployment process.\n uint256 internal constant _FEE_BENEFICIARY_PROJECT_ID = 1;\n\n //*********************************************************************//\n // --------------------- internal stored properties ------------------ //\n //*********************************************************************//\n\n /// @notice Fees that are being held to be processed later.\n /// @custom:param _projectId The ID of the project for which fees are being held.\n mapping(uint256 => JBFee[]) internal _heldFeesOf;\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice Mints ERC-721's that represent project ownership and transfers.\n IJBProjects public immutable override projects;\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n /// @notice The contract that stores splits for each project.\n IJBSplitsStore public immutable override splitsStore;\n\n /// @notice The contract that exposes price feeds.\n IJBPrices public immutable override prices;\n\n /// @notice The contract that stores and manages the terminal's data.\n address public immutable override store;\n\n /// @notice The currency to base token issuance on.\n /// @dev If this differs from `currency`, there must be a price feed available to convert `currency` to `baseWeightCurrency`.\n uint256 public immutable override baseWeightCurrency;\n\n /// @notice The group that payout splits coming from this terminal are identified by.\n uint256 public immutable override payoutSplitsGroup;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The platform fee percent.\n /// @dev Out of MAX_FEE (25_000_000 / 1_000_000_000)\n uint256 public override fee = 25_000_000; // 2.5%\n\n /// @notice The data source that returns a discount to apply to a project's fee.\n address public override feeGauge;\n\n /// @notice Addresses that can be paid towards from this terminal without incurring a fee.\n /// @dev Only addresses that are considered to be contained within the ecosystem can be feeless. Funds sent outside the ecosystem may incur fees despite being stored as feeless.\n /// @custom:param _address The address that can be paid toward.\n mapping(address => bool) public override isFeelessAddress;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Gets the current overflowed amount in this terminal for a specified project, in terms of ETH.\n /// @dev The current overflow is represented as a fixed point number with 18 decimals.\n /// @param _projectId The ID of the project to get overflow for.\n /// @return The current amount of ETH overflow that project has in this terminal, as a fixed point number with 18 decimals.\n function currentEthOverflowOf(\n uint256 _projectId\n ) external view virtual override returns (uint256) {\n // Get this terminal's current overflow.\n uint256 _overflow = IJBSingleTokenPaymentTerminalStore3_1_1(store).currentOverflowOf(\n this,\n _projectId\n );\n\n // Adjust the decimals of the fixed point number if needed to have 18 decimals.\n uint256 _adjustedOverflow = (decimals == 18)\n ? _overflow\n : JBFixedPointNumber.adjustDecimals(_overflow, decimals, 18);\n\n // Return the amount converted to ETH.\n return\n (currency == JBCurrencies.ETH)\n ? _adjustedOverflow\n : PRBMath.mulDiv(\n _adjustedOverflow,\n 10 ** decimals,\n prices.priceFor(currency, JBCurrencies.ETH, decimals)\n );\n }\n\n /// @notice The fees that are currently being held to be processed later for each project.\n /// @param _projectId The ID of the project for which fees are being held.\n /// @return An array of fees that are being held.\n function heldFeesOf(uint256 _projectId) external view override returns (JBFee[] memory) {\n return _heldFeesOf[_projectId];\n }\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if the provided interface ID is supported.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(JBSingleTokenPaymentTerminal, IERC165) returns (bool) {\n return\n _interfaceId == type(IJBPayoutRedemptionPaymentTerminal3_1_1).interfaceId ||\n _interfaceId == type(IJBPayoutRedemptionPaymentTerminal3_1).interfaceId ||\n _interfaceId == type(IJBPayoutTerminal3_1).interfaceId ||\n _interfaceId == type(IJBAllowanceTerminal3_1).interfaceId ||\n _interfaceId == type(IJBRedemptionTerminal).interfaceId ||\n _interfaceId == type(IJBOperatable).interfaceId ||\n super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // -------------------------- internal views ------------------------- //\n //*********************************************************************//\n\n /// @notice Checks the balance of tokens in this contract.\n /// @return The contract's balance.\n function _balance() internal view virtual returns (uint256);\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _token The token that this terminal manages.\n /// @param _decimals The number of decimals the token fixed point amounts are expected to have.\n /// @param _currency The currency that this terminal's token adheres to for price feeds.\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _payoutSplitsGroup The group that denotes payout splits from this terminal in the splits store.\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _prices A contract that exposes price feeds.\n /// @param _store A contract that stores the terminal's data.\n /// @param _owner The address that will own this contract.\n constructor(\n // payable constructor save the gas used to check msg.value==0\n address _token,\n uint256 _decimals,\n uint256 _currency,\n uint256 _baseWeightCurrency,\n uint256 _payoutSplitsGroup,\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBSplitsStore _splitsStore,\n IJBPrices _prices,\n address _store,\n address _owner\n )\n payable\n JBSingleTokenPaymentTerminal(_token, _decimals, _currency)\n JBOperatable(_operatorStore)\n {\n baseWeightCurrency = _baseWeightCurrency;\n payoutSplitsGroup = _payoutSplitsGroup;\n projects = _projects;\n directory = _directory;\n splitsStore = _splitsStore;\n prices = _prices;\n store = _store;\n\n transferOwnership(_owner);\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Contribute tokens to a project.\n /// @param _projectId The ID of the project being paid.\n /// @param _amount The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place.\n /// @param _token The token being paid. This terminal ignores this property since it only manages one token.\n /// @param _beneficiary The address to mint tokens for and pass along to the funding cycle's data source and delegate.\n /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\n /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals.\n function pay(\n uint256 _projectId,\n uint256 _amount,\n address _token,\n address _beneficiary,\n uint256 _minReturnedTokens,\n bool _preferClaimedTokens,\n string calldata _memo,\n bytes calldata _metadata\n ) external payable virtual override returns (uint256) {\n _token; // Prevents unused var compiler and natspec complaints.\n\n // valid terminal check\n _isTerminalOf(_projectId);\n\n // ETH shouldn't be sent if this terminal's token isn't ETH.\n if (token != JBTokens.ETH) {\n if (msg.value != 0) revert NO_MSG_VALUE_ALLOWED();\n\n // Get a reference to the balance before receiving tokens.\n uint256 _balanceBefore = _balance();\n\n // Transfer tokens to this terminal from the msg sender.\n _transferFrom(msg.sender, payable(address(this)), _amount);\n\n // The amount should reflect the change in balance.\n _amount = _balance() - _balanceBefore;\n }\n // If this terminal's token is ETH, override _amount with msg.value.\n else _amount = msg.value;\n\n return\n _pay(\n _amount,\n msg.sender,\n _projectId,\n _beneficiary,\n _minReturnedTokens,\n _preferClaimedTokens,\n _memo,\n _metadata\n );\n }\n\n /// @notice Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source.\n /// @dev Only a token holder or a designated operator can redeem its tokens.\n /// @param _holder The account to redeem tokens for.\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\n /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals.\n /// @param _token The token being reclaimed. This terminal ignores this property since it only manages one token.\n /// @param _minReturnedTokens The minimum amount of terminal tokens expected in return, as a fixed point number with the same amount of decimals as the terminal.\n /// @param _beneficiary The address to send the terminal tokens to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return reclaimAmount The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals.\n function redeemTokensOf(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n address _token,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo,\n bytes memory _metadata\n )\n external\n virtual\n override\n requirePermission(_holder, _projectId, JBOperations.REDEEM)\n returns (uint256 reclaimAmount)\n {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return\n _redeemTokensOf(\n _holder,\n _projectId,\n _tokenCount,\n _minReturnedTokens,\n _beneficiary,\n _memo,\n _metadata\n );\n }\n\n /// @notice Distributes payouts for a project with the distribution limit of its current funding cycle.\n /// @dev Payouts are sent to the preprogrammed splits. Any leftover is sent to the project's owner.\n /// @dev 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.\n /// @dev All funds distributed outside of this contract or any feeless terminals incure the protocol fee.\n /// @param _projectId The ID of the project having its payouts distributed.\n /// @param _amount The amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency.\n /// @param _token The token being distributed. This terminal ignores this property since it only manages one token.\n /// @param _minReturnedTokens 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.\n /// @param _metadata Bytes to send along to the emitted event, if provided.\n /// @return netLeftoverDistributionAmount The amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal.\n function distributePayoutsOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n address _token,\n uint256 _minReturnedTokens,\n bytes calldata _metadata\n ) external virtual override returns (uint256 netLeftoverDistributionAmount) {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return _distributePayoutsOf(_projectId, _amount, _currency, _minReturnedTokens, _metadata);\n }\n\n /// @notice Allows a project to send funds from its overflow up to the preconfigured allowance.\n /// @dev Only a project's owner or a designated operator can use its allowance.\n /// @dev Incurs the protocol fee.\n /// @param _projectId The ID of the project to use the allowance of.\n /// @param _amount The amount of terminal tokens to use from this project's current allowance, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's overflow allowance currency.\n /// @param _token The token being distributed. This terminal ignores this property since it only manages one token.\n /// @param _minReturnedTokens The minimum number of tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with 18 decimals.\n /// @param _beneficiary The address to send the funds to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the emitted event, if provided.\n /// @return netDistributedAmount The amount of tokens that was distributed to the beneficiary, as a fixed point number with the same amount of decimals as the terminal.\n function useAllowanceOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n address _token,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo,\n bytes calldata _metadata\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.USE_ALLOWANCE)\n returns (uint256 netDistributedAmount)\n {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return\n _useAllowanceOf(\n _projectId,\n _amount,\n _currency,\n _minReturnedTokens,\n _beneficiary,\n _memo,\n _metadata\n );\n }\n\n /// @notice Allows a project owner to migrate its funds and operations to a new terminal that accepts the same token type.\n /// @dev Only a project's owner or a designated operator can migrate it.\n /// @param _projectId The ID of the project being migrated.\n /// @param _to The terminal contract that will gain the project's funds.\n /// @return balance The amount of funds that were migrated, as a fixed point number with the same amount of decimals as this terminal.\n function migrate(\n uint256 _projectId,\n IJBPaymentTerminal _to\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.MIGRATE_TERMINAL)\n returns (uint256 balance)\n {\n // The terminal being migrated to must accept the same token as this terminal.\n if (!_to.acceptsToken(token, _projectId)) revert TERMINAL_TOKENS_INCOMPATIBLE();\n\n // Record the migration in the store.\n balance = IJBSingleTokenPaymentTerminalStore3_1_1(store).recordMigration(_projectId);\n\n // Transfer the balance if needed.\n if (balance != 0) {\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_to), balance);\n\n // If this terminal's token is ETH, send it in msg.value.\n uint256 _payableValue = token == JBTokens.ETH ? balance : 0;\n\n // Withdraw the balance to transfer to the new terminal;\n _to.addToBalanceOf{value: _payableValue}(_projectId, balance, token, '', bytes(''));\n }\n\n emit Migrate(_projectId, _to, balance, msg.sender);\n }\n\n /// @notice Receives funds belonging to the specified project.\n /// @param _projectId The ID of the project to which the funds received belong.\n /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\n /// @param _token The token being paid. This terminal ignores this property since it only manages one currency.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the emitted event.\n function addToBalanceOf(\n uint256 _projectId,\n uint256 _amount,\n address _token,\n string calldata _memo,\n bytes calldata _metadata\n ) external payable virtual override {\n // valid terminal check\n _isTerminalOf(_projectId);\n\n // Do not refund held fees by default.\n addToBalanceOf(_projectId, _amount, _token, false, _memo, _metadata);\n }\n\n /// @notice Process any fees that are being held for the project.\n /// @dev Only a project owner, an operator, or the contract's owner can process held fees.\n /// @param _projectId The ID of the project whos held fees should be processed.\n function processFees(\n uint256 _projectId\n )\n external\n virtual\n override\n requirePermissionAllowingOverride(\n projects.ownerOf(_projectId),\n _projectId,\n JBOperations.PROCESS_FEES,\n msg.sender == owner()\n )\n {\n // Get a reference to the project's held fees.\n JBFee[] memory _heldFees = _heldFeesOf[_projectId];\n\n // Delete the held fees.\n delete _heldFeesOf[_projectId];\n\n // Push array length in stack\n uint256 _heldFeeLength = _heldFees.length;\n\n // Keep a reference to the amount.\n uint256 _amount;\n\n // Process each fee.\n for (uint256 _i; _i < _heldFeeLength; ) {\n // Get the fee amount.\n _amount = (\n _heldFees[_i].fee == 0 || _heldFees[_i].feeDiscount == JBConstants.MAX_FEE_DISCOUNT\n ? 0\n : _feeAmount(_heldFees[_i].amount, _heldFees[_i].fee, _heldFees[_i].feeDiscount)\n );\n\n // Process the fee.\n _processFee(_amount, _heldFees[_i].beneficiary, _projectId);\n\n emit ProcessFee(_projectId, _amount, true, _heldFees[_i].beneficiary, msg.sender);\n\n unchecked {\n ++_i;\n }\n }\n }\n\n /// @notice Allows the fee to be updated.\n /// @dev Only the owner of this contract can change the fee.\n /// @param _fee The new fee, out of MAX_FEE.\n function setFee(uint256 _fee) external virtual override onlyOwner {\n // The provided fee must be within the max.\n if (_fee > _FEE_CAP) revert FEE_TOO_HIGH();\n\n // Store the new fee.\n fee = _fee;\n\n emit SetFee(_fee, msg.sender);\n }\n\n /// @notice Allows the fee gauge to be updated.\n /// @dev Only the owner of this contract can change the fee gauge.\n /// @param _feeGauge The new fee gauge.\n function setFeeGauge(address _feeGauge) external virtual override onlyOwner {\n // Store the new fee gauge.\n feeGauge = _feeGauge;\n\n emit SetFeeGauge(_feeGauge, msg.sender);\n }\n\n /// @notice Sets whether projects operating on this terminal can pay towards the specified address without incurring a fee.\n /// @dev Only the owner of this contract can set addresses as feeless.\n /// @param _address The address that can be paid towards while still bypassing fees.\n /// @param _flag A flag indicating whether the terminal should be feeless or not.\n function setFeelessAddress(address _address, bool _flag) external virtual override onlyOwner {\n // Set the flag value.\n isFeelessAddress[_address] = _flag;\n\n emit SetFeelessAddress(_address, _flag, msg.sender);\n }\n\n //*********************************************************************//\n // ----------------------- public transactions ----------------------- //\n //*********************************************************************//\n\n /// @notice Receives funds belonging to the specified project.\n /// @param _projectId The ID of the project to which the funds received belong.\n /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\n /// @param _token The token being paid. This terminal ignores this property since it only manages one currency.\n /// @param _shouldRefundHeldFees A flag indicating if held fees should be refunded based on the amount being added.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the emitted event.\n function addToBalanceOf(\n uint256 _projectId,\n uint256 _amount,\n address _token,\n bool _shouldRefundHeldFees,\n string calldata _memo,\n bytes calldata _metadata\n ) public payable virtual override {\n // valid terminal check\n _isTerminalOf(_projectId);\n\n _token; // Prevents unused var compiler and natspec complaints.\n\n // If this terminal's token isn't ETH, make sure no msg.value was sent, then transfer the tokens in from msg.sender.\n if (token != JBTokens.ETH) {\n // Amount must be greater than 0.\n if (msg.value != 0) revert NO_MSG_VALUE_ALLOWED();\n\n // Get a reference to the balance before receiving tokens.\n uint256 _balanceBefore = _balance();\n\n // Transfer tokens to this terminal from the msg sender.\n _transferFrom(msg.sender, payable(address(this)), _amount);\n\n // The amount should reflect the change in balance.\n _amount = _balance() - _balanceBefore;\n }\n // If the terminal's token is ETH, override `_amount` with msg.value.\n else _amount = msg.value;\n\n // Add to balance.\n _addToBalanceOf(_projectId, _amount, _shouldRefundHeldFees, _memo, _metadata);\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Transfers tokens.\n /// @param _from The address from which the transfer should originate.\n /// @param _to The address to which the transfer should go.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _transferFrom(address _from, address payable _to, uint256 _amount) internal virtual {\n _from; // Prevents unused var compiler and natspec complaints.\n _to; // Prevents unused var compiler and natspec complaints.\n _amount; // Prevents unused var compiler and natspec complaints.\n }\n\n /// @notice Logic to be triggered before transferring tokens from this terminal.\n /// @param _to The address to which the transfer is going.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _beforeTransferTo(address _to, uint256 _amount) internal virtual {\n _to; // Prevents unused var compiler and natspec complaints.\n _amount; // Prevents unused var compiler and natspec complaints.\n }\n\n /// @notice Logic to be triggered if a transfer should be undone\n /// @param _to The address to which the transfer went.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _cancelTransferTo(address _to, uint256 _amount) internal virtual {\n _to; // Prevents unused var compiler and natspec complaints.\n _amount; // Prevents unused var compiler and natspec complaints.\n }\n\n /// @notice Verifies this terminal is a terminal of provided project ID.\n /// @param _projectId The ID of the project to check if this contract is a terminal of.\n function _isTerminalOf(uint256 _projectId) internal view {\n if (!directory.isTerminalOf(_projectId, this)) revert PROJECT_TERMINAL_MISMATCH();\n }\n\n /// @notice Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source.\n /// @dev Only a token holder or a designated operator can redeem its tokens.\n /// @param _holder The account to redeem tokens for.\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\n /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals.\n /// @param _minReturnedTokens The minimum amount of terminal tokens expected in return, as a fixed point number with the same amount of decimals as the terminal.\n /// @param _beneficiary The address to send the terminal tokens to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return reclaimAmount The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals.\n function _redeemTokensOf(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo,\n bytes memory _metadata\n ) internal returns (uint256 reclaimAmount) {\n // Can't send reclaimed funds to the zero address.\n if (_beneficiary == address(0)) revert REDEEM_TO_ZERO_ADDRESS();\n\n // Define variables that will be needed outside the scoped section below.\n // Keep a reference to the funding cycle during which the redemption is being made.\n JBFundingCycle memory _fundingCycle;\n\n // Scoped section prevents stack too deep. `_feeEligibleDistributionAmount`, `_feeDiscount` and `_feePercent` only used within scope.\n {\n // Keep a reference to the amount being reclaimed that should have fees withheld from.\n uint256 _feeEligibleDistributionAmount;\n\n // Keep a reference to the amount of discount to apply to the fee.\n uint256 _feeDiscount;\n\n // Keep a reference to the fee.\n uint256 _feePercent = fee;\n\n // Scoped section prevents stack too deep. `_delegateAllocations` only used within scope.\n {\n JBRedemptionDelegateAllocation3_1_1[] memory _delegateAllocations;\n\n // Record the redemption.\n (\n _fundingCycle,\n reclaimAmount,\n _delegateAllocations,\n _memo\n ) = IJBSingleTokenPaymentTerminalStore3_1_1(store).recordRedemptionFor(\n _holder,\n _projectId,\n _tokenCount,\n _memo,\n _metadata\n );\n\n // Set the reference to the fee discount to apply. No fee if the beneficiary is feeless or if the redemption rate is at its max.\n _feeDiscount = isFeelessAddress[_beneficiary] ||\n (_fundingCycle.redemptionRate() == JBConstants.MAX_REDEMPTION_RATE &&\n _fundingCycle.ballotRedemptionRate() == JBConstants.MAX_REDEMPTION_RATE) ||\n _feePercent == 0\n ? JBConstants.MAX_FEE_DISCOUNT\n : _currentFeeDiscount(_projectId, JBFeeType.REDEMPTION);\n\n // The amount being reclaimed must be at least as much as was expected.\n if (reclaimAmount < _minReturnedTokens) revert INADEQUATE_RECLAIM_AMOUNT();\n\n // Burn the project tokens.\n if (_tokenCount != 0)\n IJBController(directory.controllerOf(_projectId)).burnTokensOf(\n _holder,\n _projectId,\n _tokenCount,\n '',\n false\n );\n\n // If delegate allocations were specified by the data source, fulfill them.\n if (_delegateAllocations.length != 0) {\n JBDidRedeemData3_1_1 memory _data = JBDidRedeemData3_1_1(\n _holder,\n _projectId,\n _fundingCycle.configuration,\n _tokenCount,\n JBTokenAmount(token, reclaimAmount, decimals, currency),\n JBTokenAmount(token, 0, decimals, currency),\n _beneficiary,\n _memo,\n bytes(''),\n _metadata\n );\n\n // Keep a reference to the allocation.\n JBRedemptionDelegateAllocation3_1_1 memory _delegateAllocation;\n\n // Keep a reference to the fee.\n uint256 _delegatedAmountFee;\n\n // Keep a reference to the number of allocations.\n uint256 _numDelegates = _delegateAllocations.length;\n\n for (uint256 _i; _i < _numDelegates; ) {\n // Get a reference to the delegate being iterated on.\n _delegateAllocation = _delegateAllocations[_i];\n\n // Get the fee for the delegated amount.\n _delegatedAmountFee = _feePercent == 0\n ? 0\n : _feeAmount(_delegateAllocation.amount, _feePercent, _feeDiscount);\n\n // Add the delegated amount to the amount eligible for having a fee taken.\n if (_delegatedAmountFee != 0) {\n _feeEligibleDistributionAmount += _delegateAllocation.amount;\n _delegateAllocation.amount -= _delegatedAmountFee;\n }\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_delegateAllocation.delegate), _delegateAllocation.amount);\n\n // Pass the correct token forwardedAmount to the delegate\n _data.forwardedAmount.value = _delegateAllocation.amount;\n\n // Pass the correct metadata from the data source.\n _data.dataSourceMetadata = _delegateAllocation.metadata;\n\n _delegateAllocation.delegate.didRedeem{\n value: token == JBTokens.ETH ? _delegateAllocation.amount : 0\n }(_data);\n\n emit DelegateDidRedeem(\n _delegateAllocation.delegate,\n _data,\n _delegateAllocation.amount,\n _delegatedAmountFee,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n }\n\n // Send the reclaimed funds to the beneficiary.\n if (reclaimAmount != 0) {\n // Get the fee for the reclaimed amount.\n uint256 _reclaimAmountFee = _feeDiscount == JBConstants.MAX_FEE_DISCOUNT\n ? 0\n : _feeAmount(reclaimAmount, _feePercent, _feeDiscount);\n\n if (_reclaimAmountFee != 0) {\n _feeEligibleDistributionAmount += reclaimAmount;\n reclaimAmount -= _reclaimAmountFee;\n }\n\n // Subtract the fee from the reclaim amount.\n if (reclaimAmount != 0) _transferFrom(address(this), _beneficiary, reclaimAmount);\n }\n\n // Take the fee from all outbound reclaimations.\n _feeEligibleDistributionAmount != 0\n ? _takeFeeFrom(\n _projectId,\n false,\n _feeEligibleDistributionAmount,\n _feePercent,\n _beneficiary,\n _feeDiscount\n )\n : 0;\n }\n\n emit RedeemTokens(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _holder,\n _beneficiary,\n _tokenCount,\n reclaimAmount,\n _memo,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Distributes payouts for a project with the distribution limit of its current funding cycle.\n /// @dev Payouts are sent to the preprogrammed splits. Any leftover is sent to the project's owner.\n /// @dev 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.\n /// @dev All funds distributed outside of this contract or any feeless terminals incure the protocol fee.\n /// @param _projectId The ID of the project having its payouts distributed.\n /// @param _amount The amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency.\n /// @param _minReturnedTokens 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.\n /// @param _metadata Bytes to send along to the emitted event, if provided.\n /// @return netLeftoverDistributionAmount The amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal.\n function _distributePayoutsOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n uint256 _minReturnedTokens,\n bytes calldata _metadata\n ) internal returns (uint256 netLeftoverDistributionAmount) {\n // Record the distribution.\n (\n JBFundingCycle memory _fundingCycle,\n uint256 _distributedAmount\n ) = IJBSingleTokenPaymentTerminalStore3_1_1(store).recordDistributionFor(\n _projectId,\n _amount,\n _currency\n );\n\n // The amount being distributed must be at least as much as was expected.\n if (_distributedAmount < _minReturnedTokens) revert INADEQUATE_DISTRIBUTION_AMOUNT();\n\n // Get a reference to the project owner, which will receive tokens from paying the platform fee\n // and receive any extra distributable funds not allocated to payout splits.\n address payable _projectOwner = payable(projects.ownerOf(_projectId));\n\n // Define variables that will be needed outside the scoped section below.\n // Keep a reference to the fee amount that was paid.\n uint256 _feeTaken;\n\n // Scoped section prevents stack too deep. `_feePercent`, `_feeDiscount`, `_feeEligibleDistributionAmount`, and `_leftoverDistributionAmount` only used within scope.\n {\n // Keep a reference to the fee.\n uint256 _feePercent = fee;\n\n // Get the amount of discount that should be applied to any fees taken.\n // If the fee is zero, set the discount to 100% for convenience.\n uint256 _feeDiscount = _feePercent == 0\n ? JBConstants.MAX_FEE_DISCOUNT\n : _currentFeeDiscount(_projectId, JBFeeType.PAYOUT);\n\n // The amount distributed that is eligible for incurring fees.\n uint256 _feeEligibleDistributionAmount;\n\n // The amount leftover after distributing to the splits.\n uint256 _leftoverDistributionAmount;\n\n // Payout to splits and get a reference to the leftover transfer amount after all splits have been paid.\n // Also get a reference to the amount that was distributed to splits from which fees should be taken.\n (_leftoverDistributionAmount, _feeEligibleDistributionAmount) = _distributeToPayoutSplitsOf(\n _projectId,\n _fundingCycle.configuration,\n payoutSplitsGroup,\n _distributedAmount,\n _feePercent,\n _feeDiscount\n );\n\n if (_feeDiscount != JBConstants.MAX_FEE_DISCOUNT) {\n // Leftover distribution amount is also eligible for a fee since the funds are going out of the ecosystem to _beneficiary.\n unchecked {\n _feeEligibleDistributionAmount += _leftoverDistributionAmount;\n }\n }\n\n // Take the fee.\n _feeTaken = _feeEligibleDistributionAmount != 0\n ? _takeFeeFrom(\n _projectId,\n _fundingCycle.shouldHoldFees(),\n _feeEligibleDistributionAmount,\n _feePercent,\n _projectOwner,\n _feeDiscount\n )\n : 0;\n\n // Transfer any remaining balance to the project owner and update returned leftover accordingly.\n if (_leftoverDistributionAmount != 0) {\n // Subtract the fee from the net leftover amount.\n netLeftoverDistributionAmount =\n _leftoverDistributionAmount -\n (\n _feeDiscount == JBConstants.MAX_FEE_DISCOUNT\n ? 0\n : _feeAmount(_leftoverDistributionAmount, _feePercent, _feeDiscount)\n );\n\n // Transfer the amount to the project owner.\n _transferFrom(address(this), _projectOwner, netLeftoverDistributionAmount);\n }\n }\n\n emit DistributePayouts(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _projectOwner,\n _amount,\n _distributedAmount,\n _feeTaken,\n netLeftoverDistributionAmount,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Allows a project to send funds from its overflow up to the preconfigured allowance.\n /// @dev Only a project's owner or a designated operator can use its allowance.\n /// @dev Incurs the protocol fee.\n /// @param _projectId The ID of the project to use the allowance of.\n /// @param _amount The amount of terminal tokens to use from this project's current allowance, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's overflow allowance currency.\n /// @param _minReturnedTokens The minimum number of tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with 18 decimals.\n /// @param _beneficiary The address to send the funds to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the emitted event, if provided.\n /// @return netDistributedAmount The amount of tokens that was distributed to the beneficiary, as a fixed point number with the same amount of decimals as the terminal.\n function _useAllowanceOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo,\n bytes calldata _metadata\n ) internal returns (uint256 netDistributedAmount) {\n // Record the use of the allowance.\n (\n JBFundingCycle memory _fundingCycle,\n uint256 _distributedAmount\n ) = IJBSingleTokenPaymentTerminalStore3_1_1(store).recordUsedAllowanceOf(\n _projectId,\n _amount,\n _currency\n );\n\n // The amount being withdrawn must be at least as much as was expected.\n if (_distributedAmount < _minReturnedTokens) revert INADEQUATE_DISTRIBUTION_AMOUNT();\n\n // Scoped section prevents stack too deep. `_fee`, `_projectOwner`, `_feeDiscount`, and `_netAmount` only used within scope.\n {\n // Keep a reference to the fee amount that was paid.\n uint256 _feeTaken;\n\n // Keep a reference to the fee.\n uint256 _feePercent = fee;\n\n // Get a reference to the project owner, which will receive tokens from paying the platform fee.\n address _projectOwner = projects.ownerOf(_projectId);\n\n // Get the amount of discount that should be applied to any fees taken.\n // 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.\n uint256 _feeDiscount = _feePercent == 0 || isFeelessAddress[msg.sender]\n ? JBConstants.MAX_FEE_DISCOUNT\n : _currentFeeDiscount(_projectId, JBFeeType.ALLOWANCE);\n\n // Take a fee from the `_distributedAmount`, if needed.\n _feeTaken = _feeDiscount == JBConstants.MAX_FEE_DISCOUNT\n ? 0\n : _takeFeeFrom(\n _projectId,\n _fundingCycle.shouldHoldFees(),\n _distributedAmount,\n _feePercent,\n _projectOwner,\n _feeDiscount\n );\n\n unchecked {\n // The net amount is the withdrawn amount without the fee.\n netDistributedAmount = _distributedAmount - _feeTaken;\n }\n\n // Transfer any remaining balance to the beneficiary.\n if (netDistributedAmount != 0)\n _transferFrom(address(this), _beneficiary, netDistributedAmount);\n }\n\n emit UseAllowance(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _beneficiary,\n _amount,\n _distributedAmount,\n netDistributedAmount,\n _memo,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Pays out splits for a project's funding cycle configuration.\n /// @param _projectId The ID of the project for which payout splits are being distributed.\n /// @param _domain The domain of the splits to distribute the payout between.\n /// @param _group The group of the splits to distribute the payout between.\n /// @param _amount The total amount being distributed, as a fixed point number with the same number of decimals as this terminal.\n /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE.\n /// @param _feePercent The percent of fees to take, out of MAX_FEE.\n /// @return If the leftover amount if the splits don't add up to 100%.\n /// @return feeEligibleDistributionAmount The total amount of distributions that are eligible to have fees taken from.\n function _distributeToPayoutSplitsOf(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group,\n uint256 _amount,\n uint256 _feePercent,\n uint256 _feeDiscount\n ) internal returns (uint256, uint256 feeEligibleDistributionAmount) {\n // The total percentage available to split\n uint256 _leftoverPercentage = JBConstants.SPLITS_TOTAL_PERCENT;\n\n // Get a reference to the project's payout splits.\n JBSplit[] memory _splits = splitsStore.splitsOf(_projectId, _domain, _group);\n\n // Keep a reference to the split being iterated on.\n JBSplit memory _split;\n\n // Transfer between all splits.\n for (uint256 _i; _i < _splits.length; ) {\n // Get a reference to the split being iterated on.\n _split = _splits[_i];\n\n // The amount to send towards the split.\n uint256 _payoutAmount = PRBMath.mulDiv(_amount, _split.percent, _leftoverPercentage);\n\n // The payout amount substracting any applicable incurred fees.\n uint256 _netPayoutAmount = _distributeToPayoutSplit(\n _split,\n _projectId,\n _group,\n _payoutAmount,\n _feePercent,\n _feeDiscount\n );\n\n // If the split allocator is set as feeless, this distribution is not eligible for a fee.\n if (_netPayoutAmount != 0 && _netPayoutAmount != _payoutAmount)\n feeEligibleDistributionAmount += _payoutAmount;\n\n if (_payoutAmount != 0) {\n // Subtract from the amount to be sent to the beneficiary.\n unchecked {\n _amount -= _payoutAmount;\n }\n }\n\n unchecked {\n // Decrement the leftover percentage.\n _leftoverPercentage -= _split.percent;\n }\n\n emit DistributeToPayoutSplit(\n _projectId,\n _domain,\n _group,\n _split,\n _payoutAmount,\n _netPayoutAmount,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n\n return (_amount, feeEligibleDistributionAmount);\n }\n\n /// @notice Pays out a split for a project's funding cycle configuration.\n /// @param _split The split to distribute payouts to.\n /// @param _amount The total amount being distributed to the split, as a fixed point number with the same number of decimals as this terminal.\n /// @param _feePercent The percent of fees to take, out of MAX_FEE.\n /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE.\n /// @return netPayoutAmount The amount sent to the split after subtracting fees.\n function _distributeToPayoutSplit(\n JBSplit memory _split,\n uint256 _projectId,\n uint256 _group,\n uint256 _amount,\n uint256 _feePercent,\n uint256 _feeDiscount\n ) internal returns (uint256 netPayoutAmount) {\n // By default, the net payout amount is the full amount. This will be adjusted if fees are taken.\n netPayoutAmount = _amount;\n\n // If there's an allocator set, transfer to its `allocate` function.\n if (_split.allocator != IJBSplitAllocator(address(0))) {\n // This distribution is eligible for a fee since the funds are leaving this contract and the allocator isn't listed as feeless.\n if (\n _feeDiscount != JBConstants.MAX_FEE_DISCOUNT && !isFeelessAddress[address(_split.allocator)]\n ) {\n unchecked {\n netPayoutAmount -= _feeAmount(_amount, _feePercent, _feeDiscount);\n }\n }\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_split.allocator), netPayoutAmount);\n\n // Create the data to send to the allocator.\n JBSplitAllocationData memory _data = JBSplitAllocationData(\n token,\n netPayoutAmount,\n decimals,\n _projectId,\n _group,\n _split\n );\n\n // Trigger the allocator's `allocate` function.\n bytes memory _reason;\n\n if (\n ERC165Checker.supportsInterface(\n address(_split.allocator),\n type(IJBSplitAllocator).interfaceId\n )\n )\n // If this terminal's token is ETH, send it in msg.value.\n try\n _split.allocator.allocate{value: token == JBTokens.ETH ? netPayoutAmount : 0}(_data)\n {} catch (bytes memory __reason) {\n _reason = __reason.length == 0 ? abi.encode('Allocate fail') : __reason;\n }\n else {\n _reason = abi.encode('IERC165 fail');\n }\n\n if (_reason.length != 0) {\n // Revert the payout.\n _revertTransferFrom(_projectId, address(_split.allocator), netPayoutAmount, _amount);\n\n // Set the net payout amount to 0 to signal the reversion.\n netPayoutAmount = 0;\n\n emit PayoutReverted(_projectId, _split, _amount, _reason, msg.sender);\n }\n\n // Otherwise, if a project is specified, make a payment to it.\n } else if (_split.projectId != 0) {\n // Get a reference to the Juicebox terminal being used.\n IJBPaymentTerminal _terminal = directory.primaryTerminalOf(_split.projectId, token);\n\n // The project must have a terminal to send funds to.\n if (_terminal == IJBPaymentTerminal(address(0))) {\n // Set the net payout amount to 0 to signal the reversion.\n netPayoutAmount = 0;\n\n // Revert the payout.\n _revertTransferFrom(_projectId, address(0), 0, _amount);\n\n emit PayoutReverted(_projectId, _split, _amount, 'Terminal not found', msg.sender);\n } else {\n // This distribution is eligible for a fee since the funds are leaving this contract and the terminal isn't listed as feeless.\n if (\n _terminal != this &&\n _feeDiscount != JBConstants.MAX_FEE_DISCOUNT &&\n !isFeelessAddress[address(_terminal)]\n ) {\n unchecked {\n netPayoutAmount -= _feeAmount(_amount, _feePercent, _feeDiscount);\n }\n }\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_terminal), netPayoutAmount);\n\n // Add to balance if prefered.\n if (_split.preferAddToBalance)\n try\n _terminal.addToBalanceOf{value: token == JBTokens.ETH ? netPayoutAmount : 0}(\n _split.projectId,\n netPayoutAmount,\n token,\n '',\n // Send the projectId in the metadata as a referral.\n bytes(abi.encodePacked(_projectId))\n )\n {} catch (bytes memory _reason) {\n // Revert the payout.\n _revertTransferFrom(_projectId, address(_terminal), netPayoutAmount, _amount);\n\n // Set the net payout amount to 0 to signal the reversion.\n netPayoutAmount = 0;\n\n emit PayoutReverted(_projectId, _split, _amount, _reason, msg.sender);\n }\n else\n try\n _terminal.pay{value: token == JBTokens.ETH ? netPayoutAmount : 0}(\n _split.projectId,\n netPayoutAmount,\n token,\n _split.beneficiary != address(0) ? _split.beneficiary : msg.sender,\n 0,\n _split.preferClaimed,\n '',\n // Send the projectId in the metadata as a referral.\n bytes(abi.encodePacked(_projectId))\n )\n {} catch (bytes memory _reason) {\n // Revert the payout.\n _revertTransferFrom(_projectId, address(_terminal), netPayoutAmount, _amount);\n\n // Set the net payout amount to 0 to signal the reversion.\n netPayoutAmount = 0;\n\n emit PayoutReverted(_projectId, _split, _amount, _reason, msg.sender);\n }\n }\n } else {\n // This distribution is eligible for a fee since the funds are leaving this contract and the beneficiary isn't listed as feeless.\n // Don't enforce feeless address for the beneficiary since the funds are leaving the ecosystem.\n if (_feeDiscount != JBConstants.MAX_FEE_DISCOUNT) {\n unchecked {\n netPayoutAmount -= _feeAmount(_amount, _feePercent, _feeDiscount);\n }\n }\n\n // If there's a beneficiary, send the funds directly to the beneficiary. Otherwise send to the msg.sender.\n _transferFrom(\n address(this),\n _split.beneficiary != address(0) ? _split.beneficiary : payable(msg.sender),\n netPayoutAmount\n );\n }\n }\n\n /// @notice Takes a fee into the platform's project, which has an id of _FEE_BENEFICIARY_PROJECT_ID.\n /// @param _projectId The ID of the project having fees taken from.\n /// @param _shouldHoldFees If fees should be tracked and held back.\n /// @param _feePercent The percent of fees to take, out of MAX_FEE.\n /// @param _amount The amount of the fee to take, as a floating point number with 18 decimals.\n /// @param _beneficiary The address to mint the platforms tokens for.\n /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE.\n /// @return feeAmount The amount of the fee taken.\n function _takeFeeFrom(\n uint256 _projectId,\n bool _shouldHoldFees,\n uint256 _amount,\n uint256 _feePercent,\n address _beneficiary,\n uint256 _feeDiscount\n ) internal returns (uint256 feeAmount) {\n feeAmount = _feeAmount(_amount, _feePercent, _feeDiscount);\n\n if (_shouldHoldFees) {\n // Store the held fee.\n _heldFeesOf[_projectId].push(\n JBFee(_amount, uint32(_feePercent), uint32(_feeDiscount), _beneficiary)\n );\n\n emit HoldFee(_projectId, _amount, _feePercent, _feeDiscount, _beneficiary, msg.sender);\n } else {\n // Process the fee.\n _processFee(feeAmount, _beneficiary, _projectId); // Take the fee.\n\n emit ProcessFee(_projectId, feeAmount, false, _beneficiary, msg.sender);\n }\n }\n\n /// @notice Process a fee of the specified amount.\n /// @param _amount The fee amount, as a floating point number with 18 decimals.\n /// @param _beneficiary The address to mint the platform's tokens for.\n /// @param _from The project ID the fee is being paid from.\n function _processFee(uint256 _amount, address _beneficiary, uint256 _from) internal {\n // Get the terminal for the protocol project.\n IJBPaymentTerminal _terminal = directory.primaryTerminalOf(_FEE_BENEFICIARY_PROJECT_ID, token);\n\n // Trigger any inherited pre-transfer logic if funds will be transferred.\n if (address(_terminal) != address(this)) _beforeTransferTo(address(_terminal), _amount);\n\n try\n // Send the fee.\n // If this terminal's token is ETH, send it in msg.value.\n _terminal.pay{value: token == JBTokens.ETH ? _amount : 0}(\n _FEE_BENEFICIARY_PROJECT_ID,\n _amount,\n token,\n _beneficiary,\n 0,\n false,\n '',\n // Send the projectId in the metadata.\n bytes(abi.encodePacked(_from))\n )\n {} catch (bytes memory _reason) {\n _revertTransferFrom(\n _from,\n address(_terminal) != address(this) ? address(_terminal) : address(0),\n address(_terminal) != address(this) ? _amount : 0,\n _amount\n );\n emit FeeReverted(_from, _FEE_BENEFICIARY_PROJECT_ID, _amount, _reason, msg.sender);\n }\n }\n\n /// @notice Reverts an expected payout.\n /// @param _projectId The ID of the project having paying out.\n /// @param _expectedDestination The address the payout was expected to go to.\n /// @param _allowanceAmount The amount that the destination has been allowed to use.\n /// @param _depositAmount The amount of the payout as debited from the project's balance.\n function _revertTransferFrom(\n uint256 _projectId,\n address _expectedDestination,\n uint256 _allowanceAmount,\n uint256 _depositAmount\n ) internal {\n // Cancel allowance if needed.\n if (_allowanceAmount != 0) _cancelTransferTo(_expectedDestination, _allowanceAmount);\n\n // Add undistributed amount back to project's balance.\n IJBSingleTokenPaymentTerminalStore3_1_1(store).recordAddedBalanceFor(\n _projectId,\n _depositAmount\n );\n }\n\n /// @notice Contribute tokens to a project.\n /// @param _amount The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place.\n /// @param _payer The address making the payment.\n /// @param _projectId The ID of the project being paid.\n /// @param _beneficiary The address to mint tokens for and pass along to the funding cycle's data source and delegate.\n /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\n /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return beneficiaryTokenCount The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals.\n function _pay(\n uint256 _amount,\n address _payer,\n uint256 _projectId,\n address _beneficiary,\n uint256 _minReturnedTokens,\n bool _preferClaimedTokens,\n string memory _memo,\n bytes memory _metadata\n ) internal returns (uint256 beneficiaryTokenCount) {\n // Cant send tokens to the zero address.\n if (_beneficiary == address(0)) revert PAY_TO_ZERO_ADDRESS();\n\n // Define variables that will be needed outside the scoped section below.\n // Keep a reference to the funding cycle during which the payment is being made.\n JBFundingCycle memory _fundingCycle;\n\n // Scoped section prevents stack too deep. `_delegateAllocations` and `_tokenCount` only used within scope.\n {\n JBPayDelegateAllocation3_1_1[] memory _delegateAllocations;\n uint256 _tokenCount;\n\n // Bundle the amount info into a JBTokenAmount struct.\n JBTokenAmount memory _bundledAmount = JBTokenAmount(token, _amount, decimals, currency);\n\n // Record the payment.\n (\n _fundingCycle,\n _tokenCount,\n _delegateAllocations,\n _memo\n ) = IJBSingleTokenPaymentTerminalStore3_1_1(store).recordPaymentFrom(\n _payer,\n _bundledAmount,\n _projectId,\n baseWeightCurrency,\n _beneficiary,\n _memo,\n _metadata\n );\n\n // Mint the tokens if needed.\n if (_tokenCount != 0)\n // Set token count to be the number of tokens minted for the beneficiary instead of the total amount.\n beneficiaryTokenCount = IJBController(directory.controllerOf(_projectId)).mintTokensOf(\n _projectId,\n _tokenCount,\n _beneficiary,\n '',\n _preferClaimedTokens,\n true\n );\n\n // The token count for the beneficiary must be greater than or equal to the minimum expected.\n if (beneficiaryTokenCount < _minReturnedTokens) revert INADEQUATE_TOKEN_COUNT();\n\n // If delegate allocations were specified by the data source, fulfill them.\n if (_delegateAllocations.length != 0) {\n JBDidPayData3_1_1 memory _data = JBDidPayData3_1_1(\n _payer,\n _projectId,\n _fundingCycle.configuration,\n _bundledAmount,\n JBTokenAmount(token, 0, decimals, currency),\n beneficiaryTokenCount,\n _beneficiary,\n _preferClaimedTokens,\n _memo,\n bytes(''),\n _metadata\n );\n\n // Get a reference to the number of delegates to allocate to.\n uint256 _numDelegates = _delegateAllocations.length;\n\n // Keep a reference to the allocation.\n JBPayDelegateAllocation3_1_1 memory _delegateAllocation;\n\n for (uint256 _i; _i < _numDelegates; ) {\n // Get a reference to the delegate being iterated on.\n _delegateAllocation = _delegateAllocations[_i];\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_delegateAllocation.delegate), _delegateAllocation.amount);\n\n // Pass the correct token forwardedAmount to the delegate\n _data.forwardedAmount.value = _delegateAllocation.amount;\n\n // Pass the correct metadata from the data source.\n _data.dataSourceMetadata = _delegateAllocation.metadata;\n\n _delegateAllocation.delegate.didPay{\n value: token == JBTokens.ETH ? _delegateAllocation.amount : 0\n }(_data);\n\n emit DelegateDidPay(\n _delegateAllocation.delegate,\n _data,\n _delegateAllocation.amount,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n }\n\n emit Pay(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _payer,\n _beneficiary,\n _amount,\n beneficiaryTokenCount,\n _memo,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Receives funds belonging to the specified project.\n /// @param _projectId The ID of the project to which the funds received belong.\n /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\n /// @param _shouldRefundHeldFees A flag indicating if held fees should be refunded based on the amount being added.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the emitted event.\n function _addToBalanceOf(\n uint256 _projectId,\n uint256 _amount,\n bool _shouldRefundHeldFees,\n string memory _memo,\n bytes memory _metadata\n ) internal {\n // Refund any held fees to make sure the project doesn't pay double for funds going in and out of the protocol.\n uint256 _refundedFees = _shouldRefundHeldFees ? _refundHeldFees(_projectId, _amount) : 0;\n\n // Record the added funds with any refunded fees.\n IJBSingleTokenPaymentTerminalStore3_1_1(store).recordAddedBalanceFor(\n _projectId,\n _amount + _refundedFees\n );\n\n emit AddToBalance(_projectId, _amount, _refundedFees, _memo, _metadata, msg.sender);\n }\n\n /// @notice Refund fees based on the specified amount.\n /// @param _projectId The project for which fees are being refunded.\n /// @param _amount The amount to base the refund on, as a fixed point number with the same amount of decimals as this terminal.\n /// @return refundedFees How much fees were refunded, as a fixed point number with the same number of decimals as this terminal\n function _refundHeldFees(\n uint256 _projectId,\n uint256 _amount\n ) internal returns (uint256 refundedFees) {\n // Get a reference to the project's held fees.\n JBFee[] memory _heldFees = _heldFeesOf[_projectId];\n\n // Delete the current held fees.\n delete _heldFeesOf[_projectId];\n\n // Get a reference to the leftover amount once all fees have been settled.\n uint256 leftoverAmount = _amount;\n\n // Push length in stack\n uint256 _heldFeesLength = _heldFees.length;\n\n // Process each fee.\n for (uint256 _i; _i < _heldFeesLength; ) {\n if (leftoverAmount == 0) _heldFeesOf[_projectId].push(_heldFees[_i]);\n else if (leftoverAmount >= _heldFees[_i].amount) {\n unchecked {\n leftoverAmount = leftoverAmount - _heldFees[_i].amount;\n refundedFees += (\n _heldFees[_i].fee == 0 || _heldFees[_i].feeDiscount == JBConstants.MAX_FEE_DISCOUNT\n ? 0\n : _feeAmount(_heldFees[_i].amount, _heldFees[_i].fee, _heldFees[_i].feeDiscount)\n );\n }\n } else {\n unchecked {\n _heldFeesOf[_projectId].push(\n JBFee(\n _heldFees[_i].amount - leftoverAmount,\n _heldFees[_i].fee,\n _heldFees[_i].feeDiscount,\n _heldFees[_i].beneficiary\n )\n );\n refundedFees += (\n _heldFees[_i].fee == 0 || _heldFees[_i].feeDiscount == JBConstants.MAX_FEE_DISCOUNT\n ? 0\n : _feeAmount(leftoverAmount, _heldFees[_i].fee, _heldFees[_i].feeDiscount)\n );\n }\n leftoverAmount = 0;\n }\n\n unchecked {\n ++_i;\n }\n }\n\n emit RefundHeldFees(_projectId, _amount, refundedFees, leftoverAmount, msg.sender);\n }\n\n /// @notice Returns the fee amount based on the provided amount for the specified project.\n /// @param _amount The amount that the fee is based on, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _fee The percentage of the fee, out of MAX_FEE.\n /// @param _feeDiscount The percentage discount that should be applied out of the max amount, out of MAX_FEE_DISCOUNT.\n /// @return The amount of the fee, as a fixed point number with the same amount of decimals as this terminal.\n function _feeAmount(\n uint256 _amount,\n uint256 _fee,\n uint256 _feeDiscount\n ) internal pure returns (uint256) {\n // Calculate the discounted fee.\n uint256 _discountedFee = _fee -\n PRBMath.mulDiv(_fee, _feeDiscount, JBConstants.MAX_FEE_DISCOUNT);\n\n // The amount of tokens from the `_amount` to pay as a fee.\n return\n _amount - PRBMath.mulDiv(_amount, JBConstants.MAX_FEE, _discountedFee + JBConstants.MAX_FEE);\n }\n\n /// @notice Get the fee discount from the fee gauge for the specified project.\n /// @param _projectId The ID of the project to get a fee discount for.\n /// @param _feeType The type of fee the discount is being applied to.\n /// @return feeDiscount The fee discount, which should be interpreted as a percentage out MAX_FEE_DISCOUNT.\n function _currentFeeDiscount(\n uint256 _projectId,\n JBFeeType _feeType\n ) internal view returns (uint256) {\n // Can't take a fee if the protocol project doesn't have a terminal that accepts the token.\n if (\n directory.primaryTerminalOf(_FEE_BENEFICIARY_PROJECT_ID, token) ==\n IJBPaymentTerminal(address(0))\n ) return JBConstants.MAX_FEE_DISCOUNT;\n\n // Get the fee discount.\n if (feeGauge != address(0))\n // If the guage reverts, keep the discount at 0.\n try IJBFeeGauge3_1(feeGauge).currentDiscountFor(_projectId, _feeType) returns (\n uint256 discount\n ) {\n // If the fee discount is greater than the max, we ignore the return value\n if (discount <= JBConstants.MAX_FEE_DISCOUNT) return discount;\n } catch {\n return 0;\n }\n\n return 0;\n }\n}\n" + }, + "contracts/enums/JBFeeType.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nenum JBFeeType {\n PAYOUT,\n ALLOWANCE,\n REDEMPTION\n}\n" + }, + "contracts/interfaces/IJBPayoutRedemptionPaymentTerminal3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBFee} from './../structs/JBFee.sol';\nimport {JBDidRedeemData3_1_1} from './../structs/JBDidRedeemData3_1_1.sol';\nimport {JBDidPayData3_1_1} from './../structs/JBDidPayData3_1_1.sol';\nimport {IJBPayDelegate3_1_1} from './IJBPayDelegate3_1_1.sol';\nimport {IJBRedemptionDelegate3_1_1} from './IJBRedemptionDelegate3_1_1.sol';\n\ninterface IJBPayoutRedemptionPaymentTerminal3_1_1 {\n event DelegateDidRedeem(\n IJBRedemptionDelegate3_1_1 indexed delegate,\n JBDidRedeemData3_1_1 data,\n uint256 delegatedAmount,\n uint256 fee,\n address caller\n );\n\n event DelegateDidPay(\n IJBPayDelegate3_1_1 indexed delegate,\n JBDidPayData3_1_1 data,\n uint256 delegatedAmount,\n address caller\n );\n}\n" + }, + "contracts/interfaces/IJBFeeGauge3_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBFeeType} from './../enums/JBFeeType.sol';\n\ninterface IJBFeeGauge3_1 {\n function currentDiscountFor(uint256 projectId, JBFeeType feeType) external view returns (uint256);\n}\n" + }, + "contracts/JBETHPaymentTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Address} from '@openzeppelin/contracts/utils/Address.sol';\nimport {JBPayoutRedemptionPaymentTerminal} from './abstract/JBPayoutRedemptionPaymentTerminal.sol';\nimport {JBSplitsGroups} from './libraries/JBSplitsGroups.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {JBCurrencies} from './libraries/JBCurrencies.sol';\nimport {JBTokens} from './libraries/JBTokens.sol';\n\n/// @notice Manages all inflows and outflows of ETH funds into the protocol ecosystem.\ncontract JBETHPaymentTerminal is JBPayoutRedemptionPaymentTerminal {\n //*********************************************************************//\n // -------------------------- internal views ------------------------- //\n //*********************************************************************//\n\n /// @notice Checks the balance of tokens in this contract.\n /// @return The contract's balance, as a fixed point number with the same amount of decimals as this terminal.\n function _balance() internal view override returns (uint256) {\n return address(this).balance;\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _prices A contract that exposes price feeds.\n /// @param _store A contract that stores the terminal's data.\n /// @param _owner The address that will own this contract.\n constructor(\n uint256 _baseWeightCurrency,\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBSplitsStore _splitsStore,\n IJBPrices _prices,\n address _store,\n address _owner\n )\n JBPayoutRedemptionPaymentTerminal(\n JBTokens.ETH,\n 18, // 18 decimals.\n JBCurrencies.ETH,\n _baseWeightCurrency,\n JBSplitsGroups.ETH_PAYOUT,\n _operatorStore,\n _projects,\n _directory,\n _splitsStore,\n _prices,\n _store,\n _owner\n )\n // solhint-disable-next-line no-empty-blocks\n {\n\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Transfers tokens.\n /// @param _from The address from which the transfer should originate.\n /// @param _to The address to which the transfer should go.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _transferFrom(address _from, address payable _to, uint256 _amount) internal override {\n _from; // Prevents unused var compiler and natspec complaints.\n\n Address.sendValue(_to, _amount);\n }\n}\n" + }, + "contracts/abstract/JBPayoutRedemptionPaymentTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {IJBAllowanceTerminal} from './../interfaces/IJBAllowanceTerminal.sol';\nimport {IJBController} from './../interfaces/IJBController.sol';\nimport {IJBDirectory} from './../interfaces/IJBDirectory.sol';\nimport {IJBPayoutRedemptionPaymentTerminal} from './../interfaces/IJBPayoutRedemptionPaymentTerminal.sol';\nimport {IJBSplitAllocator} from './../interfaces/IJBSplitAllocator.sol';\nimport {IJBFeeGauge} from './../interfaces/IJBFeeGauge.sol';\nimport {IJBOperatable} from './../interfaces/IJBOperatable.sol';\nimport {IJBOperatorStore} from './../interfaces/IJBOperatorStore.sol';\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\nimport {IJBPayoutTerminal} from './../interfaces/IJBPayoutTerminal.sol';\nimport {IJBPrices} from './../interfaces/IJBPrices.sol';\nimport {IJBProjects} from './../interfaces/IJBProjects.sol';\nimport {IJBRedemptionTerminal} from './../interfaces/IJBRedemptionTerminal.sol';\nimport {IJBSingleTokenPaymentTerminalStore} from './../interfaces/IJBSingleTokenPaymentTerminalStore.sol';\nimport {IJBSplitsStore} from './../interfaces/IJBSplitsStore.sol';\nimport {JBConstants} from './../libraries/JBConstants.sol';\nimport {JBCurrencies} from './../libraries/JBCurrencies.sol';\nimport {JBFixedPointNumber} from './../libraries/JBFixedPointNumber.sol';\nimport {JBFundingCycleMetadataResolver} from './../libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBOperations} from './../libraries/JBOperations.sol';\nimport {JBTokens} from './../libraries/JBTokens.sol';\nimport {JBDidPayData} from './../structs/JBDidPayData.sol';\nimport {JBDidRedeemData} from './../structs/JBDidRedeemData.sol';\nimport {JBFee} from './../structs/JBFee.sol';\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\nimport {JBPayDelegateAllocation} from './../structs/JBPayDelegateAllocation.sol';\nimport {JBTokenAmount} from './../structs/JBTokenAmount.sol';\nimport {JBRedemptionDelegateAllocation} from './../structs/JBRedemptionDelegateAllocation.sol';\nimport {JBSplit} from './../structs/JBSplit.sol';\nimport {JBSplitAllocationData} from './../structs/JBSplitAllocationData.sol';\nimport {JBOperatable} from './JBOperatable.sol';\nimport {JBSingleTokenPaymentTerminal} from './JBSingleTokenPaymentTerminal.sol';\n\n/// @notice Generic terminal managing all inflows and outflows of funds into the protocol ecosystem.\n/// A project can transfer its funds, along with the power to reconfigure and mint/burn their tokens, from this contract to another allowed terminal of the same token type contract at any time.\nabstract contract JBPayoutRedemptionPaymentTerminal is\n JBSingleTokenPaymentTerminal,\n JBOperatable,\n Ownable,\n IJBPayoutRedemptionPaymentTerminal\n{\n // A library that parses the packed funding cycle metadata into a friendlier format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error FEE_TOO_HIGH();\n error INADEQUATE_DISTRIBUTION_AMOUNT();\n error INADEQUATE_RECLAIM_AMOUNT();\n error INADEQUATE_TOKEN_COUNT();\n error NO_MSG_VALUE_ALLOWED();\n error PAY_TO_ZERO_ADDRESS();\n error PROJECT_TERMINAL_MISMATCH();\n error REDEEM_TO_ZERO_ADDRESS();\n error TERMINAL_IN_SPLIT_ZERO_ADDRESS();\n error TERMINAL_TOKENS_INCOMPATIBLE();\n\n //*********************************************************************//\n // ---------------------------- modifiers ---------------------------- //\n //*********************************************************************//\n\n /// @notice A modifier that verifies this terminal is a terminal of provided project ID.\n modifier isTerminalOf(uint256 _projectId) {\n if (!directory.isTerminalOf(_projectId, this)) revert PROJECT_TERMINAL_MISMATCH();\n _;\n }\n\n //*********************************************************************//\n // --------------------- internal stored constants ------------------- //\n //*********************************************************************//\n\n /// @notice Maximum fee that can be set for a funding cycle configuration.\n /// @dev Out of MAX_FEE (50_000_000 / 1_000_000_000).\n uint256 internal constant _FEE_CAP = 50_000_000;\n\n /// @notice The fee beneficiary project ID is 1, as it should be the first project launched during the deployment process.\n uint256 internal constant _FEE_BENEFICIARY_PROJECT_ID = 1;\n\n //*********************************************************************//\n // --------------------- internal stored properties ------------------ //\n //*********************************************************************//\n\n /// @notice Fees that are being held to be processed later.\n /// @custom:param _projectId The ID of the project for which fees are being held.\n mapping(uint256 => JBFee[]) internal _heldFeesOf;\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice Mints ERC-721's that represent project ownership and transfers.\n IJBProjects public immutable override projects;\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n /// @notice The contract that stores splits for each project.\n IJBSplitsStore public immutable override splitsStore;\n\n /// @notice The contract that exposes price feeds.\n IJBPrices public immutable override prices;\n\n /// @notice The contract that stores and manages the terminal's data.\n address public immutable override store;\n\n /// @notice The currency to base token issuance on.\n /// @dev If this differs from `currency`, there must be a price feed available to convert `currency` to `baseWeightCurrency`.\n uint256 public immutable override baseWeightCurrency;\n\n /// @notice The group that payout splits coming from this terminal are identified by.\n uint256 public immutable override payoutSplitsGroup;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The platform fee percent.\n /// @dev Out of MAX_FEE (25_000_000 / 1_000_000_000)\n uint256 public override fee = 25_000_000; // 2.5%\n\n /// @notice The data source that returns a discount to apply to a project's fee.\n address public override feeGauge;\n\n /// @notice Addresses that can be paid towards from this terminal without incurring a fee.\n /// @dev Only addresses that are considered to be contained within the ecosystem can be feeless. Funds sent outside the ecosystem may incur fees despite being stored as feeless.\n /// @custom:param _address The address that can be paid toward.\n mapping(address => bool) public override isFeelessAddress;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Gets the current overflowed amount in this terminal for a specified project, in terms of ETH.\n /// @dev The current overflow is represented as a fixed point number with 18 decimals.\n /// @param _projectId The ID of the project to get overflow for.\n /// @return The current amount of ETH overflow that project has in this terminal, as a fixed point number with 18 decimals.\n function currentEthOverflowOf(\n uint256 _projectId\n ) external view virtual override returns (uint256) {\n // Get this terminal's current overflow.\n uint256 _overflow = IJBSingleTokenPaymentTerminalStore(store).currentOverflowOf(\n this,\n _projectId\n );\n\n // Adjust the decimals of the fixed point number if needed to have 18 decimals.\n uint256 _adjustedOverflow = (decimals == 18)\n ? _overflow\n : JBFixedPointNumber.adjustDecimals(_overflow, decimals, 18);\n\n // Return the amount converted to ETH.\n return\n (currency == JBCurrencies.ETH)\n ? _adjustedOverflow\n : PRBMath.mulDiv(\n _adjustedOverflow,\n 10 ** decimals,\n prices.priceFor(currency, JBCurrencies.ETH, decimals)\n );\n }\n\n /// @notice The fees that are currently being held to be processed later for each project.\n /// @param _projectId The ID of the project for which fees are being held.\n /// @return An array of fees that are being held.\n function heldFeesOf(uint256 _projectId) external view override returns (JBFee[] memory) {\n return _heldFeesOf[_projectId];\n }\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if the provided interface ID is supported.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(JBSingleTokenPaymentTerminal, IERC165) returns (bool) {\n return\n _interfaceId == type(IJBPayoutRedemptionPaymentTerminal).interfaceId ||\n _interfaceId == type(IJBPayoutTerminal).interfaceId ||\n _interfaceId == type(IJBAllowanceTerminal).interfaceId ||\n _interfaceId == type(IJBRedemptionTerminal).interfaceId ||\n _interfaceId == type(IJBOperatable).interfaceId ||\n super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // -------------------------- internal views ------------------------- //\n //*********************************************************************//\n\n /// @notice Checks the balance of tokens in this contract.\n /// @return The contract's balance.\n function _balance() internal view virtual returns (uint256);\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _token The token that this terminal manages.\n /// @param _decimals The number of decimals the token fixed point amounts are expected to have.\n /// @param _currency The currency that this terminal's token adheres to for price feeds.\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _payoutSplitsGroup The group that denotes payout splits from this terminal in the splits store.\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _prices A contract that exposes price feeds.\n /// @param _store A contract that stores the terminal's data.\n /// @param _owner The address that will own this contract.\n constructor(\n // payable constructor save the gas used to check msg.value==0\n address _token,\n uint256 _decimals,\n uint256 _currency,\n uint256 _baseWeightCurrency,\n uint256 _payoutSplitsGroup,\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBSplitsStore _splitsStore,\n IJBPrices _prices,\n address _store,\n address _owner\n )\n payable\n JBSingleTokenPaymentTerminal(_token, _decimals, _currency)\n JBOperatable(_operatorStore)\n {\n baseWeightCurrency = _baseWeightCurrency;\n payoutSplitsGroup = _payoutSplitsGroup;\n projects = _projects;\n directory = _directory;\n splitsStore = _splitsStore;\n prices = _prices;\n store = _store;\n\n transferOwnership(_owner);\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Contribute tokens to a project.\n /// @param _projectId The ID of the project being paid.\n /// @param _amount The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place.\n /// @param _token The token being paid. This terminal ignores this property since it only manages one token.\n /// @param _beneficiary The address to mint tokens for and pass along to the funding cycle's data source and delegate.\n /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\n /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals.\n function pay(\n uint256 _projectId,\n uint256 _amount,\n address _token,\n address _beneficiary,\n uint256 _minReturnedTokens,\n bool _preferClaimedTokens,\n string calldata _memo,\n bytes calldata _metadata\n ) external payable virtual override isTerminalOf(_projectId) returns (uint256) {\n _token; // Prevents unused var compiler and natspec complaints.\n\n // ETH shouldn't be sent if this terminal's token isn't ETH.\n if (token != JBTokens.ETH) {\n if (msg.value > 0) revert NO_MSG_VALUE_ALLOWED();\n\n // Get a reference to the balance before receiving tokens.\n uint256 _balanceBefore = _balance();\n\n // Transfer tokens to this terminal from the msg sender.\n _transferFrom(msg.sender, payable(address(this)), _amount);\n\n // The amount should reflect the change in balance.\n _amount = _balance() - _balanceBefore;\n }\n // If this terminal's token is ETH, override _amount with msg.value.\n else _amount = msg.value;\n\n return\n _pay(\n _amount,\n msg.sender,\n _projectId,\n _beneficiary,\n _minReturnedTokens,\n _preferClaimedTokens,\n _memo,\n _metadata\n );\n }\n\n /// @notice Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source.\n /// @dev Only a token holder or a designated operator can redeem its tokens.\n /// @param _holder The account to redeem tokens for.\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\n /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals.\n /// @param _token The token being reclaimed. This terminal ignores this property since it only manages one token.\n /// @param _minReturnedTokens The minimum amount of terminal tokens expected in return, as a fixed point number with the same amount of decimals as the terminal.\n /// @param _beneficiary The address to send the terminal tokens to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return reclaimAmount The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals.\n function redeemTokensOf(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n address _token,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo,\n bytes memory _metadata\n )\n external\n virtual\n override\n requirePermission(_holder, _projectId, JBOperations.REDEEM)\n returns (uint256 reclaimAmount)\n {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return\n _redeemTokensOf(\n _holder,\n _projectId,\n _tokenCount,\n _minReturnedTokens,\n _beneficiary,\n _memo,\n _metadata\n );\n }\n\n /// @notice Distributes payouts for a project with the distribution limit of its current funding cycle.\n /// @dev Payouts are sent to the preprogrammed splits. Any leftover is sent to the project's owner.\n /// @dev 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.\n /// @dev All funds distributed outside of this contract or any feeless terminals incure the protocol fee.\n /// @param _projectId The ID of the project having its payouts distributed.\n /// @param _amount The amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency.\n /// @param _token The token being distributed. This terminal ignores this property since it only manages one token.\n /// @param _minReturnedTokens 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.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return netLeftoverDistributionAmount The amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal.\n function distributePayoutsOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n address _token,\n uint256 _minReturnedTokens,\n string calldata _memo\n ) external virtual override returns (uint256 netLeftoverDistributionAmount) {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return _distributePayoutsOf(_projectId, _amount, _currency, _minReturnedTokens, _memo);\n }\n\n /// @notice Allows a project to send funds from its overflow up to the preconfigured allowance.\n /// @dev Only a project's owner or a designated operator can use its allowance.\n /// @dev Incurs the protocol fee.\n /// @param _projectId The ID of the project to use the allowance of.\n /// @param _amount The amount of terminal tokens to use from this project's current allowance, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's overflow allowance currency.\n /// @param _token The token being distributed. This terminal ignores this property since it only manages one token.\n /// @param _minReturnedTokens The minimum number of tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with 18 decimals.\n /// @param _beneficiary The address to send the funds to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return netDistributedAmount The amount of tokens that was distributed to the beneficiary, as a fixed point number with the same amount of decimals as the terminal.\n function useAllowanceOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n address _token,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.USE_ALLOWANCE)\n returns (uint256 netDistributedAmount)\n {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return _useAllowanceOf(_projectId, _amount, _currency, _minReturnedTokens, _beneficiary, _memo);\n }\n\n /// @notice Allows a project owner to migrate its funds and operations to a new terminal that accepts the same token type.\n /// @dev Only a project's owner or a designated operator can migrate it.\n /// @param _projectId The ID of the project being migrated.\n /// @param _to The terminal contract that will gain the project's funds.\n /// @return balance The amount of funds that were migrated, as a fixed point number with the same amount of decimals as this terminal.\n function migrate(\n uint256 _projectId,\n IJBPaymentTerminal _to\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.MIGRATE_TERMINAL)\n returns (uint256 balance)\n {\n // The terminal being migrated to must accept the same token as this terminal.\n if (!_to.acceptsToken(token, _projectId)) revert TERMINAL_TOKENS_INCOMPATIBLE();\n\n // Record the migration in the store.\n balance = IJBSingleTokenPaymentTerminalStore(store).recordMigration(_projectId);\n\n // Transfer the balance if needed.\n if (balance > 0) {\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_to), balance);\n\n // If this terminal's token is ETH, send it in msg.value.\n uint256 _payableValue = token == JBTokens.ETH ? balance : 0;\n\n // Withdraw the balance to transfer to the new terminal;\n _to.addToBalanceOf{value: _payableValue}(_projectId, balance, token, '', bytes(''));\n }\n\n emit Migrate(_projectId, _to, balance, msg.sender);\n }\n\n /// @notice Receives funds belonging to the specified project.\n /// @param _projectId The ID of the project to which the funds received belong.\n /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\n /// @param _token The token being paid. This terminal ignores this property since it only manages one currency.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the emitted event.\n function addToBalanceOf(\n uint256 _projectId,\n uint256 _amount,\n address _token,\n string calldata _memo,\n bytes calldata _metadata\n ) external payable virtual override isTerminalOf(_projectId) {\n _token; // Prevents unused var compiler and natspec complaints.\n\n // If this terminal's token isn't ETH, make sure no msg.value was sent, then transfer the tokens in from msg.sender.\n if (token != JBTokens.ETH) {\n // Amount must be greater than 0.\n if (msg.value > 0) revert NO_MSG_VALUE_ALLOWED();\n\n // Get a reference to the balance before receiving tokens.\n uint256 _balanceBefore = _balance();\n\n // Transfer tokens to this terminal from the msg sender.\n _transferFrom(msg.sender, payable(address(this)), _amount);\n\n // The amount should reflect the change in balance.\n _amount = _balance() - _balanceBefore;\n }\n // If the terminal's token is ETH, override `_amount` with msg.value.\n else _amount = msg.value;\n\n // Add to balance while only refunding held fees if the funds aren't originating from a feeless terminal.\n _addToBalanceOf(_projectId, _amount, !isFeelessAddress[msg.sender], _memo, _metadata);\n }\n\n /// @notice Process any fees that are being held for the project.\n /// @dev Only a project owner, an operator, or the contract's owner can process held fees.\n /// @param _projectId The ID of the project whos held fees should be processed.\n function processFees(\n uint256 _projectId\n )\n external\n virtual\n override\n requirePermissionAllowingOverride(\n projects.ownerOf(_projectId),\n _projectId,\n JBOperations.PROCESS_FEES,\n msg.sender == owner()\n )\n {\n // Get a reference to the project's held fees.\n JBFee[] memory _heldFees = _heldFeesOf[_projectId];\n\n // Delete the held fees.\n delete _heldFeesOf[_projectId];\n\n // Push array length in stack\n uint256 _heldFeeLength = _heldFees.length;\n\n // Process each fee.\n for (uint256 _i; _i < _heldFeeLength; ) {\n // Get the fee amount.\n uint256 _amount = _feeAmount(\n _heldFees[_i].amount,\n _heldFees[_i].fee,\n _heldFees[_i].feeDiscount\n );\n\n // Process the fee.\n _processFee(_amount, _heldFees[_i].beneficiary);\n\n emit ProcessFee(_projectId, _amount, true, _heldFees[_i].beneficiary, msg.sender);\n\n unchecked {\n ++_i;\n }\n }\n }\n\n /// @notice Allows the fee to be updated.\n /// @dev Only the owner of this contract can change the fee.\n /// @param _fee The new fee, out of MAX_FEE.\n function setFee(uint256 _fee) external virtual override onlyOwner {\n // The provided fee must be within the max.\n if (_fee > _FEE_CAP) revert FEE_TOO_HIGH();\n\n // Store the new fee.\n fee = _fee;\n\n emit SetFee(_fee, msg.sender);\n }\n\n /// @notice Allows the fee gauge to be updated.\n /// @dev Only the owner of this contract can change the fee gauge.\n /// @param _feeGauge The new fee gauge.\n function setFeeGauge(address _feeGauge) external virtual override onlyOwner {\n // Store the new fee gauge.\n feeGauge = _feeGauge;\n\n emit SetFeeGauge(_feeGauge, msg.sender);\n }\n\n /// @notice Sets whether projects operating on this terminal can pay towards the specified address without incurring a fee.\n /// @dev Only the owner of this contract can set addresses as feeless.\n /// @param _address The address that can be paid towards while still bypassing fees.\n /// @param _flag A flag indicating whether the terminal should be feeless or not.\n function setFeelessAddress(address _address, bool _flag) external virtual override onlyOwner {\n // Set the flag value.\n isFeelessAddress[_address] = _flag;\n\n emit SetFeelessAddress(_address, _flag, msg.sender);\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Transfers tokens.\n /// @param _from The address from which the transfer should originate.\n /// @param _to The address to which the transfer should go.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _transferFrom(address _from, address payable _to, uint256 _amount) internal virtual {\n _from; // Prevents unused var compiler and natspec complaints.\n _to; // Prevents unused var compiler and natspec complaints.\n _amount; // Prevents unused var compiler and natspec complaints.\n }\n\n /// @notice Logic to be triggered before transferring tokens from this terminal.\n /// @param _to The address to which the transfer is going.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _beforeTransferTo(address _to, uint256 _amount) internal virtual {\n _to; // Prevents unused var compiler and natspec complaints.\n _amount; // Prevents unused var compiler and natspec complaints.\n }\n\n /// @notice Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source.\n /// @dev Only a token holder or a designated operator can redeem its tokens.\n /// @param _holder The account to redeem tokens for.\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\n /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals.\n /// @param _minReturnedTokens The minimum amount of terminal tokens expected in return, as a fixed point number with the same amount of decimals as the terminal.\n /// @param _beneficiary The address to send the terminal tokens to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return reclaimAmount The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals.\n function _redeemTokensOf(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo,\n bytes memory _metadata\n ) internal returns (uint256 reclaimAmount) {\n // Can't send reclaimed funds to the zero address.\n if (_beneficiary == address(0)) revert REDEEM_TO_ZERO_ADDRESS();\n\n // Define variables that will be needed outside the scoped section below.\n // Keep a reference to the funding cycle during which the redemption is being made.\n JBFundingCycle memory _fundingCycle;\n\n // Scoped section prevents stack too deep. `_delegateAllocations` only used within scope.\n {\n JBRedemptionDelegateAllocation[] memory _delegateAllocations;\n\n // Record the redemption.\n (\n _fundingCycle,\n reclaimAmount,\n _delegateAllocations,\n _memo\n ) = IJBSingleTokenPaymentTerminalStore(store).recordRedemptionFor(\n _holder,\n _projectId,\n _tokenCount,\n _memo,\n _metadata\n );\n\n // The amount being reclaimed must be at least as much as was expected.\n if (reclaimAmount < _minReturnedTokens) revert INADEQUATE_RECLAIM_AMOUNT();\n\n // Burn the project tokens.\n if (_tokenCount > 0)\n IJBController(directory.controllerOf(_projectId)).burnTokensOf(\n _holder,\n _projectId,\n _tokenCount,\n '',\n false\n );\n\n // If delegate allocations were specified by the data source, fulfill them.\n if (_delegateAllocations.length != 0) {\n // Keep a reference to the token amount being forwarded to the delegate.\n JBTokenAmount memory _forwardedAmount = JBTokenAmount(token, 0, decimals, currency);\n\n JBDidRedeemData memory _data = JBDidRedeemData(\n _holder,\n _projectId,\n _fundingCycle.configuration,\n _tokenCount,\n JBTokenAmount(token, reclaimAmount, decimals, currency),\n _forwardedAmount,\n _beneficiary,\n _memo,\n _metadata\n );\n\n uint256 _numDelegates = _delegateAllocations.length;\n\n for (uint256 _i; _i < _numDelegates; ) {\n // Get a reference to the delegate being iterated on.\n JBRedemptionDelegateAllocation memory _delegateAllocation = _delegateAllocations[_i];\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_delegateAllocation.delegate), _delegateAllocation.amount);\n\n // Keep track of the msg.value to use in the delegate call\n uint256 _payableValue;\n\n // If this terminal's token is ETH, send it in msg.value.\n if (token == JBTokens.ETH) _payableValue = _delegateAllocation.amount;\n\n // Pass the correct token forwardedAmount to the delegate\n _data.forwardedAmount.value = _delegateAllocation.amount;\n\n _delegateAllocation.delegate.didRedeem{value: _payableValue}(_data);\n\n emit DelegateDidRedeem(\n _delegateAllocation.delegate,\n _data,\n _delegateAllocation.amount,\n msg.sender\n );\n unchecked {\n ++_i;\n }\n }\n }\n }\n\n // Send the reclaimed funds to the beneficiary.\n if (reclaimAmount > 0) _transferFrom(address(this), _beneficiary, reclaimAmount);\n\n emit RedeemTokens(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _holder,\n _beneficiary,\n _tokenCount,\n reclaimAmount,\n _memo,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Distributes payouts for a project with the distribution limit of its current funding cycle.\n /// @dev Payouts are sent to the preprogrammed splits. Any leftover is sent to the project's owner.\n /// @dev 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.\n /// @dev All funds distributed outside of this contract or any feeless terminals incure the protocol fee.\n /// @param _projectId The ID of the project having its payouts distributed.\n /// @param _amount The amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency.\n /// @param _minReturnedTokens 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.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return netLeftoverDistributionAmount The amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal.\n function _distributePayoutsOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n uint256 _minReturnedTokens,\n string calldata _memo\n ) internal returns (uint256 netLeftoverDistributionAmount) {\n // Record the distribution.\n (\n JBFundingCycle memory _fundingCycle,\n uint256 _distributedAmount\n ) = IJBSingleTokenPaymentTerminalStore(store).recordDistributionFor(\n _projectId,\n _amount,\n _currency\n );\n\n // The amount being distributed must be at least as much as was expected.\n if (_distributedAmount < _minReturnedTokens) revert INADEQUATE_DISTRIBUTION_AMOUNT();\n\n // Get a reference to the project owner, which will receive tokens from paying the platform fee\n // and receive any extra distributable funds not allocated to payout splits.\n address payable _projectOwner = payable(projects.ownerOf(_projectId));\n\n // Define variables that will be needed outside the scoped section below.\n // Keep a reference to the fee amount that was paid.\n uint256 _fee;\n\n // Scoped section prevents stack too deep. `_feeDiscount`, `_feeEligibleDistributionAmount`, and `_leftoverDistributionAmount` only used within scope.\n {\n // Get the amount of discount that should be applied to any fees taken.\n // If the fee is zero, set the discount to 100% for convenience.\n uint256 _feeDiscount = fee == 0\n ? JBConstants.MAX_FEE_DISCOUNT\n : _currentFeeDiscount(_projectId);\n\n // The amount distributed that is eligible for incurring fees.\n uint256 _feeEligibleDistributionAmount;\n\n // The amount leftover after distributing to the splits.\n uint256 _leftoverDistributionAmount;\n\n // Payout to splits and get a reference to the leftover transfer amount after all splits have been paid.\n // Also get a reference to the amount that was distributed to splits from which fees should be taken.\n (_leftoverDistributionAmount, _feeEligibleDistributionAmount) = _distributeToPayoutSplitsOf(\n _projectId,\n _fundingCycle.configuration,\n payoutSplitsGroup,\n _distributedAmount,\n _feeDiscount\n );\n\n if (_feeDiscount != JBConstants.MAX_FEE_DISCOUNT) {\n // Leftover distribution amount is also eligible for a fee since the funds are going out of the ecosystem to _beneficiary.\n unchecked {\n _feeEligibleDistributionAmount += _leftoverDistributionAmount;\n }\n }\n\n // Take the fee.\n _fee = _feeEligibleDistributionAmount != 0\n ? _takeFeeFrom(\n _projectId,\n _fundingCycle,\n _feeEligibleDistributionAmount,\n _projectOwner,\n _feeDiscount\n )\n : 0;\n\n // Transfer any remaining balance to the project owner and update returned leftover accordingly.\n if (_leftoverDistributionAmount != 0) {\n // Subtract the fee from the net leftover amount.\n netLeftoverDistributionAmount =\n _leftoverDistributionAmount -\n _feeAmount(_leftoverDistributionAmount, fee, _feeDiscount);\n\n // Transfer the amount to the project owner.\n _transferFrom(address(this), _projectOwner, netLeftoverDistributionAmount);\n }\n }\n\n emit DistributePayouts(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _projectOwner,\n _amount,\n _distributedAmount,\n _fee,\n netLeftoverDistributionAmount,\n _memo,\n msg.sender\n );\n }\n\n /// @notice Allows a project to send funds from its overflow up to the preconfigured allowance.\n /// @dev Only a project's owner or a designated operator can use its allowance.\n /// @dev Incurs the protocol fee.\n /// @param _projectId The ID of the project to use the allowance of.\n /// @param _amount The amount of terminal tokens to use from this project's current allowance, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's overflow allowance currency.\n /// @param _minReturnedTokens The minimum number of tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with 18 decimals.\n /// @param _beneficiary The address to send the funds to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return netDistributedAmount The amount of tokens that was distributed to the beneficiary, as a fixed point number with the same amount of decimals as the terminal.\n function _useAllowanceOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo\n ) internal returns (uint256 netDistributedAmount) {\n // Record the use of the allowance.\n (\n JBFundingCycle memory _fundingCycle,\n uint256 _distributedAmount\n ) = IJBSingleTokenPaymentTerminalStore(store).recordUsedAllowanceOf(\n _projectId,\n _amount,\n _currency\n );\n\n // The amount being withdrawn must be at least as much as was expected.\n if (_distributedAmount < _minReturnedTokens) revert INADEQUATE_DISTRIBUTION_AMOUNT();\n\n // Scoped section prevents stack too deep. `_fee`, `_projectOwner`, `_feeDiscount`, and `_netAmount` only used within scope.\n {\n // Keep a reference to the fee amount that was paid.\n uint256 _fee;\n\n // Get a reference to the project owner, which will receive tokens from paying the platform fee.\n address _projectOwner = projects.ownerOf(_projectId);\n\n // Get the amount of discount that should be applied to any fees taken.\n // 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.\n uint256 _feeDiscount = fee == 0 || isFeelessAddress[msg.sender]\n ? JBConstants.MAX_FEE_DISCOUNT\n : _currentFeeDiscount(_projectId);\n\n // Take a fee from the `_distributedAmount`, if needed.\n _fee = _feeDiscount == JBConstants.MAX_FEE_DISCOUNT\n ? 0\n : _takeFeeFrom(_projectId, _fundingCycle, _distributedAmount, _projectOwner, _feeDiscount);\n\n unchecked {\n // The net amount is the withdrawn amount without the fee.\n netDistributedAmount = _distributedAmount - _fee;\n }\n\n // Transfer any remaining balance to the beneficiary.\n if (netDistributedAmount > 0)\n _transferFrom(address(this), _beneficiary, netDistributedAmount);\n }\n\n emit UseAllowance(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _beneficiary,\n _amount,\n _distributedAmount,\n netDistributedAmount,\n _memo,\n msg.sender\n );\n }\n\n /// @notice Pays out splits for a project's funding cycle configuration.\n /// @param _projectId The ID of the project for which payout splits are being distributed.\n /// @param _domain The domain of the splits to distribute the payout between.\n /// @param _group The group of the splits to distribute the payout between.\n /// @param _amount The total amount being distributed, as a fixed point number with the same number of decimals as this terminal.\n /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE.\n /// @return leftoverAmount If the leftover amount if the splits don't add up to 100%.\n /// @return feeEligibleDistributionAmount The total amount of distributions that are eligible to have fees taken from.\n function _distributeToPayoutSplitsOf(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group,\n uint256 _amount,\n uint256 _feeDiscount\n ) internal returns (uint256 leftoverAmount, uint256 feeEligibleDistributionAmount) {\n // Set the leftover amount to the initial amount.\n leftoverAmount = _amount;\n // The total percentage available to split\n uint256 leftoverPercentage = JBConstants.SPLITS_TOTAL_PERCENT;\n\n // Get a reference to the project's payout splits.\n JBSplit[] memory _splits = splitsStore.splitsOf(_projectId, _domain, _group);\n\n // Transfer between all splits.\n for (uint256 _i; _i < _splits.length; ) {\n // Get a reference to the split being iterated on.\n JBSplit memory _split = _splits[_i];\n\n // The amount to send towards the split.\n uint256 _payoutAmount = _split.percent == leftoverPercentage\n ? leftoverAmount\n : PRBMath.mulDiv(_amount, _split.percent, JBConstants.SPLITS_TOTAL_PERCENT);\n\n // Decrement the leftover percentage.\n leftoverPercentage -= _split.percent;\n\n // The payout amount substracting any applicable incurred fees.\n uint256 _netPayoutAmount;\n\n if (_payoutAmount > 0) {\n // Transfer tokens to the split.\n // If there's an allocator set, transfer to its `allocate` function.\n if (_split.allocator != IJBSplitAllocator(address(0))) {\n // If the split allocator is set as feeless, this distribution is not eligible for a fee.\n if (\n _feeDiscount == JBConstants.MAX_FEE_DISCOUNT ||\n isFeelessAddress[address(_split.allocator)]\n )\n _netPayoutAmount = _payoutAmount;\n // This distribution is eligible for a fee since the funds are leaving this contract and the allocator isn't listed as feeless.\n else {\n unchecked {\n _netPayoutAmount = _payoutAmount - _feeAmount(_payoutAmount, fee, _feeDiscount);\n }\n\n // This distribution is eligible for a fee since the funds are leaving the ecosystem.\n feeEligibleDistributionAmount += _payoutAmount;\n }\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_split.allocator), _netPayoutAmount);\n\n // Create the data to send to the allocator.\n JBSplitAllocationData memory _data = JBSplitAllocationData(\n token,\n _netPayoutAmount,\n decimals,\n _projectId,\n _group,\n _split\n );\n\n // Trigger the allocator's `allocate` function.\n // If this terminal's token is ETH, send it in msg.value.\n _split.allocator.allocate{value: token == JBTokens.ETH ? _netPayoutAmount : 0}(_data);\n\n // Otherwise, if a project is specified, make a payment to it.\n } else if (_split.projectId != 0) {\n // Get a reference to the Juicebox terminal being used.\n IJBPaymentTerminal _terminal = directory.primaryTerminalOf(_split.projectId, token);\n\n // The project must have a terminal to send funds to.\n if (_terminal == IJBPaymentTerminal(address(0))) revert TERMINAL_IN_SPLIT_ZERO_ADDRESS();\n\n // Save gas if this contract is being used as the terminal.\n if (_terminal == this) {\n // This distribution does not incur a fee.\n _netPayoutAmount = _payoutAmount;\n\n // Send the projectId in the metadata.\n bytes memory _projectMetadata = new bytes(32);\n _projectMetadata = bytes(abi.encodePacked(_projectId));\n\n // Add to balance if prefered.\n if (_split.preferAddToBalance)\n _addToBalanceOf(_split.projectId, _netPayoutAmount, false, '', _projectMetadata);\n else\n _pay(\n _netPayoutAmount,\n address(this),\n _split.projectId,\n (_split.beneficiary != address(0)) ? _split.beneficiary : msg.sender,\n 0,\n _split.preferClaimed,\n '',\n _projectMetadata\n );\n } else {\n // If the terminal is set as feeless, this distribution is not eligible for a fee.\n if (\n _feeDiscount == JBConstants.MAX_FEE_DISCOUNT || isFeelessAddress[address(_terminal)]\n )\n _netPayoutAmount = _payoutAmount;\n // This distribution is eligible for a fee since the funds are leaving this contract and the terminal isn't listed as feeless.\n else {\n unchecked {\n _netPayoutAmount = _payoutAmount - _feeAmount(_payoutAmount, fee, _feeDiscount);\n }\n\n feeEligibleDistributionAmount += _payoutAmount;\n }\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_terminal), _netPayoutAmount);\n\n // If this terminal's token is ETH, send it in msg.value.\n uint256 _payableValue = token == JBTokens.ETH ? _netPayoutAmount : 0;\n\n // Send the projectId in the metadata.\n bytes memory _projectMetadata = new bytes(32);\n _projectMetadata = bytes(abi.encodePacked(_projectId));\n\n // Add to balance if prefered.\n if (_split.preferAddToBalance)\n _terminal.addToBalanceOf{value: _payableValue}(\n _split.projectId,\n _netPayoutAmount,\n token,\n '',\n _projectMetadata\n );\n else\n _terminal.pay{value: _payableValue}(\n _split.projectId,\n _netPayoutAmount,\n token,\n _split.beneficiary != address(0) ? _split.beneficiary : msg.sender,\n 0,\n _split.preferClaimed,\n '',\n _projectMetadata\n );\n }\n } else {\n // Keep a reference to the beneficiary.\n address payable _beneficiary = _split.beneficiary != address(0)\n ? _split.beneficiary\n : payable(msg.sender);\n\n // If there's a full discount, this distribution is not eligible for a fee.\n // Don't enforce feeless address for the beneficiary since the funds are leaving the ecosystem.\n if (_feeDiscount == JBConstants.MAX_FEE_DISCOUNT)\n _netPayoutAmount = _payoutAmount;\n // This distribution is eligible for a fee since the funds are leaving this contract and the beneficiary isn't listed as feeless.\n else {\n unchecked {\n _netPayoutAmount = _payoutAmount - _feeAmount(_payoutAmount, fee, _feeDiscount);\n }\n\n feeEligibleDistributionAmount += _payoutAmount;\n }\n\n // If there's a beneficiary, send the funds directly to the beneficiary. Otherwise send to the msg.sender.\n _transferFrom(address(this), _beneficiary, _netPayoutAmount);\n }\n\n // Subtract from the amount to be sent to the beneficiary.\n unchecked {\n leftoverAmount = leftoverAmount - _payoutAmount;\n }\n }\n\n emit DistributeToPayoutSplit(\n _projectId,\n _domain,\n _group,\n _split,\n _netPayoutAmount,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n\n /// @notice Takes a fee into the platform's project, which has an id of _FEE_BENEFICIARY_PROJECT_ID.\n /// @param _projectId The ID of the project having fees taken from.\n /// @param _fundingCycle The funding cycle during which the fee is being taken.\n /// @param _amount The amount of the fee to take, as a floating point number with 18 decimals.\n /// @param _beneficiary The address to mint the platforms tokens for.\n /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE.\n /// @return feeAmount The amount of the fee taken.\n function _takeFeeFrom(\n uint256 _projectId,\n JBFundingCycle memory _fundingCycle,\n uint256 _amount,\n address _beneficiary,\n uint256 _feeDiscount\n ) internal returns (uint256 feeAmount) {\n feeAmount = _feeAmount(_amount, fee, _feeDiscount);\n\n if (_fundingCycle.shouldHoldFees()) {\n // Store the held fee.\n _heldFeesOf[_projectId].push(JBFee(_amount, uint32(fee), uint32(_feeDiscount), _beneficiary));\n\n emit HoldFee(_projectId, _amount, fee, _feeDiscount, _beneficiary, msg.sender);\n } else {\n // Process the fee.\n _processFee(feeAmount, _beneficiary); // Take the fee.\n\n emit ProcessFee(_projectId, feeAmount, false, _beneficiary, msg.sender);\n }\n }\n\n /// @notice Process a fee of the specified amount.\n /// @param _amount The fee amount, as a floating point number with 18 decimals.\n /// @param _beneficiary The address to mint the platform's tokens for.\n function _processFee(uint256 _amount, address _beneficiary) internal {\n // Get the terminal for the protocol project.\n IJBPaymentTerminal _terminal = directory.primaryTerminalOf(_FEE_BENEFICIARY_PROJECT_ID, token);\n\n // When processing the admin fee, save gas if the admin is using this contract as its terminal.\n if (_terminal == this)\n _pay(\n _amount,\n address(this),\n _FEE_BENEFICIARY_PROJECT_ID,\n _beneficiary,\n 0,\n false,\n '',\n bytes('')\n ); // Use the local pay call.\n else {\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_terminal), _amount);\n\n // If this terminal's token is ETH, send it in msg.value.\n uint256 _payableValue = token == JBTokens.ETH ? _amount : 0;\n\n // Send the payment.\n _terminal.pay{value: _payableValue}(\n _FEE_BENEFICIARY_PROJECT_ID,\n _amount,\n token,\n _beneficiary,\n 0,\n false,\n '',\n bytes('')\n ); // Use the external pay call of the correct terminal.\n }\n }\n\n /// @notice Contribute tokens to a project.\n /// @param _amount The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place.\n /// @param _payer The address making the payment.\n /// @param _projectId The ID of the project being paid.\n /// @param _beneficiary The address to mint tokens for and pass along to the funding cycle's data source and delegate.\n /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\n /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return beneficiaryTokenCount The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals.\n function _pay(\n uint256 _amount,\n address _payer,\n uint256 _projectId,\n address _beneficiary,\n uint256 _minReturnedTokens,\n bool _preferClaimedTokens,\n string memory _memo,\n bytes memory _metadata\n ) internal returns (uint256 beneficiaryTokenCount) {\n // Cant send tokens to the zero address.\n if (_beneficiary == address(0)) revert PAY_TO_ZERO_ADDRESS();\n\n // Define variables that will be needed outside the scoped section below.\n // Keep a reference to the funding cycle during which the payment is being made.\n JBFundingCycle memory _fundingCycle;\n\n // Scoped section prevents stack too deep. `_delegateAllocations` and `_tokenCount` only used within scope.\n {\n JBPayDelegateAllocation[] memory _delegateAllocations;\n uint256 _tokenCount;\n\n // Bundle the amount info into a JBTokenAmount struct.\n JBTokenAmount memory _bundledAmount = JBTokenAmount(token, _amount, decimals, currency);\n\n // Record the payment.\n (\n _fundingCycle,\n _tokenCount,\n _delegateAllocations,\n _memo\n ) = IJBSingleTokenPaymentTerminalStore(store).recordPaymentFrom(\n _payer,\n _bundledAmount,\n _projectId,\n baseWeightCurrency,\n _beneficiary,\n _memo,\n _metadata\n );\n\n // Mint the tokens if needed.\n if (_tokenCount > 0)\n // Set token count to be the number of tokens minted for the beneficiary instead of the total amount.\n beneficiaryTokenCount = IJBController(directory.controllerOf(_projectId)).mintTokensOf(\n _projectId,\n _tokenCount,\n _beneficiary,\n '',\n _preferClaimedTokens,\n true\n );\n\n // The token count for the beneficiary must be greater than or equal to the minimum expected.\n if (beneficiaryTokenCount < _minReturnedTokens) revert INADEQUATE_TOKEN_COUNT();\n\n // If delegate allocations were specified by the data source, fulfill them.\n if (_delegateAllocations.length != 0) {\n // Keep a reference to the token amount being forwarded to the delegate.\n JBTokenAmount memory _forwardedAmount = JBTokenAmount(token, _amount, decimals, currency);\n\n JBDidPayData memory _data = JBDidPayData(\n _payer,\n _projectId,\n _fundingCycle.configuration,\n _bundledAmount,\n _forwardedAmount,\n beneficiaryTokenCount,\n _beneficiary,\n _preferClaimedTokens,\n _memo,\n _metadata\n );\n\n // Get a reference to the number of delegates to allocate to.\n uint256 _numDelegates = _delegateAllocations.length;\n\n for (uint256 _i; _i < _numDelegates; ) {\n // Get a reference to the delegate being iterated on.\n JBPayDelegateAllocation memory _delegateAllocation = _delegateAllocations[_i];\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_delegateAllocation.delegate), _delegateAllocation.amount);\n\n // Keep track of the msg.value to use in the delegate call\n uint256 _payableValue;\n\n // If this terminal's token is ETH, send it in msg.value.\n if (token == JBTokens.ETH) _payableValue = _delegateAllocation.amount;\n\n // Pass the correct token forwardedAmount to the delegate\n _data.forwardedAmount.value = _delegateAllocation.amount;\n\n _delegateAllocation.delegate.didPay{value: _payableValue}(_data);\n\n emit DelegateDidPay(\n _delegateAllocation.delegate,\n _data,\n _delegateAllocation.amount,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n }\n\n emit Pay(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _payer,\n _beneficiary,\n _amount,\n beneficiaryTokenCount,\n _memo,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Receives funds belonging to the specified project.\n /// @param _projectId The ID of the project to which the funds received belong.\n /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\n /// @param _shouldRefundHeldFees A flag indicating if held fees should be refunded based on the amount being added.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the emitted event.\n function _addToBalanceOf(\n uint256 _projectId,\n uint256 _amount,\n bool _shouldRefundHeldFees,\n string memory _memo,\n bytes memory _metadata\n ) internal {\n // Refund any held fees to make sure the project doesn't pay double for funds going in and out of the protocol.\n uint256 _refundedFees = _shouldRefundHeldFees ? _refundHeldFees(_projectId, _amount) : 0;\n\n // Record the added funds with any refunded fees.\n IJBSingleTokenPaymentTerminalStore(store).recordAddedBalanceFor(\n _projectId,\n _amount + _refundedFees\n );\n\n emit AddToBalance(_projectId, _amount, _refundedFees, _memo, _metadata, msg.sender);\n }\n\n /// @notice Refund fees based on the specified amount.\n /// @param _projectId The project for which fees are being refunded.\n /// @param _amount The amount to base the refund on, as a fixed point number with the same amount of decimals as this terminal.\n /// @return refundedFees How much fees were refunded, as a fixed point number with the same number of decimals as this terminal\n function _refundHeldFees(\n uint256 _projectId,\n uint256 _amount\n ) internal returns (uint256 refundedFees) {\n // Get a reference to the project's held fees.\n JBFee[] memory _heldFees = _heldFeesOf[_projectId];\n\n // Delete the current held fees.\n delete _heldFeesOf[_projectId];\n\n // Get a reference to the leftover amount once all fees have been settled.\n uint256 leftoverAmount = _amount;\n\n // Push length in stack\n uint256 _heldFeesLength = _heldFees.length;\n\n // Process each fee.\n for (uint256 _i; _i < _heldFeesLength; ) {\n if (leftoverAmount == 0) _heldFeesOf[_projectId].push(_heldFees[_i]);\n else if (leftoverAmount >= _heldFees[_i].amount) {\n unchecked {\n leftoverAmount = leftoverAmount - _heldFees[_i].amount;\n refundedFees += _feeAmount(\n _heldFees[_i].amount,\n _heldFees[_i].fee,\n _heldFees[_i].feeDiscount\n );\n }\n } else {\n unchecked {\n _heldFeesOf[_projectId].push(\n JBFee(\n _heldFees[_i].amount - leftoverAmount,\n _heldFees[_i].fee,\n _heldFees[_i].feeDiscount,\n _heldFees[_i].beneficiary\n )\n );\n refundedFees += _feeAmount(leftoverAmount, _heldFees[_i].fee, _heldFees[_i].feeDiscount);\n }\n leftoverAmount = 0;\n }\n\n unchecked {\n ++_i;\n }\n }\n\n emit RefundHeldFees(_projectId, _amount, refundedFees, leftoverAmount, msg.sender);\n }\n\n /// @notice Returns the fee amount based on the provided amount for the specified project.\n /// @param _amount The amount that the fee is based on, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _fee The percentage of the fee, out of MAX_FEE.\n /// @param _feeDiscount The percentage discount that should be applied out of the max amount, out of MAX_FEE_DISCOUNT.\n /// @return The amount of the fee, as a fixed point number with the same amount of decimals as this terminal.\n function _feeAmount(\n uint256 _amount,\n uint256 _fee,\n uint256 _feeDiscount\n ) internal pure returns (uint256) {\n // Calculate the discounted fee.\n uint256 _discountedFee = _fee -\n PRBMath.mulDiv(_fee, _feeDiscount, JBConstants.MAX_FEE_DISCOUNT);\n\n // The amount of tokens from the `_amount` to pay as a fee.\n return\n _amount - PRBMath.mulDiv(_amount, JBConstants.MAX_FEE, _discountedFee + JBConstants.MAX_FEE);\n }\n\n /// @notice Get the fee discount from the fee gauge for the specified project.\n /// @param _projectId The ID of the project to get a fee discount for.\n /// @return feeDiscount The fee discount, which should be interpreted as a percentage out MAX_FEE_DISCOUNT.\n function _currentFeeDiscount(uint256 _projectId) internal view returns (uint256) {\n // Can't take a fee if the protocol project doesn't have a terminal that accepts the token.\n if (\n directory.primaryTerminalOf(_FEE_BENEFICIARY_PROJECT_ID, token) ==\n IJBPaymentTerminal(address(0))\n ) return JBConstants.MAX_FEE_DISCOUNT;\n\n // Get the fee discount.\n if (feeGauge != address(0))\n // If the guage reverts, keep the discount at 0.\n try IJBFeeGauge(feeGauge).currentDiscountFor(_projectId) returns (uint256 discount) {\n // If the fee discount is greater than the max, we ignore the return value\n if (discount <= JBConstants.MAX_FEE_DISCOUNT) return discount;\n } catch {\n return 0;\n }\n\n return 0;\n }\n}\n" + }, + "contracts/JBERC20PaymentTerminal3_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';\nimport {IERC20Metadata} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol';\nimport {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';\nimport {JBPayoutRedemptionPaymentTerminal3_1} from './abstract/JBPayoutRedemptionPaymentTerminal3_1.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\n\n/// @notice Manages the inflows and outflows of an ERC-20 token.\ncontract JBERC20PaymentTerminal3_1 is JBPayoutRedemptionPaymentTerminal3_1 {\n using SafeERC20 for IERC20;\n\n //*********************************************************************//\n // -------------------------- internal views ------------------------- //\n //*********************************************************************//\n\n /// @notice Checks the balance of tokens in this contract.\n /// @return The contract's balance, as a fixed point number with the same amount of decimals as this terminal.\n function _balance() internal view override returns (uint256) {\n return IERC20(token).balanceOf(address(this));\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _token The token that this terminal manages.\n /// @param _currency The currency that this terminal's token adheres to for price feeds.\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _payoutSplitsGroup The group that denotes payout splits from this terminal in the splits store.\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _prices A contract that exposes price feeds.\n /// @param _store A contract that stores the terminal's data.\n /// @param _owner The address that will own this contract.\n constructor(\n IERC20Metadata _token,\n uint256 _currency,\n uint256 _baseWeightCurrency,\n uint256 _payoutSplitsGroup,\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBSplitsStore _splitsStore,\n IJBPrices _prices,\n address _store,\n address _owner\n )\n JBPayoutRedemptionPaymentTerminal3_1(\n address(_token),\n _token.decimals(),\n _currency,\n _baseWeightCurrency,\n _payoutSplitsGroup,\n _operatorStore,\n _projects,\n _directory,\n _splitsStore,\n _prices,\n _store,\n _owner\n )\n // solhint-disable-next-line no-empty-blocks\n {\n\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Transfers tokens.\n /// @param _from The address from which the transfer should originate.\n /// @param _to The address to which the transfer should go.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _transferFrom(address _from, address payable _to, uint256 _amount) internal override {\n _from == address(this)\n ? IERC20(token).safeTransfer(_to, _amount)\n : IERC20(token).safeTransferFrom(_from, _to, _amount);\n }\n\n /// @notice Logic to be triggered before transferring tokens from this terminal.\n /// @param _to The address to which the transfer is going.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _beforeTransferTo(address _to, uint256 _amount) internal override {\n IERC20(token).safeIncreaseAllowance(_to, _amount);\n }\n\n /// @notice Logic to be triggered if a transfer should be undone\n /// @param _to The address to which the transfer went.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _cancelTransferTo(address _to, uint256 _amount) internal override {\n IERC20(token).safeDecreaseAllowance(_to, _amount);\n }\n}\n" + }, + "contracts/JBPrices.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {IJBPriceFeed} from './interfaces/IJBPriceFeed.sol';\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\n\n/// @notice Manages and normalizes price feeds.\ncontract JBPrices is Ownable, IJBPrices {\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error PRICE_FEED_ALREADY_EXISTS();\n error PRICE_FEED_NOT_FOUND();\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The available price feeds.\n /// @dev The feed returns the number of `_currency` units that can be converted to 1 `_base` unit.\n /// @custom:param _currency The currency units the feed's resulting price is in terms of.\n /// @custom:param _base The base currency unit being priced by the feed.\n mapping(uint256 => mapping(uint256 => IJBPriceFeed)) public override feedFor;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Gets the number of `_currency` units that can be converted to 1 `_base` unit.\n /// @param _currency The currency units the resulting price is in terms of.\n /// @param _base The base currency unit being priced.\n /// @param _decimals The number of decimals the returned fixed point price should include.\n /// @return The price of the currency in terms of the base, as a fixed point number with the specified number of decimals.\n function priceFor(\n uint256 _currency,\n uint256 _base,\n uint256 _decimals\n ) external view override returns (uint256) {\n // If the currency is the base, return 1 since they are priced the same. Include the desired number of decimals.\n if (_currency == _base) return 10 ** _decimals;\n\n // Get a reference to the feed.\n IJBPriceFeed _feed = feedFor[_currency][_base];\n\n // If it exists, return the price.\n if (_feed != IJBPriceFeed(address(0))) return _feed.currentPrice(_decimals);\n\n // Get the inverse feed.\n _feed = feedFor[_base][_currency];\n\n // If it exists, return the inverse price.\n if (_feed != IJBPriceFeed(address(0)))\n return PRBMath.mulDiv(10 ** _decimals, 10 ** _decimals, _feed.currentPrice(_decimals));\n\n // No price feed available, revert.\n revert PRICE_FEED_NOT_FOUND();\n }\n\n //*********************************************************************//\n // ---------------------------- constructor -------------------------- //\n //*********************************************************************//\n\n /// @param _owner The address that will own the contract.\n constructor(address _owner) {\n // Transfer the ownership.\n transferOwnership(_owner);\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Add a price feed for a currency in terms of the provided base currency.\n /// @dev Current feeds can't be modified.\n /// @param _currency The currency units the feed's resulting price is in terms of.\n /// @param _base The base currency unit being priced by the feed.\n /// @param _feed The price feed being added.\n function addFeedFor(\n uint256 _currency,\n uint256 _base,\n IJBPriceFeed _feed\n ) external override onlyOwner {\n // There can't already be a feed for the specified currency.\n if (\n feedFor[_currency][_base] != IJBPriceFeed(address(0)) ||\n feedFor[_base][_currency] != IJBPriceFeed(address(0))\n ) revert PRICE_FEED_ALREADY_EXISTS();\n\n // Store the feed.\n feedFor[_currency][_base] = _feed;\n\n emit AddFeed(_currency, _base, _feed);\n }\n}\n" + }, + "contracts/JBChainlinkV3PriceFeed.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {AggregatorV3Interface} from '@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol';\nimport {IJBPriceFeed} from './interfaces/IJBPriceFeed.sol';\nimport {JBFixedPointNumber} from './libraries/JBFixedPointNumber.sol';\n\n/// @notice A generalized price feed for the Chainlink AggregatorV3Interface.\ncontract JBChainlinkV3PriceFeed is IJBPriceFeed {\n // A library that provides utility for fixed point numbers.\n using JBFixedPointNumber for uint256;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error STALE_PRICE();\n error INCOMPLETE_ROUND();\n error NEGATIVE_PRICE();\n\n //*********************************************************************//\n // ---------------- public stored immutable properties --------------- //\n //*********************************************************************//\n\n /// @notice The feed that prices are reported from.\n AggregatorV3Interface public immutable feed;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Gets the current price from the feed, normalized to the specified number of decimals.\n /// @param _decimals The number of decimals the returned fixed point price should include.\n /// @return The current price of the feed, as a fixed point number with the specified number of decimals.\n function currentPrice(uint256 _decimals) external view override returns (uint256) {\n // Get the latest round information.\n (uint80 roundId, int256 _price, , uint256 updatedAt, uint80 answeredInRound) = feed\n .latestRoundData();\n\n // Make sure the price isn't stale.\n if (answeredInRound < roundId) revert STALE_PRICE();\n\n // Make sure the round is finished.\n if (updatedAt == 0) revert INCOMPLETE_ROUND();\n\n // Make sure the price is positive.\n if (_price < 0) revert NEGATIVE_PRICE();\n\n // Get a reference to the number of decimals the feed uses.\n uint256 _feedDecimals = feed.decimals();\n\n // Return the price, adjusted to the target decimals.\n return uint256(_price).adjustDecimals(_feedDecimals, _decimals);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _feed The feed to report prices from.\n constructor(AggregatorV3Interface _feed) {\n feed = _feed;\n }\n}\n" + }, + "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface AggregatorV3Interface {\n\n function decimals()\n external\n view\n returns (\n uint8\n );\n\n function description()\n external\n view\n returns (\n string memory\n );\n\n function version()\n external\n view\n returns (\n uint256\n );\n\n // getRoundData and latestRoundData should both raise \"No data present\"\n // if they do not have data to report, instead of returning unset values\n // which could be misinterpreted as actual reported values.\n function getRoundData(\n uint80 _roundId\n )\n external\n view\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n );\n\n function latestRoundData()\n external\n view\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n );\n\n}\n" + }, + "contracts/JBERC20PaymentTerminal3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';\nimport {IERC20Metadata} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol';\nimport {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';\nimport {JBPayoutRedemptionPaymentTerminal3_1_1} from './abstract/JBPayoutRedemptionPaymentTerminal3_1_1.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\n\n/// @notice Manages the inflows and outflows of an ERC-20 token.\ncontract JBERC20PaymentTerminal3_1_1 is JBPayoutRedemptionPaymentTerminal3_1_1 {\n using SafeERC20 for IERC20;\n\n //*********************************************************************//\n // -------------------------- internal views ------------------------- //\n //*********************************************************************//\n\n /// @notice Checks the balance of tokens in this contract.\n /// @return The contract's balance, as a fixed point number with the same amount of decimals as this terminal.\n function _balance() internal view override returns (uint256) {\n return IERC20(token).balanceOf(address(this));\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _token The token that this terminal manages.\n /// @param _currency The currency that this terminal's token adheres to for price feeds.\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _payoutSplitsGroup The group that denotes payout splits from this terminal in the splits store.\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _prices A contract that exposes price feeds.\n /// @param _store A contract that stores the terminal's data.\n /// @param _owner The address that will own this contract.\n constructor(\n IERC20Metadata _token,\n uint256 _currency,\n uint256 _baseWeightCurrency,\n uint256 _payoutSplitsGroup,\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBSplitsStore _splitsStore,\n IJBPrices _prices,\n address _store,\n address _owner\n )\n JBPayoutRedemptionPaymentTerminal3_1_1(\n address(_token),\n _token.decimals(),\n _currency,\n _baseWeightCurrency,\n _payoutSplitsGroup,\n _operatorStore,\n _projects,\n _directory,\n _splitsStore,\n _prices,\n _store,\n _owner\n )\n // solhint-disable-next-line no-empty-blocks\n {\n\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Transfers tokens.\n /// @param _from The address from which the transfer should originate.\n /// @param _to The address to which the transfer should go.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _transferFrom(address _from, address payable _to, uint256 _amount) internal override {\n _from == address(this)\n ? IERC20(token).safeTransfer(_to, _amount)\n : IERC20(token).safeTransferFrom(_from, _to, _amount);\n }\n\n /// @notice Logic to be triggered before transferring tokens from this terminal.\n /// @param _to The address to which the transfer is going.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _beforeTransferTo(address _to, uint256 _amount) internal override {\n IERC20(token).safeIncreaseAllowance(_to, _amount);\n }\n\n /// @notice Logic to be triggered if a transfer should be undone\n /// @param _to The address to which the transfer went.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _cancelTransferTo(address _to, uint256 _amount) internal override {\n IERC20(token).safeDecreaseAllowance(_to, _amount);\n }\n}\n" + }, + "contracts/JBERC20PaymentTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';\nimport {IERC20Metadata} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol';\nimport {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';\nimport {JBPayoutRedemptionPaymentTerminal} from './abstract/JBPayoutRedemptionPaymentTerminal.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\n\n/// @notice Manages the inflows and outflows of an ERC-20 token.\ncontract JBERC20PaymentTerminal is JBPayoutRedemptionPaymentTerminal {\n using SafeERC20 for IERC20;\n\n //*********************************************************************//\n // -------------------------- internal views ------------------------- //\n //*********************************************************************//\n\n /// @notice Checks the balance of tokens in this contract.\n /// @return The contract's balance, as a fixed point number with the same amount of decimals as this terminal.\n function _balance() internal view override returns (uint256) {\n return IERC20(token).balanceOf(address(this));\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _token The token that this terminal manages.\n /// @param _currency The currency that this terminal's token adheres to for price feeds.\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _payoutSplitsGroup The group that denotes payout splits from this terminal in the splits store.\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _prices A contract that exposes price feeds.\n /// @param _store A contract that stores the terminal's data.\n /// @param _owner The address that will own this contract.\n constructor(\n IERC20Metadata _token,\n uint256 _currency,\n uint256 _baseWeightCurrency,\n uint256 _payoutSplitsGroup,\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBSplitsStore _splitsStore,\n IJBPrices _prices,\n address _store,\n address _owner\n )\n JBPayoutRedemptionPaymentTerminal(\n address(_token),\n _token.decimals(),\n _currency,\n _baseWeightCurrency,\n _payoutSplitsGroup,\n _operatorStore,\n _projects,\n _directory,\n _splitsStore,\n _prices,\n _store,\n _owner\n )\n // solhint-disable-next-line no-empty-blocks\n {\n\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Transfers tokens.\n /// @param _from The address from which the transfer should originate.\n /// @param _to The address to which the transfer should go.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _transferFrom(address _from, address payable _to, uint256 _amount) internal override {\n _from == address(this)\n ? IERC20(token).safeTransfer(_to, _amount)\n : IERC20(token).safeTransferFrom(_from, _to, _amount);\n }\n\n /// @notice Logic to be triggered before transferring tokens from this terminal.\n /// @param _to The address to which the transfer is going.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _beforeTransferTo(address _to, uint256 _amount) internal override {\n IERC20(token).safeApprove(_to, _amount);\n }\n}\n" + }, + "contracts/JBFundingCycleStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {JBControllerUtility} from './abstract/JBControllerUtility.sol';\nimport {JBBallotState} from './enums/JBBallotState.sol';\nimport {JBConstants} from './libraries/JBConstants.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBFundingCycleBallot} from './interfaces/IJBFundingCycleBallot.sol';\nimport {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\nimport {JBFundingCycleData} from './structs/JBFundingCycleData.sol';\n\n/// @notice Manages funding cycle configurations and scheduling.\ncontract JBFundingCycleStore is JBControllerUtility, IJBFundingCycleStore {\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error INVALID_BALLOT();\n error INVALID_DISCOUNT_RATE();\n error INVALID_DURATION();\n error INVALID_TIMEFRAME();\n error INVALID_WEIGHT();\n error NO_SAME_BLOCK_RECONFIGURATION();\n\n //*********************************************************************//\n // --------------------- private stored properties ------------------- //\n //*********************************************************************//\n\n /// @notice Stores the user defined properties of each funding cycle, packed into one storage slot.\n /// @custom:param _projectId The ID of the project to get properties of.\n /// @custom:param _configuration The funding cycle configuration to get properties of.\n mapping(uint256 => mapping(uint256 => uint256)) private _packedUserPropertiesOf;\n\n /// @notice Stores the properties added by the mechanism to manage and schedule each funding cycle, packed into one storage slot.\n /// @custom:param _projectId The ID of the project to get instrinsic properties of.\n /// @custom:param _configuration The funding cycle configuration to get properties of.\n mapping(uint256 => mapping(uint256 => uint256)) private _packedIntrinsicPropertiesOf;\n\n /// @notice Stores the metadata for each funding cycle configuration, packed into one storage slot.\n /// @custom:param _projectId The ID of the project to get metadata of.\n /// @custom:param _configuration The funding cycle configuration to get metadata of.\n mapping(uint256 => mapping(uint256 => uint256)) private _metadataOf;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The latest funding cycle configuration for each project.\n /// @custom:param _projectId The ID of the project to get the latest funding cycle configuration of.\n mapping(uint256 => uint256) public override latestConfigurationOf;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Get the funding cycle with the given configuration for the specified project.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @param _configuration The configuration of the funding cycle to get.\n /// @return fundingCycle The funding cycle.\n function get(\n uint256 _projectId,\n uint256 _configuration\n ) external view override returns (JBFundingCycle memory fundingCycle) {\n return _getStructFor(_projectId, _configuration);\n }\n\n /// @notice The latest funding cycle to be configured for the specified project, and its current ballot state.\n /// @param _projectId The ID of the project to get the latest configured funding cycle of.\n /// @return fundingCycle The project's queued funding cycle.\n /// @return ballotState The state of the ballot for the reconfiguration.\n function latestConfiguredOf(\n uint256 _projectId\n ) external view override returns (JBFundingCycle memory fundingCycle, JBBallotState ballotState) {\n // Get a reference to the latest funding cycle configuration.\n uint256 _fundingCycleConfiguration = latestConfigurationOf[_projectId];\n\n // Resolve the funding cycle for the latest configuration.\n fundingCycle = _getStructFor(_projectId, _fundingCycleConfiguration);\n\n // Resolve the ballot state.\n ballotState = _ballotStateOf(\n _projectId,\n fundingCycle.configuration,\n fundingCycle.start,\n fundingCycle.basedOn\n );\n }\n\n /// @notice The funding cycle that's next up for the specified project.\n /// @dev If a queued funding cycle of the project is not found, returns an empty funding cycle with all properties set to 0.\n /// @param _projectId The ID of the project to get the queued funding cycle of.\n /// @return fundingCycle The project's queued funding cycle.\n function queuedOf(\n uint256 _projectId\n ) external view override returns (JBFundingCycle memory fundingCycle) {\n // If the project does not have a funding cycle, return an empty struct.\n if (latestConfigurationOf[_projectId] == 0) return _getStructFor(0, 0);\n\n // Get a reference to the configuration of the standby funding cycle.\n uint256 _standbyFundingCycleConfiguration = _standbyOf(_projectId);\n\n // If it exists, return its funding cycle if it is approved.\n if (_standbyFundingCycleConfiguration > 0) {\n fundingCycle = _getStructFor(_projectId, _standbyFundingCycleConfiguration);\n\n if (_isApproved(_projectId, fundingCycle)) return fundingCycle;\n\n // Resolve the funding cycle for the latest configured funding cycle.\n fundingCycle = _getStructFor(_projectId, fundingCycle.basedOn);\n } else {\n // Resolve the funding cycle for the latest configured funding cycle.\n fundingCycle = _getStructFor(_projectId, latestConfigurationOf[_projectId]);\n\n // If the latest funding cycle starts in the future, it must start in the distant future\n // since its not in standby. In this case base the queued cycles on the base cycle.\n if (fundingCycle.start > block.timestamp)\n fundingCycle = _getStructFor(_projectId, fundingCycle.basedOn);\n }\n\n // There's no queued if the current has a duration of 0.\n if (fundingCycle.duration == 0) return _getStructFor(0, 0);\n\n // Check to see if this funding cycle's ballot is approved.\n // If so, return a funding cycle based on it.\n if (_isApproved(_projectId, fundingCycle)) return _mockFundingCycleBasedOn(fundingCycle, false);\n\n // Get the funding cycle of its base funding cycle, which carries the last approved configuration.\n fundingCycle = _getStructFor(_projectId, fundingCycle.basedOn);\n\n // There's no queued if the base, which must still be the current, has a duration of 0.\n if (fundingCycle.duration == 0) return _getStructFor(0, 0);\n\n // Return a mock of the next up funding cycle.\n return _mockFundingCycleBasedOn(fundingCycle, false);\n }\n\n /// @notice The funding cycle that is currently active for the specified project.\n /// @dev If a current funding cycle of the project is not found, returns an empty funding cycle with all properties set to 0.\n /// @param _projectId The ID of the project to get the current funding cycle of.\n /// @return fundingCycle The project's current funding cycle.\n function currentOf(\n uint256 _projectId\n ) external view override returns (JBFundingCycle memory fundingCycle) {\n // If the project does not have a funding cycle, return an empty struct.\n if (latestConfigurationOf[_projectId] == 0) return _getStructFor(0, 0);\n\n // Get a reference to the configuration of the eligible funding cycle.\n uint256 _fundingCycleConfiguration = _eligibleOf(_projectId);\n\n // Keep a reference to the eligible funding cycle.\n JBFundingCycle memory _fundingCycle;\n\n // If an eligible funding cycle exists...\n if (_fundingCycleConfiguration > 0) {\n // Resolve the funding cycle for the eligible configuration.\n _fundingCycle = _getStructFor(_projectId, _fundingCycleConfiguration);\n\n // Check to see if this funding cycle's ballot is approved.\n // If so, return it.\n if (_isApproved(_projectId, _fundingCycle)) return _fundingCycle;\n\n // If it hasn't been approved, set the funding cycle configuration to be the configuration of the funding cycle that it's based on,\n // which carries the last approved configuration.\n _fundingCycleConfiguration = _fundingCycle.basedOn;\n } else {\n // No upcoming funding cycle found that is eligible to become active,\n // so use the last configuration.\n _fundingCycleConfiguration = latestConfigurationOf[_projectId];\n\n // Get the funding cycle for the latest ID.\n _fundingCycle = _getStructFor(_projectId, _fundingCycleConfiguration);\n\n // If it's not approved or if it hasn't yet started, get a reference to the funding cycle that the latest is based on, which has the latest approved configuration.\n if (!_isApproved(_projectId, _fundingCycle) || block.timestamp < _fundingCycle.start)\n _fundingCycleConfiguration = _fundingCycle.basedOn;\n }\n\n // If there is not funding cycle to base the current one on, there can't be a current one.\n if (_fundingCycleConfiguration == 0) return _getStructFor(0, 0);\n\n // The funding cycle to base a current one on.\n _fundingCycle = _getStructFor(_projectId, _fundingCycleConfiguration);\n\n // If the base has no duration, it's still the current one.\n if (_fundingCycle.duration == 0) return _fundingCycle;\n\n // Return a mock of the current funding cycle.\n return _mockFundingCycleBasedOn(_fundingCycle, true);\n }\n\n /// @notice The current ballot state of the project.\n /// @param _projectId The ID of the project to check the ballot state of.\n /// @return The project's current ballot's state.\n function currentBallotStateOf(uint256 _projectId) external view override returns (JBBallotState) {\n // Get a reference to the latest funding cycle configuration.\n uint256 _fundingCycleConfiguration = latestConfigurationOf[_projectId];\n\n // Resolve the funding cycle for the latest configuration.\n JBFundingCycle memory _fundingCycle = _getStructFor(_projectId, _fundingCycleConfiguration);\n\n return\n _ballotStateOf(\n _projectId,\n _fundingCycle.configuration,\n _fundingCycle.start,\n _fundingCycle.basedOn\n );\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n // solhint-disable-next-line no-empty-blocks\n constructor(IJBDirectory _directory) JBControllerUtility(_directory) {}\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Configures the next eligible funding cycle for the specified project.\n /// @dev Only a project's current controller can configure its funding cycles.\n /// @param _projectId The ID of the project being configured.\n /// @param _data The funding cycle configuration data.\n /// @param _metadata Arbitrary extra data to associate with this funding cycle configuration that's not used within.\n /// @param _mustStartAtOrAfter The time before which the initialized funding cycle cannot start.\n /// @return The funding cycle that the configuration will take effect during.\n function configureFor(\n uint256 _projectId,\n JBFundingCycleData calldata _data,\n uint256 _metadata,\n uint256 _mustStartAtOrAfter\n ) external override onlyController(_projectId) returns (JBFundingCycle memory) {\n // Duration must fit in a uint32.\n if (_data.duration > type(uint32).max) revert INVALID_DURATION();\n\n // Discount rate must be less than or equal to 100%.\n if (_data.discountRate > JBConstants.MAX_DISCOUNT_RATE) revert INVALID_DISCOUNT_RATE();\n\n // Weight must fit into a uint88.\n if (_data.weight > type(uint88).max) revert INVALID_WEIGHT();\n\n // If the start date is in the past, set it to be the current timestamp.\n if (_mustStartAtOrAfter < block.timestamp) _mustStartAtOrAfter = block.timestamp;\n\n // Make sure the min start date fits in a uint56, and that the start date of an upcoming cycle also starts within the max.\n if (_mustStartAtOrAfter + _data.duration > type(uint56).max) revert INVALID_TIMEFRAME();\n\n // Ballot should be a valid contract, supporting the correct interface\n if (_data.ballot != IJBFundingCycleBallot(address(0))) {\n address _ballot = address(_data.ballot);\n\n // No contract at the address ?\n if (_ballot.code.length == 0) revert INVALID_BALLOT();\n\n // Make sure the ballot supports the expected interface.\n try _data.ballot.supportsInterface(type(IJBFundingCycleBallot).interfaceId) returns (\n bool _supports\n ) {\n if (!_supports) revert INVALID_BALLOT(); // Contract exists at the address but with the wrong interface\n } catch {\n revert INVALID_BALLOT(); // No ERC165 support\n }\n }\n\n // The configuration timestamp is now.\n uint256 _configuration = block.timestamp;\n\n // Set up a reconfiguration by configuring intrinsic properties.\n _configureIntrinsicPropertiesFor(_projectId, _configuration, _data.weight, _mustStartAtOrAfter);\n\n // Efficiently stores a funding cycles provided user defined properties.\n // If all user config properties are zero, no need to store anything as the default value will have the same outcome.\n if (\n _data.ballot != IJBFundingCycleBallot(address(0)) ||\n _data.duration > 0 ||\n _data.discountRate > 0\n ) {\n // ballot in bits 0-159 bytes.\n uint256 packed = uint160(address(_data.ballot));\n\n // duration in bits 160-191 bytes.\n packed |= _data.duration << 160;\n\n // discountRate in bits 192-223 bytes.\n packed |= _data.discountRate << 192;\n\n // Set in storage.\n _packedUserPropertiesOf[_projectId][_configuration] = packed;\n }\n\n // Set the metadata if needed.\n if (_metadata > 0) _metadataOf[_projectId][_configuration] = _metadata;\n\n emit Configure(_configuration, _projectId, _data, _metadata, _mustStartAtOrAfter, msg.sender);\n\n // Return the funding cycle for the new configuration.\n return _getStructFor(_projectId, _configuration);\n }\n\n //*********************************************************************//\n // --------------------- private helper functions -------------------- //\n //*********************************************************************//\n\n /// @notice Updates the configurable funding cycle for this project if it exists, otherwise creates one.\n /// @param _projectId The ID of the project to find a configurable funding cycle for.\n /// @param _configuration The time at which the funding cycle was configured.\n /// @param _weight The weight to store in the configured funding cycle.\n /// @param _mustStartAtOrAfter The time before which the initialized funding cycle can't start.\n function _configureIntrinsicPropertiesFor(\n uint256 _projectId,\n uint256 _configuration,\n uint256 _weight,\n uint256 _mustStartAtOrAfter\n ) private {\n // If there's not yet a funding cycle for the project, initialize one.\n if (latestConfigurationOf[_projectId] == 0)\n // Use an empty funding cycle as the base.\n return\n _initFor(_projectId, _getStructFor(0, 0), _configuration, _mustStartAtOrAfter, _weight);\n\n // Get the active funding cycle's configuration.\n uint256 _currentConfiguration = _eligibleOf(_projectId);\n\n // If an eligible funding cycle does not exist, get a reference to the latest funding cycle configuration for the project.\n if (_currentConfiguration == 0)\n // Get the latest funding cycle's configuration.\n _currentConfiguration = latestConfigurationOf[_projectId];\n\n // Get a reference to the funding cycle.\n JBFundingCycle memory _baseFundingCycle = _getStructFor(_projectId, _currentConfiguration);\n\n if (!_isApproved(_projectId, _baseFundingCycle) || block.timestamp < _baseFundingCycle.start)\n // If it hasn't been approved or hasn't yet started, set the ID to be the funding cycle it's based on,\n // which carries the latest approved configuration.\n _baseFundingCycle = _getStructFor(_projectId, _baseFundingCycle.basedOn);\n\n // The configuration can't be the same as the base configuration.\n if (_baseFundingCycle.configuration == _configuration) revert NO_SAME_BLOCK_RECONFIGURATION();\n\n // The time after the ballot of the provided funding cycle has expired.\n // If the provided funding cycle has no ballot, return the current timestamp.\n uint256 _timestampAfterBallot = _baseFundingCycle.ballot == IJBFundingCycleBallot(address(0))\n ? 0\n : _configuration + _baseFundingCycle.ballot.duration();\n\n _initFor(\n _projectId,\n _baseFundingCycle,\n _configuration,\n // Can only start after the ballot.\n _timestampAfterBallot > _mustStartAtOrAfter ? _timestampAfterBallot : _mustStartAtOrAfter,\n _weight\n );\n }\n\n /// @notice Initializes a funding cycle with the specified properties.\n /// @param _projectId The ID of the project to which the funding cycle being initialized belongs.\n /// @param _baseFundingCycle The funding cycle to base the initialized one on.\n /// @param _configuration The configuration of the funding cycle being initialized.\n /// @param _mustStartAtOrAfter The time before which the initialized funding cycle cannot start.\n /// @param _weight The weight to give the newly initialized funding cycle.\n function _initFor(\n uint256 _projectId,\n JBFundingCycle memory _baseFundingCycle,\n uint256 _configuration,\n uint256 _mustStartAtOrAfter,\n uint256 _weight\n ) private {\n // If there is no base, initialize a first cycle.\n if (_baseFundingCycle.number == 0) {\n // The first number is 1.\n uint256 _number = 1;\n\n // Set fresh intrinsic properties.\n _packAndStoreIntrinsicPropertiesOf(\n _configuration,\n _projectId,\n _number,\n _weight,\n _baseFundingCycle.configuration,\n _mustStartAtOrAfter\n );\n } else {\n // Derive the correct next start time from the base.\n uint256 _start = _deriveStartFrom(_baseFundingCycle, _mustStartAtOrAfter);\n\n // A weight of 1 is treated as a weight of 0.\n // This is to allow a weight of 0 (default) to represent inheriting the discounted weight of the previous funding cycle.\n _weight = _weight > 0\n ? (_weight == 1 ? 0 : _weight)\n : _deriveWeightFrom(_baseFundingCycle, _start);\n\n // Derive the correct number.\n uint256 _number = _deriveNumberFrom(_baseFundingCycle, _start);\n\n // Update the intrinsic properties.\n _packAndStoreIntrinsicPropertiesOf(\n _configuration,\n _projectId,\n _number,\n _weight,\n _baseFundingCycle.configuration,\n _start\n );\n }\n\n // Set the project's latest funding cycle configuration.\n latestConfigurationOf[_projectId] = _configuration;\n\n emit Init(_configuration, _projectId, _baseFundingCycle.configuration);\n }\n\n /// @notice Efficiently stores a funding cycle's provided intrinsic properties.\n /// @param _configuration The configuration of the funding cycle to pack and store.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @param _number The number of the funding cycle.\n /// @param _weight The weight of the funding cycle.\n /// @param _basedOn The configuration of the base funding cycle.\n /// @param _start The start time of this funding cycle.\n function _packAndStoreIntrinsicPropertiesOf(\n uint256 _configuration,\n uint256 _projectId,\n uint256 _number,\n uint256 _weight,\n uint256 _basedOn,\n uint256 _start\n ) private {\n // weight in bits 0-87.\n uint256 packed = _weight;\n\n // basedOn in bits 88-143.\n packed |= _basedOn << 88;\n\n // start in bits 144-199.\n packed |= _start << 144;\n\n // number in bits 200-255.\n packed |= _number << 200;\n\n // Store the packed value.\n _packedIntrinsicPropertiesOf[_projectId][_configuration] = packed;\n }\n\n /// @notice The project's stored funding cycle that hasn't yet started and should be used next, if one exists.\n /// @dev A value of 0 is returned if no funding cycle was found.\n /// @dev Assumes the project has a latest configuration.\n /// @param _projectId The ID of a project to look through for a standby cycle.\n /// @return configuration The configuration of the standby funding cycle if one exists, or 0 if one doesn't exist.\n function _standbyOf(uint256 _projectId) private view returns (uint256 configuration) {\n // Get a reference to the project's latest funding cycle.\n configuration = latestConfigurationOf[_projectId];\n\n // Get the necessary properties for the latest funding cycle.\n JBFundingCycle memory _fundingCycle = _getStructFor(_projectId, configuration);\n\n // There is no upcoming funding cycle if the latest funding cycle has already started.\n if (block.timestamp >= _fundingCycle.start) return 0;\n\n // If this is the first funding cycle, it is queued.\n if (_fundingCycle.number == 1) return configuration;\n\n // Get the necessary properties for the base funding cycle.\n JBFundingCycle memory _baseFundingCycle = _getStructFor(_projectId, _fundingCycle.basedOn);\n\n // If the latest configuration doesn't start until after another base cycle, return 0.\n if (\n _baseFundingCycle.duration > 0 &&\n block.timestamp < _fundingCycle.start - _baseFundingCycle.duration\n ) return 0;\n }\n\n /// @notice The project's stored funding cycle that has started and hasn't yet expired.\n /// @dev A value of 0 is returned if no funding cycle was found.\n /// @dev Assumes the project has a latest configuration.\n /// @param _projectId The ID of the project to look through.\n /// @return configuration The configuration of an eligible funding cycle if one exists, or 0 if one doesn't exist.\n function _eligibleOf(uint256 _projectId) private view returns (uint256 configuration) {\n // Get a reference to the project's latest funding cycle.\n configuration = latestConfigurationOf[_projectId];\n\n // Get the latest funding cycle.\n JBFundingCycle memory _fundingCycle = _getStructFor(_projectId, configuration);\n\n // If the latest is expired, return an empty funding cycle.\n // A duration of 0 cannot be expired.\n if (\n _fundingCycle.duration > 0 && block.timestamp >= _fundingCycle.start + _fundingCycle.duration\n ) return 0;\n\n // Return the funding cycle's configuration if it has started.\n if (block.timestamp >= _fundingCycle.start) return _fundingCycle.configuration;\n\n // Get a reference to the cycle's base configuration.\n JBFundingCycle memory _baseFundingCycle = _getStructFor(_projectId, _fundingCycle.basedOn);\n\n // If the base cycle isn't eligible, the project has no eligible cycle.\n // A duration of 0 is always eligible.\n if (\n _baseFundingCycle.duration > 0 &&\n block.timestamp >= _baseFundingCycle.start + _baseFundingCycle.duration\n ) return 0;\n\n // Return the configuration that the latest funding cycle is based on.\n configuration = _fundingCycle.basedOn;\n }\n\n /// @notice A view of the funding cycle that would be created based on the provided one if the project doesn't make a reconfiguration.\n /// @dev Returns an empty funding cycle if there can't be a mock funding cycle based on the provided one.\n /// @dev Assumes a funding cycle with a duration of 0 will never be asked to be the base of a mock.\n /// @param _baseFundingCycle The funding cycle that the resulting funding cycle should follow.\n /// @param _allowMidCycle A flag indicating if the mocked funding cycle is allowed to already be mid cycle.\n /// @return A mock of what the next funding cycle will be.\n function _mockFundingCycleBasedOn(\n JBFundingCycle memory _baseFundingCycle,\n bool _allowMidCycle\n ) private view returns (JBFundingCycle memory) {\n // Get the distance of the current time to the start of the next possible funding cycle.\n // If the returned mock cycle must not yet have started, the start time of the mock must be in the future.\n uint256 _mustStartAtOrAfter = !_allowMidCycle\n ? block.timestamp + 1\n : block.timestamp - _baseFundingCycle.duration + 1;\n\n // Derive what the start time should be.\n uint256 _start = _deriveStartFrom(_baseFundingCycle, _mustStartAtOrAfter);\n\n // Derive what the number should be.\n uint256 _number = _deriveNumberFrom(_baseFundingCycle, _start);\n\n return\n JBFundingCycle(\n _number,\n _baseFundingCycle.configuration,\n _baseFundingCycle.basedOn,\n _start,\n _baseFundingCycle.duration,\n _deriveWeightFrom(_baseFundingCycle, _start),\n _baseFundingCycle.discountRate,\n _baseFundingCycle.ballot,\n _baseFundingCycle.metadata\n );\n }\n\n /// @notice The date that is the nearest multiple of the specified funding cycle's duration from its end.\n /// @param _baseFundingCycle The funding cycle to base the calculation on.\n /// @param _mustStartAtOrAfter A date that the derived start must be on or come after.\n /// @return start The next start time.\n function _deriveStartFrom(\n JBFundingCycle memory _baseFundingCycle,\n uint256 _mustStartAtOrAfter\n ) private pure returns (uint256 start) {\n // A subsequent cycle to one with a duration of 0 should start as soon as possible.\n if (_baseFundingCycle.duration == 0) return _mustStartAtOrAfter;\n\n // The time when the funding cycle immediately after the specified funding cycle starts.\n uint256 _nextImmediateStart = _baseFundingCycle.start + _baseFundingCycle.duration;\n\n // If the next immediate start is now or in the future, return it.\n if (_nextImmediateStart >= _mustStartAtOrAfter) return _nextImmediateStart;\n\n // The amount of seconds since the `_mustStartAtOrAfter` time which results in a start time that might satisfy the specified constraints.\n uint256 _timeFromImmediateStartMultiple = (_mustStartAtOrAfter - _nextImmediateStart) %\n _baseFundingCycle.duration;\n\n // A reference to the first possible start timestamp.\n start = _mustStartAtOrAfter - _timeFromImmediateStartMultiple;\n\n // Add increments of duration as necessary to satisfy the threshold.\n while (_mustStartAtOrAfter > start) start = start + _baseFundingCycle.duration;\n }\n\n /// @notice The accumulated weight change since the specified funding cycle.\n /// @param _baseFundingCycle The funding cycle to base the calculation on.\n /// @param _start The start time of the funding cycle to derive a number for.\n /// @return weight The derived weight, as a fixed point number with 18 decimals.\n function _deriveWeightFrom(\n JBFundingCycle memory _baseFundingCycle,\n uint256 _start\n ) private pure returns (uint256 weight) {\n // A subsequent cycle to one with a duration of 0 should have the next possible weight.\n if (_baseFundingCycle.duration == 0)\n return\n PRBMath.mulDiv(\n _baseFundingCycle.weight,\n JBConstants.MAX_DISCOUNT_RATE - _baseFundingCycle.discountRate,\n JBConstants.MAX_DISCOUNT_RATE\n );\n\n // The weight should be based off the base funding cycle's weight.\n weight = _baseFundingCycle.weight;\n\n // If the discount is 0, the weight doesn't change.\n if (_baseFundingCycle.discountRate == 0) return weight;\n\n // The difference between the start of the base funding cycle and the proposed start.\n uint256 _startDistance = _start - _baseFundingCycle.start;\n\n // Apply the base funding cycle's discount rate for each cycle that has passed.\n uint256 _discountMultiple;\n unchecked {\n _discountMultiple = _startDistance / _baseFundingCycle.duration; // Non-null duration is excluded above\n }\n\n for (uint256 _i; _i < _discountMultiple; ) {\n // The number of times to apply the discount rate.\n // Base the new weight on the specified funding cycle's weight.\n weight = PRBMath.mulDiv(\n weight,\n JBConstants.MAX_DISCOUNT_RATE - _baseFundingCycle.discountRate,\n JBConstants.MAX_DISCOUNT_RATE\n );\n\n // The calculation doesn't need to continue if the weight is 0.\n if (weight == 0) break;\n\n unchecked {\n ++_i;\n }\n }\n }\n\n /// @notice The number of the next funding cycle given the specified funding cycle.\n /// @param _baseFundingCycle The funding cycle to base the calculation on.\n /// @param _start The start time of the funding cycle to derive a number for.\n /// @return The funding cycle number.\n function _deriveNumberFrom(\n JBFundingCycle memory _baseFundingCycle,\n uint256 _start\n ) private pure returns (uint256) {\n // A subsequent cycle to one with a duration of 0 should be the next number.\n if (_baseFundingCycle.duration == 0) return _baseFundingCycle.number + 1;\n\n // The difference between the start of the base funding cycle and the proposed start.\n uint256 _startDistance = _start - _baseFundingCycle.start;\n\n // Find the number of base cycles that fit in the start distance.\n return _baseFundingCycle.number + (_startDistance / _baseFundingCycle.duration);\n }\n\n /// @notice Checks to see if the provided funding cycle is approved according to the correct ballot.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @param _fundingCycle The funding cycle to get an approval flag for.\n /// @return The approval flag.\n function _isApproved(\n uint256 _projectId,\n JBFundingCycle memory _fundingCycle\n ) private view returns (bool) {\n return\n _ballotStateOf(\n _projectId,\n _fundingCycle.configuration,\n _fundingCycle.start,\n _fundingCycle.basedOn\n ) == JBBallotState.Approved;\n }\n\n /// @notice A project's latest funding cycle configuration approval status.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @param _configuration The funding cycle configuration to get the ballot state of.\n /// @param _start The start time of the funding cycle configuration to get the ballot state of.\n /// @param _ballotFundingCycleConfiguration The configuration of the funding cycle which is configured with the ballot that should be used.\n /// @return The ballot state of the project.\n function _ballotStateOf(\n uint256 _projectId,\n uint256 _configuration,\n uint256 _start,\n uint256 _ballotFundingCycleConfiguration\n ) private view returns (JBBallotState) {\n // If there is no ballot funding cycle, implicitly approve.\n if (_ballotFundingCycleConfiguration == 0) return JBBallotState.Approved;\n\n // Get the ballot funding cycle.\n JBFundingCycle memory _ballotFundingCycle = _getStructFor(\n _projectId,\n _ballotFundingCycleConfiguration\n );\n\n // If there is no ballot, the ID is auto approved.\n if (_ballotFundingCycle.ballot == IJBFundingCycleBallot(address(0)))\n return JBBallotState.Approved;\n\n // Return the ballot's state\n return _ballotFundingCycle.ballot.stateOf(_projectId, _configuration, _start);\n }\n\n /// @notice Unpack a funding cycle's packed stored values into an easy-to-work-with funding cycle struct.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @param _configuration The funding cycle configuration to get the full struct for.\n /// @return fundingCycle A funding cycle struct.\n function _getStructFor(\n uint256 _projectId,\n uint256 _configuration\n ) private view returns (JBFundingCycle memory fundingCycle) {\n // Return an empty funding cycle if the configuration specified is 0.\n if (_configuration == 0) return fundingCycle;\n\n fundingCycle.configuration = _configuration;\n\n uint256 _packedIntrinsicProperties = _packedIntrinsicPropertiesOf[_projectId][_configuration];\n\n // weight in bits 0-87 bits.\n fundingCycle.weight = uint256(uint88(_packedIntrinsicProperties));\n // basedOn in bits 88-143 bits.\n fundingCycle.basedOn = uint256(uint56(_packedIntrinsicProperties >> 88));\n // start in bits 144-199 bits.\n fundingCycle.start = uint256(uint56(_packedIntrinsicProperties >> 144));\n // number in bits 200-255 bits.\n fundingCycle.number = uint256(uint56(_packedIntrinsicProperties >> 200));\n\n uint256 _packedUserProperties = _packedUserPropertiesOf[_projectId][_configuration];\n\n // ballot in bits 0-159 bits.\n fundingCycle.ballot = IJBFundingCycleBallot(address(uint160(_packedUserProperties)));\n // duration in bits 160-191 bits.\n fundingCycle.duration = uint256(uint32(_packedUserProperties >> 160));\n // discountRate in bits 192-223 bits.\n fundingCycle.discountRate = uint256(uint32(_packedUserProperties >> 192));\n\n fundingCycle.metadata = _metadataOf[_projectId][_configuration];\n }\n}\n" + }, + "contracts/JBController.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {ERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {SafeCast} from '@openzeppelin/contracts/utils/math/SafeCast.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {JBOperatable} from './abstract/JBOperatable.sol';\nimport {JBBallotState} from './enums/JBBallotState.sol';\nimport {IJBController} from './interfaces/IJBController.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol';\nimport {IJBMigratable} from './interfaces/IJBMigratable.sol';\nimport {IJBOperatable} from './interfaces/IJBOperatable.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {IJBSplitAllocator} from './interfaces/IJBSplitAllocator.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {IJBTokenStore} from './interfaces/IJBTokenStore.sol';\nimport {JBConstants} from './libraries/JBConstants.sol';\nimport {JBFundingCycleMetadataResolver} from './libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBOperations} from './libraries/JBOperations.sol';\nimport {JBSplitsGroups} from './libraries/JBSplitsGroups.sol';\nimport {JBSplitAllocationData} from './structs/JBSplitAllocationData.sol';\nimport {JBFundAccessConstraints} from './structs/JBFundAccessConstraints.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\nimport {JBFundingCycleData} from './structs/JBFundingCycleData.sol';\nimport {JBFundingCycleMetadata} from './structs/JBFundingCycleMetadata.sol';\nimport {JBGroupedSplits} from './structs/JBGroupedSplits.sol';\nimport {JBProjectMetadata} from './structs/JBProjectMetadata.sol';\nimport {JBSplit} from './structs/JBSplit.sol';\n\n/// @notice Stitches together funding cycles and project tokens, making sure all activity is accounted for and correct.\ncontract JBController is JBOperatable, ERC165, IJBController, IJBMigratable {\n // A library that parses the packed funding cycle metadata into a more friendly format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error BURN_PAUSED_AND_SENDER_NOT_VALID_TERMINAL_DELEGATE();\n error CANT_MIGRATE_TO_CURRENT_CONTROLLER();\n error FUNDING_CYCLE_ALREADY_LAUNCHED();\n error INVALID_BALLOT_REDEMPTION_RATE();\n error INVALID_DISTRIBUTION_LIMIT();\n error INVALID_DISTRIBUTION_LIMIT_CURRENCY();\n error INVALID_OVERFLOW_ALLOWANCE();\n error INVALID_OVERFLOW_ALLOWANCE_CURRENCY();\n error INVALID_REDEMPTION_RATE();\n error INVALID_RESERVED_RATE();\n error MIGRATION_NOT_ALLOWED();\n error MINT_NOT_ALLOWED_AND_NOT_TERMINAL_DELEGATE();\n error NO_BURNABLE_TOKENS();\n error NOT_CURRENT_CONTROLLER();\n error ZERO_TOKENS_TO_MINT();\n\n //*********************************************************************//\n // --------------------- internal stored properties ------------------ //\n //*********************************************************************//\n\n /// @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.\n /// @custom:param _projectId The ID of the project to get the tracker of.\n mapping(uint256 => int256) internal _processedTokenTrackerOf;\n\n /// @notice Data regarding the distribution limit of a project during a configuration.\n /// @dev bits 0-231: The amount of token that a project can distribute per funding cycle.\n /// @dev bits 232-255: The currency of amount that a project can distribute.\n /// @custom:param _projectId The ID of the project to get the packed distribution limit data of.\n /// @custom:param _configuration The configuration during which the packed distribution limit data applies.\n /// @custom:param _terminal The terminal from which distributions are being limited.\n /// @custom:param _token The token for which distributions are being limited.\n mapping(uint256 => mapping(uint256 => mapping(IJBPaymentTerminal => mapping(address => uint256))))\n internal _packedDistributionLimitDataOf;\n\n /// @notice Data regarding the overflow allowance of a project during a configuration.\n /// @dev bits 0-231: The amount of overflow that a project is allowed to tap into on-demand throughout the configuration.\n /// @dev bits 232-255: The currency of the amount of overflow that a project is allowed to tap.\n /// @custom:param _projectId The ID of the project to get the packed overflow allowance data of.\n /// @custom:param _configuration The configuration during which the packed overflow allowance data applies.\n /// @custom:param _terminal The terminal managing the overflow.\n /// @custom:param _token The token for which overflow is being allowed.\n mapping(uint256 => mapping(uint256 => mapping(IJBPaymentTerminal => mapping(address => uint256))))\n internal _packedOverflowAllowanceDataOf;\n\n //*********************************************************************//\n // --------------- public immutable stored properties ---------------- //\n //*********************************************************************//\n\n /// @notice Mints ERC-721's that represent project ownership.\n IJBProjects public immutable override projects;\n\n /// @notice The contract storing all funding cycle configurations.\n IJBFundingCycleStore public immutable override fundingCycleStore;\n\n /// @notice The contract that manages token minting and burning.\n IJBTokenStore public immutable override tokenStore;\n\n /// @notice The contract that stores splits for each project.\n IJBSplitsStore public immutable override splitsStore;\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice The amount of token that a project can distribute per funding cycle, and the currency it's in terms of.\n /// @dev The number of decimals in the returned fixed point amount is the same as that of the specified terminal.\n /// @param _projectId The ID of the project to get the distribution limit of.\n /// @param _configuration The configuration during which the distribution limit applies.\n /// @param _terminal The terminal from which distributions are being limited.\n /// @param _token The token for which the distribution limit applies.\n /// @return The distribution limit, as a fixed point number with the same number of decimals as the provided terminal.\n /// @return The currency of the distribution limit.\n function distributionLimitOf(\n uint256 _projectId,\n uint256 _configuration,\n IJBPaymentTerminal _terminal,\n address _token\n ) external view override returns (uint256, uint256) {\n // Get a reference to the packed data.\n uint256 _data = _packedDistributionLimitDataOf[_projectId][_configuration][_terminal][_token];\n\n // The limit is in bits 0-231. The currency is in bits 232-255.\n return (uint256(uint232(_data)), _data >> 232);\n }\n\n /// @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.\n /// @dev The number of decimals in the returned fixed point amount is the same as that of the specified terminal.\n /// @param _projectId The ID of the project to get the overflow allowance of.\n /// @param _configuration The configuration of the during which the allowance applies.\n /// @param _terminal The terminal managing the overflow.\n /// @param _token The token for which the overflow allowance applies.\n /// @return The overflow allowance, as a fixed point number with the same number of decimals as the provided terminal.\n /// @return The currency of the overflow allowance.\n function overflowAllowanceOf(\n uint256 _projectId,\n uint256 _configuration,\n IJBPaymentTerminal _terminal,\n address _token\n ) external view override returns (uint256, uint256) {\n // Get a reference to the packed data.\n uint256 _data = _packedOverflowAllowanceDataOf[_projectId][_configuration][_terminal][_token];\n\n // The allowance is in bits 0-231. The currency is in bits 232-255.\n return (uint256(uint232(_data)), _data >> 232);\n }\n\n /// @notice Gets the amount of reserved tokens that a project has available to distribute.\n /// @param _projectId The ID of the project to get a reserved token balance of.\n /// @param _reservedRate The reserved rate to use when making the calculation.\n /// @return The current amount of reserved tokens.\n function reservedTokenBalanceOf(\n uint256 _projectId,\n uint256 _reservedRate\n ) external view override returns (uint256) {\n return\n _reservedTokenAmountFrom(\n _processedTokenTrackerOf[_projectId],\n _reservedRate,\n tokenStore.totalSupplyOf(_projectId)\n );\n }\n\n /// @notice Gets the current total amount of outstanding tokens for a project, given a reserved rate.\n /// @param _projectId The ID of the project to get total outstanding tokens of.\n /// @param _reservedRate The reserved rate to use when making the calculation.\n /// @return The current total amount of outstanding tokens for the project.\n function totalOutstandingTokensOf(\n uint256 _projectId,\n uint256 _reservedRate\n ) external view override returns (uint256) {\n // Get the total number of tokens in circulation.\n uint256 _totalSupply = tokenStore.totalSupplyOf(_projectId);\n\n // Get the number of reserved tokens the project has.\n uint256 _reservedTokenAmount = _reservedTokenAmountFrom(\n _processedTokenTrackerOf[_projectId],\n _reservedRate,\n _totalSupply\n );\n\n // Add the reserved tokens to the total supply.\n return _totalSupply + _reservedTokenAmount;\n }\n\n /// @notice A project's funding cycle for the specified configuration along with its metadata.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The funding cycle.\n /// @return metadata The funding cycle's metadata.\n function getFundingCycleOf(\n uint256 _projectId,\n uint256 _configuration\n )\n external\n view\n override\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata)\n {\n fundingCycle = fundingCycleStore.get(_projectId, _configuration);\n metadata = fundingCycle.expandMetadata();\n }\n\n /// @notice A project's latest configured funding cycle along with its metadata and the ballot state of the configuration.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The latest configured funding cycle.\n /// @return metadata The latest configured funding cycle's metadata.\n /// @return ballotState The state of the configuration.\n function latestConfiguredFundingCycleOf(\n uint256 _projectId\n )\n external\n view\n override\n returns (\n JBFundingCycle memory fundingCycle,\n JBFundingCycleMetadata memory metadata,\n JBBallotState ballotState\n )\n {\n (fundingCycle, ballotState) = fundingCycleStore.latestConfiguredOf(_projectId);\n metadata = fundingCycle.expandMetadata();\n }\n\n /// @notice A project's current funding cycle along with its metadata.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The current funding cycle.\n /// @return metadata The current funding cycle's metadata.\n function currentFundingCycleOf(\n uint256 _projectId\n )\n external\n view\n override\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata)\n {\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n metadata = fundingCycle.expandMetadata();\n }\n\n /// @notice A project's queued funding cycle along with its metadata.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The queued funding cycle.\n /// @return metadata The queued funding cycle's metadata.\n function queuedFundingCycleOf(\n uint256 _projectId\n )\n external\n view\n override\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata)\n {\n fundingCycle = fundingCycleStore.queuedOf(_projectId);\n metadata = fundingCycle.expandMetadata();\n }\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if the provided interface ID is supported.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(ERC165, IERC165) returns (bool) {\n return\n _interfaceId == type(IJBController).interfaceId ||\n _interfaceId == type(IJBMigratable).interfaceId ||\n _interfaceId == type(IJBOperatable).interfaceId ||\n super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // ---------------------------- constructor -------------------------- //\n //*********************************************************************//\n\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _fundingCycleStore A contract storing all funding cycle configurations.\n /// @param _tokenStore A contract that manages token minting and burning.\n /// @param _splitsStore A contract that stores splits for each project.\n constructor(\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBFundingCycleStore _fundingCycleStore,\n IJBTokenStore _tokenStore,\n IJBSplitsStore _splitsStore\n ) JBOperatable(_operatorStore) {\n projects = _projects;\n directory = _directory;\n fundingCycleStore = _fundingCycleStore;\n tokenStore = _tokenStore;\n splitsStore = _splitsStore;\n }\n\n //*********************************************************************//\n // --------------------- external transactions ----------------------- //\n //*********************************************************************//\n\n /// @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.\n /// @dev Each operation within this transaction can be done in sequence separately.\n /// @dev Anyone can deploy a project on an owner's behalf.\n /// @param _owner The address to set as the owner of the project. The project ERC-721 will be owned by this address.\n /// @param _projectMetadata Metadata to associate with the project within a particular domain. This can be updated any time by the owner of the project.\n /// @param _data Data that defines the project's first funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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`.\n /// @param _terminals Payment terminals to add for the project.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return projectId The ID of the project.\n function launchProjectFor(\n address _owner,\n JBProjectMetadata calldata _projectMetadata,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] calldata _groupedSplits,\n JBFundAccessConstraints[] calldata _fundAccessConstraints,\n IJBPaymentTerminal[] memory _terminals,\n string memory _memo\n ) external virtual override returns (uint256 projectId) {\n // Keep a reference to the directory.\n IJBDirectory _directory = directory;\n\n // Mint the project into the wallet of the owner.\n projectId = projects.createFor(_owner, _projectMetadata);\n\n // Set this contract as the project's controller in the directory.\n _directory.setControllerOf(projectId, address(this));\n\n // Configure the first funding cycle.\n uint256 _configuration = _configure(\n projectId,\n _data,\n _metadata,\n _mustStartAtOrAfter,\n _groupedSplits,\n _fundAccessConstraints\n );\n\n // Add the provided terminals to the list of terminals.\n if (_terminals.length > 0) _directory.setTerminalsOf(projectId, _terminals);\n\n emit LaunchProject(_configuration, projectId, _memo, msg.sender);\n }\n\n /// @notice Creates a funding cycle for an already existing project ERC-721.\n /// @dev Each operation within this transaction can be done in sequence separately.\n /// @dev Only a project owner or operator can launch its funding cycles.\n /// @param _projectId The ID of the project to launch funding cycles for.\n /// @param _data Data that defines the project's first funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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`.\n /// @param _terminals Payment terminals to add for the project.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return configuration The configuration of the funding cycle that was successfully created.\n function launchFundingCyclesFor(\n uint256 _projectId,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] calldata _groupedSplits,\n JBFundAccessConstraints[] memory _fundAccessConstraints,\n IJBPaymentTerminal[] memory _terminals,\n string memory _memo\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.RECONFIGURE)\n returns (uint256 configuration)\n {\n // If there is a previous configuration, reconfigureFundingCyclesOf should be called instead\n if (fundingCycleStore.latestConfigurationOf(_projectId) > 0)\n revert FUNDING_CYCLE_ALREADY_LAUNCHED();\n\n // Set this contract as the project's controller in the directory.\n directory.setControllerOf(_projectId, address(this));\n\n // Configure the first funding cycle.\n configuration = _configure(\n _projectId,\n _data,\n _metadata,\n _mustStartAtOrAfter,\n _groupedSplits,\n _fundAccessConstraints\n );\n\n // Add the provided terminals to the list of terminals.\n if (_terminals.length > 0) directory.setTerminalsOf(_projectId, _terminals);\n\n emit LaunchFundingCycles(configuration, _projectId, _memo, msg.sender);\n }\n\n /// @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.\n /// @dev Only a project's owner or a designated operator can configure its funding cycles.\n /// @param _projectId The ID of the project whose funding cycles are being reconfigured.\n /// @param _data Data that defines the funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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`.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return configuration The configuration of the funding cycle that was successfully reconfigured.\n function reconfigureFundingCyclesOf(\n uint256 _projectId,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] calldata _groupedSplits,\n JBFundAccessConstraints[] calldata _fundAccessConstraints,\n string calldata _memo\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.RECONFIGURE)\n returns (uint256 configuration)\n {\n // Configure the next funding cycle.\n configuration = _configure(\n _projectId,\n _data,\n _metadata,\n _mustStartAtOrAfter,\n _groupedSplits,\n _fundAccessConstraints\n );\n\n emit ReconfigureFundingCycles(configuration, _projectId, _memo, msg.sender);\n }\n\n /// @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.\n /// @dev Only a project's owner, a designated operator, one of its terminals, or the current data source can mint its tokens.\n /// @param _projectId The ID of the project to which the tokens being minted belong.\n /// @param _tokenCount The amount of tokens to mint in total, counting however many should be reserved.\n /// @param _beneficiary The account that the tokens are being minted for.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _preferClaimedTokens A flag indicating whether a project's attached token contract should be minted if they have been issued.\n /// @param _useReservedRate Whether to use the current funding cycle's reserved rate in the mint calculation.\n /// @return beneficiaryTokenCount The amount of tokens minted for the beneficiary.\n function mintTokensOf(\n uint256 _projectId,\n uint256 _tokenCount,\n address _beneficiary,\n string calldata _memo,\n bool _preferClaimedTokens,\n bool _useReservedRate\n ) external virtual override returns (uint256 beneficiaryTokenCount) {\n // There should be tokens to mint.\n if (_tokenCount == 0) revert ZERO_TOKENS_TO_MINT();\n\n // Define variables that will be needed outside scoped section below.\n // Keep a reference to the reserved rate to use\n uint256 _reservedRate;\n\n // Scoped section prevents stack too deep. `_fundingCycle` only used within scope.\n {\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Minting limited to: project owner, authorized callers, project terminal and current funding cycle data source\n _requirePermissionAllowingOverride(\n projects.ownerOf(_projectId),\n _projectId,\n JBOperations.MINT,\n directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender)) ||\n msg.sender == address(_fundingCycle.dataSource())\n );\n\n // If the message sender is not a terminal or a datasource, the current funding cycle must allow minting.\n if (\n !_fundingCycle.mintingAllowed() &&\n !directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender)) &&\n msg.sender != address(_fundingCycle.dataSource())\n ) revert MINT_NOT_ALLOWED_AND_NOT_TERMINAL_DELEGATE();\n\n // Determine the reserved rate to use.\n _reservedRate = _useReservedRate ? _fundingCycle.reservedRate() : 0;\n\n // Override the claimed token preference with the funding cycle value.\n _preferClaimedTokens = _preferClaimedTokens == true\n ? _preferClaimedTokens\n : _fundingCycle.preferClaimedTokenOverride();\n }\n\n if (_reservedRate == JBConstants.MAX_RESERVED_RATE)\n // Subtract the total weighted amount from the tracker so the full reserved token amount can be printed later.\n _processedTokenTrackerOf[_projectId] =\n _processedTokenTrackerOf[_projectId] -\n SafeCast.toInt256(_tokenCount);\n else {\n // The unreserved token count that will be minted for the beneficiary.\n beneficiaryTokenCount = PRBMath.mulDiv(\n _tokenCount,\n JBConstants.MAX_RESERVED_RATE - _reservedRate,\n JBConstants.MAX_RESERVED_RATE\n );\n\n if (_reservedRate == 0)\n // If there's no reserved rate, increment the tracker with the newly minted tokens.\n _processedTokenTrackerOf[_projectId] =\n _processedTokenTrackerOf[_projectId] +\n SafeCast.toInt256(beneficiaryTokenCount);\n\n // Mint the tokens.\n tokenStore.mintFor(_beneficiary, _projectId, beneficiaryTokenCount, _preferClaimedTokens);\n }\n\n emit MintTokens(\n _beneficiary,\n _projectId,\n _tokenCount,\n beneficiaryTokenCount,\n _memo,\n _reservedRate,\n msg.sender\n );\n }\n\n /// @notice Burns a token holder's supply.\n /// @dev Only a token's holder, a designated operator, or a project's terminal can burn it.\n /// @param _holder The account that is having its tokens burned.\n /// @param _projectId The ID of the project to which the tokens being burned belong.\n /// @param _tokenCount The number of tokens to burn.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _preferClaimedTokens A flag indicating whether a project's attached token contract should be burned first if they have been issued.\n function burnTokensOf(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n string calldata _memo,\n bool _preferClaimedTokens\n )\n external\n virtual\n override\n requirePermissionAllowingOverride(\n _holder,\n _projectId,\n JBOperations.BURN,\n directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender))\n )\n {\n // There should be tokens to burn\n if (_tokenCount == 0) revert NO_BURNABLE_TOKENS();\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // If the message sender is a terminal, the current funding cycle must not be paused.\n if (\n _fundingCycle.burnPaused() &&\n !directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender))\n ) revert BURN_PAUSED_AND_SENDER_NOT_VALID_TERMINAL_DELEGATE();\n\n // Update the token tracker so that reserved tokens will still be correctly mintable.\n _processedTokenTrackerOf[_projectId] =\n _processedTokenTrackerOf[_projectId] -\n SafeCast.toInt256(_tokenCount);\n\n // Burn the tokens.\n tokenStore.burnFrom(_holder, _projectId, _tokenCount, _preferClaimedTokens);\n\n emit BurnTokens(_holder, _projectId, _tokenCount, _memo, msg.sender);\n }\n\n /// @notice Distributes all outstanding reserved tokens for a project.\n /// @param _projectId The ID of the project to which the reserved tokens belong.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return The amount of minted reserved tokens.\n function distributeReservedTokensOf(\n uint256 _projectId,\n string calldata _memo\n ) external virtual override returns (uint256) {\n return _distributeReservedTokensOf(_projectId, _memo);\n }\n\n /// @notice Allows other controllers to signal to this one that a migration is expected for the specified project.\n /// @dev This controller should not yet be the project's controller.\n /// @param _projectId The ID of the project that will be migrated to this controller.\n /// @param _from The controller being migrated from.\n function prepForMigrationOf(uint256 _projectId, address _from) external virtual override {\n // This controller must not be the project's current controller.\n if (directory.controllerOf(_projectId) == address(this))\n revert CANT_MIGRATE_TO_CURRENT_CONTROLLER();\n\n // Set the tracker as the total supply.\n _processedTokenTrackerOf[_projectId] = SafeCast.toInt256(tokenStore.totalSupplyOf(_projectId));\n\n emit PrepMigration(_projectId, _from, msg.sender);\n }\n\n /// @notice Allows a project to migrate from this controller to another.\n /// @dev Only a project's owner or a designated operator can migrate it.\n /// @param _projectId The ID of the project that will be migrated from this controller.\n /// @param _to The controller to which the project is migrating.\n function migrate(\n uint256 _projectId,\n IJBMigratable _to\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.MIGRATE_CONTROLLER)\n {\n // Keep a reference to the directory.\n IJBDirectory _directory = directory;\n\n // This controller must be the project's current controller.\n if (_directory.controllerOf(_projectId) != address(this)) revert NOT_CURRENT_CONTROLLER();\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Migration must be allowed.\n if (!_fundingCycle.controllerMigrationAllowed()) revert MIGRATION_NOT_ALLOWED();\n\n // All reserved tokens must be minted before migrating.\n if (\n _processedTokenTrackerOf[_projectId] < 0 ||\n uint256(_processedTokenTrackerOf[_projectId]) != tokenStore.totalSupplyOf(_projectId)\n ) _distributeReservedTokensOf(_projectId, '');\n\n // Make sure the new controller is prepped for the migration.\n _to.prepForMigrationOf(_projectId, address(this));\n\n // Set the new controller.\n _directory.setControllerOf(_projectId, address(_to));\n\n emit Migrate(_projectId, _to, msg.sender);\n }\n\n //*********************************************************************//\n // ------------------------ internal functions ----------------------- //\n //*********************************************************************//\n\n /// @notice Distributes all outstanding reserved tokens for a project.\n /// @param _projectId The ID of the project to which the reserved tokens belong.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return tokenCount The amount of minted reserved tokens.\n function _distributeReservedTokensOf(\n uint256 _projectId,\n string memory _memo\n ) internal returns (uint256 tokenCount) {\n // Keep a reference to the token store.\n IJBTokenStore _tokenStore = tokenStore;\n\n // Get the current funding cycle to read the reserved rate from.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Get a reference to new total supply of tokens before minting reserved tokens.\n uint256 _totalTokens = _tokenStore.totalSupplyOf(_projectId);\n\n // Get a reference to the number of tokens that need to be minted.\n tokenCount = _reservedTokenAmountFrom(\n _processedTokenTrackerOf[_projectId],\n _fundingCycle.reservedRate(),\n _totalTokens\n );\n\n // Set the tracker to be the new total supply.\n _processedTokenTrackerOf[_projectId] = SafeCast.toInt256(_totalTokens + tokenCount);\n\n // Get a reference to the project owner.\n address _owner = projects.ownerOf(_projectId);\n\n // Distribute tokens to splits and get a reference to the leftover amount to mint after all splits have gotten their share.\n uint256 _leftoverTokenCount = tokenCount == 0\n ? 0\n : _distributeToReservedTokenSplitsOf(\n _projectId,\n _fundingCycle.configuration,\n JBSplitsGroups.RESERVED_TOKENS,\n tokenCount\n );\n\n // Mint any leftover tokens to the project owner.\n if (_leftoverTokenCount > 0)\n _tokenStore.mintFor(_owner, _projectId, _leftoverTokenCount, false);\n\n emit DistributeReservedTokens(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _owner,\n tokenCount,\n _leftoverTokenCount,\n _memo,\n msg.sender\n );\n }\n\n /// @notice Distribute tokens to the splits according to the specified funding cycle configuration.\n /// @param _projectId The ID of the project for which reserved token splits are being distributed.\n /// @param _domain The domain of the splits to distribute the reserved tokens between.\n /// @param _group The group of the splits to distribute the reserved tokens between.\n /// @param _amount The total amount of tokens to mint.\n /// @return leftoverAmount If the splits percents dont add up to 100%, the leftover amount is returned.\n function _distributeToReservedTokenSplitsOf(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group,\n uint256 _amount\n ) internal returns (uint256 leftoverAmount) {\n // Keep a reference to the token store.\n IJBTokenStore _tokenStore = tokenStore;\n\n // Set the leftover amount to the initial amount.\n leftoverAmount = _amount;\n\n // Get a reference to the project's reserved token splits.\n JBSplit[] memory _splits = splitsStore.splitsOf(_projectId, _domain, _group);\n\n //Transfer between all splits.\n for (uint256 _i; _i < _splits.length; ) {\n // Get a reference to the split being iterated on.\n JBSplit memory _split = _splits[_i];\n\n // The amount to send towards the split.\n uint256 _tokenCount = PRBMath.mulDiv(\n _amount,\n _split.percent,\n JBConstants.SPLITS_TOTAL_PERCENT\n );\n\n // Mints tokens for the split if needed.\n if (_tokenCount > 0) {\n _tokenStore.mintFor(\n // If an allocator is set in the splits, set it as the beneficiary.\n // Otherwise if a projectId is set in the split, set the project's owner as the beneficiary.\n // If the split has a beneficiary send to the split's beneficiary. Otherwise send to the msg.sender.\n _split.allocator != IJBSplitAllocator(address(0))\n ? address(_split.allocator)\n : _split.projectId != 0\n ? projects.ownerOf(_split.projectId)\n : _split.beneficiary != address(0)\n ? _split.beneficiary\n : msg.sender,\n _projectId,\n _tokenCount,\n _split.preferClaimed\n );\n\n // If there's an allocator set, trigger its `allocate` function.\n if (_split.allocator != IJBSplitAllocator(address(0)))\n _split.allocator.allocate(\n JBSplitAllocationData(\n address(_tokenStore.tokenOf(_projectId)),\n _tokenCount,\n 18,\n _projectId,\n _group,\n _split\n )\n );\n\n // Subtract from the amount to be sent to the beneficiary.\n leftoverAmount = leftoverAmount - _tokenCount;\n }\n\n emit DistributeToReservedTokenSplit(\n _projectId,\n _domain,\n _group,\n _split,\n _tokenCount,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n\n /// @notice Configures a funding cycle and stores information pertinent to the configuration.\n /// @param _projectId The ID of the project whose funding cycles are being reconfigured.\n /// @param _data Data that defines the funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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.\n /// @return configuration The configuration of the funding cycle that was successfully reconfigured.\n function _configure(\n uint256 _projectId,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] memory _groupedSplits,\n JBFundAccessConstraints[] memory _fundAccessConstraints\n ) internal returns (uint256) {\n // Make sure the provided reserved rate is valid.\n if (_metadata.reservedRate > JBConstants.MAX_RESERVED_RATE) revert INVALID_RESERVED_RATE();\n\n // Make sure the provided redemption rate is valid.\n if (_metadata.redemptionRate > JBConstants.MAX_REDEMPTION_RATE)\n revert INVALID_REDEMPTION_RATE();\n\n // Make sure the provided ballot redemption rate is valid.\n if (_metadata.ballotRedemptionRate > JBConstants.MAX_REDEMPTION_RATE)\n revert INVALID_BALLOT_REDEMPTION_RATE();\n\n // Configure the funding cycle's properties.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.configureFor(\n _projectId,\n _data,\n JBFundingCycleMetadataResolver.packFundingCycleMetadata(_metadata),\n _mustStartAtOrAfter\n );\n\n // Set splits for the group.\n splitsStore.set(_projectId, _fundingCycle.configuration, _groupedSplits);\n\n // Set distribution limits if there are any.\n for (uint256 _i; _i < _fundAccessConstraints.length; ) {\n JBFundAccessConstraints memory _constraints = _fundAccessConstraints[_i];\n\n // If distribution limit value is larger than 232 bits, revert.\n if (_constraints.distributionLimit > type(uint232).max) revert INVALID_DISTRIBUTION_LIMIT();\n\n // If distribution limit currency value is larger than 24 bits, revert.\n if (_constraints.distributionLimitCurrency > type(uint24).max)\n revert INVALID_DISTRIBUTION_LIMIT_CURRENCY();\n\n // If overflow allowance value is larger than 232 bits, revert.\n if (_constraints.overflowAllowance > type(uint232).max) revert INVALID_OVERFLOW_ALLOWANCE();\n\n // If overflow allowance currency value is larger than 24 bits, revert.\n if (_constraints.overflowAllowanceCurrency > type(uint24).max)\n revert INVALID_OVERFLOW_ALLOWANCE_CURRENCY();\n\n // Set the distribution limit if there is one.\n if (_constraints.distributionLimit > 0)\n _packedDistributionLimitDataOf[_projectId][_fundingCycle.configuration][\n _constraints.terminal\n ][_constraints.token] =\n _constraints.distributionLimit |\n (_constraints.distributionLimitCurrency << 232);\n\n // Set the overflow allowance if there is one.\n if (_constraints.overflowAllowance > 0)\n _packedOverflowAllowanceDataOf[_projectId][_fundingCycle.configuration][\n _constraints.terminal\n ][_constraints.token] =\n _constraints.overflowAllowance |\n (_constraints.overflowAllowanceCurrency << 232);\n\n emit SetFundAccessConstraints(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _constraints,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n\n return _fundingCycle.configuration;\n }\n\n /// @notice Gets the amount of reserved tokens currently tracked for a project given a reserved rate.\n /// @param _processedTokenTracker The tracker to make the calculation with.\n /// @param _reservedRate The reserved rate to use to make the calculation.\n /// @param _totalEligibleTokens The total amount to make the calculation with.\n /// @return amount reserved token amount.\n function _reservedTokenAmountFrom(\n int256 _processedTokenTracker,\n uint256 _reservedRate,\n uint256 _totalEligibleTokens\n ) internal pure returns (uint256) {\n // Get a reference to the amount of tokens that are unprocessed.\n uint256 _unprocessedTokenBalanceOf = _processedTokenTracker >= 0\n ? _totalEligibleTokens - uint256(_processedTokenTracker)\n : _totalEligibleTokens + uint256(-_processedTokenTracker);\n\n // If there are no unprocessed tokens, return.\n if (_unprocessedTokenBalanceOf == 0) return 0;\n\n // If all tokens are reserved, return the full unprocessed amount.\n if (_reservedRate == JBConstants.MAX_RESERVED_RATE) return _unprocessedTokenBalanceOf;\n\n return\n PRBMath.mulDiv(\n _unprocessedTokenBalanceOf,\n JBConstants.MAX_RESERVED_RATE,\n JBConstants.MAX_RESERVED_RATE - _reservedRate\n ) - _unprocessedTokenBalanceOf;\n }\n}\n" + }, + "contracts/JBReconfigurationBufferBallot.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {ERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBBallotState} from './enums/JBBallotState.sol';\nimport {IJBFundingCycleBallot} from './interfaces/IJBFundingCycleBallot.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\n\n/// @notice Manages approving funding cycle reconfigurations automatically after a buffer period.\ncontract JBReconfigurationBufferBallot is ERC165, IJBFundingCycleBallot {\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice The number of seconds that must pass for a funding cycle reconfiguration to become either `Approved` or `Failed`.\n uint256 public immutable override duration;\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice The approval state of a particular funding cycle.\n /// @param _projectId The ID of the project to which the funding cycle being checked belongs.\n /// @param _configured The configuration of the funding cycle to check the state of.\n /// @param _start The start timestamp of the funding cycle to check the state of.\n /// @return The state of the provided ballot.\n function stateOf(\n uint256 _projectId,\n uint256 _configured,\n uint256 _start\n ) public view override returns (JBBallotState) {\n _projectId; // Prevents unused var compiler and natspec complaints.\n\n // If the provided configured timestamp is after the start timestamp, the ballot is Failed.\n if (_configured > _start) return JBBallotState.Failed;\n\n unchecked {\n // If there was sufficient time between configuration and the start of the cycle, it is approved. Otherwise, it is failed.\n return (_start - _configured < duration) ? JBBallotState.Failed : JBBallotState.Approved;\n }\n }\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if this contract adheres to the specified interface.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(ERC165, IERC165) returns (bool) {\n return\n _interfaceId == type(IJBFundingCycleBallot).interfaceId ||\n super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _duration The number of seconds to wait until a reconfiguration can be either `Approved` or `Failed`.\n constructor(uint256 _duration) {\n duration = _duration;\n }\n}\n" + }, + "contracts/JBETHERC20ProjectPayerDeployer.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Clones} from '@openzeppelin/contracts/proxy/Clones.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBProjectPayer} from './interfaces/IJBProjectPayer.sol';\nimport {IJBETHERC20ProjectPayerDeployer} from './interfaces/IJBETHERC20ProjectPayerDeployer.sol';\nimport {JBETHERC20ProjectPayer} from './JBETHERC20ProjectPayer.sol';\n\n/// @notice Deploys project payer contracts.\ncontract JBETHERC20ProjectPayerDeployer is IJBETHERC20ProjectPayerDeployer {\n //*********************************************************************//\n // --------------- public immutable stored properties ---------------- //\n //*********************************************************************//\n\n /// @notice The implementation contract on which Clones will be based.\n address immutable implementation;\n\n /// @notice directory instance which keeps a track of which controller is linked to which project.\n IJBDirectory immutable directory;\n\n //*********************************************************************//\n // ---------------------------- constructor -------------------------- //\n //*********************************************************************//\n\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n constructor(IJBDirectory _directory) {\n implementation = address(new JBETHERC20ProjectPayer(_directory));\n directory = _directory;\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Allows anyone to deploy a new project payer contract.\n /// @param _defaultProjectId The ID of the project whose treasury should be forwarded the project payer contract's received payments.\n /// @param _defaultBeneficiary The address that'll receive the project's tokens when the project payer receives payments.\n /// @param _defaultPreferClaimedTokens A flag indicating whether issued tokens from the project payer's received payments should be automatically claimed into the beneficiary's wallet.\n /// @param _defaultMemo The memo that'll be forwarded with the project payer's received payments.\n /// @param _defaultMetadata The metadata that'll be forwarded with the project payer's received payments.\n /// @param _defaultPreferAddToBalance A flag indicating if received payments should call the `pay` function or the `addToBalance` function of a project.\n /// @param _owner The address that will own the project payer.\n /// @return projectPayer The project payer contract.\n function deployProjectPayer(\n uint256 _defaultProjectId,\n address payable _defaultBeneficiary,\n bool _defaultPreferClaimedTokens,\n string memory _defaultMemo,\n bytes memory _defaultMetadata,\n bool _defaultPreferAddToBalance,\n address _owner\n ) external override returns (IJBProjectPayer projectPayer) {\n // Deploy the project payer.\n projectPayer = IJBProjectPayer(payable(Clones.clone(implementation)));\n\n // Initialize the project payer.\n projectPayer.initialize(\n _defaultProjectId,\n _defaultBeneficiary,\n _defaultPreferClaimedTokens,\n _defaultMemo,\n _defaultMetadata,\n _defaultPreferAddToBalance,\n _owner\n );\n\n emit DeployProjectPayer(\n projectPayer,\n _defaultProjectId,\n _defaultBeneficiary,\n _defaultPreferClaimedTokens,\n _defaultMemo,\n _defaultMetadata,\n _defaultPreferAddToBalance,\n directory,\n _owner,\n msg.sender\n );\n }\n}\n" + }, + "contracts/interfaces/IJBETHERC20ProjectPayerDeployer.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBDirectory} from './IJBDirectory.sol';\nimport {IJBProjectPayer} from './IJBProjectPayer.sol';\n\ninterface IJBETHERC20ProjectPayerDeployer {\n event DeployProjectPayer(\n IJBProjectPayer indexed projectPayer,\n uint256 defaultProjectId,\n address defaultBeneficiary,\n bool defaultPreferClaimedTokens,\n string defaultMemo,\n bytes defaultMetadata,\n bool preferAddToBalance,\n IJBDirectory directory,\n address owner,\n address caller\n );\n\n function deployProjectPayer(\n uint256 defaultProjectId,\n address payable defaultBeneficiary,\n bool defaultPreferClaimedTokens,\n string memory defaultMemo,\n bytes memory defaultMetadata,\n bool preferAddToBalance,\n address owner\n ) external returns (IJBProjectPayer projectPayer);\n}\n" + }, + "contracts/JBOperatorStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {JBOperatorData} from './structs/JBOperatorData.sol';\n\n/// @notice Stores operator permissions for all addresses. Addresses can give permissions to any other address to take specific indexed actions on their behalf.\ncontract JBOperatorStore is IJBOperatorStore {\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error PERMISSION_INDEX_OUT_OF_BOUNDS();\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The permissions that an operator has been given to operate on a specific domain.\n /// @dev An account can give an operator permissions that only pertain to a specific domain namespace.\n /// @dev There is no domain with a value of 0 – accounts can use the 0 domain to give an operator permissions to all domains on their behalf.\n /// @dev Permissions are stored in a packed `uint256`. Each 256 bits represents the on/off state of a permission. Applications can specify the significance of each index.\n /// @custom:param _operator The address of the operator.\n /// @custom:param _account The address of the account being operated.\n /// @custom:param _domain The domain within which the permissions apply. Applications can use the domain namespace as they wish.\n mapping(address => mapping(address => mapping(uint256 => uint256))) public override permissionsOf;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Whether or not an operator has the permission to take a certain action pertaining to the specified domain.\n /// @param _operator The operator to check.\n /// @param _account The account that has given out permissions to the operator.\n /// @param _domain The domain that the operator has been given permissions to operate.\n /// @param _permissionIndex The permission index to check for.\n /// @return A flag indicating whether the operator has the specified permission.\n function hasPermission(\n address _operator,\n address _account,\n uint256 _domain,\n uint256 _permissionIndex\n ) external view override returns (bool) {\n if (_permissionIndex > 255) revert PERMISSION_INDEX_OUT_OF_BOUNDS();\n\n return (((permissionsOf[_operator][_account][_domain] >> _permissionIndex) & 1) == 1);\n }\n\n /// @notice Whether or not an operator has the permission to take certain actions pertaining to the specified domain.\n /// @param _operator The operator to check.\n /// @param _account The account that has given out permissions to the operator.\n /// @param _domain The domain that the operator has been given permissions to operate.\n /// @param _permissionIndexes An array of permission indexes to check for.\n /// @return A flag indicating whether the operator has all specified permissions.\n function hasPermissions(\n address _operator,\n address _account,\n uint256 _domain,\n uint256[] calldata _permissionIndexes\n ) external view override returns (bool) {\n for (uint256 _i; _i < _permissionIndexes.length; ) {\n uint256 _permissionIndex = _permissionIndexes[_i];\n\n if (_permissionIndex > 255) revert PERMISSION_INDEX_OUT_OF_BOUNDS();\n\n if (((permissionsOf[_operator][_account][_domain] >> _permissionIndex) & 1) == 0)\n return false;\n\n unchecked {\n ++_i;\n }\n }\n return true;\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Sets permissions for an operators.\n /// @dev Only an address can set its own operators.\n /// @param _operatorData The data that specifies the params for the operator being set.\n function setOperator(JBOperatorData calldata _operatorData) external override {\n // Pack the indexes into a uint256.\n uint256 _packed = _packedPermissions(_operatorData.permissionIndexes);\n\n // Store the new value.\n permissionsOf[_operatorData.operator][msg.sender][_operatorData.domain] = _packed;\n\n emit SetOperator(\n _operatorData.operator,\n msg.sender,\n _operatorData.domain,\n _operatorData.permissionIndexes,\n _packed\n );\n }\n\n /// @notice Sets permissions for many operators.\n /// @dev Only an address can set its own operators.\n /// @param _operatorData The data that specify the params for each operator being set.\n function setOperators(JBOperatorData[] calldata _operatorData) external override {\n for (uint256 _i; _i < _operatorData.length; ) {\n // Pack the indexes into a uint256.\n uint256 _packed = _packedPermissions(_operatorData[_i].permissionIndexes);\n\n // Store the new value.\n permissionsOf[_operatorData[_i].operator][msg.sender][_operatorData[_i].domain] = _packed;\n\n emit SetOperator(\n _operatorData[_i].operator,\n msg.sender,\n _operatorData[_i].domain,\n _operatorData[_i].permissionIndexes,\n _packed\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n\n //*********************************************************************//\n // --------------------- private helper functions -------------------- //\n //*********************************************************************//\n\n /// @notice Converts an array of permission indexes to a packed `uint256`.\n /// @param _indexes The indexes of the permissions to pack.\n /// @return packed The packed value.\n function _packedPermissions(uint256[] calldata _indexes) private pure returns (uint256 packed) {\n for (uint256 _i; _i < _indexes.length; ) {\n uint256 _index = _indexes[_i];\n\n if (_index > 255) revert PERMISSION_INDEX_OUT_OF_BOUNDS();\n\n // Turn the bit at the index on.\n packed |= 1 << _index;\n\n unchecked {\n ++_i;\n }\n }\n }\n}\n" + }, + "contracts/JBFundAccessConstraintsStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {ERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol';\nimport {JBControllerUtility} from './abstract/JBControllerUtility.sol';\nimport {IJBFundAccessConstraintsStore} from './interfaces/IJBFundAccessConstraintsStore.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\nimport {JBFundAccessConstraints} from './structs/JBFundAccessConstraints.sol';\n\n/// @notice Information pertaining to how much funds can be accessed by a project from each payment terminal.\ncontract JBFundAccessConstraintsStore is\n JBControllerUtility,\n ERC165,\n IJBFundAccessConstraintsStore\n{\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n\n error INVALID_DISTRIBUTION_LIMIT();\n error INVALID_DISTRIBUTION_LIMIT_CURRENCY();\n error INVALID_OVERFLOW_ALLOWANCE();\n error INVALID_OVERFLOW_ALLOWANCE_CURRENCY();\n\n //*********************************************************************//\n // --------------------- internal stored properties ------------------ //\n //*********************************************************************//\n\n /// @notice Data regarding the distribution limit of a project during a configuration.\n /// @dev bits 0-231: The amount of token that a project can distribute per funding cycle.\n /// @dev bits 232-255: The currency of amount that a project can distribute.\n /// @custom:param _projectId The ID of the project to get the packed distribution limit data of.\n /// @custom:param _configuration The configuration during which the packed distribution limit data applies.\n /// @custom:param _terminal The terminal from which distributions are being limited.\n /// @custom:param _token The token for which distributions are being limited.\n mapping(uint256 => mapping(uint256 => mapping(IJBPaymentTerminal => mapping(address => uint256))))\n internal _packedDistributionLimitDataOf;\n\n /// @notice Data regarding the overflow allowance of a project during a configuration.\n /// @dev bits 0-231: The amount of overflow that a project is allowed to tap into on-demand throughout the configuration.\n /// @dev bits 232-255: The currency of the amount of overflow that a project is allowed to tap.\n /// @custom:param _projectId The ID of the project to get the packed overflow allowance data of.\n /// @custom:param _configuration The configuration during which the packed overflow allowance data applies.\n /// @custom:param _terminal The terminal managing the overflow.\n /// @custom:param _token The token for which overflow is being allowed.\n mapping(uint256 => mapping(uint256 => mapping(IJBPaymentTerminal => mapping(address => uint256))))\n internal _packedOverflowAllowanceDataOf;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice The amount of token that a project can distribute per funding cycle, and the currency it's in terms of.\n /// @dev The number of decimals in the returned fixed point amount is the same as that of the specified terminal.\n /// @param _projectId The ID of the project to get the distribution limit of.\n /// @param _configuration The configuration during which the distribution limit applies.\n /// @param _terminal The terminal from which distributions are being limited.\n /// @param _token The token for which the distribution limit applies.\n /// @return The distribution limit, as a fixed point number with the same number of decimals as the provided terminal.\n /// @return The currency of the distribution limit.\n function distributionLimitOf(\n uint256 _projectId,\n uint256 _configuration,\n IJBPaymentTerminal _terminal,\n address _token\n ) external view override returns (uint256, uint256) {\n // Get a reference to the packed data.\n uint256 _data = _packedDistributionLimitDataOf[_projectId][_configuration][_terminal][_token];\n\n // The limit is in bits 0-231. The currency is in bits 232-255.\n return (uint256(uint232(_data)), _data >> 232);\n }\n\n /// @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.\n /// @dev The number of decimals in the returned fixed point amount is the same as that of the specified terminal.\n /// @param _projectId The ID of the project to get the overflow allowance of.\n /// @param _configuration The configuration of the during which the allowance applies.\n /// @param _terminal The terminal managing the overflow.\n /// @param _token The token for which the overflow allowance applies.\n /// @return The overflow allowance, as a fixed point number with the same number of decimals as the provided terminal.\n /// @return The currency of the overflow allowance.\n function overflowAllowanceOf(\n uint256 _projectId,\n uint256 _configuration,\n IJBPaymentTerminal _terminal,\n address _token\n ) external view override returns (uint256, uint256) {\n // Get a reference to the packed data.\n uint256 _data = _packedOverflowAllowanceDataOf[_projectId][_configuration][_terminal][_token];\n\n // The allowance is in bits 0-231. The currency is in bits 232-255.\n return (uint256(uint232(_data)), _data >> 232);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n // solhint-disable-next-line no-empty-blocks\n constructor(IJBDirectory _directory) JBControllerUtility(_directory) {}\n\n //*********************************************************************//\n // --------------------- external transactions ----------------------- //\n //*********************************************************************//\n\n /// @notice Sets a project's constraints for accessing treasury funds.\n /// @dev Only a project's current controller can set its fund access constraints.\n /// @param _projectId The ID of the project whose fund access constraints are being set.\n /// @param _configuration The funding cycle configuration the constraints apply within.\n /// @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`.\n function setFor(\n uint256 _projectId,\n uint256 _configuration,\n JBFundAccessConstraints[] calldata _fundAccessConstraints\n ) external override onlyController(_projectId) {\n // Save the number of constraints.\n uint256 _numberOfFundAccessConstraints = _fundAccessConstraints.length;\n\n // Set distribution limits if there are any.\n for (uint256 _i; _i < _numberOfFundAccessConstraints; ) {\n // If distribution limit value is larger than 232 bits, revert.\n if (_fundAccessConstraints[_i].distributionLimit > type(uint232).max)\n revert INVALID_DISTRIBUTION_LIMIT();\n\n // If distribution limit currency value is larger than 24 bits, revert.\n if (_fundAccessConstraints[_i].distributionLimitCurrency > type(uint24).max)\n revert INVALID_DISTRIBUTION_LIMIT_CURRENCY();\n\n // If overflow allowance value is larger than 232 bits, revert.\n if (_fundAccessConstraints[_i].overflowAllowance > type(uint232).max)\n revert INVALID_OVERFLOW_ALLOWANCE();\n\n // If overflow allowance currency value is larger than 24 bits, revert.\n if (_fundAccessConstraints[_i].overflowAllowanceCurrency > type(uint24).max)\n revert INVALID_OVERFLOW_ALLOWANCE_CURRENCY();\n\n // Set the distribution limit if there is one.\n if (_fundAccessConstraints[_i].distributionLimit > 0)\n _packedDistributionLimitDataOf[_projectId][_configuration][\n _fundAccessConstraints[_i].terminal\n ][_fundAccessConstraints[_i].token] =\n _fundAccessConstraints[_i].distributionLimit |\n (_fundAccessConstraints[_i].distributionLimitCurrency << 232);\n\n // Set the overflow allowance if there is one.\n if (_fundAccessConstraints[_i].overflowAllowance > 0)\n _packedOverflowAllowanceDataOf[_projectId][_configuration][\n _fundAccessConstraints[_i].terminal\n ][_fundAccessConstraints[_i].token] =\n _fundAccessConstraints[_i].overflowAllowance |\n (_fundAccessConstraints[_i].overflowAllowanceCurrency << 232);\n\n emit SetFundAccessConstraints(\n _configuration,\n _projectId,\n _fundAccessConstraints[_i],\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n}\n" + }, + "contracts/interfaces/IJBTerminalUtility.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBDirectory} from './IJBDirectory.sol';\n\ninterface IJBPaymentTerminalUtility {\n function directory() external view returns (IJBDirectory);\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": [ + "ast" + ] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} \ No newline at end of file diff --git a/deployments/sepolia/solcInputs/f58e5b1a8ab27311c5c442a686fda095.json b/deployments/sepolia/solcInputs/f58e5b1a8ab27311c5c442a686fda095.json new file mode 100644 index 000000000..6a8aad861 --- /dev/null +++ b/deployments/sepolia/solcInputs/f58e5b1a8ab27311c5c442a686fda095.json @@ -0,0 +1,461 @@ +{ + "language": "Solidity", + "sources": { + "contracts/abstract/JBControllerUtility.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {IJBControllerUtility} from './../interfaces/IJBControllerUtility.sol';\nimport {IJBDirectory} from './../interfaces/IJBDirectory.sol';\n\n/// @notice Provides tools for contracts with functionality that can only be accessed by a project's controller.\nabstract contract JBControllerUtility is IJBControllerUtility {\n //*********************************************************************//\n // --------------------------- custom errors -------------------------- //\n //*********************************************************************//\n error CONTROLLER_UNAUTHORIZED();\n\n //*********************************************************************//\n // ---------------------------- modifiers ---------------------------- //\n //*********************************************************************//\n\n /// @notice Only allows the controller of the specified project to proceed.\n /// @param _projectId The ID of the project.\n modifier onlyController(uint256 _projectId) {\n if (address(directory.controllerOf(_projectId)) != msg.sender) revert CONTROLLER_UNAUTHORIZED();\n _;\n }\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n constructor(IJBDirectory _directory) {\n directory = _directory;\n }\n}\n" + }, + "contracts/interfaces/IJBControllerUtility.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBDirectory} from './IJBDirectory.sol';\n\ninterface IJBControllerUtility {\n function directory() external view returns (IJBDirectory);\n}\n" + }, + "contracts/interfaces/IJBDirectory.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\nimport {IJBProjects} from './IJBProjects.sol';\n\ninterface IJBDirectory {\n event SetController(uint256 indexed projectId, address indexed controller, address caller);\n\n event AddTerminal(uint256 indexed projectId, IJBPaymentTerminal indexed terminal, address caller);\n\n event SetTerminals(uint256 indexed projectId, IJBPaymentTerminal[] terminals, address caller);\n\n event SetPrimaryTerminal(\n uint256 indexed projectId,\n address indexed token,\n IJBPaymentTerminal indexed terminal,\n address caller\n );\n\n event SetIsAllowedToSetFirstController(address indexed addr, bool indexed flag, address caller);\n\n function projects() external view returns (IJBProjects);\n\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\n\n function controllerOf(uint256 projectId) external view returns (address);\n\n function isAllowedToSetFirstController(address account) external view returns (bool);\n\n function terminalsOf(uint256 projectId) external view returns (IJBPaymentTerminal[] memory);\n\n function isTerminalOf(\n uint256 projectId,\n IJBPaymentTerminal terminal\n ) external view returns (bool);\n\n function primaryTerminalOf(\n uint256 projectId,\n address token\n ) external view returns (IJBPaymentTerminal);\n\n function setControllerOf(uint256 projectId, address controller) external;\n\n function setTerminalsOf(uint256 projectId, IJBPaymentTerminal[] calldata terminals) external;\n\n function setPrimaryTerminalOf(\n uint256 projectId,\n address token,\n IJBPaymentTerminal terminal\n ) external;\n\n function setIsAllowedToSetFirstController(address account, bool flag) external;\n}\n" + }, + "contracts/interfaces/IJBFundingCycleStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBBallotState} from './../enums/JBBallotState.sol';\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\nimport {JBFundingCycleData} from './../structs/JBFundingCycleData.sol';\n\ninterface IJBFundingCycleStore {\n event Configure(\n uint256 indexed configuration,\n uint256 indexed projectId,\n JBFundingCycleData data,\n uint256 metadata,\n uint256 mustStartAtOrAfter,\n address caller\n );\n\n event Init(uint256 indexed configuration, uint256 indexed projectId, uint256 indexed basedOn);\n\n function latestConfigurationOf(uint256 projectId) external view returns (uint256);\n\n function get(\n uint256 projectId,\n uint256 configuration\n ) external view returns (JBFundingCycle memory);\n\n function latestConfiguredOf(\n uint256 projectId\n ) external view returns (JBFundingCycle memory fundingCycle, JBBallotState ballotState);\n\n function queuedOf(uint256 projectId) external view returns (JBFundingCycle memory fundingCycle);\n\n function currentOf(uint256 projectId) external view returns (JBFundingCycle memory fundingCycle);\n\n function currentBallotStateOf(uint256 projectId) external view returns (JBBallotState);\n\n function configureFor(\n uint256 projectId,\n JBFundingCycleData calldata data,\n uint256 metadata,\n uint256 mustStartAtOrAfter\n ) external returns (JBFundingCycle memory fundingCycle);\n}\n" + }, + "contracts/interfaces/IJBPaymentTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\n\ninterface IJBPaymentTerminal is IERC165 {\n function acceptsToken(address token, uint256 projectId) external view returns (bool);\n\n function currencyForToken(address token) external view returns (uint256);\n\n function decimalsForToken(address token) external view returns (uint256);\n\n // Return value must be a fixed point number with 18 decimals.\n function currentEthOverflowOf(uint256 projectId) external view returns (uint256);\n\n function pay(\n uint256 projectId,\n uint256 amount,\n address token,\n address beneficiary,\n uint256 minReturnedTokens,\n bool preferClaimedTokens,\n string calldata memo,\n bytes calldata metadata\n ) external payable returns (uint256 beneficiaryTokenCount);\n\n function addToBalanceOf(\n uint256 projectId,\n uint256 amount,\n address token,\n string calldata memo,\n bytes calldata metadata\n ) external payable;\n}\n" + }, + "contracts/interfaces/IJBProjects.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC721} from '@openzeppelin/contracts/token/ERC721/IERC721.sol';\nimport {JBProjectMetadata} from './../structs/JBProjectMetadata.sol';\nimport {IJBTokenUriResolver} from './IJBTokenUriResolver.sol';\n\ninterface IJBProjects is IERC721 {\n event Create(\n uint256 indexed projectId,\n address indexed owner,\n JBProjectMetadata metadata,\n address caller\n );\n\n event SetMetadata(uint256 indexed projectId, JBProjectMetadata metadata, address caller);\n\n event SetTokenUriResolver(IJBTokenUriResolver indexed resolver, address caller);\n\n function count() external view returns (uint256);\n\n function metadataContentOf(\n uint256 projectId,\n uint256 domain\n ) external view returns (string memory);\n\n function tokenUriResolver() external view returns (IJBTokenUriResolver);\n\n function createFor(\n address owner,\n JBProjectMetadata calldata metadata\n ) external returns (uint256 projectId);\n\n function setMetadataOf(uint256 projectId, JBProjectMetadata calldata metadata) external;\n\n function setTokenUriResolver(IJBTokenUriResolver newResolver) external;\n}\n" + }, + "contracts/enums/JBBallotState.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nenum JBBallotState {\n Active,\n Approved,\n Failed\n}\n" + }, + "contracts/structs/JBFundingCycle.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBFundingCycleBallot} from './../interfaces/IJBFundingCycleBallot.sol';\n\n/// @custom:member number The funding cycle number for the cycle's project. Each funding cycle has a number that is an increment of the cycle that directly preceded it. Each project's first funding cycle has a number of 1.\n/// @custom:member configuration The timestamp when the parameters for this funding cycle were configured. This value will stay the same for subsequent funding cycles that roll over from an originally configured cycle.\n/// @custom:member basedOn The `configuration` of the funding cycle that was active when this cycle was created.\n/// @custom:member start The timestamp marking the moment from which the funding cycle is considered active. It is a unix timestamp measured in seconds.\n/// @custom:member duration The number of seconds the funding cycle lasts for, after which a new funding cycle will start. A duration of 0 means that the funding cycle will stay active until the project owner explicitly issues a reconfiguration, at which point a new funding cycle will immediately start with the updated properties. If the duration is greater than 0, a project owner cannot make changes to a funding cycle's parameters while it is active – any proposed changes will apply to the subsequent cycle. If no changes are proposed, a funding cycle rolls over to another one with the same properties but new `start` timestamp and a discounted `weight`.\n/// @custom:member weight A fixed point number with 18 decimals that contracts can use to base arbitrary calculations on. For example, payment terminals can use this to determine how many tokens should be minted when a payment is received.\n/// @custom:member discountRate A percent by how much the `weight` of the subsequent funding cycle should be reduced, if the project owner hasn't configured the subsequent funding cycle with an explicit `weight`. If it's 0, each funding cycle will have equal weight. If the number is 90%, the next funding cycle will have a 10% smaller weight. This weight is out of `JBConstants.MAX_DISCOUNT_RATE`.\n/// @custom:member ballot An address of a contract that says whether a proposed reconfiguration should be accepted or rejected. It can be used to create rules around how a project owner can change funding cycle parameters over time.\n/// @custom:member metadata Extra data that can be associated with a funding cycle.\nstruct JBFundingCycle {\n uint256 number;\n uint256 configuration;\n uint256 basedOn;\n uint256 start;\n uint256 duration;\n uint256 weight;\n uint256 discountRate;\n IJBFundingCycleBallot ballot;\n uint256 metadata;\n}\n" + }, + "contracts/structs/JBFundingCycleData.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBFundingCycleBallot} from './../interfaces/IJBFundingCycleBallot.sol';\n\n/// @custom:member duration The number of seconds the funding cycle lasts for, after which a new funding cycle will start. A duration of 0 means that the funding cycle will stay active until the project owner explicitly issues a reconfiguration, at which point a new funding cycle will immediately start with the updated properties. If the duration is greater than 0, a project owner cannot make changes to a funding cycle's parameters while it is active – any proposed changes will apply to the subsequent cycle. If no changes are proposed, a funding cycle rolls over to another one with the same properties but new `start` timestamp and a discounted `weight`.\n/// @custom:member weight A fixed point number with 18 decimals that contracts can use to base arbitrary calculations on. For example, payment terminals can use this to determine how many tokens should be minted when a payment is received.\n/// @custom:member discountRate A percent by how much the `weight` of the subsequent funding cycle should be reduced, if the project owner hasn't configured the subsequent funding cycle with an explicit `weight`. If it's 0, each funding cycle will have equal weight. If the number is 90%, the next funding cycle will have a 10% smaller weight. This weight is out of `JBConstants.MAX_DISCOUNT_RATE`.\n/// @custom:member ballot An address of a contract that says whether a proposed reconfiguration should be accepted or rejected. It can be used to create rules around how a project owner can change funding cycle parameters over time.\nstruct JBFundingCycleData {\n uint256 duration;\n uint256 weight;\n uint256 discountRate;\n IJBFundingCycleBallot ballot;\n}\n" + }, + "contracts/interfaces/IJBFundingCycleBallot.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBBallotState} from './../enums/JBBallotState.sol';\n\ninterface IJBFundingCycleBallot is IERC165 {\n function duration() external view returns (uint256);\n\n function stateOf(\n uint256 projectId,\n uint256 configuration,\n uint256 start\n ) external view returns (JBBallotState);\n}\n" + }, + "@openzeppelin/contracts/utils/introspection/IERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n" + }, + "@openzeppelin/contracts/token/ERC721/IERC721.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../../utils/introspection/IERC165.sol\";\n\n/**\n * @dev Required interface of an ERC721 compliant contract.\n */\ninterface IERC721 is IERC165 {\n /**\n * @dev Emitted when `tokenId` token is transferred from `from` to `to`.\n */\n event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);\n\n /**\n * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.\n */\n event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);\n\n /**\n * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.\n */\n event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n /**\n * @dev Returns the number of tokens in ``owner``'s account.\n */\n function balanceOf(address owner) external view returns (uint256 balance);\n\n /**\n * @dev Returns the owner of the `tokenId` token.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n */\n function ownerOf(uint256 tokenId) external view returns (address owner);\n\n /**\n * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\n * are aware of the ERC721 protocol to prevent tokens from being forever locked.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must exist and be owned by `from`.\n * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId\n ) external;\n\n /**\n * @dev Transfers `tokenId` token from `from` to `to`.\n *\n * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must be owned by `from`.\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 tokenId\n ) external;\n\n /**\n * @dev Gives permission to `to` to transfer `tokenId` token to another account.\n * The approval is cleared when the token is transferred.\n *\n * Only a single account can be approved at a time, so approving the zero address clears previous approvals.\n *\n * Requirements:\n *\n * - The caller must own the token or be an approved operator.\n * - `tokenId` must exist.\n *\n * Emits an {Approval} event.\n */\n function approve(address to, uint256 tokenId) external;\n\n /**\n * @dev Returns the account approved for `tokenId` token.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n */\n function getApproved(uint256 tokenId) external view returns (address operator);\n\n /**\n * @dev Approve or remove `operator` as an operator for the caller.\n * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.\n *\n * Requirements:\n *\n * - The `operator` cannot be the caller.\n *\n * Emits an {ApprovalForAll} event.\n */\n function setApprovalForAll(address operator, bool _approved) external;\n\n /**\n * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.\n *\n * See {setApprovalForAll}\n */\n function isApprovedForAll(address owner, address operator) external view returns (bool);\n\n /**\n * @dev Safely transfers `tokenId` token from `from` to `to`.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must exist and be owned by `from`.\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId,\n bytes calldata data\n ) external;\n}\n" + }, + "contracts/structs/JBProjectMetadata.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @custom:member content The metadata content.\n/// @custom:member domain The domain within which the metadata applies.\nstruct JBProjectMetadata {\n string content;\n uint256 domain;\n}\n" + }, + "contracts/interfaces/IJBTokenUriResolver.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBTokenUriResolver {\n function getUri(uint256 projectId) external view returns (string memory tokenUri);\n}\n" + }, + "contracts/JBTokenStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {JBControllerUtility} from './abstract/JBControllerUtility.sol';\nimport {JBOperatable} from './abstract/JBOperatable.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {IJBToken} from './interfaces/IJBToken.sol';\nimport {IJBTokenStore} from './interfaces/IJBTokenStore.sol';\nimport {JBFundingCycleMetadataResolver} from './libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBOperations} from './libraries/JBOperations.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\nimport {JBToken} from './JBToken.sol';\n\n/// @notice Manage token minting, burning, and account balances.\n/// @dev Token balances can be either represented internally or claimed as ERC-20s into wallets. This contract manages these two representations and allows claiming.\n/// @dev The total supply of a project's tokens and the balance of each account are calculated in this contract.\n/// @dev Each project can bring their own token if they prefer, and swap between tokens at any time.\ncontract JBTokenStore is JBControllerUtility, JBOperatable, IJBTokenStore {\n // A library that parses the packed funding cycle metadata into a friendlier format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error ALREADY_SET();\n error EMPTY_NAME();\n error EMPTY_SYMBOL();\n error EMPTY_TOKEN();\n error INSUFFICIENT_FUNDS();\n error INSUFFICIENT_UNCLAIMED_TOKENS();\n error PROJECT_ALREADY_HAS_TOKEN();\n error RECIPIENT_ZERO_ADDRESS();\n error TOKEN_NOT_FOUND();\n error TOKENS_MUST_HAVE_18_DECIMALS();\n error TRANSFERS_PAUSED();\n error OVERFLOW_ALERT();\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice Mints ERC-721's that represent project ownership and transfers. \n IJBProjects public immutable override projects;\n\n /// @notice The contract storing all funding cycle configurations. \n IJBFundingCycleStore public immutable override fundingCycleStore;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice Each project's attached token contract.\n /// @custom:param _projectId The ID of the project to which the token belongs. \n mapping(uint256 => IJBToken) public override tokenOf;\n\n /// @notice The total supply of unclaimed tokens for each project.\n /// @custom:param _projectId The ID of the project to which the token belongs. \n mapping(uint256 => uint256) public override unclaimedTotalSupplyOf;\n\n /// @notice Each holder's balance of unclaimed tokens for each project.\n /// @custom:param _holder The holder of balance.\n /// @custom:param _projectId The ID of the project to which the token belongs.\n mapping(address => mapping(uint256 => uint256)) public override unclaimedBalanceOf;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice The total balance of tokens a holder has for a specified project, including claimed and unclaimed tokens.\n /// @param _holder The token holder to get a balance for.\n /// @param _projectId The project to get the `_holder`s balance of.\n /// @return balance The project token balance of the `_holder \n function balanceOf(address _holder, uint256 _projectId)\n external\n view\n override\n returns (uint256 balance)\n {\n // Get a reference to the holder's unclaimed balance for the project.\n balance = unclaimedBalanceOf[_holder][_projectId];\n\n // Get a reference to the project's current token.\n IJBToken _token = tokenOf[_projectId];\n\n // If the project has a current token, add the holder's balance to the total.\n if (_token != IJBToken(address(0))) balance = balance + _token.balanceOf(_holder, _projectId);\n }\n\n //*********************************************************************//\n // --------------------------- public views -------------------------- //\n //*********************************************************************//\n\n /// @notice The total supply of tokens for each project, including claimed and unclaimed tokens.\n /// @param _projectId The ID of the project to get the total token supply of.\n /// @return totalSupply The total supply of the project's tokens.\n function totalSupplyOf(uint256 _projectId) public view override returns (uint256 totalSupply) {\n // Get a reference to the total supply of the project's unclaimed tokens.\n totalSupply = unclaimedTotalSupplyOf[_projectId];\n\n // Get a reference to the project's current token.\n IJBToken _token = tokenOf[_projectId];\n\n // If the project has a current token, add its total supply to the total.\n if (_token != IJBToken(address(0))) totalSupply = totalSupply + _token.totalSupply(_projectId);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _fundingCycleStore A contract storing all funding cycle configurations.\n constructor(\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBFundingCycleStore _fundingCycleStore\n ) JBOperatable(_operatorStore) JBControllerUtility(_directory) {\n projects = _projects;\n fundingCycleStore = _fundingCycleStore;\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Issues a project's ERC-20 tokens that'll be used when claiming tokens.\n /// @dev Deploys a project's ERC-20 token contract.\n /// @dev Only a project's owner or operator can issue its token.\n /// @param _projectId The ID of the project being issued tokens.\n /// @param _name The ERC-20's name.\n /// @param _symbol The ERC-20's symbol.\n /// @return token The token that was issued.\n function issueFor(\n uint256 _projectId,\n string calldata _name,\n string calldata _symbol\n )\n external\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.ISSUE)\n returns (IJBToken token)\n {\n // There must be a name.\n if (bytes(_name).length == 0) revert EMPTY_NAME();\n\n // There must be a symbol.\n if (bytes(_symbol).length == 0) revert EMPTY_SYMBOL();\n \n // The project shouldn't already have a token.\n if (tokenOf[_projectId] != IJBToken(address(0))) revert PROJECT_ALREADY_HAS_TOKEN();\n\n // Deploy the token contract.\n token = new JBToken(_name, _symbol, _projectId);\n\n // Store the token contract.\n tokenOf[_projectId] = token;\n\n emit Issue(_projectId, token, _name, _symbol, msg.sender);\n }\n\n /// @notice Set a project's token if not already set.\n /// @dev Only a project's owner or operator can set its token.\n /// @param _projectId The ID of the project to which the set token belongs.\n /// @param _token The new token. \n function setFor(uint256 _projectId, IJBToken _token)\n external\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.SET_TOKEN)\n {\n // Can't set to the zero address.\n if (_token == IJBToken(address(0))) revert EMPTY_TOKEN();\n\n // Can't set token if already set.\n if (tokenOf[_projectId] != IJBToken(address(0))) revert ALREADY_SET();\n\n // Can't change to a token that doesn't use 18 decimals.\n if (_token.decimals() != 18) revert TOKENS_MUST_HAVE_18_DECIMALS();\n\n // Store the new token.\n tokenOf[_projectId] = _token;\n\n emit Set(_projectId, _token, msg.sender);\n }\n\n /// @notice Mint new project tokens.\n /// @dev Only a project's current controller can mint its tokens.\n /// @param _holder The address receiving the new tokens.\n /// @param _projectId The ID of the project to which the tokens belong.\n /// @param _amount The amount of tokens to mint.\n /// @param _preferClaimedTokens A flag indicating whether there's a preference for minted tokens to be claimed automatically into the `_holder`s wallet if the project currently has a token contract attached.\n function mintFor(\n address _holder,\n uint256 _projectId,\n uint256 _amount,\n bool _preferClaimedTokens\n ) external override onlyController(_projectId) {\n // Get a reference to the project's current token.\n IJBToken _token = tokenOf[_projectId];\n\n // Save a reference to whether there exists a token and the caller prefers these claimed tokens.\n bool _shouldClaimTokens = _preferClaimedTokens && _token != IJBToken(address(0));\n\n if (_shouldClaimTokens)\n // If tokens should be claimed, mint tokens into the holder's wallet.\n _token.mint(_projectId, _holder, _amount);\n else {\n // Otherwise, add the tokens to the unclaimed balance and total supply.\n unclaimedBalanceOf[_holder][_projectId] = unclaimedBalanceOf[_holder][_projectId] + _amount;\n unclaimedTotalSupplyOf[_projectId] = unclaimedTotalSupplyOf[_projectId] + _amount;\n }\n\n // The total supply can't exceed the maximum value storable in a uint224.\n if (totalSupplyOf(_projectId) > type(uint224).max) revert OVERFLOW_ALERT();\n\n emit Mint(_holder, _projectId, _amount, _shouldClaimTokens, _preferClaimedTokens, msg.sender);\n }\n\n /// @notice Burns a project's tokens.\n /// @dev Only a project's current controller can burn its tokens.\n /// @param _holder The address that owns the tokens being burned.\n /// @param _projectId The ID of the project to which the burned tokens belong.\n /// @param _amount The amount of tokens to burn.\n /// @param _preferClaimedTokens A flag indicating whether there's a preference for tokens to burned from the `_holder`s wallet if the project currently has a token contract attached.\n function burnFrom(\n address _holder,\n uint256 _projectId,\n uint256 _amount,\n bool _preferClaimedTokens\n ) external override onlyController(_projectId) {\n // Get a reference to the project's current token.\n IJBToken _token = tokenOf[_projectId];\n\n // Get a reference to the amount of unclaimed project tokens the holder has.\n uint256 _unclaimedBalance = unclaimedBalanceOf[_holder][_projectId];\n\n // Get a reference to the amount of the project's current token the holder has in their wallet.\n uint256 _claimedBalance = _token == IJBToken(address(0))\n ? 0\n : _token.balanceOf(_holder, _projectId);\n\n // There must be adequate tokens to burn across the holder's claimed and unclaimed balance.\n if (_amount > _claimedBalance + _unclaimedBalance) revert INSUFFICIENT_FUNDS();\n\n // The amount of tokens to burn.\n uint256 _claimedTokensToBurn;\n\n // Get a reference to how many claimed tokens should be burned\n if (_claimedBalance != 0)\n if (_preferClaimedTokens)\n // If prefer converted, burn the claimed tokens before the unclaimed.\n _claimedTokensToBurn = _claimedBalance < _amount ? _claimedBalance : _amount;\n // Otherwise, burn unclaimed tokens before claimed tokens.\n else {\n unchecked {\n _claimedTokensToBurn = _unclaimedBalance < _amount ? _amount - _unclaimedBalance : 0;\n }\n }\n\n // The amount of unclaimed tokens to burn.\n uint256 _unclaimedTokensToBurn;\n unchecked {\n _unclaimedTokensToBurn = _amount - _claimedTokensToBurn;\n }\n\n // Subtract the tokens from the unclaimed balance and total supply.\n if (_unclaimedTokensToBurn > 0) {\n // Reduce the holders balance and the total supply.\n unclaimedBalanceOf[_holder][_projectId] =\n unclaimedBalanceOf[_holder][_projectId] -\n _unclaimedTokensToBurn;\n unclaimedTotalSupplyOf[_projectId] =\n unclaimedTotalSupplyOf[_projectId] -\n _unclaimedTokensToBurn;\n }\n\n // Burn the claimed tokens.\n if (_claimedTokensToBurn > 0) _token.burn(_projectId, _holder, _claimedTokensToBurn);\n\n emit Burn(\n _holder,\n _projectId,\n _amount,\n _unclaimedBalance,\n _claimedBalance,\n _preferClaimedTokens,\n msg.sender\n );\n }\n\n /// @notice Claims internally accounted for tokens into a holder's wallet.\n /// @dev Only a token holder or an operator specified by the token holder can claim its unclaimed tokens.\n /// @param _holder The owner of the tokens being claimed.\n /// @param _projectId The ID of the project whose tokens are being claimed.\n /// @param _amount The amount of tokens to claim.\n function claimFor(\n address _holder,\n uint256 _projectId,\n uint256 _amount\n ) external override requirePermission(_holder, _projectId, JBOperations.CLAIM) {\n // Get a reference to the project's current token.\n IJBToken _token = tokenOf[_projectId];\n\n // The project must have a token contract attached.\n if (_token == IJBToken(address(0))) revert TOKEN_NOT_FOUND();\n\n // Get a reference to the amount of unclaimed project tokens the holder has.\n uint256 _unclaimedBalance = unclaimedBalanceOf[_holder][_projectId];\n\n // There must be enough unclaimed tokens to claim.\n if (_unclaimedBalance < _amount) revert INSUFFICIENT_UNCLAIMED_TOKENS();\n\n unchecked {\n // Subtract the claim amount from the holder's unclaimed project token balance.\n unclaimedBalanceOf[_holder][_projectId] = _unclaimedBalance - _amount;\n\n // Subtract the claim amount from the project's unclaimed total supply.\n unclaimedTotalSupplyOf[_projectId] = unclaimedTotalSupplyOf[_projectId] - _amount;\n }\n\n // Mint the equivalent amount of the project's token for the holder.\n _token.mint(_projectId, _holder, _amount);\n\n emit Claim(_holder, _projectId, _unclaimedBalance, _amount, msg.sender);\n }\n\n /// @notice Allows a holder to transfer unclaimed tokens to another account.\n /// @dev Only a token holder or an operator can transfer its unclaimed tokens.\n /// @param _holder The address to transfer tokens from.\n /// @param _projectId The ID of the project whose tokens are being transferred.\n /// @param _recipient The recipient of the tokens.\n /// @param _amount The amount of tokens to transfer.\n function transferFrom(\n address _holder,\n uint256 _projectId,\n address _recipient,\n uint256 _amount\n ) external override requirePermission(_holder, _projectId, JBOperations.TRANSFER) {\n // Get a reference to the current funding cycle for the project.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Must not be paused.\n if (_fundingCycle.global().pauseTransfers) revert TRANSFERS_PAUSED();\n\n // Can't transfer to the zero address.\n if (_recipient == address(0)) revert RECIPIENT_ZERO_ADDRESS();\n\n // Get a reference to the holder's unclaimed project token balance.\n uint256 _unclaimedBalance = unclaimedBalanceOf[_holder][_projectId];\n\n // The holder must have enough unclaimed tokens to transfer.\n if (_amount > _unclaimedBalance) revert INSUFFICIENT_UNCLAIMED_TOKENS();\n\n // Subtract from the holder's unclaimed token balance.\n unchecked {\n unclaimedBalanceOf[_holder][_projectId] = _unclaimedBalance - _amount;\n }\n\n // Add the unclaimed project tokens to the recipient's balance.\n unclaimedBalanceOf[_recipient][_projectId] =\n unclaimedBalanceOf[_recipient][_projectId] +\n _amount;\n\n emit Transfer(_holder, _projectId, _recipient, _amount, msg.sender);\n }\n}\n" + }, + "contracts/abstract/JBOperatable.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {IJBOperatable} from './../interfaces/IJBOperatable.sol';\nimport {IJBOperatorStore} from './../interfaces/IJBOperatorStore.sol';\n\n/// @notice Modifiers to allow access to functions based on the message sender's operator status.\nabstract contract JBOperatable is IJBOperatable {\n //*********************************************************************//\n // --------------------------- custom errors -------------------------- //\n //*********************************************************************//\n error UNAUTHORIZED();\n\n //*********************************************************************//\n // ---------------------------- modifiers ---------------------------- //\n //*********************************************************************//\n\n /// @notice Only allows the speficied account or an operator of the account to proceed.\n /// @param _account The account to check for.\n /// @param _domain The domain namespace to look for an operator within.\n /// @param _permissionIndex The index of the permission to check for.\n modifier requirePermission(\n address _account,\n uint256 _domain,\n uint256 _permissionIndex\n ) {\n _requirePermission(_account, _domain, _permissionIndex);\n _;\n }\n\n /// @notice Only allows the speficied account, an operator of the account to proceed, or a truthy override flag.\n /// @param _account The account to check for.\n /// @param _domain The domain namespace to look for an operator within.\n /// @param _permissionIndex The index of the permission to check for.\n /// @param _override A condition to force allowance for.\n modifier requirePermissionAllowingOverride(\n address _account,\n uint256 _domain,\n uint256 _permissionIndex,\n bool _override\n ) {\n _requirePermissionAllowingOverride(_account, _domain, _permissionIndex, _override);\n _;\n }\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice A contract storing operator assignments.\n IJBOperatorStore public immutable override operatorStore;\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _operatorStore A contract storing operator assignments.\n constructor(IJBOperatorStore _operatorStore) {\n operatorStore = _operatorStore;\n }\n\n //*********************************************************************//\n // -------------------------- internal views ------------------------- //\n //*********************************************************************//\n\n /// @notice Require the message sender is either the account or has the specified permission.\n /// @param _account The account to allow.\n /// @param _domain The domain namespace within which the permission index will be checked.\n /// @param _permissionIndex The permission index that an operator must have within the specified domain to be allowed.\n function _requirePermission(\n address _account,\n uint256 _domain,\n uint256 _permissionIndex\n ) internal view {\n if (\n msg.sender != _account &&\n !operatorStore.hasPermission(msg.sender, _account, _domain, _permissionIndex) &&\n !operatorStore.hasPermission(msg.sender, _account, 0, _permissionIndex)\n ) revert UNAUTHORIZED();\n }\n\n /// @notice Require the message sender is either the account, has the specified permission, or the override condition is true.\n /// @param _account The account to allow.\n /// @param _domain The domain namespace within which the permission index will be checked.\n /// @param _domain The permission index that an operator must have within the specified domain to be allowed.\n /// @param _override The override condition to allow.\n function _requirePermissionAllowingOverride(\n address _account,\n uint256 _domain,\n uint256 _permissionIndex,\n bool _override\n ) internal view {\n if (\n !_override &&\n msg.sender != _account &&\n !operatorStore.hasPermission(msg.sender, _account, _domain, _permissionIndex) &&\n !operatorStore.hasPermission(msg.sender, _account, 0, _permissionIndex)\n ) revert UNAUTHORIZED();\n }\n}\n" + }, + "contracts/interfaces/IJBOperatorStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBOperatorData} from './../structs/JBOperatorData.sol';\n\ninterface IJBOperatorStore {\n event SetOperator(\n address indexed operator,\n address indexed account,\n uint256 indexed domain,\n uint256[] permissionIndexes,\n uint256 packed\n );\n\n function permissionsOf(\n address operator,\n address account,\n uint256 domain\n ) external view returns (uint256);\n\n function hasPermission(\n address operator,\n address account,\n uint256 domain,\n uint256 permissionIndex\n ) external view returns (bool);\n\n function hasPermissions(\n address operator,\n address account,\n uint256 domain,\n uint256[] calldata permissionIndexes\n ) external view returns (bool);\n\n function setOperator(JBOperatorData calldata operatorData) external;\n\n function setOperators(JBOperatorData[] calldata operatorData) external;\n}\n" + }, + "contracts/interfaces/IJBToken.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBToken {\n function projectId() external view returns (uint256);\n\n function decimals() external view returns (uint8);\n\n function totalSupply(uint256 projectId) external view returns (uint256);\n\n function balanceOf(address account, uint256 projectId) external view returns (uint256);\n\n function mint(uint256 projectId, address account, uint256 amount) external;\n\n function burn(uint256 projectId, address account, uint256 amount) external;\n\n function approve(uint256, address spender, uint256 amount) external;\n\n function transfer(uint256 projectId, address to, uint256 amount) external;\n\n function transferFrom(uint256 projectId, address from, address to, uint256 amount) external;\n}\n" + }, + "contracts/interfaces/IJBTokenStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\nimport {IJBProjects} from './IJBProjects.sol';\nimport {IJBToken} from './IJBToken.sol';\n\ninterface IJBTokenStore {\n event Issue(\n uint256 indexed projectId,\n IJBToken indexed token,\n string name,\n string symbol,\n address caller\n );\n\n event Mint(\n address indexed holder,\n uint256 indexed projectId,\n uint256 amount,\n bool tokensWereClaimed,\n bool preferClaimedTokens,\n address caller\n );\n\n event Burn(\n address indexed holder,\n uint256 indexed projectId,\n uint256 amount,\n uint256 initialUnclaimedBalance,\n uint256 initialClaimedBalance,\n bool preferClaimedTokens,\n address caller\n );\n\n event Claim(\n address indexed holder,\n uint256 indexed projectId,\n uint256 initialUnclaimedBalance,\n uint256 amount,\n address caller\n );\n\n event Set(uint256 indexed projectId, IJBToken indexed newToken, address caller);\n\n event Transfer(\n address indexed holder,\n uint256 indexed projectId,\n address indexed recipient,\n uint256 amount,\n address caller\n );\n\n function tokenOf(uint256 projectId) external view returns (IJBToken);\n\n function projects() external view returns (IJBProjects);\n\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\n\n function unclaimedBalanceOf(address holder, uint256 projectId) external view returns (uint256);\n\n function unclaimedTotalSupplyOf(uint256 projectId) external view returns (uint256);\n\n function totalSupplyOf(uint256 projectId) external view returns (uint256);\n\n function balanceOf(address holder, uint256 projectId) external view returns (uint256 result);\n\n function issueFor(\n uint256 projectId,\n string calldata name,\n string calldata symbol\n ) external returns (IJBToken token);\n\n function setFor(uint256 projectId, IJBToken token) external;\n\n function burnFrom(\n address holder,\n uint256 projectId,\n uint256 amount,\n bool preferClaimedTokens\n ) external;\n\n function mintFor(\n address holder,\n uint256 projectId,\n uint256 amount,\n bool preferClaimedTokens\n ) external;\n\n function claimFor(address holder, uint256 projectId, uint256 amount) external;\n\n function transferFrom(\n address holder,\n uint256 projectId,\n address recipient,\n uint256 amount\n ) external;\n}\n" + }, + "contracts/libraries/JBFundingCycleMetadataResolver.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\nimport {JBFundingCycleMetadata} from './../structs/JBFundingCycleMetadata.sol';\nimport {JBGlobalFundingCycleMetadata} from './../structs/JBGlobalFundingCycleMetadata.sol';\nimport {JBConstants} from './JBConstants.sol';\nimport {JBGlobalFundingCycleMetadataResolver} from './JBGlobalFundingCycleMetadataResolver.sol';\n\nlibrary JBFundingCycleMetadataResolver {\n function global(JBFundingCycle memory _fundingCycle)\n internal\n pure\n returns (JBGlobalFundingCycleMetadata memory)\n {\n return JBGlobalFundingCycleMetadataResolver.expandMetadata(uint8(_fundingCycle.metadata >> 8));\n }\n\n function reservedRate(JBFundingCycle memory _fundingCycle) internal pure returns (uint256) {\n return uint256(uint16(_fundingCycle.metadata >> 24));\n }\n\n function redemptionRate(JBFundingCycle memory _fundingCycle) internal pure returns (uint256) {\n // Redemption rate is a number 0-10000. It's inverse was stored so the most common case of 100% results in no storage needs.\n return JBConstants.MAX_REDEMPTION_RATE - uint256(uint16(_fundingCycle.metadata >> 40));\n }\n\n function ballotRedemptionRate(JBFundingCycle memory _fundingCycle)\n internal\n pure\n returns (uint256)\n {\n // Redemption rate is a number 0-10000. It's inverse was stored so the most common case of 100% results in no storage needs.\n return JBConstants.MAX_REDEMPTION_RATE - uint256(uint16(_fundingCycle.metadata >> 56));\n }\n\n function payPaused(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\n return ((_fundingCycle.metadata >> 72) & 1) == 1;\n }\n\n function distributionsPaused(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\n return ((_fundingCycle.metadata >> 73) & 1) == 1;\n }\n\n function redeemPaused(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\n return ((_fundingCycle.metadata >> 74) & 1) == 1;\n }\n\n function burnPaused(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\n return ((_fundingCycle.metadata >> 75) & 1) == 1;\n }\n\n function mintingAllowed(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\n return ((_fundingCycle.metadata >> 76) & 1) == 1;\n }\n\n function terminalMigrationAllowed(JBFundingCycle memory _fundingCycle)\n internal\n pure\n returns (bool)\n {\n return ((_fundingCycle.metadata >> 77) & 1) == 1;\n }\n\n function controllerMigrationAllowed(JBFundingCycle memory _fundingCycle)\n internal\n pure\n returns (bool)\n {\n return ((_fundingCycle.metadata >> 78) & 1) == 1;\n }\n\n function shouldHoldFees(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\n return ((_fundingCycle.metadata >> 79) & 1) == 1;\n }\n\n function preferClaimedTokenOverride(JBFundingCycle memory _fundingCycle)\n internal\n pure\n returns (bool)\n {\n return ((_fundingCycle.metadata >> 80) & 1) == 1;\n }\n\n function useTotalOverflowForRedemptions(JBFundingCycle memory _fundingCycle)\n internal\n pure\n returns (bool)\n {\n return ((_fundingCycle.metadata >> 81) & 1) == 1;\n }\n\n function useDataSourceForPay(JBFundingCycle memory _fundingCycle) internal pure returns (bool) {\n return (_fundingCycle.metadata >> 82) & 1 == 1;\n }\n\n function useDataSourceForRedeem(JBFundingCycle memory _fundingCycle)\n internal\n pure\n returns (bool)\n {\n return (_fundingCycle.metadata >> 83) & 1 == 1;\n }\n\n function dataSource(JBFundingCycle memory _fundingCycle) internal pure returns (address) {\n return address(uint160(_fundingCycle.metadata >> 84));\n }\n\n function metadata(JBFundingCycle memory _fundingCycle) internal pure returns (uint256) {\n return uint256(uint8(_fundingCycle.metadata >> 244));\n }\n\n /// @notice Pack the funding cycle metadata.\n /// @param _metadata The metadata to validate and pack.\n /// @return packed The packed uint256 of all metadata params. The first 8 bits specify the version. \n function packFundingCycleMetadata(JBFundingCycleMetadata memory _metadata)\n internal\n pure\n returns (uint256 packed)\n {\n // version 1 in the bits 0-7 (8 bits).\n packed = 1;\n // global metadta in bits 8-23 (16 bits).\n packed |=\n JBGlobalFundingCycleMetadataResolver.packFundingCycleGlobalMetadata(_metadata.global) <<\n 8;\n // reserved rate in bits 24-39 (16 bits).\n packed |= _metadata.reservedRate << 24;\n // redemption rate in bits 40-55 (16 bits).\n // redemption rate is a number 0-10000. Store the reverse so the most common case of 100% results in no storage needs.\n packed |= (JBConstants.MAX_REDEMPTION_RATE - _metadata.redemptionRate) << 40;\n // ballot redemption rate rate in bits 56-71 (16 bits).\n // ballot redemption rate is a number 0-10000. Store the reverse so the most common case of 100% results in no storage needs.\n packed |= (JBConstants.MAX_REDEMPTION_RATE - _metadata.ballotRedemptionRate) << 56;\n // pause pay in bit 72.\n if (_metadata.pausePay) packed |= 1 << 72;\n // pause tap in bit 73.\n if (_metadata.pauseDistributions) packed |= 1 << 73;\n // pause redeem in bit 74.\n if (_metadata.pauseRedeem) packed |= 1 << 74;\n // pause burn in bit 75.\n if (_metadata.pauseBurn) packed |= 1 << 75;\n // allow minting in bit 76.\n if (_metadata.allowMinting) packed |= 1 << 76;\n // allow terminal migration in bit 77.\n if (_metadata.allowTerminalMigration) packed |= 1 << 77;\n // allow controller migration in bit 78.\n if (_metadata.allowControllerMigration) packed |= 1 << 78;\n // hold fees in bit 79.\n if (_metadata.holdFees) packed |= 1 << 79;\n // prefer claimed token override in bit 80.\n if (_metadata.preferClaimedTokenOverride) packed |= 1 << 80;\n // useTotalOverflowForRedemptions in bit 81.\n if (_metadata.useTotalOverflowForRedemptions) packed |= 1 << 81;\n // use pay data source in bit 82.\n if (_metadata.useDataSourceForPay) packed |= 1 << 82;\n // use redeem data source in bit 83.\n if (_metadata.useDataSourceForRedeem) packed |= 1 << 83;\n // data source address in bits 84-243.\n packed |= uint256(uint160(address(_metadata.dataSource))) << 84;\n // metadata in bits 244-252 (8 bits).\n packed |= _metadata.metadata << 244;\n }\n\n /// @notice Expand the funding cycle metadata.\n /// @param _fundingCycle The funding cycle having its metadata expanded.\n /// @return metadata The metadata object. \n function expandMetadata(JBFundingCycle memory _fundingCycle)\n internal\n pure\n returns (JBFundingCycleMetadata memory)\n {\n return\n JBFundingCycleMetadata(\n global(_fundingCycle),\n reservedRate(_fundingCycle),\n redemptionRate(_fundingCycle),\n ballotRedemptionRate(_fundingCycle),\n payPaused(_fundingCycle),\n distributionsPaused(_fundingCycle),\n redeemPaused(_fundingCycle),\n burnPaused(_fundingCycle),\n mintingAllowed(_fundingCycle),\n terminalMigrationAllowed(_fundingCycle),\n controllerMigrationAllowed(_fundingCycle),\n shouldHoldFees(_fundingCycle),\n preferClaimedTokenOverride(_fundingCycle),\n useTotalOverflowForRedemptions(_fundingCycle),\n useDataSourceForPay(_fundingCycle),\n useDataSourceForRedeem(_fundingCycle),\n dataSource(_fundingCycle),\n metadata(_fundingCycle)\n );\n }\n}\n" + }, + "contracts/libraries/JBOperations.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nlibrary JBOperations {\n uint256 public constant RECONFIGURE = 1;\n uint256 public constant REDEEM = 2;\n uint256 public constant MIGRATE_CONTROLLER = 3;\n uint256 public constant MIGRATE_TERMINAL = 4;\n uint256 public constant PROCESS_FEES = 5;\n uint256 public constant SET_METADATA = 6;\n uint256 public constant ISSUE = 7;\n uint256 public constant SET_TOKEN = 8;\n uint256 public constant MINT = 9;\n uint256 public constant BURN = 10;\n uint256 public constant CLAIM = 11;\n uint256 public constant TRANSFER = 12;\n uint256 public constant REQUIRE_CLAIM = 13; // unused in v3\n uint256 public constant SET_CONTROLLER = 14;\n uint256 public constant SET_TERMINALS = 15;\n uint256 public constant SET_PRIMARY_TERMINAL = 16;\n uint256 public constant USE_ALLOWANCE = 17;\n uint256 public constant SET_SPLITS = 18;\n}\n" + }, + "contracts/JBToken.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';\nimport {ERC20Votes, ERC20, ERC20Permit} from '@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.sol';\nimport {IJBToken} from './interfaces/IJBToken.sol';\n\n/// @notice An ERC-20 token that can be used by a project in the `JBTokenStore`.\ncontract JBToken is ERC20Votes, Ownable, IJBToken {\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error BAD_PROJECT();\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The ID of the project that this token should be exclusively used for. Send 0 to support any project.\n uint256 public immutable override projectId;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice The total supply of this ERC20.\n /// @param _projectId the ID of the project to which the token belongs. This is ignored.\n /// @return The total supply of this ERC20, as a fixed point number.\n function totalSupply(uint256 _projectId) external view override returns (uint256) {\n _projectId; // Prevents unused var compiler and natspec complaints.\n\n return super.totalSupply();\n }\n\n /// @notice An account's balance of this ERC20.\n /// @param _account The account to get a balance of.\n /// @param _projectId is the ID of the project to which the token belongs. This is ignored.\n /// @return The balance of the `_account` of this ERC20, as a fixed point number with 18 decimals.\n function balanceOf(\n address _account,\n uint256 _projectId\n ) external view override returns (uint256) {\n _account; // Prevents unused var compiler and natspec complaints.\n _projectId; // Prevents unused var compiler and natspec complaints.\n\n return super.balanceOf(_account);\n }\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice The number of decimals included in the fixed point accounting of this token.\n /// @return The number of decimals.\n function decimals() public view override(ERC20, IJBToken) returns (uint8) {\n return super.decimals();\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _name The name of the token.\n /// @param _symbol The symbol that the token should be represented by.\n /// @param _projectId The ID of the project that this token should be exclusively used for. Send 0 to support any project.\n constructor(\n string memory _name,\n string memory _symbol,\n uint256 _projectId\n ) ERC20(_name, _symbol) ERC20Permit(_name) {\n projectId = _projectId;\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Mints more of the token.\n /// @dev Only the owner of this contract cant mint more of it.\n /// @param _projectId The ID of the project to which the token belongs.\n /// @param _account The account to mint the tokens for.\n /// @param _amount The amount of tokens to mint, as a fixed point number with 18 decimals.\n function mint(uint256 _projectId, address _account, uint256 _amount) external override onlyOwner {\n // Can't mint for a wrong project.\n if (projectId != 0 && _projectId != projectId) revert BAD_PROJECT();\n\n return _mint(_account, _amount);\n }\n\n /// @notice Burn some outstanding tokens.\n /// @dev Only the owner of this contract cant burn some of its supply.\n /// @param _projectId The ID of the project to which the token belongs.\n /// @param _account The account to burn tokens from.\n /// @param _amount The amount of tokens to burn, as a fixed point number with 18 decimals.\n function burn(uint256 _projectId, address _account, uint256 _amount) external override onlyOwner {\n // Can't burn for a wrong project.\n if (projectId != 0 && _projectId != projectId) revert BAD_PROJECT();\n\n return _burn(_account, _amount);\n }\n\n /// @notice Approves an account to spend tokens on the `msg.sender`s behalf.\n /// @param _projectId the ID of the project to which the token belongs.\n /// @param _spender The address that will be spending tokens on the `msg.sender`s behalf.\n /// @param _amount The amount the `_spender` is allowed to spend.\n function approve(uint256 _projectId, address _spender, uint256 _amount) external override {\n // Can't approve for a wrong project.\n if (projectId != 0 && _projectId != projectId) revert BAD_PROJECT();\n\n approve(_spender, _amount);\n }\n\n /// @notice Transfer tokens to an account.\n /// @param _projectId The ID of the project to which the token belongs.\n /// @param _to The destination address.\n /// @param _amount The amount of the transfer, as a fixed point number with 18 decimals.\n function transfer(uint256 _projectId, address _to, uint256 _amount) external override {\n // Can't transfer for a wrong project.\n if (projectId != 0 && _projectId != projectId) revert BAD_PROJECT();\n\n transfer(_to, _amount);\n }\n\n /// @notice Transfer tokens between accounts.\n /// @param _projectId The ID of the project to which the token belongs.\n /// @param _from The originating address.\n /// @param _to The destination address.\n /// @param _amount The amount of the transfer, as a fixed point number with 18 decimals.\n function transferFrom(\n uint256 _projectId,\n address _from,\n address _to,\n uint256 _amount\n ) external override {\n // Can't transfer for a wrong project.\n if (projectId != 0 && _projectId != projectId) revert BAD_PROJECT();\n\n transferFrom(_from, _to, _amount);\n }\n}\n" + }, + "contracts/interfaces/IJBOperatable.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBOperatorStore} from './IJBOperatorStore.sol';\n\ninterface IJBOperatable {\n function operatorStore() external view returns (IJBOperatorStore);\n}\n" + }, + "contracts/structs/JBOperatorData.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @custom:member operator The address of the operator.\n/// @custom:member domain The domain within which the operator is being given permissions. A domain of 0 is a wildcard domain, which gives an operator access to all domains.\n/// @custom:member permissionIndexes The indexes of the permissions the operator is being given.\nstruct JBOperatorData {\n address operator;\n uint256 domain;\n uint256[] permissionIndexes;\n}\n" + }, + "contracts/structs/JBFundingCycleMetadata.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBGlobalFundingCycleMetadata} from './JBGlobalFundingCycleMetadata.sol';\n\n/// @custom:member global Data used globally in non-migratable ecosystem contracts.\n/// @custom:member reservedRate The reserved rate of the funding cycle. This number is a percentage calculated out of `JBConstants.MAX_RESERVED_RATE`.\n/// @custom:member redemptionRate The redemption rate of the funding cycle. This number is a percentage calculated out of `JBConstants.MAX_REDEMPTION_RATE`.\n/// @custom:member ballotRedemptionRate The redemption rate to use during an active ballot of the funding cycle. This number is a percentage calculated out of `JBConstants.MAX_REDEMPTION_RATE`.\n/// @custom:member pausePay A flag indicating if the pay functionality should be paused during the funding cycle.\n/// @custom:member pauseDistributions A flag indicating if the distribute functionality should be paused during the funding cycle.\n/// @custom:member pauseRedeem A flag indicating if the redeem functionality should be paused during the funding cycle.\n/// @custom:member pauseBurn A flag indicating if the burn functionality should be paused during the funding cycle.\n/// @custom:member allowMinting A flag indicating if minting tokens should be allowed during this funding cycle.\n/// @custom:member allowTerminalMigration A flag indicating if migrating terminals should be allowed during this funding cycle.\n/// @custom:member allowControllerMigration A flag indicating if migrating controllers should be allowed during this funding cycle.\n/// @custom:member holdFees A flag indicating if fees should be held during this funding cycle.\n/// @custom:member preferClaimedTokenOverride A flag indicating if claimed tokens should always be prefered to unclaimed tokens when minting.\n/// @custom:member useTotalOverflowForRedemptions A flag indicating if redemptions should use the project's balance held in all terminals instead of the project's local terminal balance from which the redemption is being fulfilled.\n/// @custom:member useDataSourceForPay A flag indicating if the data source should be used for pay transactions during this funding cycle.\n/// @custom:member useDataSourceForRedeem A flag indicating if the data source should be used for redeem transactions during this funding cycle.\n/// @custom:member dataSource The data source to use during this funding cycle.\n/// @custom:member metadata Metadata of the metadata, up to uint8 in size.\nstruct JBFundingCycleMetadata {\n JBGlobalFundingCycleMetadata global;\n uint256 reservedRate;\n uint256 redemptionRate;\n uint256 ballotRedemptionRate;\n bool pausePay;\n bool pauseDistributions;\n bool pauseRedeem;\n bool pauseBurn;\n bool allowMinting;\n bool allowTerminalMigration;\n bool allowControllerMigration;\n bool holdFees;\n bool preferClaimedTokenOverride;\n bool useTotalOverflowForRedemptions;\n bool useDataSourceForPay;\n bool useDataSourceForRedeem;\n address dataSource;\n uint256 metadata;\n}\n" + }, + "contracts/structs/JBGlobalFundingCycleMetadata.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @custom:member allowSetTerminals A flag indicating if setting terminals should be allowed during this funding cycle.\n/// @custom:member allowSetController A flag indicating if setting a new controller should be allowed during this funding cycle.\n/// @custom:member pauseTransfers A flag indicating if the project token transfer functionality should be paused during the funding cycle.\nstruct JBGlobalFundingCycleMetadata {\n bool allowSetTerminals;\n bool allowSetController;\n bool pauseTransfers;\n}\n" + }, + "contracts/libraries/JBConstants.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @notice Global constants used across Juicebox contracts.\nlibrary JBConstants {\n uint256 public constant MAX_RESERVED_RATE = 10_000;\n uint256 public constant MAX_REDEMPTION_RATE = 10_000;\n uint256 public constant MAX_DISCOUNT_RATE = 1_000_000_000;\n uint256 public constant SPLITS_TOTAL_PERCENT = 1_000_000_000;\n uint256 public constant MAX_FEE = 1_000_000_000;\n uint256 public constant MAX_FEE_DISCOUNT = 1_000_000_000;\n}\n" + }, + "contracts/libraries/JBGlobalFundingCycleMetadataResolver.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {JBFundingCycleMetadata} from './../structs/JBFundingCycleMetadata.sol';\nimport {JBGlobalFundingCycleMetadata} from './../structs/JBGlobalFundingCycleMetadata.sol';\n\nlibrary JBGlobalFundingCycleMetadataResolver {\n function setTerminalsAllowed(uint8 _data) internal pure returns (bool) {\n return (_data & 1) == 1;\n }\n\n function setControllerAllowed(uint8 _data) internal pure returns (bool) {\n return ((_data >> 1) & 1) == 1;\n }\n\n function transfersPaused(uint8 _data) internal pure returns (bool) {\n return ((_data >> 2) & 1) == 1;\n }\n\n /// @notice Pack the global funding cycle metadata.\n /// @param _metadata The metadata to validate and pack.\n /// @return packed The packed uint256 of all global metadata params. The first 8 bits specify the version.\n function packFundingCycleGlobalMetadata(\n JBGlobalFundingCycleMetadata memory _metadata\n ) internal pure returns (uint256 packed) {\n // allow set terminals in bit 0.\n if (_metadata.allowSetTerminals) packed |= 1;\n // allow set controller in bit 1.\n if (_metadata.allowSetController) packed |= 1 << 1;\n // pause transfers in bit 2.\n if (_metadata.pauseTransfers) packed |= 1 << 2;\n }\n\n /// @notice Expand the global funding cycle metadata.\n /// @param _packedMetadata The packed metadata to expand.\n /// @return metadata The global metadata object.\n function expandMetadata(\n uint8 _packedMetadata\n ) internal pure returns (JBGlobalFundingCycleMetadata memory metadata) {\n return\n JBGlobalFundingCycleMetadata(\n setTerminalsAllowed(_packedMetadata),\n setControllerAllowed(_packedMetadata),\n transfersPaused(_packedMetadata)\n );\n }\n}\n" + }, + "@openzeppelin/contracts/access/Ownable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n _;\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (token/ERC20/extensions/ERC20Votes.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./draft-ERC20Permit.sol\";\nimport \"../../../utils/math/Math.sol\";\nimport \"../../../governance/utils/IVotes.sol\";\nimport \"../../../utils/math/SafeCast.sol\";\nimport \"../../../utils/cryptography/ECDSA.sol\";\n\n/**\n * @dev Extension of ERC20 to support Compound-like voting and delegation. This version is more generic than Compound's,\n * and supports token supply up to 2^224^ - 1, while COMP is limited to 2^96^ - 1.\n *\n * NOTE: If exact COMP compatibility is required, use the {ERC20VotesComp} variant of this module.\n *\n * This extension keeps a history (checkpoints) of each account's vote power. Vote power can be delegated either\n * by calling the {delegate} function directly, or by providing a signature to be used with {delegateBySig}. Voting\n * power can be queried through the public accessors {getVotes} and {getPastVotes}.\n *\n * By default, token balance does not account for voting power. This makes transfers cheaper. The downside is that it\n * requires users to delegate to themselves in order to activate checkpoints and have their voting power tracked.\n *\n * _Available since v4.2._\n */\nabstract contract ERC20Votes is IVotes, ERC20Permit {\n struct Checkpoint {\n uint32 fromBlock;\n uint224 votes;\n }\n\n bytes32 private constant _DELEGATION_TYPEHASH =\n keccak256(\"Delegation(address delegatee,uint256 nonce,uint256 expiry)\");\n\n mapping(address => address) private _delegates;\n mapping(address => Checkpoint[]) private _checkpoints;\n Checkpoint[] private _totalSupplyCheckpoints;\n\n /**\n * @dev Get the `pos`-th checkpoint for `account`.\n */\n function checkpoints(address account, uint32 pos) public view virtual returns (Checkpoint memory) {\n return _checkpoints[account][pos];\n }\n\n /**\n * @dev Get number of checkpoints for `account`.\n */\n function numCheckpoints(address account) public view virtual returns (uint32) {\n return SafeCast.toUint32(_checkpoints[account].length);\n }\n\n /**\n * @dev Get the address `account` is currently delegating to.\n */\n function delegates(address account) public view virtual override returns (address) {\n return _delegates[account];\n }\n\n /**\n * @dev Gets the current votes balance for `account`\n */\n function getVotes(address account) public view virtual override returns (uint256) {\n uint256 pos = _checkpoints[account].length;\n return pos == 0 ? 0 : _checkpoints[account][pos - 1].votes;\n }\n\n /**\n * @dev Retrieve the number of votes for `account` at the end of `blockNumber`.\n *\n * Requirements:\n *\n * - `blockNumber` must have been already mined\n */\n function getPastVotes(address account, uint256 blockNumber) public view virtual override returns (uint256) {\n require(blockNumber < block.number, \"ERC20Votes: block not yet mined\");\n return _checkpointsLookup(_checkpoints[account], blockNumber);\n }\n\n /**\n * @dev Retrieve the `totalSupply` at the end of `blockNumber`. Note, this value is the sum of all balances.\n * It is but NOT the sum of all the delegated votes!\n *\n * Requirements:\n *\n * - `blockNumber` must have been already mined\n */\n function getPastTotalSupply(uint256 blockNumber) public view virtual override returns (uint256) {\n require(blockNumber < block.number, \"ERC20Votes: block not yet mined\");\n return _checkpointsLookup(_totalSupplyCheckpoints, blockNumber);\n }\n\n /**\n * @dev Lookup a value in a list of (sorted) checkpoints.\n */\n function _checkpointsLookup(Checkpoint[] storage ckpts, uint256 blockNumber) private view returns (uint256) {\n // We run a binary search to look for the earliest checkpoint taken after `blockNumber`.\n //\n // During the loop, the index of the wanted checkpoint remains in the range [low-1, high).\n // With each iteration, either `low` or `high` is moved towards the middle of the range to maintain the invariant.\n // - If the middle checkpoint is after `blockNumber`, we look in [low, mid)\n // - If the middle checkpoint is before or equal to `blockNumber`, we look in [mid+1, high)\n // Once we reach a single value (when low == high), we've found the right checkpoint at the index high-1, if not\n // out of bounds (in which case we're looking too far in the past and the result is 0).\n // Note that if the latest checkpoint available is exactly for `blockNumber`, we end up with an index that is\n // past the end of the array, so we technically don't find a checkpoint after `blockNumber`, but it works out\n // the same.\n uint256 high = ckpts.length;\n uint256 low = 0;\n while (low < high) {\n uint256 mid = Math.average(low, high);\n if (ckpts[mid].fromBlock > blockNumber) {\n high = mid;\n } else {\n low = mid + 1;\n }\n }\n\n return high == 0 ? 0 : ckpts[high - 1].votes;\n }\n\n /**\n * @dev Delegate votes from the sender to `delegatee`.\n */\n function delegate(address delegatee) public virtual override {\n _delegate(_msgSender(), delegatee);\n }\n\n /**\n * @dev Delegates votes from signer to `delegatee`\n */\n function delegateBySig(\n address delegatee,\n uint256 nonce,\n uint256 expiry,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) public virtual override {\n require(block.timestamp <= expiry, \"ERC20Votes: signature expired\");\n address signer = ECDSA.recover(\n _hashTypedDataV4(keccak256(abi.encode(_DELEGATION_TYPEHASH, delegatee, nonce, expiry))),\n v,\n r,\n s\n );\n require(nonce == _useNonce(signer), \"ERC20Votes: invalid nonce\");\n _delegate(signer, delegatee);\n }\n\n /**\n * @dev Maximum token supply. Defaults to `type(uint224).max` (2^224^ - 1).\n */\n function _maxSupply() internal view virtual returns (uint224) {\n return type(uint224).max;\n }\n\n /**\n * @dev Snapshots the totalSupply after it has been increased.\n */\n function _mint(address account, uint256 amount) internal virtual override {\n super._mint(account, amount);\n require(totalSupply() <= _maxSupply(), \"ERC20Votes: total supply risks overflowing votes\");\n\n _writeCheckpoint(_totalSupplyCheckpoints, _add, amount);\n }\n\n /**\n * @dev Snapshots the totalSupply after it has been decreased.\n */\n function _burn(address account, uint256 amount) internal virtual override {\n super._burn(account, amount);\n\n _writeCheckpoint(_totalSupplyCheckpoints, _subtract, amount);\n }\n\n /**\n * @dev Move voting power when tokens are transferred.\n *\n * Emits a {DelegateVotesChanged} event.\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual override {\n super._afterTokenTransfer(from, to, amount);\n\n _moveVotingPower(delegates(from), delegates(to), amount);\n }\n\n /**\n * @dev Change delegation for `delegator` to `delegatee`.\n *\n * Emits events {DelegateChanged} and {DelegateVotesChanged}.\n */\n function _delegate(address delegator, address delegatee) internal virtual {\n address currentDelegate = delegates(delegator);\n uint256 delegatorBalance = balanceOf(delegator);\n _delegates[delegator] = delegatee;\n\n emit DelegateChanged(delegator, currentDelegate, delegatee);\n\n _moveVotingPower(currentDelegate, delegatee, delegatorBalance);\n }\n\n function _moveVotingPower(\n address src,\n address dst,\n uint256 amount\n ) private {\n if (src != dst && amount > 0) {\n if (src != address(0)) {\n (uint256 oldWeight, uint256 newWeight) = _writeCheckpoint(_checkpoints[src], _subtract, amount);\n emit DelegateVotesChanged(src, oldWeight, newWeight);\n }\n\n if (dst != address(0)) {\n (uint256 oldWeight, uint256 newWeight) = _writeCheckpoint(_checkpoints[dst], _add, amount);\n emit DelegateVotesChanged(dst, oldWeight, newWeight);\n }\n }\n }\n\n function _writeCheckpoint(\n Checkpoint[] storage ckpts,\n function(uint256, uint256) view returns (uint256) op,\n uint256 delta\n ) private returns (uint256 oldWeight, uint256 newWeight) {\n uint256 pos = ckpts.length;\n oldWeight = pos == 0 ? 0 : ckpts[pos - 1].votes;\n newWeight = op(oldWeight, delta);\n\n if (pos > 0 && ckpts[pos - 1].fromBlock == block.number) {\n ckpts[pos - 1].votes = SafeCast.toUint224(newWeight);\n } else {\n ckpts.push(Checkpoint({fromBlock: SafeCast.toUint32(block.number), votes: SafeCast.toUint224(newWeight)}));\n }\n }\n\n function _add(uint256 a, uint256 b) private pure returns (uint256) {\n return a + b;\n }\n\n function _subtract(uint256 a, uint256 b) private pure returns (uint256) {\n return a - b;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Context.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-ERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./draft-IERC20Permit.sol\";\nimport \"../ERC20.sol\";\nimport \"../../../utils/cryptography/draft-EIP712.sol\";\nimport \"../../../utils/cryptography/ECDSA.sol\";\nimport \"../../../utils/Counters.sol\";\n\n/**\n * @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * _Available since v3.4._\n */\nabstract contract ERC20Permit is ERC20, IERC20Permit, EIP712 {\n using Counters for Counters.Counter;\n\n mapping(address => Counters.Counter) private _nonces;\n\n // solhint-disable-next-line var-name-mixedcase\n bytes32 private immutable _PERMIT_TYPEHASH =\n keccak256(\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\");\n\n /**\n * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `\"1\"`.\n *\n * It's a good idea to use the same `name` that is defined as the ERC20 token name.\n */\n constructor(string memory name) EIP712(name, \"1\") {}\n\n /**\n * @dev See {IERC20Permit-permit}.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) public virtual override {\n require(block.timestamp <= deadline, \"ERC20Permit: expired deadline\");\n\n bytes32 structHash = keccak256(abi.encode(_PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline));\n\n bytes32 hash = _hashTypedDataV4(structHash);\n\n address signer = ECDSA.recover(hash, v, r, s);\n require(signer == owner, \"ERC20Permit: invalid signature\");\n\n _approve(owner, spender, value);\n }\n\n /**\n * @dev See {IERC20Permit-nonces}.\n */\n function nonces(address owner) public view virtual override returns (uint256) {\n return _nonces[owner].current();\n }\n\n /**\n * @dev See {IERC20Permit-DOMAIN_SEPARATOR}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view override returns (bytes32) {\n return _domainSeparatorV4();\n }\n\n /**\n * @dev \"Consume a nonce\": return the current value and increment.\n *\n * _Available since v4.1._\n */\n function _useNonce(address owner) internal virtual returns (uint256 current) {\n Counters.Counter storage nonce = _nonces[owner];\n current = nonce.current();\n nonce.increment();\n }\n}\n" + }, + "@openzeppelin/contracts/utils/math/Math.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n /**\n * @dev Returns the largest of two numbers.\n */\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\n return a >= b ? a : b;\n }\n\n /**\n * @dev Returns the smallest of two numbers.\n */\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\n return a < b ? a : b;\n }\n\n /**\n * @dev Returns the average of two numbers. The result is rounded towards\n * zero.\n */\n function average(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b) / 2 can overflow.\n return (a & b) + (a ^ b) / 2;\n }\n\n /**\n * @dev Returns the ceiling of the division of two numbers.\n *\n * This differs from standard division with `/` in that it rounds up instead\n * of rounding down.\n */\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b - 1) / b can overflow on addition, so we distribute.\n return a / b + (a % b == 0 ? 0 : 1);\n }\n\n /**\n * @dev Returns the absolute unsigned value of a signed value.\n */\n function abs(int256 n) internal pure returns (uint256) {\n unchecked {\n // must be unchecked in order to support `n = type(int256).min`\n return uint256(n >= 0 ? n : -n);\n }\n }\n}\n" + }, + "@openzeppelin/contracts/governance/utils/IVotes.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (governance/utils/IVotes.sol)\npragma solidity ^0.8.0;\n\n/**\n * @dev Common interface for {ERC20Votes}, {ERC721Votes}, and other {Votes}-enabled contracts.\n *\n * _Available since v4.5._\n */\ninterface IVotes {\n /**\n * @dev Emitted when an account changes their delegate.\n */\n event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);\n\n /**\n * @dev Emitted when a token transfer or delegate change results in changes to a delegate's number of votes.\n */\n event DelegateVotesChanged(address indexed delegate, uint256 previousBalance, uint256 newBalance);\n\n /**\n * @dev Returns the current amount of votes that `account` has.\n */\n function getVotes(address account) external view returns (uint256);\n\n /**\n * @dev Returns the amount of votes that `account` had at the end of a past block (`blockNumber`).\n */\n function getPastVotes(address account, uint256 blockNumber) external view returns (uint256);\n\n /**\n * @dev Returns the total supply of votes available at the end of a past block (`blockNumber`).\n *\n * NOTE: This value is the sum of all available votes, which is not necessarily the sum of all delegated votes.\n * Votes that have not been delegated are still part of total supply, even though they would not participate in a\n * vote.\n */\n function getPastTotalSupply(uint256 blockNumber) external view returns (uint256);\n\n /**\n * @dev Returns the delegate that `account` has chosen.\n */\n function delegates(address account) external view returns (address);\n\n /**\n * @dev Delegates votes from the sender to `delegatee`.\n */\n function delegate(address delegatee) external;\n\n /**\n * @dev Delegates votes from signer to `delegatee`.\n */\n function delegateBySig(\n address delegatee,\n uint256 nonce,\n uint256 expiry,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n}\n" + }, + "@openzeppelin/contracts/utils/math/SafeCast.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeCast.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow\n * checks.\n *\n * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can\n * easily result in undesired exploitation or bugs, since developers usually\n * assume that overflows raise errors. `SafeCast` restores this intuition by\n * reverting the transaction when such an operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n *\n * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing\n * all math on `uint256` and `int256` and then downcasting.\n */\nlibrary SafeCast {\n /**\n * @dev Returns the downcasted uint224 from uint256, reverting on\n * overflow (when the input is greater than largest uint224).\n *\n * Counterpart to Solidity's `uint224` operator.\n *\n * Requirements:\n *\n * - input must fit into 224 bits\n */\n function toUint224(uint256 value) internal pure returns (uint224) {\n require(value <= type(uint224).max, \"SafeCast: value doesn't fit in 224 bits\");\n return uint224(value);\n }\n\n /**\n * @dev Returns the downcasted uint128 from uint256, reverting on\n * overflow (when the input is greater than largest uint128).\n *\n * Counterpart to Solidity's `uint128` operator.\n *\n * Requirements:\n *\n * - input must fit into 128 bits\n */\n function toUint128(uint256 value) internal pure returns (uint128) {\n require(value <= type(uint128).max, \"SafeCast: value doesn't fit in 128 bits\");\n return uint128(value);\n }\n\n /**\n * @dev Returns the downcasted uint96 from uint256, reverting on\n * overflow (when the input is greater than largest uint96).\n *\n * Counterpart to Solidity's `uint96` operator.\n *\n * Requirements:\n *\n * - input must fit into 96 bits\n */\n function toUint96(uint256 value) internal pure returns (uint96) {\n require(value <= type(uint96).max, \"SafeCast: value doesn't fit in 96 bits\");\n return uint96(value);\n }\n\n /**\n * @dev Returns the downcasted uint64 from uint256, reverting on\n * overflow (when the input is greater than largest uint64).\n *\n * Counterpart to Solidity's `uint64` operator.\n *\n * Requirements:\n *\n * - input must fit into 64 bits\n */\n function toUint64(uint256 value) internal pure returns (uint64) {\n require(value <= type(uint64).max, \"SafeCast: value doesn't fit in 64 bits\");\n return uint64(value);\n }\n\n /**\n * @dev Returns the downcasted uint32 from uint256, reverting on\n * overflow (when the input is greater than largest uint32).\n *\n * Counterpart to Solidity's `uint32` operator.\n *\n * Requirements:\n *\n * - input must fit into 32 bits\n */\n function toUint32(uint256 value) internal pure returns (uint32) {\n require(value <= type(uint32).max, \"SafeCast: value doesn't fit in 32 bits\");\n return uint32(value);\n }\n\n /**\n * @dev Returns the downcasted uint16 from uint256, reverting on\n * overflow (when the input is greater than largest uint16).\n *\n * Counterpart to Solidity's `uint16` operator.\n *\n * Requirements:\n *\n * - input must fit into 16 bits\n */\n function toUint16(uint256 value) internal pure returns (uint16) {\n require(value <= type(uint16).max, \"SafeCast: value doesn't fit in 16 bits\");\n return uint16(value);\n }\n\n /**\n * @dev Returns the downcasted uint8 from uint256, reverting on\n * overflow (when the input is greater than largest uint8).\n *\n * Counterpart to Solidity's `uint8` operator.\n *\n * Requirements:\n *\n * - input must fit into 8 bits.\n */\n function toUint8(uint256 value) internal pure returns (uint8) {\n require(value <= type(uint8).max, \"SafeCast: value doesn't fit in 8 bits\");\n return uint8(value);\n }\n\n /**\n * @dev Converts a signed int256 into an unsigned uint256.\n *\n * Requirements:\n *\n * - input must be greater than or equal to 0.\n */\n function toUint256(int256 value) internal pure returns (uint256) {\n require(value >= 0, \"SafeCast: value must be positive\");\n return uint256(value);\n }\n\n /**\n * @dev Returns the downcasted int128 from int256, reverting on\n * overflow (when the input is less than smallest int128 or\n * greater than largest int128).\n *\n * Counterpart to Solidity's `int128` operator.\n *\n * Requirements:\n *\n * - input must fit into 128 bits\n *\n * _Available since v3.1._\n */\n function toInt128(int256 value) internal pure returns (int128) {\n require(value >= type(int128).min && value <= type(int128).max, \"SafeCast: value doesn't fit in 128 bits\");\n return int128(value);\n }\n\n /**\n * @dev Returns the downcasted int64 from int256, reverting on\n * overflow (when the input is less than smallest int64 or\n * greater than largest int64).\n *\n * Counterpart to Solidity's `int64` operator.\n *\n * Requirements:\n *\n * - input must fit into 64 bits\n *\n * _Available since v3.1._\n */\n function toInt64(int256 value) internal pure returns (int64) {\n require(value >= type(int64).min && value <= type(int64).max, \"SafeCast: value doesn't fit in 64 bits\");\n return int64(value);\n }\n\n /**\n * @dev Returns the downcasted int32 from int256, reverting on\n * overflow (when the input is less than smallest int32 or\n * greater than largest int32).\n *\n * Counterpart to Solidity's `int32` operator.\n *\n * Requirements:\n *\n * - input must fit into 32 bits\n *\n * _Available since v3.1._\n */\n function toInt32(int256 value) internal pure returns (int32) {\n require(value >= type(int32).min && value <= type(int32).max, \"SafeCast: value doesn't fit in 32 bits\");\n return int32(value);\n }\n\n /**\n * @dev Returns the downcasted int16 from int256, reverting on\n * overflow (when the input is less than smallest int16 or\n * greater than largest int16).\n *\n * Counterpart to Solidity's `int16` operator.\n *\n * Requirements:\n *\n * - input must fit into 16 bits\n *\n * _Available since v3.1._\n */\n function toInt16(int256 value) internal pure returns (int16) {\n require(value >= type(int16).min && value <= type(int16).max, \"SafeCast: value doesn't fit in 16 bits\");\n return int16(value);\n }\n\n /**\n * @dev Returns the downcasted int8 from int256, reverting on\n * overflow (when the input is less than smallest int8 or\n * greater than largest int8).\n *\n * Counterpart to Solidity's `int8` operator.\n *\n * Requirements:\n *\n * - input must fit into 8 bits.\n *\n * _Available since v3.1._\n */\n function toInt8(int256 value) internal pure returns (int8) {\n require(value >= type(int8).min && value <= type(int8).max, \"SafeCast: value doesn't fit in 8 bits\");\n return int8(value);\n }\n\n /**\n * @dev Converts an unsigned uint256 into a signed int256.\n *\n * Requirements:\n *\n * - input must be less than or equal to maxInt256.\n */\n function toInt256(uint256 value) internal pure returns (int256) {\n // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive\n require(value <= uint256(type(int256).max), \"SafeCast: value doesn't fit in an int256\");\n return int256(value);\n }\n}\n" + }, + "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS,\n InvalidSignatureV\n }\n\n function _throwError(RecoverError error) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert(\"ECDSA: invalid signature\");\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert(\"ECDSA: invalid signature length\");\n } else if (error == RecoverError.InvalidSignatureS) {\n revert(\"ECDSA: invalid signature 's' value\");\n } else if (error == RecoverError.InvalidSignatureV) {\n revert(\"ECDSA: invalid signature 'v' value\");\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature` or error string. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n *\n * _Available since v4.3._\n */\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n // Check the signature length\n // - case 65: r,s,v signature (standard)\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else if (signature.length == 64) {\n bytes32 r;\n bytes32 vs;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly {\n r := mload(add(signature, 0x20))\n vs := mload(add(signature, 0x40))\n }\n return tryRecover(hash, r, vs);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength);\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, signature);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address, RecoverError) {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n *\n * _Available since v4.2._\n */\n function recover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n *\n * _Available since v4.3._\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address, RecoverError) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS);\n }\n if (v != 27 && v != 28) {\n return (address(0), RecoverError.InvalidSignatureV);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature);\n }\n\n return (signer, RecoverError.NoError);\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address) {\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n _throwError(error);\n return recovered;\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n // 32 is the length in bytes of hash,\n // enforced by the type signature above\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n }\n\n /**\n * @dev Returns an Ethereum Signed Message, created from `s`. This\n * produces hash corresponding to the one signed with the\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n * JSON-RPC method as part of EIP-191.\n *\n * See {recover}.\n */\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n }\n\n /**\n * @dev Returns an Ethereum Signed Typed Data, created from a\n * `domainSeparator` and a `structHash`. This produces hash corresponding\n * to the one signed with the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n * JSON-RPC method as part of EIP-712.\n *\n * See {recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/ERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * The default value of {decimals} is 18. To select a different value for\n * {decimals} you should overload it.\n *\n * All two of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\n * overridden;\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual override returns (uint8) {\n return 18;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view virtual override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view virtual override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `recipient` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address recipient, uint256 amount) public virtual override returns (bool) {\n _transfer(_msgSender(), recipient, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n _approve(_msgSender(), spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `sender` and `recipient` cannot be the zero address.\n * - `sender` must have a balance of at least `amount`.\n * - the caller must have allowance for ``sender``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) public virtual override returns (bool) {\n uint256 currentAllowance = _allowances[sender][_msgSender()];\n if (currentAllowance != type(uint256).max) {\n require(currentAllowance >= amount, \"ERC20: transfer amount exceeds allowance\");\n unchecked {\n _approve(sender, _msgSender(), currentAllowance - amount);\n }\n }\n\n _transfer(sender, recipient, amount);\n\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n _approve(_msgSender(), spender, _allowances[_msgSender()][spender] + addedValue);\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n uint256 currentAllowance = _allowances[_msgSender()][spender];\n require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n unchecked {\n _approve(_msgSender(), spender, currentAllowance - subtractedValue);\n }\n\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `sender` cannot be the zero address.\n * - `recipient` cannot be the zero address.\n * - `sender` must have a balance of at least `amount`.\n */\n function _transfer(\n address sender,\n address recipient,\n uint256 amount\n ) internal virtual {\n require(sender != address(0), \"ERC20: transfer from the zero address\");\n require(recipient != address(0), \"ERC20: transfer to the zero address\");\n\n _beforeTokenTransfer(sender, recipient, amount);\n\n uint256 senderBalance = _balances[sender];\n require(senderBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n unchecked {\n _balances[sender] = senderBalance - amount;\n }\n _balances[recipient] += amount;\n\n emit Transfer(sender, recipient, amount);\n\n _afterTokenTransfer(sender, recipient, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply += amount;\n _balances[account] += amount;\n emit Transfer(address(0), account, amount);\n\n _afterTokenTransfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _beforeTokenTransfer(account, address(0), amount);\n\n uint256 accountBalance = _balances[account];\n require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n unchecked {\n _balances[account] = accountBalance - amount;\n }\n _totalSupply -= amount;\n\n emit Transfer(account, address(0), amount);\n\n _afterTokenTransfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * has been transferred to `to`.\n * - when `from` is zero, `amount` tokens have been minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n" + }, + "@openzeppelin/contracts/utils/cryptography/draft-EIP712.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/cryptography/draft-EIP712.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./ECDSA.sol\";\n\n/**\n * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.\n *\n * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,\n * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding\n * they need in their contracts using a combination of `abi.encode` and `keccak256`.\n *\n * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding\n * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA\n * ({_hashTypedDataV4}).\n *\n * The implementation of the domain separator was designed to be as efficient as possible while still properly updating\n * the chain id to protect against replay attacks on an eventual fork of the chain.\n *\n * NOTE: This contract implements the version of the encoding known as \"v4\", as implemented by the JSON RPC method\n * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].\n *\n * _Available since v3.4._\n */\nabstract contract EIP712 {\n /* solhint-disable var-name-mixedcase */\n // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to\n // invalidate the cached domain separator if the chain id changes.\n bytes32 private immutable _CACHED_DOMAIN_SEPARATOR;\n uint256 private immutable _CACHED_CHAIN_ID;\n address private immutable _CACHED_THIS;\n\n bytes32 private immutable _HASHED_NAME;\n bytes32 private immutable _HASHED_VERSION;\n bytes32 private immutable _TYPE_HASH;\n\n /* solhint-enable var-name-mixedcase */\n\n /**\n * @dev Initializes the domain separator and parameter caches.\n *\n * The meaning of `name` and `version` is specified in\n * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:\n *\n * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.\n * - `version`: the current major version of the signing domain.\n *\n * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart\n * contract upgrade].\n */\n constructor(string memory name, string memory version) {\n bytes32 hashedName = keccak256(bytes(name));\n bytes32 hashedVersion = keccak256(bytes(version));\n bytes32 typeHash = keccak256(\n \"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\"\n );\n _HASHED_NAME = hashedName;\n _HASHED_VERSION = hashedVersion;\n _CACHED_CHAIN_ID = block.chainid;\n _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion);\n _CACHED_THIS = address(this);\n _TYPE_HASH = typeHash;\n }\n\n /**\n * @dev Returns the domain separator for the current chain.\n */\n function _domainSeparatorV4() internal view returns (bytes32) {\n if (address(this) == _CACHED_THIS && block.chainid == _CACHED_CHAIN_ID) {\n return _CACHED_DOMAIN_SEPARATOR;\n } else {\n return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION);\n }\n }\n\n function _buildDomainSeparator(\n bytes32 typeHash,\n bytes32 nameHash,\n bytes32 versionHash\n ) private view returns (bytes32) {\n return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this)));\n }\n\n /**\n * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this\n * function returns the hash of the fully encoded EIP712 message for this domain.\n *\n * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:\n *\n * ```solidity\n * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(\n * keccak256(\"Mail(address to,string contents)\"),\n * mailTo,\n * keccak256(bytes(mailContents))\n * )));\n * address signer = ECDSA.recover(digest, signature);\n * ```\n */\n function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {\n return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Counters.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Counters.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @title Counters\n * @author Matt Condon (@shrugs)\n * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number\n * of elements in a mapping, issuing ERC721 ids, or counting request ids.\n *\n * Include with `using Counters for Counters.Counter;`\n */\nlibrary Counters {\n struct Counter {\n // This variable should never be directly accessed by users of the library: interactions must be restricted to\n // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add\n // this feature: see https://github.com/ethereum/solidity/issues/4637\n uint256 _value; // default: 0\n }\n\n function current(Counter storage counter) internal view returns (uint256) {\n return counter._value;\n }\n\n function increment(Counter storage counter) internal {\n unchecked {\n counter._value += 1;\n }\n }\n\n function decrement(Counter storage counter) internal {\n uint256 value = counter._value;\n require(value > 0, \"Counter: decrement overflow\");\n unchecked {\n counter._value = value - 1;\n }\n }\n\n function reset(Counter storage counter) internal {\n counter._value = 0;\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/IERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address recipient, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) external returns (bool);\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n" + }, + "@openzeppelin/contracts/utils/Strings.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n}\n" + }, + "contracts/JBController3_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {ERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {JBOperatable} from './abstract/JBOperatable.sol';\nimport {JBBallotState} from './enums/JBBallotState.sol';\nimport {IJBController3_0_1} from './interfaces/IJBController3_0_1.sol';\nimport {IJBController3_1} from './interfaces/IJBController3_1.sol';\nimport {IJBController} from './interfaces/IJBController.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBFundAccessConstraintsStore} from './interfaces/IJBFundAccessConstraintsStore.sol';\nimport {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol';\nimport {IJBMigratable} from './interfaces/IJBMigratable.sol';\nimport {IJBOperatable} from './interfaces/IJBOperatable.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {IJBSplitAllocator} from './interfaces/IJBSplitAllocator.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {IJBTokenStore} from './interfaces/IJBTokenStore.sol';\nimport {JBConstants} from './libraries/JBConstants.sol';\nimport {JBFundingCycleMetadataResolver} from './libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBOperations} from './libraries/JBOperations.sol';\nimport {JBSplitsGroups} from './libraries/JBSplitsGroups.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\nimport {JBSplitAllocationData} from './structs/JBSplitAllocationData.sol';\nimport {JBFundAccessConstraints} from './structs/JBFundAccessConstraints.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\nimport {JBFundingCycleData} from './structs/JBFundingCycleData.sol';\nimport {JBFundingCycleMetadata} from './structs/JBFundingCycleMetadata.sol';\nimport {JBGroupedSplits} from './structs/JBGroupedSplits.sol';\nimport {JBProjectMetadata} from './structs/JBProjectMetadata.sol';\nimport {JBSplit} from './structs/JBSplit.sol';\n\n/// @notice Stitches together funding cycles and project tokens, making sure all activity is accounted for and correct.\n/// @dev This Controller has the same functionality as JBController3_0_1, except it is not backwards compatible with the original IJBController view methods.\ncontract JBController3_1 is JBOperatable, ERC165, IJBController3_1, IJBMigratable {\n // A library that parses the packed funding cycle metadata into a more friendly format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n\n error BURN_PAUSED_AND_SENDER_NOT_VALID_TERMINAL_DELEGATE();\n error FUNDING_CYCLE_ALREADY_LAUNCHED();\n error INVALID_BALLOT_REDEMPTION_RATE();\n error INVALID_REDEMPTION_RATE();\n error INVALID_RESERVED_RATE();\n error MIGRATION_NOT_ALLOWED();\n error MINT_NOT_ALLOWED_AND_NOT_TERMINAL_DELEGATE();\n error NO_BURNABLE_TOKENS();\n error NOT_CURRENT_CONTROLLER();\n error ZERO_TOKENS_TO_MINT();\n\n //*********************************************************************//\n // --------------------- internal stored properties ------------------ //\n //*********************************************************************//\n\n /// @notice Data regarding the distribution limit of a project during a configuration.\n /// @dev bits 0-231: The amount of token that a project can distribute per funding cycle.\n /// @dev bits 232-255: The currency of amount that a project can distribute.\n /// @custom:param _projectId The ID of the project to get the packed distribution limit data of.\n /// @custom:param _configuration The configuration during which the packed distribution limit data applies.\n /// @custom:param _terminal The terminal from which distributions are being limited.\n /// @custom:param _token The token for which distributions are being limited.\n mapping(uint256 => mapping(uint256 => mapping(IJBPaymentTerminal => mapping(address => uint256))))\n internal _packedDistributionLimitDataOf;\n\n /// @notice Data regarding the overflow allowance of a project during a configuration.\n /// @dev bits 0-231: The amount of overflow that a project is allowed to tap into on-demand throughout the configuration.\n /// @dev bits 232-255: The currency of the amount of overflow that a project is allowed to tap.\n /// @custom:param _projectId The ID of the project to get the packed overflow allowance data of.\n /// @custom:param _configuration The configuration during which the packed overflow allowance data applies.\n /// @custom:param _terminal The terminal managing the overflow.\n /// @custom:param _token The token for which overflow is being allowed.\n mapping(uint256 => mapping(uint256 => mapping(IJBPaymentTerminal => mapping(address => uint256))))\n internal _packedOverflowAllowanceDataOf;\n\n //*********************************************************************//\n // --------------- public immutable stored properties ---------------- //\n //*********************************************************************//\n\n /// @notice Mints ERC-721's that represent project ownership.\n IJBProjects public immutable override projects;\n\n /// @notice The contract storing all funding cycle configurations.\n IJBFundingCycleStore public immutable override fundingCycleStore;\n\n /// @notice The contract that manages token minting and burning.\n IJBTokenStore public immutable override tokenStore;\n\n /// @notice The contract that stores splits for each project.\n IJBSplitsStore public immutable override splitsStore;\n\n /// @notice A contract that stores fund access constraints for each project.\n IJBFundAccessConstraintsStore public immutable override fundAccessConstraintsStore;\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The current undistributed reserved token balance of.\n mapping(uint256 => uint256) public override reservedTokenBalanceOf;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice A project's funding cycle for the specified configuration along with its metadata.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The funding cycle.\n /// @return metadata The funding cycle's metadata.\n function getFundingCycleOf(\n uint256 _projectId,\n uint256 _configuration\n )\n external\n view\n override\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata)\n {\n fundingCycle = fundingCycleStore.get(_projectId, _configuration);\n metadata = fundingCycle.expandMetadata();\n }\n\n /// @notice A project's latest configured funding cycle along with its metadata and the ballot state of the configuration.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The latest configured funding cycle.\n /// @return metadata The latest configured funding cycle's metadata.\n /// @return ballotState The state of the configuration.\n function latestConfiguredFundingCycleOf(\n uint256 _projectId\n )\n external\n view\n override\n returns (\n JBFundingCycle memory fundingCycle,\n JBFundingCycleMetadata memory metadata,\n JBBallotState ballotState\n )\n {\n (fundingCycle, ballotState) = fundingCycleStore.latestConfiguredOf(_projectId);\n metadata = fundingCycle.expandMetadata();\n }\n\n /// @notice A project's current funding cycle along with its metadata.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The current funding cycle.\n /// @return metadata The current funding cycle's metadata.\n function currentFundingCycleOf(\n uint256 _projectId\n )\n external\n view\n override\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata)\n {\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n metadata = fundingCycle.expandMetadata();\n }\n\n /// @notice A project's queued funding cycle along with its metadata.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The queued funding cycle.\n /// @return metadata The queued funding cycle's metadata.\n function queuedFundingCycleOf(\n uint256 _projectId\n )\n external\n view\n override\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata)\n {\n fundingCycle = fundingCycleStore.queuedOf(_projectId);\n metadata = fundingCycle.expandMetadata();\n }\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice Gets the current total amount of outstanding tokens for a project.\n /// @param _projectId The ID of the project to get total outstanding tokens of.\n /// @return The current total amount of outstanding tokens for the project.\n function totalOutstandingTokensOf(uint256 _projectId) public view override returns (uint256) {\n // Add the reserved tokens to the total supply.\n return tokenStore.totalSupplyOf(_projectId) + reservedTokenBalanceOf[_projectId];\n }\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if the provided interface ID is supported.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(ERC165, IERC165) returns (bool) {\n return\n _interfaceId == type(IJBController3_1).interfaceId ||\n _interfaceId == type(IJBController3_0_1).interfaceId ||\n _interfaceId == type(IJBMigratable).interfaceId ||\n _interfaceId == type(IJBOperatable).interfaceId ||\n super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // ---------------------------- constructor -------------------------- //\n //*********************************************************************//\n\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _fundingCycleStore A contract storing all funding cycle configurations.\n /// @param _tokenStore A contract that manages token minting and burning.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _fundAccessConstraintsStore A contract that stores fund access constraints for each project.\n constructor(\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBFundingCycleStore _fundingCycleStore,\n IJBTokenStore _tokenStore,\n IJBSplitsStore _splitsStore,\n IJBFundAccessConstraintsStore _fundAccessConstraintsStore\n ) JBOperatable(_operatorStore) {\n projects = _projects;\n directory = _directory;\n fundingCycleStore = _fundingCycleStore;\n tokenStore = _tokenStore;\n splitsStore = _splitsStore;\n fundAccessConstraintsStore = _fundAccessConstraintsStore;\n }\n\n //*********************************************************************//\n // --------------------- external transactions ----------------------- //\n //*********************************************************************//\n\n /// @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.\n /// @dev Each operation within this transaction can be done in sequence separately.\n /// @dev Anyone can deploy a project on an owner's behalf.\n /// @param _owner The address to set as the owner of the project. The project ERC-721 will be owned by this address.\n /// @param _projectMetadata Metadata to associate with the project within a particular domain. This can be updated any time by the owner of the project.\n /// @param _data Data that defines the project's first funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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`.\n /// @param _terminals Payment terminals to add for the project.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return projectId The ID of the project.\n function launchProjectFor(\n address _owner,\n JBProjectMetadata calldata _projectMetadata,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] calldata _groupedSplits,\n JBFundAccessConstraints[] calldata _fundAccessConstraints,\n IJBPaymentTerminal[] memory _terminals,\n string memory _memo\n ) external virtual override returns (uint256 projectId) {\n // Keep a reference to the directory.\n IJBDirectory _directory = directory;\n\n // Mint the project into the wallet of the owner.\n projectId = projects.createFor(_owner, _projectMetadata);\n\n // Set this contract as the project's controller in the directory.\n _directory.setControllerOf(projectId, address(this));\n\n // Configure the first funding cycle.\n uint256 _configuration = _configure(\n projectId,\n _data,\n _metadata,\n _mustStartAtOrAfter,\n _groupedSplits,\n _fundAccessConstraints\n );\n\n // Add the provided terminals to the list of terminals.\n if (_terminals.length > 0) _directory.setTerminalsOf(projectId, _terminals);\n\n emit LaunchProject(_configuration, projectId, _memo, msg.sender);\n }\n\n /// @notice Creates a funding cycle for an already existing project ERC-721.\n /// @dev Each operation within this transaction can be done in sequence separately.\n /// @dev Only a project owner or operator can launch its funding cycles.\n /// @param _projectId The ID of the project to launch funding cycles for.\n /// @param _data Data that defines the project's first funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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`.\n /// @param _terminals Payment terminals to add for the project.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return configuration The configuration of the funding cycle that was successfully created.\n function launchFundingCyclesFor(\n uint256 _projectId,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] calldata _groupedSplits,\n JBFundAccessConstraints[] memory _fundAccessConstraints,\n IJBPaymentTerminal[] memory _terminals,\n string memory _memo\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.RECONFIGURE)\n returns (uint256 configuration)\n {\n // If there is a previous configuration, reconfigureFundingCyclesOf should be called instead\n if (fundingCycleStore.latestConfigurationOf(_projectId) > 0)\n revert FUNDING_CYCLE_ALREADY_LAUNCHED();\n\n // Set this contract as the project's controller in the directory.\n directory.setControllerOf(_projectId, address(this));\n\n // Configure the first funding cycle.\n configuration = _configure(\n _projectId,\n _data,\n _metadata,\n _mustStartAtOrAfter,\n _groupedSplits,\n _fundAccessConstraints\n );\n\n // Add the provided terminals to the list of terminals.\n if (_terminals.length > 0) directory.setTerminalsOf(_projectId, _terminals);\n\n emit LaunchFundingCycles(configuration, _projectId, _memo, msg.sender);\n }\n\n /// @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.\n /// @dev Only a project's owner or a designated operator can configure its funding cycles.\n /// @param _projectId The ID of the project whose funding cycles are being reconfigured.\n /// @param _data Data that defines the funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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`.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return configuration The configuration of the funding cycle that was successfully reconfigured.\n function reconfigureFundingCyclesOf(\n uint256 _projectId,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] calldata _groupedSplits,\n JBFundAccessConstraints[] calldata _fundAccessConstraints,\n string calldata _memo\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.RECONFIGURE)\n returns (uint256 configuration)\n {\n // Configure the next funding cycle.\n configuration = _configure(\n _projectId,\n _data,\n _metadata,\n _mustStartAtOrAfter,\n _groupedSplits,\n _fundAccessConstraints\n );\n\n emit ReconfigureFundingCycles(configuration, _projectId, _memo, msg.sender);\n }\n\n /// @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.\n /// @dev Only a project's owner, a designated operator, one of its terminals, or the current data source can mint its tokens.\n /// @param _projectId The ID of the project to which the tokens being minted belong.\n /// @param _tokenCount The amount of tokens to mint in total, counting however many should be reserved.\n /// @param _beneficiary The account that the tokens are being minted for.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _preferClaimedTokens A flag indicating whether a project's attached token contract should be minted if they have been issued.\n /// @param _useReservedRate Whether to use the current funding cycle's reserved rate in the mint calculation.\n /// @return beneficiaryTokenCount The amount of tokens minted for the beneficiary.\n function mintTokensOf(\n uint256 _projectId,\n uint256 _tokenCount,\n address _beneficiary,\n string calldata _memo,\n bool _preferClaimedTokens,\n bool _useReservedRate\n ) external virtual override returns (uint256 beneficiaryTokenCount) {\n // There should be tokens to mint.\n if (_tokenCount == 0) revert ZERO_TOKENS_TO_MINT();\n\n // Define variables that will be needed outside scoped section below.\n // Keep a reference to the reserved rate to use\n uint256 _reservedRate;\n\n // Scoped section prevents stack too deep. `_fundingCycle` only used within scope.\n {\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Minting limited to: project owner, authorized callers, project terminal and current funding cycle data source\n _requirePermissionAllowingOverride(\n projects.ownerOf(_projectId),\n _projectId,\n JBOperations.MINT,\n directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender)) ||\n msg.sender == address(_fundingCycle.dataSource())\n );\n\n // If the message sender is not a terminal or a datasource, the current funding cycle must allow minting.\n if (\n !_fundingCycle.mintingAllowed() &&\n !directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender)) &&\n msg.sender != address(_fundingCycle.dataSource())\n ) revert MINT_NOT_ALLOWED_AND_NOT_TERMINAL_DELEGATE();\n\n // Determine the reserved rate to use.\n _reservedRate = _useReservedRate ? _fundingCycle.reservedRate() : 0;\n\n // Override the claimed token preference with the funding cycle value.\n _preferClaimedTokens = _preferClaimedTokens == true\n ? _preferClaimedTokens\n : _fundingCycle.preferClaimedTokenOverride();\n }\n\n if (_reservedRate != JBConstants.MAX_RESERVED_RATE) {\n // The unreserved token count that will be minted for the beneficiary.\n beneficiaryTokenCount = PRBMath.mulDiv(\n _tokenCount,\n JBConstants.MAX_RESERVED_RATE - _reservedRate,\n JBConstants.MAX_RESERVED_RATE\n );\n\n // Mint the tokens.\n tokenStore.mintFor(_beneficiary, _projectId, beneficiaryTokenCount, _preferClaimedTokens);\n }\n\n // Add reserved tokens if needed\n if (_reservedRate > 0)\n reservedTokenBalanceOf[_projectId] += _tokenCount - beneficiaryTokenCount;\n\n emit MintTokens(\n _beneficiary,\n _projectId,\n _tokenCount,\n beneficiaryTokenCount,\n _memo,\n _reservedRate,\n msg.sender\n );\n }\n\n /// @notice Burns a token holder's supply.\n /// @dev Only a token's holder, a designated operator, or a project's terminal can burn it.\n /// @param _holder The account that is having its tokens burned.\n /// @param _projectId The ID of the project to which the tokens being burned belong.\n /// @param _tokenCount The number of tokens to burn.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _preferClaimedTokens A flag indicating whether a project's attached token contract should be burned first if they have been issued.\n function burnTokensOf(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n string calldata _memo,\n bool _preferClaimedTokens\n )\n external\n virtual\n override\n requirePermissionAllowingOverride(\n _holder,\n _projectId,\n JBOperations.BURN,\n directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender))\n )\n {\n // There should be tokens to burn\n if (_tokenCount == 0) revert NO_BURNABLE_TOKENS();\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // If the message sender is a terminal, the current funding cycle must not be paused.\n if (\n _fundingCycle.burnPaused() &&\n !directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender))\n ) revert BURN_PAUSED_AND_SENDER_NOT_VALID_TERMINAL_DELEGATE();\n\n // Burn the tokens.\n tokenStore.burnFrom(_holder, _projectId, _tokenCount, _preferClaimedTokens);\n\n emit BurnTokens(_holder, _projectId, _tokenCount, _memo, msg.sender);\n }\n\n /// @notice Distributes all outstanding reserved tokens for a project.\n /// @param _projectId The ID of the project to which the reserved tokens belong.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return The amount of minted reserved tokens.\n function distributeReservedTokensOf(\n uint256 _projectId,\n string calldata _memo\n ) external virtual override returns (uint256) {\n return _distributeReservedTokensOf(_projectId, _memo);\n }\n\n /// @notice Allows other controllers to signal to this one that a migration is expected for the specified project.\n /// @dev This controller should not yet be the project's controller.\n /// @param _projectId The ID of the project that will be migrated to this controller.\n /// @param _from The controller being migrated from.\n function prepForMigrationOf(uint256 _projectId, address _from) external virtual override {\n _projectId; // Prevents unused var compiler and natspec complaints.\n _from; // Prevents unused var compiler and natspec complaints.\n }\n\n /// @notice Allows a project to migrate from this controller to another.\n /// @dev Only a project's owner or a designated operator can migrate it.\n /// @param _projectId The ID of the project that will be migrated from this controller.\n /// @param _to The controller to which the project is migrating.\n function migrate(\n uint256 _projectId,\n IJBMigratable _to\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.MIGRATE_CONTROLLER)\n {\n // Keep a reference to the directory.\n IJBDirectory _directory = directory;\n\n // This controller must be the project's current controller.\n if (_directory.controllerOf(_projectId) != address(this)) revert NOT_CURRENT_CONTROLLER();\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Migration must be allowed.\n if (!_fundingCycle.controllerMigrationAllowed()) revert MIGRATION_NOT_ALLOWED();\n\n // All reserved tokens must be minted before migrating.\n if (reservedTokenBalanceOf[_projectId] != 0) _distributeReservedTokensOf(_projectId, '');\n\n // Make sure the new controller is prepped for the migration.\n _to.prepForMigrationOf(_projectId, address(this));\n\n // Set the new controller.\n _directory.setControllerOf(_projectId, address(_to));\n\n emit Migrate(_projectId, _to, msg.sender);\n }\n\n //*********************************************************************//\n // ------------------------ internal functions ----------------------- //\n //*********************************************************************//\n\n /// @notice Distributes all outstanding reserved tokens for a project.\n /// @param _projectId The ID of the project to which the reserved tokens belong.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return tokenCount The amount of minted reserved tokens.\n function _distributeReservedTokensOf(\n uint256 _projectId,\n string memory _memo\n ) internal returns (uint256 tokenCount) {\n // Keep a reference to the token store.\n IJBTokenStore _tokenStore = tokenStore;\n\n // Get the current funding cycle to read the reserved rate from.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Get a reference to the number of tokens that need to be minted.\n tokenCount = reservedTokenBalanceOf[_projectId];\n\n // Reset the reserved token balance\n reservedTokenBalanceOf[_projectId] = 0;\n\n // Get a reference to the project owner.\n address _owner = projects.ownerOf(_projectId);\n\n // Distribute tokens to splits and get a reference to the leftover amount to mint after all splits have gotten their share.\n uint256 _leftoverTokenCount = tokenCount == 0\n ? 0\n : _distributeToReservedTokenSplitsOf(\n _projectId,\n _fundingCycle.configuration,\n JBSplitsGroups.RESERVED_TOKENS,\n tokenCount\n );\n\n // Mint any leftover tokens to the project owner.\n if (_leftoverTokenCount > 0)\n _tokenStore.mintFor(_owner, _projectId, _leftoverTokenCount, false);\n\n emit DistributeReservedTokens(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _owner,\n tokenCount,\n _leftoverTokenCount,\n _memo,\n msg.sender\n );\n }\n\n /// @notice Distribute tokens to the splits according to the specified funding cycle configuration.\n /// @param _projectId The ID of the project for which reserved token splits are being distributed.\n /// @param _domain The domain of the splits to distribute the reserved tokens between.\n /// @param _group The group of the splits to distribute the reserved tokens between.\n /// @param _amount The total amount of tokens to mint.\n /// @return leftoverAmount If the splits percents dont add up to 100%, the leftover amount is returned.\n function _distributeToReservedTokenSplitsOf(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group,\n uint256 _amount\n ) internal returns (uint256 leftoverAmount) {\n // Keep a reference to the token store.\n IJBTokenStore _tokenStore = tokenStore;\n\n // Set the leftover amount to the initial amount.\n leftoverAmount = _amount;\n\n // Get a reference to the project's reserved token splits.\n JBSplit[] memory _splits = splitsStore.splitsOf(_projectId, _domain, _group);\n\n //Transfer between all splits.\n for (uint256 _i; _i < _splits.length; ) {\n // Get a reference to the split being iterated on.\n JBSplit memory _split = _splits[_i];\n\n // The amount to send towards the split.\n uint256 _tokenCount = PRBMath.mulDiv(\n _amount,\n _split.percent,\n JBConstants.SPLITS_TOTAL_PERCENT\n );\n\n // Mints tokens for the split if needed.\n if (_tokenCount > 0) {\n _tokenStore.mintFor(\n // If an allocator is set in the splits, set it as the beneficiary.\n // Otherwise if a projectId is set in the split, set the project's owner as the beneficiary.\n // If the split has a beneficiary send to the split's beneficiary. Otherwise send to the msg.sender.\n _split.allocator != IJBSplitAllocator(address(0))\n ? address(_split.allocator)\n : _split.projectId != 0\n ? projects.ownerOf(_split.projectId)\n : _split.beneficiary != address(0)\n ? _split.beneficiary\n : msg.sender,\n _projectId,\n _tokenCount,\n _split.preferClaimed\n );\n\n // If there's an allocator set, trigger its `allocate` function.\n if (_split.allocator != IJBSplitAllocator(address(0)))\n _split.allocator.allocate(\n JBSplitAllocationData(\n address(_tokenStore.tokenOf(_projectId)),\n _tokenCount,\n 18,\n _projectId,\n _group,\n _split\n )\n );\n\n // Subtract from the amount to be sent to the beneficiary.\n leftoverAmount = leftoverAmount - _tokenCount;\n }\n\n emit DistributeToReservedTokenSplit(\n _projectId,\n _domain,\n _group,\n _split,\n _tokenCount,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n\n /// @notice Configures a funding cycle and stores information pertinent to the configuration.\n /// @param _projectId The ID of the project whose funding cycles are being reconfigured.\n /// @param _data Data that defines the funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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.\n /// @return configuration The configuration of the funding cycle that was successfully reconfigured.\n function _configure(\n uint256 _projectId,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] memory _groupedSplits,\n JBFundAccessConstraints[] memory _fundAccessConstraints\n ) internal returns (uint256) {\n // Make sure the provided reserved rate is valid.\n if (_metadata.reservedRate > JBConstants.MAX_RESERVED_RATE) revert INVALID_RESERVED_RATE();\n\n // Make sure the provided redemption rate is valid.\n if (_metadata.redemptionRate > JBConstants.MAX_REDEMPTION_RATE)\n revert INVALID_REDEMPTION_RATE();\n\n // Make sure the provided ballot redemption rate is valid.\n if (_metadata.ballotRedemptionRate > JBConstants.MAX_REDEMPTION_RATE)\n revert INVALID_BALLOT_REDEMPTION_RATE();\n\n // Configure the funding cycle's properties.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.configureFor(\n _projectId,\n _data,\n JBFundingCycleMetadataResolver.packFundingCycleMetadata(_metadata),\n _mustStartAtOrAfter\n );\n\n // Set splits for the group.\n splitsStore.set(_projectId, _fundingCycle.configuration, _groupedSplits);\n\n // Set the funds access constraints.\n fundAccessConstraintsStore.setFor(\n _projectId,\n _fundingCycle.configuration,\n _fundAccessConstraints\n );\n\n return _fundingCycle.configuration;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/introspection/ERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC165.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n *\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n" + }, + "@paulrberg/contracts/math/PRBMath.sol": { + "content": "// SPDX-License-Identifier: Unlicense\npragma solidity >=0.8.4;\n\nimport \"prb-math/contracts/PRBMath.sol\";\n" + }, + "contracts/interfaces/IJBController3_0_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBController3_0_1 {\n function reservedTokenBalanceOf(uint256 projectId) external view returns (uint256);\n\n function totalOutstandingTokensOf(uint256 projectId) external view returns (uint256);\n}\n" + }, + "contracts/interfaces/IJBController3_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBBallotState} from './../enums/JBBallotState.sol';\nimport {JBFundAccessConstraints} from './../structs/JBFundAccessConstraints.sol';\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\nimport {JBFundingCycleData} from './../structs/JBFundingCycleData.sol';\nimport {JBFundingCycleMetadata} from './../structs/JBFundingCycleMetadata.sol';\nimport {JBGroupedSplits} from './../structs/JBGroupedSplits.sol';\nimport {JBProjectMetadata} from './../structs/JBProjectMetadata.sol';\nimport {JBSplit} from './../structs/JBSplit.sol';\nimport {IJBController3_0_1} from './IJBController3_0_1.sol';\nimport {IJBDirectory} from './IJBDirectory.sol';\nimport {IJBFundAccessConstraintsStore} from './IJBFundAccessConstraintsStore.sol';\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\nimport {IJBMigratable} from './IJBMigratable.sol';\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\nimport {IJBProjects} from './IJBProjects.sol';\nimport {IJBSplitsStore} from './IJBSplitsStore.sol';\nimport {IJBTokenStore} from './IJBTokenStore.sol';\n\ninterface IJBController3_1 is IJBController3_0_1, IERC165 {\n event LaunchProject(uint256 configuration, uint256 projectId, string memo, address caller);\n\n event LaunchFundingCycles(uint256 configuration, uint256 projectId, string memo, address caller);\n\n event ReconfigureFundingCycles(\n uint256 configuration,\n uint256 projectId,\n string memo,\n address caller\n );\n\n event DistributeReservedTokens(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n address beneficiary,\n uint256 tokenCount,\n uint256 beneficiaryTokenCount,\n string memo,\n address caller\n );\n\n event DistributeToReservedTokenSplit(\n uint256 indexed projectId,\n uint256 indexed domain,\n uint256 indexed group,\n JBSplit split,\n uint256 tokenCount,\n address caller\n );\n\n event MintTokens(\n address indexed beneficiary,\n uint256 indexed projectId,\n uint256 tokenCount,\n uint256 beneficiaryTokenCount,\n string memo,\n uint256 reservedRate,\n address caller\n );\n\n event BurnTokens(\n address indexed holder,\n uint256 indexed projectId,\n uint256 tokenCount,\n string memo,\n address caller\n );\n\n event Migrate(uint256 indexed projectId, IJBMigratable to, address caller);\n\n event PrepMigration(uint256 indexed projectId, address from, address caller);\n\n function projects() external view returns (IJBProjects);\n\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\n\n function tokenStore() external view returns (IJBTokenStore);\n\n function splitsStore() external view returns (IJBSplitsStore);\n\n function fundAccessConstraintsStore() external view returns (IJBFundAccessConstraintsStore);\n\n function directory() external view returns (IJBDirectory);\n\n function reservedTokenBalanceOf(uint256 projectId) external view returns (uint256);\n\n function totalOutstandingTokensOf(uint256 projectId) external view returns (uint256);\n\n function getFundingCycleOf(\n uint256 projectId,\n uint256 configuration\n )\n external\n view\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata);\n\n function latestConfiguredFundingCycleOf(\n uint256 projectId\n )\n external\n view\n returns (JBFundingCycle memory, JBFundingCycleMetadata memory metadata, JBBallotState);\n\n function currentFundingCycleOf(\n uint256 projectId\n )\n external\n view\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata);\n\n function queuedFundingCycleOf(\n uint256 projectId\n )\n external\n view\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata);\n\n function launchProjectFor(\n address owner,\n JBProjectMetadata calldata projectMetadata,\n JBFundingCycleData calldata data,\n JBFundingCycleMetadata calldata metadata,\n uint256 mustStartAtOrAfter,\n JBGroupedSplits[] memory groupedSplits,\n JBFundAccessConstraints[] memory fundAccessConstraints,\n IJBPaymentTerminal[] memory terminals,\n string calldata memo\n ) external returns (uint256 projectId);\n\n function launchFundingCyclesFor(\n uint256 projectId,\n JBFundingCycleData calldata data,\n JBFundingCycleMetadata calldata metadata,\n uint256 mustStartAtOrAfter,\n JBGroupedSplits[] memory groupedSplits,\n JBFundAccessConstraints[] memory fundAccessConstraints,\n IJBPaymentTerminal[] memory terminals,\n string calldata memo\n ) external returns (uint256 configuration);\n\n function reconfigureFundingCyclesOf(\n uint256 projectId,\n JBFundingCycleData calldata data,\n JBFundingCycleMetadata calldata metadata,\n uint256 mustStartAtOrAfter,\n JBGroupedSplits[] memory groupedSplits,\n JBFundAccessConstraints[] memory fundAccessConstraints,\n string calldata memo\n ) external returns (uint256);\n\n function mintTokensOf(\n uint256 projectId,\n uint256 tokenCount,\n address beneficiary,\n string calldata memo,\n bool preferClaimedTokens,\n bool useReservedRate\n ) external returns (uint256 beneficiaryTokenCount);\n\n function burnTokensOf(\n address holder,\n uint256 projectId,\n uint256 tokenCount,\n string calldata memo,\n bool preferClaimedTokens\n ) external;\n\n function distributeReservedTokensOf(\n uint256 projectId,\n string memory memo\n ) external returns (uint256);\n\n function migrate(uint256 projectId, IJBMigratable to) external;\n}\n" + }, + "contracts/interfaces/IJBController.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBBallotState} from './../enums/JBBallotState.sol';\nimport {JBFundAccessConstraints} from './../structs/JBFundAccessConstraints.sol';\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\nimport {JBFundingCycleData} from './../structs/JBFundingCycleData.sol';\nimport {JBFundingCycleMetadata} from './../structs/JBFundingCycleMetadata.sol';\nimport {JBGroupedSplits} from './../structs/JBGroupedSplits.sol';\nimport {JBProjectMetadata} from './../structs/JBProjectMetadata.sol';\nimport {JBSplit} from './../structs/JBSplit.sol';\nimport {IJBDirectory} from './IJBDirectory.sol';\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\nimport {IJBMigratable} from './IJBMigratable.sol';\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\nimport {IJBProjects} from './IJBProjects.sol';\nimport {IJBSplitsStore} from './IJBSplitsStore.sol';\nimport {IJBTokenStore} from './IJBTokenStore.sol';\n\ninterface IJBController is IERC165 {\n event LaunchProject(uint256 configuration, uint256 projectId, string memo, address caller);\n\n event LaunchFundingCycles(uint256 configuration, uint256 projectId, string memo, address caller);\n\n event ReconfigureFundingCycles(\n uint256 configuration,\n uint256 projectId,\n string memo,\n address caller\n );\n\n event SetFundAccessConstraints(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n JBFundAccessConstraints constraints,\n address caller\n );\n\n event DistributeReservedTokens(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n address beneficiary,\n uint256 tokenCount,\n uint256 beneficiaryTokenCount,\n string memo,\n address caller\n );\n\n event DistributeToReservedTokenSplit(\n uint256 indexed projectId,\n uint256 indexed domain,\n uint256 indexed group,\n JBSplit split,\n uint256 tokenCount,\n address caller\n );\n\n event MintTokens(\n address indexed beneficiary,\n uint256 indexed projectId,\n uint256 tokenCount,\n uint256 beneficiaryTokenCount,\n string memo,\n uint256 reservedRate,\n address caller\n );\n\n event BurnTokens(\n address indexed holder,\n uint256 indexed projectId,\n uint256 tokenCount,\n string memo,\n address caller\n );\n\n event Migrate(uint256 indexed projectId, IJBMigratable to, address caller);\n\n event PrepMigration(uint256 indexed projectId, address from, address caller);\n\n function projects() external view returns (IJBProjects);\n\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\n\n function tokenStore() external view returns (IJBTokenStore);\n\n function splitsStore() external view returns (IJBSplitsStore);\n\n function directory() external view returns (IJBDirectory);\n\n function reservedTokenBalanceOf(\n uint256 projectId,\n uint256 reservedRate\n ) external view returns (uint256);\n\n function distributionLimitOf(\n uint256 projectId,\n uint256 configuration,\n IJBPaymentTerminal terminal,\n address token\n ) external view returns (uint256 distributionLimit, uint256 distributionLimitCurrency);\n\n function overflowAllowanceOf(\n uint256 projectId,\n uint256 configuration,\n IJBPaymentTerminal terminal,\n address token\n ) external view returns (uint256 overflowAllowance, uint256 overflowAllowanceCurrency);\n\n function totalOutstandingTokensOf(\n uint256 projectId,\n uint256 reservedRate\n ) external view returns (uint256);\n\n function getFundingCycleOf(\n uint256 projectId,\n uint256 configuration\n )\n external\n view\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata);\n\n function latestConfiguredFundingCycleOf(\n uint256 projectId\n )\n external\n view\n returns (JBFundingCycle memory, JBFundingCycleMetadata memory metadata, JBBallotState);\n\n function currentFundingCycleOf(\n uint256 projectId\n )\n external\n view\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata);\n\n function queuedFundingCycleOf(\n uint256 projectId\n )\n external\n view\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata);\n\n function launchProjectFor(\n address owner,\n JBProjectMetadata calldata projectMetadata,\n JBFundingCycleData calldata data,\n JBFundingCycleMetadata calldata metadata,\n uint256 mustStartAtOrAfter,\n JBGroupedSplits[] memory groupedSplits,\n JBFundAccessConstraints[] memory fundAccessConstraints,\n IJBPaymentTerminal[] memory terminals,\n string calldata memo\n ) external returns (uint256 projectId);\n\n function launchFundingCyclesFor(\n uint256 projectId,\n JBFundingCycleData calldata data,\n JBFundingCycleMetadata calldata metadata,\n uint256 mustStartAtOrAfter,\n JBGroupedSplits[] memory groupedSplits,\n JBFundAccessConstraints[] memory fundAccessConstraints,\n IJBPaymentTerminal[] memory terminals,\n string calldata memo\n ) external returns (uint256 configuration);\n\n function reconfigureFundingCyclesOf(\n uint256 projectId,\n JBFundingCycleData calldata data,\n JBFundingCycleMetadata calldata metadata,\n uint256 mustStartAtOrAfter,\n JBGroupedSplits[] memory groupedSplits,\n JBFundAccessConstraints[] memory fundAccessConstraints,\n string calldata memo\n ) external returns (uint256);\n\n function mintTokensOf(\n uint256 projectId,\n uint256 tokenCount,\n address beneficiary,\n string calldata memo,\n bool preferClaimedTokens,\n bool useReservedRate\n ) external returns (uint256 beneficiaryTokenCount);\n\n function burnTokensOf(\n address holder,\n uint256 projectId,\n uint256 tokenCount,\n string calldata memo,\n bool preferClaimedTokens\n ) external;\n\n function distributeReservedTokensOf(\n uint256 projectId,\n string memory memo\n ) external returns (uint256);\n\n function migrate(uint256 projectId, IJBMigratable to) external;\n}\n" + }, + "contracts/interfaces/IJBFundAccessConstraintsStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBFundAccessConstraints} from './../structs/JBFundAccessConstraints.sol';\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\n\ninterface IJBFundAccessConstraintsStore is IERC165 {\n event SetFundAccessConstraints(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed projectId,\n JBFundAccessConstraints constraints,\n address caller\n );\n\n function distributionLimitOf(\n uint256 projectId,\n uint256 configuration,\n IJBPaymentTerminal terminal,\n address token\n ) external view returns (uint256 distributionLimit, uint256 distributionLimitCurrency);\n\n function overflowAllowanceOf(\n uint256 projectId,\n uint256 configuration,\n IJBPaymentTerminal terminal,\n address token\n ) external view returns (uint256 overflowAllowance, uint256 overflowAllowanceCurrency);\n\n function setFor(\n uint256 projectId,\n uint256 configuration,\n JBFundAccessConstraints[] memory fundAccessConstaints\n ) external;\n}\n" + }, + "contracts/interfaces/IJBMigratable.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBMigratable {\n function prepForMigrationOf(uint256 projectId, address from) external;\n}\n" + }, + "contracts/interfaces/IJBSplitAllocator.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBSplitAllocationData} from '../structs/JBSplitAllocationData.sol';\n\n/// @title Split allocator\n/// @notice Provide a way to process a single split with extra logic\n/// @dev The contract address should be set as an allocator in the adequate split\ninterface IJBSplitAllocator is IERC165 {\n /// @notice This function is called by JBPaymentTerminal.distributePayoutOf(..), during the processing of the split including it\n /// @dev Critical business logic should be protected by an appropriate access control. The token and/or eth are optimistically transfered to the allocator for its logic.\n /// @param data the data passed by the terminal, as a JBSplitAllocationData struct:\n function allocate(JBSplitAllocationData calldata data) external payable;\n}\n" + }, + "contracts/interfaces/IJBSplitsStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBGroupedSplits} from './../structs/JBGroupedSplits.sol';\nimport {JBSplit} from './../structs/JBSplit.sol';\nimport {IJBDirectory} from './IJBDirectory.sol';\nimport {IJBProjects} from './IJBProjects.sol';\n\ninterface IJBSplitsStore {\n event SetSplit(\n uint256 indexed projectId,\n uint256 indexed domain,\n uint256 indexed group,\n JBSplit split,\n address caller\n );\n\n function projects() external view returns (IJBProjects);\n\n function directory() external view returns (IJBDirectory);\n\n function splitsOf(\n uint256 projectId,\n uint256 domain,\n uint256 group\n ) external view returns (JBSplit[] memory);\n\n function set(uint256 projectId, uint256 domain, JBGroupedSplits[] memory groupedSplits) external;\n}\n" + }, + "contracts/libraries/JBSplitsGroups.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nlibrary JBSplitsGroups {\n uint256 public constant ETH_PAYOUT = 1;\n uint256 public constant RESERVED_TOKENS = 2;\n}\n" + }, + "contracts/structs/JBSplitAllocationData.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBSplit} from './JBSplit.sol';\n\n/// @custom:member token The token being sent to the split allocator.\n/// @custom:member amount The amount being sent to the split allocator, as a fixed point number.\n/// @custom:member decimals The number of decimals in the amount.\n/// @custom:member projectId The project to which the split belongs.\n/// @custom:member group The group to which the split belongs.\n/// @custom:member split The split that caused the allocation.\nstruct JBSplitAllocationData {\n address token;\n uint256 amount;\n uint256 decimals;\n uint256 projectId;\n uint256 group;\n JBSplit split;\n}\n" + }, + "contracts/structs/JBFundAccessConstraints.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\n\n/// @custom:member terminal The terminal within which the distribution limit and the overflow allowance applies.\n/// @custom:member token The token for which the fund access constraints apply.\n/// @custom:member distributionLimit The amount of the distribution limit, as a fixed point number with the same number of decimals as the terminal within which the limit applies.\n/// @custom:member distributionLimitCurrency The currency of the distribution limit.\n/// @custom:member overflowAllowance The amount of the allowance, as a fixed point number with the same number of decimals as the terminal within which the allowance applies.\n/// @custom:member overflowAllowanceCurrency The currency of the overflow allowance.\nstruct JBFundAccessConstraints {\n IJBPaymentTerminal terminal;\n address token;\n uint256 distributionLimit;\n uint256 distributionLimitCurrency;\n uint256 overflowAllowance;\n uint256 overflowAllowanceCurrency;\n}\n" + }, + "contracts/structs/JBGroupedSplits.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBSplit} from './JBSplit.sol';\n\n/// @custom:member group The group indentifier.\n/// @custom:member splits The splits to associate with the group.\nstruct JBGroupedSplits {\n uint256 group;\n JBSplit[] splits;\n}\n" + }, + "contracts/structs/JBSplit.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBSplitAllocator} from './../interfaces/IJBSplitAllocator.sol';\n\n/// @custom:member preferClaimed A flag that only has effect if a projectId is also specified, and the project has a token contract attached. If so, this flag indicates if the tokens that result from making a payment to the project should be delivered claimed into the beneficiary's wallet, or unclaimed to save gas.\n/// @custom:member preferAddToBalance A flag indicating if a distribution to a project should prefer triggering it's addToBalance function instead of its pay function.\n/// @custom:member percent The percent of the whole group that this split occupies. This number is out of `JBConstants.SPLITS_TOTAL_PERCENT`.\n/// @custom:member projectId The ID of a project. If an allocator is not set but a projectId is set, funds will be sent to the protocol treasury belonging to the project who's ID is specified. Resulting tokens will be routed to the beneficiary with the claimed token preference respected.\n/// @custom:member beneficiary An address. The role the of the beneficary depends on whether or not projectId is specified, and whether or not an allocator is specified. If allocator is set, the beneficiary will be forwarded to the allocator for it to use. If allocator is not set but projectId is set, the beneficiary is the address to which the project's tokens will be sent that result from a payment to it. If neither allocator or projectId are set, the beneficiary is where the funds from the split will be sent.\n/// @custom:member lockedUntil Specifies if the split should be unchangeable until the specified time, with the exception of extending the locked period.\n/// @custom:member allocator If an allocator is specified, funds will be sent to the allocator contract along with all properties of this split.\nstruct JBSplit {\n bool preferClaimed;\n bool preferAddToBalance;\n uint256 percent;\n uint256 projectId;\n address payable beneficiary;\n uint256 lockedUntil;\n IJBSplitAllocator allocator;\n}\n" + }, + "prb-math/contracts/PRBMath.sol": { + "content": "// SPDX-License-Identifier: Unlicense\npragma solidity >=0.8.4;\n\n/// @notice Emitted when the result overflows uint256.\nerror PRBMath__MulDivFixedPointOverflow(uint256 prod1);\n\n/// @notice Emitted when the result overflows uint256.\nerror PRBMath__MulDivOverflow(uint256 prod1, uint256 denominator);\n\n/// @notice Emitted when one of the inputs is type(int256).min.\nerror PRBMath__MulDivSignedInputTooSmall();\n\n/// @notice Emitted when the intermediary absolute result overflows int256.\nerror PRBMath__MulDivSignedOverflow(uint256 rAbs);\n\n/// @notice Emitted when the input is MIN_SD59x18.\nerror PRBMathSD59x18__AbsInputTooSmall();\n\n/// @notice Emitted when ceiling a number overflows SD59x18.\nerror PRBMathSD59x18__CeilOverflow(int256 x);\n\n/// @notice Emitted when one of the inputs is MIN_SD59x18.\nerror PRBMathSD59x18__DivInputTooSmall();\n\n/// @notice Emitted when one of the intermediary unsigned results overflows SD59x18.\nerror PRBMathSD59x18__DivOverflow(uint256 rAbs);\n\n/// @notice Emitted when the input is greater than 133.084258667509499441.\nerror PRBMathSD59x18__ExpInputTooBig(int256 x);\n\n/// @notice Emitted when the input is greater than 192.\nerror PRBMathSD59x18__Exp2InputTooBig(int256 x);\n\n/// @notice Emitted when flooring a number underflows SD59x18.\nerror PRBMathSD59x18__FloorUnderflow(int256 x);\n\n/// @notice Emitted when converting a basic integer to the fixed-point format overflows SD59x18.\nerror PRBMathSD59x18__FromIntOverflow(int256 x);\n\n/// @notice Emitted when converting a basic integer to the fixed-point format underflows SD59x18.\nerror PRBMathSD59x18__FromIntUnderflow(int256 x);\n\n/// @notice Emitted when the product of the inputs is negative.\nerror PRBMathSD59x18__GmNegativeProduct(int256 x, int256 y);\n\n/// @notice Emitted when multiplying the inputs overflows SD59x18.\nerror PRBMathSD59x18__GmOverflow(int256 x, int256 y);\n\n/// @notice Emitted when the input is less than or equal to zero.\nerror PRBMathSD59x18__LogInputTooSmall(int256 x);\n\n/// @notice Emitted when one of the inputs is MIN_SD59x18.\nerror PRBMathSD59x18__MulInputTooSmall();\n\n/// @notice Emitted when the intermediary absolute result overflows SD59x18.\nerror PRBMathSD59x18__MulOverflow(uint256 rAbs);\n\n/// @notice Emitted when the intermediary absolute result overflows SD59x18.\nerror PRBMathSD59x18__PowuOverflow(uint256 rAbs);\n\n/// @notice Emitted when the input is negative.\nerror PRBMathSD59x18__SqrtNegativeInput(int256 x);\n\n/// @notice Emitted when the calculating the square root overflows SD59x18.\nerror PRBMathSD59x18__SqrtOverflow(int256 x);\n\n/// @notice Emitted when addition overflows UD60x18.\nerror PRBMathUD60x18__AddOverflow(uint256 x, uint256 y);\n\n/// @notice Emitted when ceiling a number overflows UD60x18.\nerror PRBMathUD60x18__CeilOverflow(uint256 x);\n\n/// @notice Emitted when the input is greater than 133.084258667509499441.\nerror PRBMathUD60x18__ExpInputTooBig(uint256 x);\n\n/// @notice Emitted when the input is greater than 192.\nerror PRBMathUD60x18__Exp2InputTooBig(uint256 x);\n\n/// @notice Emitted when converting a basic integer to the fixed-point format format overflows UD60x18.\nerror PRBMathUD60x18__FromUintOverflow(uint256 x);\n\n/// @notice Emitted when multiplying the inputs overflows UD60x18.\nerror PRBMathUD60x18__GmOverflow(uint256 x, uint256 y);\n\n/// @notice Emitted when the input is less than 1.\nerror PRBMathUD60x18__LogInputTooSmall(uint256 x);\n\n/// @notice Emitted when the calculating the square root overflows UD60x18.\nerror PRBMathUD60x18__SqrtOverflow(uint256 x);\n\n/// @notice Emitted when subtraction underflows UD60x18.\nerror PRBMathUD60x18__SubUnderflow(uint256 x, uint256 y);\n\n/// @dev Common mathematical functions used in both PRBMathSD59x18 and PRBMathUD60x18. Note that this shared library\n/// does not always assume the signed 59.18-decimal fixed-point or the unsigned 60.18-decimal fixed-point\n/// representation. When it does not, it is explicitly mentioned in the NatSpec documentation.\nlibrary PRBMath {\n /// STRUCTS ///\n\n struct SD59x18 {\n int256 value;\n }\n\n struct UD60x18 {\n uint256 value;\n }\n\n /// STORAGE ///\n\n /// @dev How many trailing decimals can be represented.\n uint256 internal constant SCALE = 1e18;\n\n /// @dev Largest power of two divisor of SCALE.\n uint256 internal constant SCALE_LPOTD = 262144;\n\n /// @dev SCALE inverted mod 2^256.\n uint256 internal constant SCALE_INVERSE =\n 78156646155174841979727994598816262306175212592076161876661_508869554232690281;\n\n /// FUNCTIONS ///\n\n /// @notice Calculates the binary exponent of x using the binary fraction method.\n /// @dev Has to use 192.64-bit fixed-point numbers.\n /// See https://ethereum.stackexchange.com/a/96594/24693.\n /// @param x The exponent as an unsigned 192.64-bit fixed-point number.\n /// @return result The result as an unsigned 60.18-decimal fixed-point number.\n function exp2(uint256 x) internal pure returns (uint256 result) {\n unchecked {\n // Start from 0.5 in the 192.64-bit fixed-point format.\n result = 0x800000000000000000000000000000000000000000000000;\n\n // Multiply the result by root(2, 2^-i) when the bit at position i is 1. None of the intermediary results overflows\n // because the initial result is 2^191 and all magic factors are less than 2^65.\n if (x & 0x8000000000000000 > 0) {\n result = (result * 0x16A09E667F3BCC909) >> 64;\n }\n if (x & 0x4000000000000000 > 0) {\n result = (result * 0x1306FE0A31B7152DF) >> 64;\n }\n if (x & 0x2000000000000000 > 0) {\n result = (result * 0x1172B83C7D517ADCE) >> 64;\n }\n if (x & 0x1000000000000000 > 0) {\n result = (result * 0x10B5586CF9890F62A) >> 64;\n }\n if (x & 0x800000000000000 > 0) {\n result = (result * 0x1059B0D31585743AE) >> 64;\n }\n if (x & 0x400000000000000 > 0) {\n result = (result * 0x102C9A3E778060EE7) >> 64;\n }\n if (x & 0x200000000000000 > 0) {\n result = (result * 0x10163DA9FB33356D8) >> 64;\n }\n if (x & 0x100000000000000 > 0) {\n result = (result * 0x100B1AFA5ABCBED61) >> 64;\n }\n if (x & 0x80000000000000 > 0) {\n result = (result * 0x10058C86DA1C09EA2) >> 64;\n }\n if (x & 0x40000000000000 > 0) {\n result = (result * 0x1002C605E2E8CEC50) >> 64;\n }\n if (x & 0x20000000000000 > 0) {\n result = (result * 0x100162F3904051FA1) >> 64;\n }\n if (x & 0x10000000000000 > 0) {\n result = (result * 0x1000B175EFFDC76BA) >> 64;\n }\n if (x & 0x8000000000000 > 0) {\n result = (result * 0x100058BA01FB9F96D) >> 64;\n }\n if (x & 0x4000000000000 > 0) {\n result = (result * 0x10002C5CC37DA9492) >> 64;\n }\n if (x & 0x2000000000000 > 0) {\n result = (result * 0x1000162E525EE0547) >> 64;\n }\n if (x & 0x1000000000000 > 0) {\n result = (result * 0x10000B17255775C04) >> 64;\n }\n if (x & 0x800000000000 > 0) {\n result = (result * 0x1000058B91B5BC9AE) >> 64;\n }\n if (x & 0x400000000000 > 0) {\n result = (result * 0x100002C5C89D5EC6D) >> 64;\n }\n if (x & 0x200000000000 > 0) {\n result = (result * 0x10000162E43F4F831) >> 64;\n }\n if (x & 0x100000000000 > 0) {\n result = (result * 0x100000B1721BCFC9A) >> 64;\n }\n if (x & 0x80000000000 > 0) {\n result = (result * 0x10000058B90CF1E6E) >> 64;\n }\n if (x & 0x40000000000 > 0) {\n result = (result * 0x1000002C5C863B73F) >> 64;\n }\n if (x & 0x20000000000 > 0) {\n result = (result * 0x100000162E430E5A2) >> 64;\n }\n if (x & 0x10000000000 > 0) {\n result = (result * 0x1000000B172183551) >> 64;\n }\n if (x & 0x8000000000 > 0) {\n result = (result * 0x100000058B90C0B49) >> 64;\n }\n if (x & 0x4000000000 > 0) {\n result = (result * 0x10000002C5C8601CC) >> 64;\n }\n if (x & 0x2000000000 > 0) {\n result = (result * 0x1000000162E42FFF0) >> 64;\n }\n if (x & 0x1000000000 > 0) {\n result = (result * 0x10000000B17217FBB) >> 64;\n }\n if (x & 0x800000000 > 0) {\n result = (result * 0x1000000058B90BFCE) >> 64;\n }\n if (x & 0x400000000 > 0) {\n result = (result * 0x100000002C5C85FE3) >> 64;\n }\n if (x & 0x200000000 > 0) {\n result = (result * 0x10000000162E42FF1) >> 64;\n }\n if (x & 0x100000000 > 0) {\n result = (result * 0x100000000B17217F8) >> 64;\n }\n if (x & 0x80000000 > 0) {\n result = (result * 0x10000000058B90BFC) >> 64;\n }\n if (x & 0x40000000 > 0) {\n result = (result * 0x1000000002C5C85FE) >> 64;\n }\n if (x & 0x20000000 > 0) {\n result = (result * 0x100000000162E42FF) >> 64;\n }\n if (x & 0x10000000 > 0) {\n result = (result * 0x1000000000B17217F) >> 64;\n }\n if (x & 0x8000000 > 0) {\n result = (result * 0x100000000058B90C0) >> 64;\n }\n if (x & 0x4000000 > 0) {\n result = (result * 0x10000000002C5C860) >> 64;\n }\n if (x & 0x2000000 > 0) {\n result = (result * 0x1000000000162E430) >> 64;\n }\n if (x & 0x1000000 > 0) {\n result = (result * 0x10000000000B17218) >> 64;\n }\n if (x & 0x800000 > 0) {\n result = (result * 0x1000000000058B90C) >> 64;\n }\n if (x & 0x400000 > 0) {\n result = (result * 0x100000000002C5C86) >> 64;\n }\n if (x & 0x200000 > 0) {\n result = (result * 0x10000000000162E43) >> 64;\n }\n if (x & 0x100000 > 0) {\n result = (result * 0x100000000000B1721) >> 64;\n }\n if (x & 0x80000 > 0) {\n result = (result * 0x10000000000058B91) >> 64;\n }\n if (x & 0x40000 > 0) {\n result = (result * 0x1000000000002C5C8) >> 64;\n }\n if (x & 0x20000 > 0) {\n result = (result * 0x100000000000162E4) >> 64;\n }\n if (x & 0x10000 > 0) {\n result = (result * 0x1000000000000B172) >> 64;\n }\n if (x & 0x8000 > 0) {\n result = (result * 0x100000000000058B9) >> 64;\n }\n if (x & 0x4000 > 0) {\n result = (result * 0x10000000000002C5D) >> 64;\n }\n if (x & 0x2000 > 0) {\n result = (result * 0x1000000000000162E) >> 64;\n }\n if (x & 0x1000 > 0) {\n result = (result * 0x10000000000000B17) >> 64;\n }\n if (x & 0x800 > 0) {\n result = (result * 0x1000000000000058C) >> 64;\n }\n if (x & 0x400 > 0) {\n result = (result * 0x100000000000002C6) >> 64;\n }\n if (x & 0x200 > 0) {\n result = (result * 0x10000000000000163) >> 64;\n }\n if (x & 0x100 > 0) {\n result = (result * 0x100000000000000B1) >> 64;\n }\n if (x & 0x80 > 0) {\n result = (result * 0x10000000000000059) >> 64;\n }\n if (x & 0x40 > 0) {\n result = (result * 0x1000000000000002C) >> 64;\n }\n if (x & 0x20 > 0) {\n result = (result * 0x10000000000000016) >> 64;\n }\n if (x & 0x10 > 0) {\n result = (result * 0x1000000000000000B) >> 64;\n }\n if (x & 0x8 > 0) {\n result = (result * 0x10000000000000006) >> 64;\n }\n if (x & 0x4 > 0) {\n result = (result * 0x10000000000000003) >> 64;\n }\n if (x & 0x2 > 0) {\n result = (result * 0x10000000000000001) >> 64;\n }\n if (x & 0x1 > 0) {\n result = (result * 0x10000000000000001) >> 64;\n }\n\n // We're doing two things at the same time:\n //\n // 1. Multiply the result by 2^n + 1, where \"2^n\" is the integer part and the one is added to account for\n // the fact that we initially set the result to 0.5. This is accomplished by subtracting from 191\n // rather than 192.\n // 2. Convert the result to the unsigned 60.18-decimal fixed-point format.\n //\n // This works because 2^(191-ip) = 2^ip / 2^191, where \"ip\" is the integer part \"2^n\".\n result *= SCALE;\n result >>= (191 - (x >> 64));\n }\n }\n\n /// @notice Finds the zero-based index of the first one in the binary representation of x.\n /// @dev See the note on msb in the \"Find First Set\" Wikipedia article https://en.wikipedia.org/wiki/Find_first_set\n /// @param x The uint256 number for which to find the index of the most significant bit.\n /// @return msb The index of the most significant bit as an uint256.\n function mostSignificantBit(uint256 x) internal pure returns (uint256 msb) {\n if (x >= 2**128) {\n x >>= 128;\n msb += 128;\n }\n if (x >= 2**64) {\n x >>= 64;\n msb += 64;\n }\n if (x >= 2**32) {\n x >>= 32;\n msb += 32;\n }\n if (x >= 2**16) {\n x >>= 16;\n msb += 16;\n }\n if (x >= 2**8) {\n x >>= 8;\n msb += 8;\n }\n if (x >= 2**4) {\n x >>= 4;\n msb += 4;\n }\n if (x >= 2**2) {\n x >>= 2;\n msb += 2;\n }\n if (x >= 2**1) {\n // No need to shift x any more.\n msb += 1;\n }\n }\n\n /// @notice Calculates floor(x*y÷denominator) with full precision.\n ///\n /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv.\n ///\n /// Requirements:\n /// - The denominator cannot be zero.\n /// - The result must fit within uint256.\n ///\n /// Caveats:\n /// - This function does not work with fixed-point numbers.\n ///\n /// @param x The multiplicand as an uint256.\n /// @param y The multiplier as an uint256.\n /// @param denominator The divisor as an uint256.\n /// @return result The result as an uint256.\n function mulDiv(\n uint256 x,\n uint256 y,\n uint256 denominator\n ) internal pure returns (uint256 result) {\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n // variables such that product = prod1 * 2^256 + prod0.\n uint256 prod0; // Least significant 256 bits of the product\n uint256 prod1; // Most significant 256 bits of the product\n assembly {\n let mm := mulmod(x, y, not(0))\n prod0 := mul(x, y)\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n }\n\n // Handle non-overflow cases, 256 by 256 division.\n if (prod1 == 0) {\n unchecked {\n result = prod0 / denominator;\n }\n return result;\n }\n\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\n if (prod1 >= denominator) {\n revert PRBMath__MulDivOverflow(prod1, denominator);\n }\n\n ///////////////////////////////////////////////\n // 512 by 256 division.\n ///////////////////////////////////////////////\n\n // Make division exact by subtracting the remainder from [prod1 prod0].\n uint256 remainder;\n assembly {\n // Compute remainder using mulmod.\n remainder := mulmod(x, y, denominator)\n\n // Subtract 256 bit number from 512 bit number.\n prod1 := sub(prod1, gt(remainder, prod0))\n prod0 := sub(prod0, remainder)\n }\n\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\n // See https://cs.stackexchange.com/q/138556/92363.\n unchecked {\n // Does not overflow because the denominator cannot be zero at this stage in the function.\n uint256 lpotdod = denominator & (~denominator + 1);\n assembly {\n // Divide denominator by lpotdod.\n denominator := div(denominator, lpotdod)\n\n // Divide [prod1 prod0] by lpotdod.\n prod0 := div(prod0, lpotdod)\n\n // Flip lpotdod such that it is 2^256 / lpotdod. If lpotdod is zero, then it becomes one.\n lpotdod := add(div(sub(0, lpotdod), lpotdod), 1)\n }\n\n // Shift in bits from prod1 into prod0.\n prod0 |= prod1 * lpotdod;\n\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\n // four bits. That is, denominator * inv = 1 mod 2^4.\n uint256 inverse = (3 * denominator) ^ 2;\n\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\n // in modular arithmetic, doubling the correct bits in each step.\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\n\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\n // is no longer required.\n result = prod0 * inverse;\n return result;\n }\n }\n\n /// @notice Calculates floor(x*y÷1e18) with full precision.\n ///\n /// @dev Variant of \"mulDiv\" with constant folding, i.e. in which the denominator is always 1e18. Before returning the\n /// final result, we add 1 if (x * y) % SCALE >= HALF_SCALE. Without this, 6.6e-19 would be truncated to 0 instead of\n /// being rounded to 1e-18. See \"Listing 6\" and text above it at https://accu.org/index.php/journals/1717.\n ///\n /// Requirements:\n /// - The result must fit within uint256.\n ///\n /// Caveats:\n /// - The body is purposely left uncommented; see the NatSpec comments in \"PRBMath.mulDiv\" to understand how this works.\n /// - It is assumed that the result can never be type(uint256).max when x and y solve the following two equations:\n /// 1. x * y = type(uint256).max * SCALE\n /// 2. (x * y) % SCALE >= SCALE / 2\n ///\n /// @param x The multiplicand as an unsigned 60.18-decimal fixed-point number.\n /// @param y The multiplier as an unsigned 60.18-decimal fixed-point number.\n /// @return result The result as an unsigned 60.18-decimal fixed-point number.\n function mulDivFixedPoint(uint256 x, uint256 y) internal pure returns (uint256 result) {\n uint256 prod0;\n uint256 prod1;\n assembly {\n let mm := mulmod(x, y, not(0))\n prod0 := mul(x, y)\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n }\n\n if (prod1 >= SCALE) {\n revert PRBMath__MulDivFixedPointOverflow(prod1);\n }\n\n uint256 remainder;\n uint256 roundUpUnit;\n assembly {\n remainder := mulmod(x, y, SCALE)\n roundUpUnit := gt(remainder, 499999999999999999)\n }\n\n if (prod1 == 0) {\n unchecked {\n result = (prod0 / SCALE) + roundUpUnit;\n return result;\n }\n }\n\n assembly {\n result := add(\n mul(\n or(\n div(sub(prod0, remainder), SCALE_LPOTD),\n mul(sub(prod1, gt(remainder, prod0)), add(div(sub(0, SCALE_LPOTD), SCALE_LPOTD), 1))\n ),\n SCALE_INVERSE\n ),\n roundUpUnit\n )\n }\n }\n\n /// @notice Calculates floor(x*y÷denominator) with full precision.\n ///\n /// @dev An extension of \"mulDiv\" for signed numbers. Works by computing the signs and the absolute values separately.\n ///\n /// Requirements:\n /// - None of the inputs can be type(int256).min.\n /// - The result must fit within int256.\n ///\n /// @param x The multiplicand as an int256.\n /// @param y The multiplier as an int256.\n /// @param denominator The divisor as an int256.\n /// @return result The result as an int256.\n function mulDivSigned(\n int256 x,\n int256 y,\n int256 denominator\n ) internal pure returns (int256 result) {\n if (x == type(int256).min || y == type(int256).min || denominator == type(int256).min) {\n revert PRBMath__MulDivSignedInputTooSmall();\n }\n\n // Get hold of the absolute values of x, y and the denominator.\n uint256 ax;\n uint256 ay;\n uint256 ad;\n unchecked {\n ax = x < 0 ? uint256(-x) : uint256(x);\n ay = y < 0 ? uint256(-y) : uint256(y);\n ad = denominator < 0 ? uint256(-denominator) : uint256(denominator);\n }\n\n // Compute the absolute value of (x*y)÷denominator. The result must fit within int256.\n uint256 rAbs = mulDiv(ax, ay, ad);\n if (rAbs > uint256(type(int256).max)) {\n revert PRBMath__MulDivSignedOverflow(rAbs);\n }\n\n // Get the signs of x, y and the denominator.\n uint256 sx;\n uint256 sy;\n uint256 sd;\n assembly {\n sx := sgt(x, sub(0, 1))\n sy := sgt(y, sub(0, 1))\n sd := sgt(denominator, sub(0, 1))\n }\n\n // XOR over sx, sy and sd. This is checking whether there are one or three negative signs in the inputs.\n // If yes, the result should be negative.\n result = sx ^ sy ^ sd == 0 ? -int256(rAbs) : int256(rAbs);\n }\n\n /// @notice Calculates the square root of x, rounding down.\n /// @dev Uses the Babylonian method https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method.\n ///\n /// Caveats:\n /// - This function does not work with fixed-point numbers.\n ///\n /// @param x The uint256 number for which to calculate the square root.\n /// @return result The result as an uint256.\n function sqrt(uint256 x) internal pure returns (uint256 result) {\n if (x == 0) {\n return 0;\n }\n\n // Set the initial guess to the closest power of two that is higher than x.\n uint256 xAux = uint256(x);\n result = 1;\n if (xAux >= 0x100000000000000000000000000000000) {\n xAux >>= 128;\n result <<= 64;\n }\n if (xAux >= 0x10000000000000000) {\n xAux >>= 64;\n result <<= 32;\n }\n if (xAux >= 0x100000000) {\n xAux >>= 32;\n result <<= 16;\n }\n if (xAux >= 0x10000) {\n xAux >>= 16;\n result <<= 8;\n }\n if (xAux >= 0x100) {\n xAux >>= 8;\n result <<= 4;\n }\n if (xAux >= 0x10) {\n xAux >>= 4;\n result <<= 2;\n }\n if (xAux >= 0x8) {\n result <<= 1;\n }\n\n // The operations can never overflow because the result is max 2^127 when it enters this block.\n unchecked {\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1;\n result = (result + x / result) >> 1; // Seven iterations should be enough\n uint256 roundedDownResult = x / result;\n return result >= roundedDownResult ? roundedDownResult : result;\n }\n }\n}\n" + }, + "contracts/JBSplitsStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {JBOperatable} from './abstract/JBOperatable.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {IJBSplitAllocator} from './interfaces/IJBSplitAllocator.sol';\nimport {JBConstants} from './libraries/JBConstants.sol';\nimport {JBOperations} from './libraries/JBOperations.sol';\nimport {JBGroupedSplits} from './structs/JBGroupedSplits.sol';\nimport {JBSplit} from './structs/JBSplit.sol';\n\n/// @notice Stores splits for each project.\ncontract JBSplitsStore is JBOperatable, IJBSplitsStore {\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error INVALID_LOCKED_UNTIL();\n error INVALID_PROJECT_ID();\n error INVALID_SPLIT_PERCENT();\n error INVALID_TOTAL_PERCENT();\n error PREVIOUS_LOCKED_SPLITS_NOT_INCLUDED();\n\n //*********************************************************************//\n // --------------------- private stored properties ------------------- //\n //*********************************************************************//\n\n /// @notice The number of splits currently set for each project ID's configurations.\n /// @custom:param _projectId The ID of the project to get the split count for.\n /// @custom:param _domain An identifier within which the returned splits should be considered active.\n /// @custom:param _group The identifying group of the splits.\n mapping(uint256 => mapping(uint256 => mapping(uint256 => uint256))) private _splitCountOf;\n\n /// @notice Packed data of splits for each project ID's configurations.\n /// @custom:param _projectId The ID of the project to get packed splits data for.\n /// @custom:param _domain An identifier within which the returned splits should be considered active.\n /// @custom:param _group The identifying group of the splits.\n /// @custom:param _index The indexed order that the split was set at.\n mapping(uint256 => mapping(uint256 => mapping(uint256 => mapping(uint256 => uint256))))\n private _packedSplitParts1Of;\n\n /// @notice More packed data of splits for each project ID's configurations.\n /// @dev This packed data is often 0.\n /// @custom:param _projectId The ID of the project to get packed splits data for.\n /// @custom:param _domain An identifier within which the returned splits should be considered active.\n /// @custom:param _group The identifying group of the splits.\n /// @custom:param _index The indexed order that the split was set at.\n mapping(uint256 => mapping(uint256 => mapping(uint256 => mapping(uint256 => uint256))))\n private _packedSplitParts2Of;\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice Mints ERC-721's that represent project ownership and transfers.\n IJBProjects public immutable override projects;\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Get all splits for the specified project ID, within the specified domain, for the specified group.\n /// @param _projectId The ID of the project to get splits for.\n /// @param _domain An identifier within which the returned splits should be considered active.\n /// @param _group The identifying group of the splits.\n /// @return An array of all splits for the project.\n function splitsOf(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group\n ) external view override returns (JBSplit[] memory) {\n return _getStructsFor(_projectId, _domain, _group);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n constructor(\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory\n ) JBOperatable(_operatorStore) {\n projects = _projects;\n directory = _directory;\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Sets a project's splits.\n /// @dev Only the owner or operator of a project, or the current controller contract of the project, can set its splits.\n /// @dev The new splits must include any currently set splits that are locked.\n /// @param _projectId The ID of the project for which splits are being added.\n /// @param _domain An identifier within which the splits should be considered active.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n function set(\n uint256 _projectId,\n uint256 _domain,\n JBGroupedSplits[] calldata _groupedSplits\n )\n external\n override\n requirePermissionAllowingOverride(\n projects.ownerOf(_projectId),\n _projectId,\n JBOperations.SET_SPLITS,\n address(directory.controllerOf(_projectId)) == msg.sender\n )\n {\n // Push array length in stack\n uint256 _groupedSplitsLength = _groupedSplits.length;\n\n // Set each grouped splits.\n for (uint256 _i; _i < _groupedSplitsLength; ) {\n // Get a reference to the grouped split being iterated on.\n JBGroupedSplits memory _groupedSplit = _groupedSplits[_i];\n\n // Set the splits for the group.\n _set(_projectId, _domain, _groupedSplit.group, _groupedSplit.splits);\n\n unchecked {\n ++_i;\n }\n }\n }\n\n //*********************************************************************//\n // --------------------- private helper functions -------------------- //\n //*********************************************************************//\n\n /// @notice Sets a project's splits.\n /// @dev The new splits must include any currently set splits that are locked.\n /// @param _projectId The ID of the project for which splits are being added.\n /// @param _domain An identifier within which the splits should be considered active.\n /// @param _group An identifier between of splits being set. All splits within this _group must add up to within 100%.\n /// @param _splits The splits to set.\n function _set(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group,\n JBSplit[] memory _splits\n ) internal {\n // Get a reference to the project's current splits.\n JBSplit[] memory _currentSplits = _getStructsFor(_projectId, _domain, _group);\n\n // Keep a reference to the number of splits.\n uint256 _currentSplitsLength = _currentSplits.length;\n\n // Check to see if all locked splits are included.\n for (uint256 _i; _i < _currentSplitsLength; ) {\n // If not locked, continue.\n if (\n block.timestamp < _currentSplits[_i].lockedUntil &&\n !_includesLocked(_splits, _currentSplits[_i])\n ) revert PREVIOUS_LOCKED_SPLITS_NOT_INCLUDED();\n\n unchecked {\n ++_i;\n }\n }\n\n // Add up all the percents to make sure they cumulatively are under 100%.\n uint256 _percentTotal;\n\n // Keep a reference to the number of splits.\n uint256 _splitsLength = _splits.length;\n\n for (uint256 _i; _i < _splitsLength; ) {\n // The percent should be greater than 0.\n if (_splits[_i].percent == 0) revert INVALID_SPLIT_PERCENT();\n\n // ProjectId should be within a uint56\n if (_splits[_i].projectId > type(uint56).max) revert INVALID_PROJECT_ID();\n\n // Add to the total percents.\n _percentTotal = _percentTotal + _splits[_i].percent;\n\n // Validate the total does not exceed the expected value.\n if (_percentTotal > JBConstants.SPLITS_TOTAL_PERCENT) revert INVALID_TOTAL_PERCENT();\n\n uint256 _packedSplitParts1;\n\n // prefer claimed in bit 0.\n if (_splits[_i].preferClaimed) _packedSplitParts1 = 1;\n // prefer add to balance in bit 1.\n if (_splits[_i].preferAddToBalance) _packedSplitParts1 |= 1 << 1;\n // percent in bits 2-33.\n _packedSplitParts1 |= _splits[_i].percent << 2;\n // projectId in bits 32-89.\n _packedSplitParts1 |= _splits[_i].projectId << 34;\n // beneficiary in bits 90-249.\n _packedSplitParts1 |= uint256(uint160(address(_splits[_i].beneficiary))) << 90;\n\n // Store the first split part.\n _packedSplitParts1Of[_projectId][_domain][_group][_i] = _packedSplitParts1;\n\n // If there's data to store in the second packed split part, pack and store.\n if (_splits[_i].lockedUntil > 0 || _splits[_i].allocator != IJBSplitAllocator(address(0))) {\n // Locked until should be within a uint48\n if (_splits[_i].lockedUntil > type(uint48).max) revert INVALID_LOCKED_UNTIL();\n\n // lockedUntil in bits 0-47.\n uint256 _packedSplitParts2 = uint48(_splits[_i].lockedUntil);\n // allocator in bits 48-207.\n _packedSplitParts2 |= uint256(uint160(address(_splits[_i].allocator))) << 48;\n\n // Store the second split part.\n _packedSplitParts2Of[_projectId][_domain][_group][_i] = _packedSplitParts2;\n\n // Otherwise if there's a value stored in the indexed position, delete it.\n } else if (_packedSplitParts2Of[_projectId][_domain][_group][_i] > 0)\n delete _packedSplitParts2Of[_projectId][_domain][_group][_i];\n\n emit SetSplit(_projectId, _domain, _group, _splits[_i], msg.sender);\n\n unchecked {\n ++_i;\n }\n }\n\n // Set the new length of the splits.\n _splitCountOf[_projectId][_domain][_group] = _splitsLength;\n }\n\n /// @notice A flag indiciating if the provided splits array includes the locked split.\n /// @param _splits The array of splits to check within.\n /// @param _lockedSplit The locked split.\n /// @return A flag indicating if the `_lockedSplit` is contained in the `_splits`.\n function _includesLocked(\n JBSplit[] memory _splits,\n JBSplit memory _lockedSplit\n ) private pure returns (bool) {\n // Keep a reference to the number of splits.\n uint256 _numberOfSplits = _splits.length;\n\n for (uint256 _i; _i < _numberOfSplits; ) {\n // Check for sameness.\n if (\n _splits[_i].percent == _lockedSplit.percent &&\n _splits[_i].beneficiary == _lockedSplit.beneficiary &&\n _splits[_i].allocator == _lockedSplit.allocator &&\n _splits[_i].projectId == _lockedSplit.projectId &&\n _splits[_i].preferClaimed == _lockedSplit.preferClaimed &&\n _splits[_i].preferAddToBalance == _lockedSplit.preferAddToBalance &&\n // Allow lock extention.\n _splits[_i].lockedUntil >= _lockedSplit.lockedUntil\n ) return true;\n\n unchecked {\n ++_i;\n }\n }\n\n return false;\n }\n\n /// @notice Unpack splits' packed stored values into easy-to-work-with split structs.\n /// @param _projectId The ID of the project to which the split belongs.\n /// @param _domain The identifier within which the returned splits should be considered active.\n /// @param _group The identifying group of the splits.\n /// @return splits The split structs.\n function _getStructsFor(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group\n ) private view returns (JBSplit[] memory) {\n // Get a reference to the number of splits that need to be added to the returned array.\n uint256 _splitCount = _splitCountOf[_projectId][_domain][_group];\n\n // Initialize an array to be returned that has the set length.\n JBSplit[] memory _splits = new JBSplit[](_splitCount);\n\n // Loop through each split and unpack the values into structs.\n for (uint256 _i; _i < _splitCount; ) {\n // Get a reference to the fist packed data.\n uint256 _packedSplitPart1 = _packedSplitParts1Of[_projectId][_domain][_group][_i];\n\n // Populate the split struct.\n JBSplit memory _split;\n\n // prefer claimed in bit 0.\n _split.preferClaimed = _packedSplitPart1 & 1 == 1;\n // prefer add to balance in bit 1.\n _split.preferAddToBalance = (_packedSplitPart1 >> 1) & 1 == 1;\n // percent in bits 2-33.\n _split.percent = uint256(uint32(_packedSplitPart1 >> 2));\n // projectId in bits 32-89.\n _split.projectId = uint256(uint56(_packedSplitPart1 >> 34));\n // beneficiary in bits 90-249.\n _split.beneficiary = payable(address(uint160(_packedSplitPart1 >> 90)));\n\n // Get a reference to the second packed data.\n uint256 _packedSplitPart2 = _packedSplitParts2Of[_projectId][_domain][_group][_i];\n\n // If there's anything in it, unpack.\n if (_packedSplitPart2 > 0) {\n // lockedUntil in bits 0-47.\n _split.lockedUntil = uint256(uint48(_packedSplitPart2));\n // allocator in bits 48-207.\n _split.allocator = IJBSplitAllocator(address(uint160(_packedSplitPart2 >> 48)));\n }\n\n // Add the split to the value being returned.\n _splits[_i] = _split;\n\n unchecked {\n ++_i;\n }\n }\n\n return _splits;\n }\n}\n" + }, + "contracts/JBETHERC20SplitsPayerDeployer.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Clones} from '@openzeppelin/contracts/proxy/Clones.sol';\nimport {IJBETHERC20SplitsPayerDeployer} from './interfaces/IJBETHERC20SplitsPayerDeployer.sol';\nimport {IJBSplitsPayer} from './interfaces/IJBSplitsPayer.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {JBSplit} from './structs/JBSplit.sol';\nimport {JBGroupedSplits} from './structs/JBGroupedSplits.sol';\nimport {JBETHERC20SplitsPayer} from './JBETHERC20SplitsPayer.sol';\n\n/// @notice Deploys splits payer contracts.\ncontract JBETHERC20SplitsPayerDeployer is IJBETHERC20SplitsPayerDeployer {\n //*********************************************************************//\n // --------------- public immutable stored properties ---------------- //\n //*********************************************************************//\n\n /// @notice The implementation contract on which Clones will be based.\n address immutable implementation;\n\n /// @notice The contract that stores splits for each project.\n IJBSplitsStore immutable splitsStore;\n\n //*********************************************************************//\n // ---------------------------- constructor -------------------------- //\n //*********************************************************************//\n\n /// @param _splitsStore The contract that stores splits for each project.\n constructor(IJBSplitsStore _splitsStore) {\n implementation = address(new JBETHERC20SplitsPayer(_splitsStore));\n splitsStore = _splitsStore;\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Allows anyone to deploy a new splits payer contract.\n /// @dev This contract must have Operator permissions over the SET_SPLITS permission of the specified `_defaultSplitsProjectId`.\n /// @param _defaultSplitsProjectId The ID of project for which the default splits are stored.\n /// @param _defaultSplits The splits to payout when this contract receives direct payments.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _defaultProjectId The ID of the project whose treasury should be forwarded the splits payer contract's received payment leftovers after distributing to the default splits group.\n /// @param _defaultBeneficiary The address that'll receive the project's tokens when the splits payer receives payments.\n /// @param _defaultPreferClaimedTokens A flag indicating whether issued tokens from the splits payer's received payments should be automatically claimed into the beneficiary's wallet.\n /// @param _defaultMemo The memo that'll be forwarded with the splits payer's received payments.\n /// @param _defaultMetadata The metadata that'll be forwarded with the splits payer's received payments.\n /// @param _defaultPreferAddToBalance A flag indicating if received payments should call the `pay` function or the `addToBalance` function of a project.\n /// @param _owner The address that will own the splits payer.\n /// @return splitsPayer The splits payer contract.\n function deploySplitsPayerWithSplits(\n uint256 _defaultSplitsProjectId,\n JBSplit[] memory _defaultSplits,\n IJBSplitsStore _splitsStore,\n uint256 _defaultProjectId,\n address payable _defaultBeneficiary,\n bool _defaultPreferClaimedTokens,\n string memory _defaultMemo,\n bytes memory _defaultMetadata,\n bool _defaultPreferAddToBalance,\n address _owner\n ) external override returns (IJBSplitsPayer splitsPayer) {\n // Use this contract's address as the domain.\n uint256 _domain = uint256(uint160(address(this)));\n\n // Create the random hash using data unique to this instance that'll be used as the storage domain.\n uint256 _group = uint256(keccak256(abi.encodePacked(msg.sender, block.number)));\n\n // Set the splits in the store.\n JBGroupedSplits[] memory _groupedSplits;\n _groupedSplits = new JBGroupedSplits[](1);\n _groupedSplits[0] = JBGroupedSplits(_group, _defaultSplits);\n _splitsStore.set(_defaultSplitsProjectId, _domain, _groupedSplits);\n\n return\n deploySplitsPayer(\n _defaultSplitsProjectId,\n _domain,\n _group,\n _defaultProjectId,\n _defaultBeneficiary,\n _defaultPreferClaimedTokens,\n _defaultMemo,\n _defaultMetadata,\n _defaultPreferAddToBalance,\n _owner\n );\n }\n\n //*********************************************************************//\n // ---------------------- public transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Allows anyone to deploy a new splits payer contract.\n /// @param _defaultSplitsProjectId The ID of project for which the default splits are stored.\n /// @param _defaultSplitsDomain The splits domain to payout when this contract receives direct payments.\n /// @param _defaultSplitsGroup The splits group to payout when this contract receives direct payments.\n /// @param _defaultProjectId The ID of the project whose treasury should be forwarded the splits payer contract's received payment leftovers after distributing to the default splits group.\n /// @param _defaultBeneficiary The address that'll receive the project's tokens when the splits payer receives payments.\n /// @param _defaultPreferClaimedTokens A flag indicating whether issued tokens from the splits payer's received payments should be automatically claimed into the beneficiary's wallet.\n /// @param _defaultMemo The memo that'll be forwarded with the splits payer's received payments.\n /// @param _defaultMetadata The metadata that'll be forwarded with the splits payer's received payments.\n /// @param _defaultPreferAddToBalance A flag indicating if received payments should call the `pay` function or the `addToBalance` function of a project.\n /// @param _owner The address that will own the splits payer.\n /// @return splitsPayer The splits payer contract.\n function deploySplitsPayer(\n uint256 _defaultSplitsProjectId,\n uint256 _defaultSplitsDomain,\n uint256 _defaultSplitsGroup,\n uint256 _defaultProjectId,\n address payable _defaultBeneficiary,\n bool _defaultPreferClaimedTokens,\n string memory _defaultMemo,\n bytes memory _defaultMetadata,\n bool _defaultPreferAddToBalance,\n address _owner\n ) public override returns (IJBSplitsPayer splitsPayer) {\n // Deploy the splits payer.\n splitsPayer = IJBSplitsPayer(payable(Clones.clone(implementation)));\n\n splitsPayer.initialize(\n _defaultSplitsProjectId,\n _defaultSplitsDomain,\n _defaultSplitsGroup,\n _defaultProjectId,\n _defaultBeneficiary,\n _defaultPreferClaimedTokens,\n _defaultMemo,\n _defaultMetadata,\n _defaultPreferAddToBalance,\n _owner\n );\n\n emit DeploySplitsPayer(\n splitsPayer,\n _defaultSplitsProjectId,\n _defaultSplitsDomain,\n _defaultSplitsGroup,\n splitsStore,\n _defaultProjectId,\n _defaultBeneficiary,\n _defaultPreferClaimedTokens,\n _defaultMemo,\n _defaultMetadata,\n _defaultPreferAddToBalance,\n _owner,\n msg.sender\n );\n }\n}\n" + }, + "@openzeppelin/contracts/proxy/Clones.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (proxy/Clones.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for\n * deploying minimal proxy contracts, also known as \"clones\".\n *\n * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies\n * > a minimal bytecode implementation that delegates all calls to a known, fixed address.\n *\n * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`\n * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the\n * deterministic method.\n *\n * _Available since v3.4._\n */\nlibrary Clones {\n /**\n * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.\n *\n * This function uses the create opcode, which should never revert.\n */\n function clone(address implementation) internal returns (address instance) {\n assembly {\n let ptr := mload(0x40)\n mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)\n mstore(add(ptr, 0x14), shl(0x60, implementation))\n mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)\n instance := create(0, ptr, 0x37)\n }\n require(instance != address(0), \"ERC1167: create failed\");\n }\n\n /**\n * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.\n *\n * This function uses the create2 opcode and a `salt` to deterministically deploy\n * the clone. Using the same `implementation` and `salt` multiple time will revert, since\n * the clones cannot be deployed twice at the same address.\n */\n function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {\n assembly {\n let ptr := mload(0x40)\n mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)\n mstore(add(ptr, 0x14), shl(0x60, implementation))\n mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)\n instance := create2(0, ptr, 0x37, salt)\n }\n require(instance != address(0), \"ERC1167: create2 failed\");\n }\n\n /**\n * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.\n */\n function predictDeterministicAddress(\n address implementation,\n bytes32 salt,\n address deployer\n ) internal pure returns (address predicted) {\n assembly {\n let ptr := mload(0x40)\n mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)\n mstore(add(ptr, 0x14), shl(0x60, implementation))\n mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf3ff00000000000000000000000000000000)\n mstore(add(ptr, 0x38), shl(0x60, deployer))\n mstore(add(ptr, 0x4c), salt)\n mstore(add(ptr, 0x6c), keccak256(ptr, 0x37))\n predicted := keccak256(add(ptr, 0x37), 0x55)\n }\n }\n\n /**\n * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.\n */\n function predictDeterministicAddress(address implementation, bytes32 salt)\n internal\n view\n returns (address predicted)\n {\n return predictDeterministicAddress(implementation, salt, address(this));\n }\n}\n" + }, + "contracts/interfaces/IJBETHERC20SplitsPayerDeployer.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBSplitsPayer} from './IJBSplitsPayer.sol';\nimport {IJBSplitsStore} from './IJBSplitsStore.sol';\nimport {JBSplit} from './../structs/JBSplit.sol';\n\ninterface IJBETHERC20SplitsPayerDeployer {\n event DeploySplitsPayer(\n IJBSplitsPayer indexed splitsPayer,\n uint256 defaultSplitsProjectId,\n uint256 defaultSplitsDomain,\n uint256 defaultSplitsGroup,\n IJBSplitsStore splitsStore,\n uint256 defaultProjectId,\n address defaultBeneficiary,\n bool defaultPreferClaimedTokens,\n string defaultMemo,\n bytes defaultMetadata,\n bool preferAddToBalance,\n address owner,\n address caller\n );\n\n function deploySplitsPayer(\n uint256 defaultSplitsProjectId,\n uint256 defaultSplitsDomain,\n uint256 defaultSplitsGroup,\n uint256 defaultProjectId,\n address payable defaultBeneficiary,\n bool defaultPreferClaimedTokens,\n string calldata defaultMemo,\n bytes calldata defaultMetadata,\n bool preferAddToBalance,\n address owner\n ) external returns (IJBSplitsPayer splitsPayer);\n\n function deploySplitsPayerWithSplits(\n uint256 defaultSplitsProjectId,\n JBSplit[] memory defaultSplits,\n IJBSplitsStore splitsStore,\n uint256 defaultProjectId,\n address payable defaultBeneficiary,\n bool defaultPreferClaimedTokens,\n string memory defaultMemo,\n bytes memory defaultMetadata,\n bool defaultPreferAddToBalance,\n address owner\n ) external returns (IJBSplitsPayer splitsPayer);\n}\n" + }, + "contracts/interfaces/IJBSplitsPayer.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBSplit} from './../structs/JBSplit.sol';\nimport {JBGroupedSplits} from './../structs/JBGroupedSplits.sol';\nimport {IJBSplitsStore} from './IJBSplitsStore.sol';\n\ninterface IJBSplitsPayer is IERC165 {\n event SetDefaultSplitsReference(\n uint256 indexed projectId,\n uint256 indexed domain,\n uint256 indexed group,\n address caller\n );\n event Pay(\n uint256 indexed projectId,\n address beneficiary,\n address token,\n uint256 amount,\n uint256 decimals,\n uint256 leftoverAmount,\n uint256 minReturnedTokens,\n bool preferClaimedTokens,\n string memo,\n bytes metadata,\n address caller\n );\n\n event AddToBalance(\n uint256 indexed projectId,\n address beneficiary,\n address token,\n uint256 amount,\n uint256 decimals,\n uint256 leftoverAmount,\n string memo,\n bytes metadata,\n address caller\n );\n\n event DistributeToSplitGroup(\n uint256 indexed projectId,\n uint256 indexed domain,\n uint256 indexed group,\n address caller\n );\n\n event DistributeToSplit(\n JBSplit split,\n uint256 amount,\n address defaultBeneficiary,\n address caller\n );\n\n function defaultSplitsProjectId() external view returns (uint256);\n\n function defaultSplitsDomain() external view returns (uint256);\n\n function defaultSplitsGroup() external view returns (uint256);\n\n function splitsStore() external view returns (IJBSplitsStore);\n\n function initialize(\n uint256 defaultSplitsProjectId,\n uint256 defaultSplitsDomain,\n uint256 defaultSplitsGroup,\n uint256 defaultProjectId,\n address payable defaultBeneficiary,\n bool defaultPreferClaimedTokens,\n string memory defaultMemo,\n bytes memory defaultMetadata,\n bool preferAddToBalance,\n address owner\n ) external;\n\n function setDefaultSplitsReference(uint256 projectId, uint256 domain, uint256 group) external;\n\n function setDefaultSplits(\n uint256 projectId,\n uint256 domain,\n uint256 group,\n JBGroupedSplits[] memory splitsGroup\n ) external;\n}\n" + }, + "contracts/JBETHERC20SplitsPayer.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {ReentrancyGuard} from '@openzeppelin/contracts/security/ReentrancyGuard.sol';\nimport {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';\nimport {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';\nimport {Address} from '@openzeppelin/contracts/utils/Address.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {IJBSplitsPayer} from './interfaces/IJBSplitsPayer.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {JBConstants} from './libraries/JBConstants.sol';\nimport {JBETHERC20ProjectPayer} from './JBETHERC20ProjectPayer.sol';\nimport {IJBSplitAllocator} from './interfaces/IJBSplitAllocator.sol';\nimport {JBTokens} from './libraries/JBTokens.sol';\nimport {JBGroupedSplits} from './structs/JBGroupedSplits.sol';\nimport {JBSplit} from './structs/JBSplit.sol';\nimport {JBSplitAllocationData} from './structs/JBSplitAllocationData.sol';\n\n/// @notice Sends ETH or ERC20's to a group of splits as it receives direct payments or has its functions called.\n/// @dev Inherit from this contract or borrow from its logic to forward ETH or ERC20's to a group of splits from within other contracts.\ncontract JBETHERC20SplitsPayer is JBETHERC20ProjectPayer, ReentrancyGuard, IJBSplitsPayer {\n using SafeERC20 for IERC20;\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice The contract that stores splits for each project.\n IJBSplitsStore public immutable override splitsStore;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The ID of project for which the default splits are stored.\n uint256 public override defaultSplitsProjectId;\n\n /// @notice The domain within which the default splits are stored.\n uint256 public override defaultSplitsDomain;\n\n /// @notice The group within which the default splits are stored.\n uint256 public override defaultSplitsGroup;\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if this contract adheres to the specified interface.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(JBETHERC20ProjectPayer, IERC165) returns (bool) {\n return\n _interfaceId == type(IJBSplitsPayer).interfaceId || super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _splitsStore A contract that stores splits for each project.\n constructor(IJBSplitsStore _splitsStore) JBETHERC20ProjectPayer(_splitsStore.directory()) {\n splitsStore = _splitsStore;\n }\n\n /// @dev The re-initialize check is done in the inherited paroject payer\n /// @param _defaultSplitsProjectId The ID of project for which the default splits are stored.\n /// @param _defaultSplitsDomain The splits domain to payout when this contract receives direct payments.\n /// @param _defaultSplitsGroup The splits group to payout when this contract receives direct payments.\n /// @param _defaultProjectId The ID of the project whose treasury should be forwarded the splits payer contract's received payment leftovers after distributing to the default splits group.\n /// @param _defaultBeneficiary The address that'll receive the project's tokens.\n /// @param _defaultPreferClaimedTokens A flag indicating whether issued tokens should be automatically claimed into the beneficiary's wallet.\n /// @param _defaultMemo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _defaultMetadata Bytes to send along to the project's data source and delegate, if provided.\n /// @param _preferAddToBalance A flag indicating if received payments should call the `pay` function or the `addToBalance` function of a project.\n /// @param _owner The address that will own the contract.\n function initialize(\n uint256 _defaultSplitsProjectId,\n uint256 _defaultSplitsDomain,\n uint256 _defaultSplitsGroup,\n uint256 _defaultProjectId,\n address payable _defaultBeneficiary,\n bool _defaultPreferClaimedTokens,\n string memory _defaultMemo,\n bytes memory _defaultMetadata,\n bool _preferAddToBalance,\n address _owner\n ) external override {\n super.initialize(\n _defaultProjectId,\n _defaultBeneficiary,\n _defaultPreferClaimedTokens,\n _defaultMemo,\n _defaultMetadata,\n _preferAddToBalance,\n _owner\n );\n\n defaultSplitsProjectId = _defaultSplitsProjectId;\n defaultSplitsDomain = _defaultSplitsDomain;\n defaultSplitsGroup = _defaultSplitsGroup;\n }\n\n //*********************************************************************//\n // ------------------------- default receive ------------------------- //\n //*********************************************************************//\n\n /// @notice Received funds are paid to the default split group using the stored default properties.\n /// @dev This function is called automatically when the contract receives an ETH payment.\n receive() external payable virtual override nonReentrant {\n // Pay the splits and get a reference to the amount leftover.\n uint256 _leftoverAmount = _payToSplits(\n defaultSplitsProjectId,\n defaultSplitsDomain,\n defaultSplitsGroup,\n JBTokens.ETH,\n address(this).balance,\n 18, // decimals.\n defaultBeneficiary != address(0) ? defaultBeneficiary : tx.origin\n );\n\n // If there is no leftover amount, nothing left to pay.\n if (_leftoverAmount == 0) return;\n\n // If there's a default project ID, try to pay it.\n if (defaultProjectId != 0)\n if (defaultPreferAddToBalance)\n // Pay the project by adding to its balance if prefered.\n _addToBalanceOf(\n defaultProjectId,\n JBTokens.ETH,\n _leftoverAmount,\n 18, // decimals.\n defaultMemo,\n defaultMetadata\n );\n // Otherwise, issue a payment to the project.\n else\n _pay(\n defaultProjectId,\n JBTokens.ETH,\n _leftoverAmount,\n 18, // decimals.\n defaultBeneficiary != address(0) ? defaultBeneficiary : tx.origin,\n 0, // min returned tokens.\n defaultPreferClaimedTokens,\n defaultMemo,\n defaultMetadata\n );\n // If no project was specified, send the funds directly to the beneficiary or the tx.origin.\n else\n Address.sendValue(\n defaultBeneficiary != address(0) ? payable(defaultBeneficiary) : payable(tx.origin),\n _leftoverAmount\n );\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Sets the splits in the splits store that payments this contract receives will be split between.\n /// @param _projectId The ID of project for which the default splits are stored.\n /// @param _domain The domain within which the default splits are stored.\n /// @param _group The group within which the default splits are stored.\n /// @param _groupedSplits The split groups to set.\n function setDefaultSplits(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group,\n JBGroupedSplits[] memory _groupedSplits\n ) external virtual override onlyOwner {\n // Set the splits in the store.\n splitsStore.set(_projectId, _domain, _groupedSplits);\n\n // Set the splits reference.\n setDefaultSplitsReference(_projectId, _domain, _group);\n }\n\n //*********************************************************************//\n // ----------------------- public transactions ----------------------- //\n //*********************************************************************//\n\n /// @notice Sets the location of the splits that payments this contract receives will be split between.\n /// @param _projectId The ID of project for which the default splits are stored.\n /// @param _domain The domain within which the default splits are stored.\n /// @param _group The group within which the default splits are stored.\n function setDefaultSplitsReference(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group\n ) public virtual override onlyOwner {\n // Set the default splits project ID if it's changing.\n if (_projectId != defaultSplitsProjectId) defaultSplitsProjectId = _projectId;\n\n // Set the default splits domain if it's changing.\n if (_domain != defaultSplitsDomain) defaultSplitsDomain = _domain;\n\n // Set the default splits group if it's changing.\n if (_group != defaultSplitsGroup) defaultSplitsGroup = _group;\n\n emit SetDefaultSplitsReference(_projectId, _domain, _group, msg.sender);\n }\n\n /// @notice Make a payment to the specified project after first splitting the amount among the stored default splits.\n /// @param _projectId The ID of the project that is being paid after.\n /// @param _token The token being paid in.\n /// @param _amount The amount of tokens being paid, as a fixed point number. If the token is ETH, this is ignored and msg.value is used in its place.\n /// @param _decimals The number of decimals in the `_amount` fixed point number. If the token is ETH, this is ignored and 18 is used in its place, which corresponds to the amount of decimals expected in msg.value.\n /// @param _beneficiary The address who will receive tokens from the payment made with leftover funds.\n /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with 18 decimals.\n /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\n /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n function pay(\n uint256 _projectId,\n address _token,\n uint256 _amount,\n uint256 _decimals,\n address _beneficiary,\n uint256 _minReturnedTokens,\n bool _preferClaimedTokens,\n string calldata _memo,\n bytes calldata _metadata\n ) public payable virtual override nonReentrant {\n // ETH shouldn't be sent if the token isn't ETH.\n if (address(_token) != JBTokens.ETH) {\n if (msg.value > 0) revert NO_MSG_VALUE_ALLOWED();\n\n // Get a reference to the balance before receiving tokens.\n uint256 _balanceBefore = IERC20(_token).balanceOf(address(this));\n\n // Transfer tokens to this contract from the msg sender.\n IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount);\n\n // The amount should reflect the change in balance.\n _amount = IERC20(_token).balanceOf(address(this)) - _balanceBefore;\n } else {\n // If ETH is being paid, set the amount to the message value, and decimals to 18.\n _amount = msg.value;\n _decimals = 18;\n }\n\n // Pay the splits and get a reference to the amount leftover.\n uint256 _leftoverAmount = _payToSplits(\n defaultSplitsProjectId,\n defaultSplitsDomain,\n defaultSplitsGroup,\n _token,\n _amount,\n _decimals,\n defaultBeneficiary != address(0) ? defaultBeneficiary : tx.origin\n );\n\n // Pay any leftover amount.\n if (_leftoverAmount > 0) {\n // If there's a default project ID, try to pay it.\n if (_projectId != 0) {\n _pay(\n _projectId,\n _token,\n _leftoverAmount,\n _decimals,\n _beneficiary != address(0) ? _beneficiary : defaultBeneficiary != address(0)\n ? defaultBeneficiary\n : tx.origin,\n _minReturnedTokens,\n _preferClaimedTokens,\n _memo,\n _metadata\n );\n }\n // If no project was specified, send the funds directly to the beneficiary or the tx.origin.\n else {\n // Transfer the ETH.\n if (_token == JBTokens.ETH)\n Address.sendValue(\n // If there's a beneficiary, send the funds directly to the beneficiary. Otherwise send to the tx.origin.\n _beneficiary != address(0) ? payable(_beneficiary) : defaultBeneficiary != address(0)\n ? defaultBeneficiary\n : payable(tx.origin),\n _leftoverAmount\n );\n // Or, transfer the ERC20.\n else\n IERC20(_token).safeTransfer(\n // If there's a beneficiary, send the funds directly to the beneficiary. Otherwise send to the tx.origin.\n _beneficiary != address(0) ? _beneficiary : defaultBeneficiary != address(0)\n ? defaultBeneficiary\n : tx.origin,\n _leftoverAmount\n );\n }\n }\n\n emit Pay(\n _projectId,\n _beneficiary != address(0) ? _beneficiary : defaultBeneficiary != address(0)\n ? defaultBeneficiary\n : tx.origin,\n _token,\n _amount,\n _decimals,\n _leftoverAmount,\n _minReturnedTokens,\n _preferClaimedTokens,\n _memo,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Add to the balance of the specified project after first splitting the amount among the stored default splits.\n /// @param _projectId The ID of the project that is being paid after.\n /// @param _token The token being paid in.\n /// @param _amount The amount of tokens being paid, as a fixed point number. If the token is ETH, this is ignored and msg.value is used in its place.\n /// @param _decimals The number of decimals in the `_amount` fixed point number. If the token is ETH, this is ignored and 18 is used in its place, which corresponds to the amount of decimals expected in msg.value.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the terminal.\n function addToBalanceOf(\n uint256 _projectId,\n address _token,\n uint256 _amount,\n uint256 _decimals,\n string calldata _memo,\n bytes calldata _metadata\n ) public payable virtual override nonReentrant {\n // ETH shouldn't be sent if this terminal's token isn't ETH.\n if (address(_token) != JBTokens.ETH) {\n if (msg.value > 0) revert NO_MSG_VALUE_ALLOWED();\n\n // Get a reference to the balance before receiving tokens.\n uint256 _balanceBefore = IERC20(_token).balanceOf(address(this));\n\n // Transfer tokens to this contract from the msg sender.\n IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount);\n\n // The amount should reflect the change in balance.\n _amount = IERC20(_token).balanceOf(address(this)) - _balanceBefore;\n } else {\n // If ETH is being paid, set the amount to the message value, and decimals to 18.\n _amount = msg.value;\n _decimals = 18;\n }\n\n // Pay the splits and get a reference to the amount leftover.\n uint256 _leftoverAmount = _payToSplits(\n defaultSplitsProjectId,\n defaultSplitsDomain,\n defaultSplitsGroup,\n _token,\n _amount,\n _decimals,\n defaultBeneficiary != address(0) ? defaultBeneficiary : tx.origin\n );\n\n // Distribute any leftover amount.\n if (_leftoverAmount > 0) {\n // If there's a default project ID, try to add to its balance.\n if (_projectId != 0)\n // Add to the project's balance.\n _addToBalanceOf(_projectId, _token, _leftoverAmount, _decimals, _memo, _metadata);\n\n // Otherwise, send a payment to the beneficiary.\n else {\n // Transfer the ETH.\n if (_token == JBTokens.ETH)\n Address.sendValue(\n // If there's a default beneficiary, send the funds directly to the beneficiary. Otherwise send to the tx.origin.\n defaultBeneficiary != address(0) ? defaultBeneficiary : payable(tx.origin),\n _leftoverAmount\n );\n // Or, transfer the ERC20.\n else\n IERC20(_token).safeTransfer(\n // If there's a default beneficiary, send the funds directly to the beneficiary. Otherwise send to the tx.origin.\n defaultBeneficiary != address(0) ? defaultBeneficiary : tx.origin,\n _leftoverAmount\n );\n }\n }\n\n emit AddToBalance(\n _projectId,\n defaultBeneficiary != address(0) ? defaultBeneficiary : tx.origin,\n _token,\n _amount,\n _decimals,\n _leftoverAmount,\n _memo,\n _metadata,\n msg.sender\n );\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Split an amount between all splits.\n /// @param _splitsProjectId The ID of the project to which the splits belong.\n /// @param _splitsDomain The splits domain to which the group belongs.\n /// @param _splitsGroup The splits group to pay.\n /// @param _token The token the amonut being split is in.\n /// @param _amount The amount of tokens being split, as a fixed point number. If the `_token` is ETH, this is ignored and msg.value is used in its place.\n /// @param _decimals The number of decimals in the `_amount` fixed point number.\n /// @param _defaultBeneficiary The address that will benefit from any non-specified beneficiaries in splits.\n /// @return leftoverAmount The amount leftover after all splits were paid.\n function _payToSplits(\n uint256 _splitsProjectId,\n uint256 _splitsDomain,\n uint256 _splitsGroup,\n address _token,\n uint256 _amount,\n uint256 _decimals,\n address _defaultBeneficiary\n ) internal virtual returns (uint256 leftoverAmount) {\n // Pay the splits.\n leftoverAmount = _payTo(\n splitsStore.splitsOf(_splitsProjectId, _splitsDomain, _splitsGroup),\n _token,\n _amount,\n _decimals,\n _defaultBeneficiary\n );\n emit DistributeToSplitGroup(_splitsProjectId, _splitsDomain, _splitsGroup, msg.sender);\n }\n\n /// @notice Split an amount between all splits.\n /// @param _splits The splits.\n /// @param _token The token the amonut being split is in.\n /// @param _amount The amount of tokens being split, as a fixed point number. If the `_token` is ETH, this is ignored and msg.value is used in its place.\n /// @param _decimals The number of decimals in the `_amount` fixed point number.\n /// @param _defaultBeneficiary The address that will benefit from any non-specified beneficiaries in splits.\n /// @return leftoverAmount The amount leftover after all splits were paid.\n function _payTo(\n JBSplit[] memory _splits,\n address _token,\n uint256 _amount,\n uint256 _decimals,\n address _defaultBeneficiary\n ) internal virtual returns (uint256 leftoverAmount) {\n // Set the leftover amount to the initial balance.\n leftoverAmount = _amount;\n\n // Settle between all splits.\n for (uint256 i; i < _splits.length; ) {\n // Get a reference to the split being iterated on.\n JBSplit memory _split = _splits[i];\n\n // The amount to send towards the split.\n uint256 _splitAmount = PRBMath.mulDiv(\n _amount,\n _split.percent,\n JBConstants.SPLITS_TOTAL_PERCENT\n );\n\n if (_splitAmount > 0) {\n // Transfer tokens to the split.\n // If there's an allocator set, transfer to its `allocate` function.\n if (_split.allocator != IJBSplitAllocator(address(0))) {\n // Create the data to send to the allocator.\n JBSplitAllocationData memory _data = JBSplitAllocationData(\n _token,\n _splitAmount,\n _decimals,\n defaultProjectId,\n 0,\n _split\n );\n\n // Approve the `_amount` of tokens for the split allocator to transfer tokens from this contract.\n if (_token != JBTokens.ETH)\n IERC20(_token).safeApprove(address(_split.allocator), _splitAmount);\n\n // If the token is ETH, send it in msg.value.\n uint256 _payableValue = _token == JBTokens.ETH ? _splitAmount : 0;\n\n // Trigger the allocator's `allocate` function.\n _split.allocator.allocate{value: _payableValue}(_data);\n\n // Otherwise, if a project is specified, make a payment to it.\n } else if (_split.projectId != 0) {\n if (_split.preferAddToBalance)\n _addToBalanceOf(\n _split.projectId,\n _token,\n _splitAmount,\n _decimals,\n defaultMemo,\n defaultMetadata\n );\n else\n _pay(\n _split.projectId,\n _token,\n _splitAmount,\n _decimals,\n _split.beneficiary != address(0) ? _split.beneficiary : _defaultBeneficiary,\n 0,\n _split.preferClaimed,\n defaultMemo,\n defaultMetadata\n );\n } else {\n // Transfer the ETH.\n if (_token == JBTokens.ETH)\n Address.sendValue(\n // Get a reference to the address receiving the tokens. If there's a beneficiary, send the funds directly to the beneficiary. Otherwise send to _defaultBeneficiary.\n _split.beneficiary != address(0) ? _split.beneficiary : payable(_defaultBeneficiary),\n _splitAmount\n );\n // Or, transfer the ERC20.\n else {\n IERC20(_token).safeTransfer(\n // Get a reference to the address receiving the tokens. If there's a beneficiary, send the funds directly to the beneficiary. Otherwise send to _defaultBeneficiary.\n _split.beneficiary != address(0) ? _split.beneficiary : _defaultBeneficiary,\n _splitAmount\n );\n }\n }\n\n // Subtract from the amount to be sent to the beneficiary.\n leftoverAmount = leftoverAmount - _splitAmount;\n }\n\n emit DistributeToSplit(_split, _splitAmount, _defaultBeneficiary, msg.sender);\n\n unchecked {\n ++i;\n }\n }\n }\n}\n" + }, + "@openzeppelin/contracts/security/ReentrancyGuard.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuard {\n // Booleans are more expensive than uint256 or any type that takes up a full\n // word because each write operation emits an extra SLOAD to first read the\n // slot's contents, replace the bits taken up by the boolean, and then write\n // back. This is the compiler's defense against contract upgrades and\n // pointer aliasing, and it cannot be disabled.\n\n // The values being non-zero value makes deployment a bit more expensive,\n // but in exchange the refund on every call to nonReentrant will be lower in\n // amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to\n // increase the likelihood of the full refund coming into effect.\n uint256 private constant _NOT_ENTERED = 1;\n uint256 private constant _ENTERED = 2;\n\n uint256 private _status;\n\n constructor() {\n _status = _NOT_ENTERED;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a `nonReentrant` function from another `nonReentrant`\n * function is not supported. It is possible to prevent this from happening\n * by making the `nonReentrant` function external, and making it call a\n * `private` function that does the actual work.\n */\n modifier nonReentrant() {\n // On the first call to nonReentrant, _notEntered will be true\n require(_status != _ENTERED, \"ReentrancyGuard: reentrant call\");\n\n // Any calls to nonReentrant after this point will fail\n _status = _ENTERED;\n\n _;\n\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _status = _NOT_ENTERED;\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n }\n\n /**\n * @dev Deprecated. This function has issues similar to the ones found in\n * {IERC20-approve}, and its usage is discouraged.\n *\n * Whenever possible, use {safeIncreaseAllowance} and\n * {safeDecreaseAllowance} instead.\n */\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender) + value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n unchecked {\n uint256 oldAllowance = token.allowance(address(this), spender);\n require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n uint256 newAllowance = oldAllowance - value;\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n if (returndata.length > 0) {\n // Return data is optional\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Address.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n *\n * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCall(target, data, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n require(isContract(target), \"Address: call to non-contract\");\n\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n require(isContract(target), \"Address: static call to non-contract\");\n\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a delegate call.\n *\n * _Available since v3.4._\n */\n function functionDelegateCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(isContract(target), \"Address: delegate call to non-contract\");\n\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n }\n}\n" + }, + "contracts/JBETHERC20ProjectPayer.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';\nimport {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';\nimport {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';\nimport {ERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBProjectPayer} from './interfaces/IJBProjectPayer.sol';\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\nimport {JBTokens} from './libraries/JBTokens.sol';\n\n/// @notice Sends ETH or ERC20's to a project treasury as it receives direct payments or has it's functions called.\n/// @dev Inherit from this contract or borrow from its logic to forward ETH or ERC20's to project treasuries from within other contracts.\ncontract JBETHERC20ProjectPayer is Ownable, ERC165, IJBProjectPayer {\n using SafeERC20 for IERC20;\n\n //*********************************************************************//\n // -------------------------- custom errors -------------------------- //\n //*********************************************************************//\n error INCORRECT_DECIMAL_AMOUNT();\n error ALREADY_INITIALIZED();\n error NO_MSG_VALUE_ALLOWED();\n error TERMINAL_NOT_FOUND();\n\n //*********************************************************************//\n // ------------------- public immutable properties ------------------- //\n //*********************************************************************//\n\n /// @notice A contract storing directories of terminals and controllers for each project.\n IJBDirectory public immutable override directory;\n\n /// @notice The deployer associated with this implementation. Used to rule out double initialization.\n address public immutable override projectPayerDeployer;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The ID of the project that should be used to forward this contract's received payments.\n uint256 public override defaultProjectId;\n\n /// @notice The beneficiary that should be used in the payment made when this contract receives payments.\n address payable public override defaultBeneficiary;\n\n /// @notice A flag indicating whether issued tokens should be automatically claimed into the beneficiary's wallet. Leaving tokens unclaimed saves gas.\n bool public override defaultPreferClaimedTokens;\n\n /// @notice The memo that should be used in the payment made when this contract receives payments.\n string public override defaultMemo;\n\n /// @notice The metadata that should be used in the payment made when this contract receives payments.\n bytes public override defaultMetadata;\n\n /// @notice A flag indicating if received payments should call the `pay` function or the `addToBalance` function of a project.\n bool public override defaultPreferAddToBalance;\n\n //*********************************************************************//\n // ------------------------- public views ---------------------------- //\n //*********************************************************************//\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if the provided interface ID is supported.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(ERC165, IERC165) returns (bool) {\n return\n _interfaceId == type(IJBProjectPayer).interfaceId || super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // -------------------------- constructors --------------------------- //\n //*********************************************************************//\n\n /// @dev This is the constructor of the implementation. The directory is shared between project payers and is immutable. If a new JBDirectory is needed, a new JBProjectPayerDeployer should be deployed.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n constructor(IJBDirectory _directory) {\n directory = _directory;\n projectPayerDeployer = msg.sender;\n }\n\n /// @param _defaultProjectId The ID of the project whose treasury should be forwarded this contract's received payments.\n /// @param _defaultBeneficiary The address that'll receive the project's tokens.\n /// @param _defaultPreferClaimedTokens A flag indicating whether issued tokens should be automatically claimed into the beneficiary's wallet.\n /// @param _defaultMemo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _defaultMetadata Bytes to send along to the project's data source and delegate, if provided.\n /// @param _defaultPreferAddToBalance A flag indicating if received payments should call the `pay` function or the `addToBalance` function of a project.\n /// @param _owner The address that will own the contract.\n function initialize(\n uint256 _defaultProjectId,\n address payable _defaultBeneficiary,\n bool _defaultPreferClaimedTokens,\n string memory _defaultMemo,\n bytes memory _defaultMetadata,\n bool _defaultPreferAddToBalance,\n address _owner\n ) public {\n if (msg.sender != projectPayerDeployer) revert ALREADY_INITIALIZED();\n\n defaultProjectId = _defaultProjectId;\n defaultBeneficiary = _defaultBeneficiary;\n defaultPreferClaimedTokens = _defaultPreferClaimedTokens;\n defaultMemo = _defaultMemo;\n defaultMetadata = _defaultMetadata;\n defaultPreferAddToBalance = _defaultPreferAddToBalance;\n _transferOwnership(_owner);\n }\n\n //*********************************************************************//\n // ------------------------- default receive ------------------------- //\n //*********************************************************************//\n\n /// @notice Received funds are paid to the default project ID using the stored default properties.\n /// @dev Use the `addToBalance` function if there's a preference to do so. Otherwise use `pay`.\n /// @dev This function is called automatically when the contract receives an ETH payment.\n receive() external payable virtual override {\n if (defaultPreferAddToBalance)\n _addToBalanceOf(\n defaultProjectId,\n JBTokens.ETH,\n address(this).balance,\n 18, // balance is a fixed point number with 18 decimals.\n defaultMemo,\n defaultMetadata\n );\n else\n _pay(\n defaultProjectId,\n JBTokens.ETH,\n address(this).balance,\n 18, // balance is a fixed point number with 18 decimals.\n defaultBeneficiary == address(0) ? tx.origin : defaultBeneficiary,\n 0, // Can't determine expectation of returned tokens ahead of time.\n defaultPreferClaimedTokens,\n defaultMemo,\n defaultMetadata\n );\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Sets the default values that determine how to interact with a protocol treasury when this contract receives ETH directly.\n /// @param _projectId The ID of the project whose treasury should be forwarded this contract's received payments.\n /// @param _beneficiary The address that'll receive the project's tokens.\n /// @param _preferClaimedTokens A flag indicating whether issued tokens should be automatically claimed into the beneficiary's wallet.\n /// @param _memo The memo that'll be used.\n /// @param _metadata The metadata that'll be sent.\n /// @param _defaultPreferAddToBalance A flag indicating if received payments should call the `pay` function or the `addToBalance` function of a project.\n function setDefaultValues(\n uint256 _projectId,\n address payable _beneficiary,\n bool _preferClaimedTokens,\n string memory _memo,\n bytes memory _metadata,\n bool _defaultPreferAddToBalance\n ) external virtual override onlyOwner {\n // Set the default project ID if it has changed.\n if (_projectId != defaultProjectId) defaultProjectId = _projectId;\n\n // Set the default beneficiary if it has changed.\n if (_beneficiary != defaultBeneficiary) defaultBeneficiary = _beneficiary;\n\n // Set the default claimed token preference if it has changed.\n if (_preferClaimedTokens != defaultPreferClaimedTokens)\n defaultPreferClaimedTokens = _preferClaimedTokens;\n\n // Set the default memo if it has changed.\n if (keccak256(abi.encodePacked(_memo)) != keccak256(abi.encodePacked(defaultMemo)))\n defaultMemo = _memo;\n\n // Set the default metadata if it has changed.\n if (keccak256(abi.encodePacked(_metadata)) != keccak256(abi.encodePacked(defaultMetadata)))\n defaultMetadata = _metadata;\n\n // Set the add to balance preference if it has changed.\n if (_defaultPreferAddToBalance != defaultPreferAddToBalance)\n defaultPreferAddToBalance = _defaultPreferAddToBalance;\n\n emit SetDefaultValues(\n _projectId,\n _beneficiary,\n _preferClaimedTokens,\n _memo,\n _metadata,\n _defaultPreferAddToBalance,\n msg.sender\n );\n }\n\n //*********************************************************************//\n // ----------------------- public transactions ----------------------- //\n //*********************************************************************//\n\n /// @notice Make a payment to the specified project.\n /// @param _projectId The ID of the project that is being paid.\n /// @param _token The token being paid in.\n /// @param _amount The amount of tokens being paid, as a fixed point number. If the token is ETH, this is ignored and msg.value is used in its place.\n /// @param _decimals The number of decimals in the `_amount` fixed point number. If the token is ETH, this is ignored and 18 is used in its place, which corresponds to the amount of decimals expected in msg.value.\n /// @param _beneficiary The address who will receive tokens from the payment.\n /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with 18 decimals.\n /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\n /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n function pay(\n uint256 _projectId,\n address _token,\n uint256 _amount,\n uint256 _decimals,\n address _beneficiary,\n uint256 _minReturnedTokens,\n bool _preferClaimedTokens,\n string calldata _memo,\n bytes calldata _metadata\n ) public payable virtual override {\n // ETH shouldn't be sent if the token isn't ETH.\n if (address(_token) != JBTokens.ETH) {\n if (msg.value > 0) revert NO_MSG_VALUE_ALLOWED();\n\n // Get a reference to the balance before receiving tokens.\n uint256 _balanceBefore = IERC20(_token).balanceOf(address(this));\n\n // Transfer tokens to this contract from the msg sender.\n IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount);\n\n // The amount should reflect the change in balance.\n _amount = IERC20(_token).balanceOf(address(this)) - _balanceBefore;\n } else {\n // If ETH is being paid, set the amount to the message value, and decimals to 18.\n _amount = msg.value;\n _decimals = 18;\n }\n\n _pay(\n _projectId,\n _token,\n _amount,\n _decimals,\n _beneficiary,\n _minReturnedTokens,\n _preferClaimedTokens,\n _memo,\n _metadata\n );\n }\n\n /// @notice Add to the balance of the specified project.\n /// @param _projectId The ID of the project that is being paid.\n /// @param _token The token being paid in.\n /// @param _amount The amount of tokens being paid, as a fixed point number. If the token is ETH, this is ignored and msg.value is used in its place.\n /// @param _decimals The number of decimals in the `_amount` fixed point number. If the token is ETH, this is ignored and 18 is used in its place, which corresponds to the amount of decimals expected in msg.value.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the terminal.\n function addToBalanceOf(\n uint256 _projectId,\n address _token,\n uint256 _amount,\n uint256 _decimals,\n string calldata _memo,\n bytes calldata _metadata\n ) public payable virtual override {\n // ETH shouldn't be sent if the token isn't ETH.\n if (address(_token) != JBTokens.ETH) {\n if (msg.value > 0) revert NO_MSG_VALUE_ALLOWED();\n\n // Get a reference to the balance before receiving tokens.\n uint256 _balanceBefore = IERC20(_token).balanceOf(address(this));\n\n // Transfer tokens to this contract from the msg sender.\n IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount);\n\n // The amount should reflect the change in balance.\n _amount = IERC20(_token).balanceOf(address(this)) - _balanceBefore;\n } else {\n // If ETH is being paid, set the amount to the message value, and decimals to 18.\n _amount = msg.value;\n _decimals = 18;\n }\n\n _addToBalanceOf(_projectId, _token, _amount, _decimals, _memo, _metadata);\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Make a payment to the specified project.\n /// @param _projectId The ID of the project that is being paid.\n /// @param _token The token being paid in.\n /// @param _amount The amount of tokens being paid, as a fixed point number.\n /// @param _decimals The number of decimals in the `_amount` fixed point number.\n /// @param _beneficiary The address who will receive tokens from the payment.\n /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with 18 decimals.\n /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\n /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _metadata Bytes to send along to the data source and delegate, if provided.\n function _pay(\n uint256 _projectId,\n address _token,\n uint256 _amount,\n uint256 _decimals,\n address _beneficiary,\n uint256 _minReturnedTokens,\n bool _preferClaimedTokens,\n string memory _memo,\n bytes memory _metadata\n ) internal virtual {\n // Find the terminal for the specified project.\n IJBPaymentTerminal _terminal = directory.primaryTerminalOf(_projectId, _token);\n\n // There must be a terminal.\n if (_terminal == IJBPaymentTerminal(address(0))) revert TERMINAL_NOT_FOUND();\n\n // The amount's decimals must match the terminal's expected decimals.\n if (_terminal.decimalsForToken(_token) != _decimals) revert INCORRECT_DECIMAL_AMOUNT();\n\n // Approve the `_amount` of tokens from the destination terminal to transfer tokens from this contract.\n if (_token != JBTokens.ETH) IERC20(_token).safeApprove(address(_terminal), _amount);\n\n // If the token is ETH, send it in msg.value.\n uint256 _payableValue = _token == JBTokens.ETH ? _amount : 0;\n\n // Send funds to the terminal.\n // If the token is ETH, send it in msg.value.\n _terminal.pay{value: _payableValue}(\n _projectId,\n _amount, // ignored if the token is JBTokens.ETH.\n _token,\n _beneficiary != address(0) ? _beneficiary : defaultBeneficiary != address(0)\n ? defaultBeneficiary\n : tx.origin,\n _minReturnedTokens,\n _preferClaimedTokens,\n _memo,\n _metadata\n );\n }\n\n /// @notice Add to the balance of the specified project.\n /// @param _projectId The ID of the project that is being paid.\n /// @param _token The token being paid in.\n /// @param _amount The amount of tokens being paid, as a fixed point number. If the token is ETH, this is ignored and msg.value is used in its place.\n /// @param _decimals The number of decimals in the `_amount` fixed point number. If the token is ETH, this is ignored and 18 is used in its place, which corresponds to the amount of decimals expected in msg.value.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the terminal.\n function _addToBalanceOf(\n uint256 _projectId,\n address _token,\n uint256 _amount,\n uint256 _decimals,\n string memory _memo,\n bytes memory _metadata\n ) internal virtual {\n // Find the terminal for the specified project.\n IJBPaymentTerminal _terminal = directory.primaryTerminalOf(_projectId, _token);\n\n // There must be a terminal.\n if (_terminal == IJBPaymentTerminal(address(0))) revert TERMINAL_NOT_FOUND();\n\n // The amount's decimals must match the terminal's expected decimals.\n if (_terminal.decimalsForToken(_token) != _decimals) revert INCORRECT_DECIMAL_AMOUNT();\n\n // Approve the `_amount` of tokens from the destination terminal to transfer tokens from this contract.\n if (_token != JBTokens.ETH) IERC20(_token).safeApprove(address(_terminal), _amount);\n\n // If the token is ETH, send it in msg.value.\n uint256 _payableValue = _token == JBTokens.ETH ? _amount : 0;\n\n // Add to balance so tokens don't get issued.\n _terminal.addToBalanceOf{value: _payableValue}(_projectId, _amount, _token, _memo, _metadata);\n }\n}\n" + }, + "contracts/libraries/JBTokens.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nlibrary JBTokens {\n /// @notice The ETH token address in Juicebox is represented by 0x000000000000000000000000000000000000EEEe.\n address public constant ETH = address(0x000000000000000000000000000000000000EEEe);\n}\n" + }, + "contracts/interfaces/IJBProjectPayer.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {IJBDirectory} from './IJBDirectory.sol';\n\ninterface IJBProjectPayer is IERC165 {\n event SetDefaultValues(\n uint256 indexed projectId,\n address indexed beneficiary,\n bool preferClaimedTokens,\n string memo,\n bytes metadata,\n bool preferAddToBalance,\n address caller\n );\n\n function directory() external view returns (IJBDirectory);\n\n function projectPayerDeployer() external view returns (address);\n\n function defaultProjectId() external view returns (uint256);\n\n function defaultBeneficiary() external view returns (address payable);\n\n function defaultPreferClaimedTokens() external view returns (bool);\n\n function defaultMemo() external view returns (string memory);\n\n function defaultMetadata() external view returns (bytes memory);\n\n function defaultPreferAddToBalance() external view returns (bool);\n\n function initialize(\n uint256 defaultProjectId,\n address payable defaultBeneficiary,\n bool defaultPreferClaimedTokens,\n string memory defaultMemo,\n bytes memory defaultMetadata,\n bool defaultPreferAddToBalance,\n address owner\n ) external;\n\n function setDefaultValues(\n uint256 projectId,\n address payable beneficiary,\n bool preferClaimedTokens,\n string memory memo,\n bytes memory metadata,\n bool defaultPreferAddToBalance\n ) external;\n\n function pay(\n uint256 projectId,\n address token,\n uint256 amount,\n uint256 decimals,\n address beneficiary,\n uint256 minReturnedTokens,\n bool preferClaimedTokens,\n string memory memo,\n bytes memory metadata\n ) external payable;\n\n function addToBalanceOf(\n uint256 projectId,\n address token,\n uint256 amount,\n uint256 decimals,\n string memory memo,\n bytes memory metadata\n ) external payable;\n\n receive() external payable;\n}\n" + }, + "contracts/JBController3_0_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {ERC165, IERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {SafeCast} from '@openzeppelin/contracts/utils/math/SafeCast.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {JBOperatable} from './abstract/JBOperatable.sol';\nimport {JBBallotState} from './enums/JBBallotState.sol';\nimport {IJBController3_0_1} from './interfaces/IJBController3_0_1.sol';\nimport {IJBController} from './interfaces/IJBController.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol';\nimport {IJBMigratable} from './interfaces/IJBMigratable.sol';\nimport {IJBOperatable} from './interfaces/IJBOperatable.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {IJBSplitAllocator} from './interfaces/IJBSplitAllocator.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {IJBTokenStore} from './interfaces/IJBTokenStore.sol';\nimport {JBConstants} from './libraries/JBConstants.sol';\nimport {JBFundingCycleMetadataResolver} from './libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBOperations} from './libraries/JBOperations.sol';\nimport {JBSplitsGroups} from './libraries/JBSplitsGroups.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\nimport {JBSplitAllocationData} from './structs/JBSplitAllocationData.sol';\nimport {JBFundAccessConstraints} from './structs/JBFundAccessConstraints.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\nimport {JBFundingCycleData} from './structs/JBFundingCycleData.sol';\nimport {JBFundingCycleMetadata} from './structs/JBFundingCycleMetadata.sol';\nimport {JBGroupedSplits} from './structs/JBGroupedSplits.sol';\nimport {JBProjectMetadata} from './structs/JBProjectMetadata.sol';\nimport {JBSplit} from './structs/JBSplit.sol';\n\n/// @notice Stitches together funding cycles and project tokens, making sure all activity is accounted for and correct.\n/// @dev This Controller manages a project's reserved tokens explicitly instead of through a passive tracker property.\n/// @dev It is backwards compatible with the original IJBController, and exposes convenience view methods as part of IJBController3_1 for clearer queries.\ncontract JBController3_0_1 is\n JBOperatable,\n ERC165,\n IJBController,\n IJBController3_0_1,\n IJBMigratable\n{\n // A library that parses the packed funding cycle metadata into a more friendly format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error BURN_PAUSED_AND_SENDER_NOT_VALID_TERMINAL_DELEGATE();\n error FUNDING_CYCLE_ALREADY_LAUNCHED();\n error INVALID_BALLOT_REDEMPTION_RATE();\n error INVALID_DISTRIBUTION_LIMIT();\n error INVALID_DISTRIBUTION_LIMIT_CURRENCY();\n error INVALID_OVERFLOW_ALLOWANCE();\n error INVALID_OVERFLOW_ALLOWANCE_CURRENCY();\n error INVALID_REDEMPTION_RATE();\n error INVALID_RESERVED_RATE();\n error MIGRATION_NOT_ALLOWED();\n error MINT_NOT_ALLOWED_AND_NOT_TERMINAL_DELEGATE();\n error NO_BURNABLE_TOKENS();\n error NOT_CURRENT_CONTROLLER();\n error ZERO_TOKENS_TO_MINT();\n\n //*********************************************************************//\n // --------------------- internal stored properties ------------------ //\n //*********************************************************************//\n\n /// @notice Data regarding the distribution limit of a project during a configuration.\n /// @dev bits 0-231: The amount of token that a project can distribute per funding cycle.\n /// @dev bits 232-255: The currency of amount that a project can distribute.\n /// @custom:param _projectId The ID of the project to get the packed distribution limit data of.\n /// @custom:param _configuration The configuration during which the packed distribution limit data applies.\n /// @custom:param _terminal The terminal from which distributions are being limited.\n /// @custom:param _token The token for which distributions are being limited.\n mapping(uint256 => mapping(uint256 => mapping(IJBPaymentTerminal => mapping(address => uint256))))\n internal _packedDistributionLimitDataOf;\n\n /// @notice Data regarding the overflow allowance of a project during a configuration.\n /// @dev bits 0-231: The amount of overflow that a project is allowed to tap into on-demand throughout the configuration.\n /// @dev bits 232-255: The currency of the amount of overflow that a project is allowed to tap.\n /// @custom:param _projectId The ID of the project to get the packed overflow allowance data of.\n /// @custom:param _configuration The configuration during which the packed overflow allowance data applies.\n /// @custom:param _terminal The terminal managing the overflow.\n /// @custom:param _token The token for which overflow is being allowed.\n mapping(uint256 => mapping(uint256 => mapping(IJBPaymentTerminal => mapping(address => uint256))))\n internal _packedOverflowAllowanceDataOf;\n\n /// @notice The current undistributed reserved token balance of.\n /// @custom:param _projectId The ID of the project to get a reserved token balance of.\n mapping(uint256 => uint256) internal _reservedTokenBalanceOf;\n\n //*********************************************************************//\n // --------------- public immutable stored properties ---------------- //\n //*********************************************************************//\n\n /// @notice Mints ERC-721's that represent project ownership.\n IJBProjects public immutable override projects;\n\n /// @notice The contract storing all funding cycle configurations.\n IJBFundingCycleStore public immutable override fundingCycleStore;\n\n /// @notice The contract that manages token minting and burning.\n IJBTokenStore public immutable override tokenStore;\n\n /// @notice The contract that stores splits for each project.\n IJBSplitsStore public immutable override splitsStore;\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice The amount of token that a project can distribute per funding cycle, and the currency it's in terms of.\n /// @dev The number of decimals in the returned fixed point amount is the same as that of the specified terminal.\n /// @param _projectId The ID of the project to get the distribution limit of.\n /// @param _configuration The configuration during which the distribution limit applies.\n /// @param _terminal The terminal from which distributions are being limited.\n /// @param _token The token for which the distribution limit applies.\n /// @return The distribution limit, as a fixed point number with the same number of decimals as the provided terminal.\n /// @return The currency of the distribution limit.\n function distributionLimitOf(\n uint256 _projectId,\n uint256 _configuration,\n IJBPaymentTerminal _terminal,\n address _token\n ) external view override returns (uint256, uint256) {\n // Get a reference to the packed data.\n uint256 _data = _packedDistributionLimitDataOf[_projectId][_configuration][_terminal][_token];\n\n // The limit is in bits 0-231. The currency is in bits 232-255.\n return (uint256(uint232(_data)), _data >> 232);\n }\n\n /// @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.\n /// @dev The number of decimals in the returned fixed point amount is the same as that of the specified terminal.\n /// @param _projectId The ID of the project to get the overflow allowance of.\n /// @param _configuration The configuration of the during which the allowance applies.\n /// @param _terminal The terminal managing the overflow.\n /// @param _token The token for which the overflow allowance applies.\n /// @return The overflow allowance, as a fixed point number with the same number of decimals as the provided terminal.\n /// @return The currency of the overflow allowance.\n function overflowAllowanceOf(\n uint256 _projectId,\n uint256 _configuration,\n IJBPaymentTerminal _terminal,\n address _token\n ) external view override returns (uint256, uint256) {\n // Get a reference to the packed data.\n uint256 _data = _packedOverflowAllowanceDataOf[_projectId][_configuration][_terminal][_token];\n\n // The allowance is in bits 0-231. The currency is in bits 232-255.\n return (uint256(uint232(_data)), _data >> 232);\n }\n\n /// @notice A project's funding cycle for the specified configuration along with its metadata.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The funding cycle.\n /// @return metadata The funding cycle's metadata.\n function getFundingCycleOf(\n uint256 _projectId,\n uint256 _configuration\n )\n external\n view\n override\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata)\n {\n fundingCycle = fundingCycleStore.get(_projectId, _configuration);\n metadata = fundingCycle.expandMetadata();\n }\n\n /// @notice A project's latest configured funding cycle along with its metadata and the ballot state of the configuration.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The latest configured funding cycle.\n /// @return metadata The latest configured funding cycle's metadata.\n /// @return ballotState The state of the configuration.\n function latestConfiguredFundingCycleOf(\n uint256 _projectId\n )\n external\n view\n override\n returns (\n JBFundingCycle memory fundingCycle,\n JBFundingCycleMetadata memory metadata,\n JBBallotState ballotState\n )\n {\n (fundingCycle, ballotState) = fundingCycleStore.latestConfiguredOf(_projectId);\n metadata = fundingCycle.expandMetadata();\n }\n\n /// @notice A project's current funding cycle along with its metadata.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The current funding cycle.\n /// @return metadata The current funding cycle's metadata.\n function currentFundingCycleOf(\n uint256 _projectId\n )\n external\n view\n override\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata)\n {\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n metadata = fundingCycle.expandMetadata();\n }\n\n /// @notice A project's queued funding cycle along with its metadata.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The queued funding cycle.\n /// @return metadata The queued funding cycle's metadata.\n function queuedFundingCycleOf(\n uint256 _projectId\n )\n external\n view\n override\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata)\n {\n fundingCycle = fundingCycleStore.queuedOf(_projectId);\n metadata = fundingCycle.expandMetadata();\n }\n\n /// @notice\tGets the amount of reserved tokens that a project has available to distribute.\n /// @param _projectId The ID of the project to get a reserved token balance of.\n /// @return The current amount of reserved tokens.\n function reservedTokenBalanceOf(uint256 _projectId) external view override returns (uint256) {\n return _reservedTokenBalanceOf[_projectId];\n }\n\n /// @notice\tGets the amount of reserved tokens that a project has available to distribute.\n /// @dev This is just for IJBController backwards compatibility.\n /// @param _projectId The ID of the project to get a reserved token balance of.\n /// @param _reservedRate The reserved rate to use when making the calculation.\n /// @return The current amount of reserved tokens.\n function reservedTokenBalanceOf(\n uint256 _projectId,\n uint256 _reservedRate\n ) external view override returns (uint256) {\n _reservedRate;\n return _reservedTokenBalanceOf[_projectId];\n }\n\n /// @notice\tGets the current total amount of outstanding tokens for a project, given a reserved rate.\n /// @dev This is just for IJBController backwards compatibility.\n /// @param _projectId The ID of the project to get total outstanding tokens of.\n /// @param _reservedRate The reserved rate to use when making the calculation.\n /// @return The current total amount of outstanding tokens for the project.\n function totalOutstandingTokensOf(\n uint256 _projectId,\n uint256 _reservedRate\n ) external view override returns (uint256) {\n _reservedRate;\n // Add the reserved tokens to the total supply.\n return totalOutstandingTokensOf(_projectId);\n }\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice Gets the current total amount of outstanding tokens for a project.\n /// @param _projectId The ID of the project to get total outstanding tokens of.\n /// @return The current total amount of outstanding tokens for the project.\n function totalOutstandingTokensOf(uint256 _projectId) public view override returns (uint256) {\n // Add the reserved tokens to the total supply.\n return tokenStore.totalSupplyOf(_projectId) + _reservedTokenBalanceOf[_projectId];\n }\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if the provided interface ID is supported.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(ERC165, IERC165) returns (bool) {\n return\n _interfaceId == type(IJBController3_0_1).interfaceId ||\n _interfaceId == type(IJBMigratable).interfaceId ||\n _interfaceId == type(IJBOperatable).interfaceId ||\n super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // ---------------------------- constructor -------------------------- //\n //*********************************************************************//\n\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _fundingCycleStore A contract storing all funding cycle configurations.\n /// @param _tokenStore A contract that manages token minting and burning.\n /// @param _splitsStore A contract that stores splits for each project.\n constructor(\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBFundingCycleStore _fundingCycleStore,\n IJBTokenStore _tokenStore,\n IJBSplitsStore _splitsStore\n ) JBOperatable(_operatorStore) {\n projects = _projects;\n directory = _directory;\n fundingCycleStore = _fundingCycleStore;\n tokenStore = _tokenStore;\n splitsStore = _splitsStore;\n }\n\n //*********************************************************************//\n // --------------------- external transactions ----------------------- //\n //*********************************************************************//\n\n /// @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.\n /// @dev Each operation within this transaction can be done in sequence separately.\n /// @dev Anyone can deploy a project on an owner's behalf.\n /// @param _owner The address to set as the owner of the project. The project ERC-721 will be owned by this address.\n /// @param _projectMetadata Metadata to associate with the project within a particular domain. This can be updated any time by the owner of the project.\n /// @param _data Data that defines the project's first funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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`.\n /// @param _terminals Payment terminals to add for the project.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return projectId The ID of the project.\n function launchProjectFor(\n address _owner,\n JBProjectMetadata calldata _projectMetadata,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] calldata _groupedSplits,\n JBFundAccessConstraints[] calldata _fundAccessConstraints,\n IJBPaymentTerminal[] memory _terminals,\n string memory _memo\n ) external virtual override returns (uint256 projectId) {\n // Keep a reference to the directory.\n IJBDirectory _directory = directory;\n\n // Mint the project into the wallet of the owner.\n projectId = projects.createFor(_owner, _projectMetadata);\n\n // Set this contract as the project's controller in the directory.\n _directory.setControllerOf(projectId, address(this));\n\n // Configure the first funding cycle.\n uint256 _configuration = _configure(\n projectId,\n _data,\n _metadata,\n _mustStartAtOrAfter,\n _groupedSplits,\n _fundAccessConstraints\n );\n\n // Add the provided terminals to the list of terminals.\n if (_terminals.length > 0) _directory.setTerminalsOf(projectId, _terminals);\n\n emit LaunchProject(_configuration, projectId, _memo, msg.sender);\n }\n\n /// @notice Creates a funding cycle for an already existing project ERC-721.\n /// @dev Each operation within this transaction can be done in sequence separately.\n /// @dev Only a project owner or operator can launch its funding cycles.\n /// @param _projectId The ID of the project to launch funding cycles for.\n /// @param _data Data that defines the project's first funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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`.\n /// @param _terminals Payment terminals to add for the project.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return configuration The configuration of the funding cycle that was successfully created.\n function launchFundingCyclesFor(\n uint256 _projectId,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] calldata _groupedSplits,\n JBFundAccessConstraints[] memory _fundAccessConstraints,\n IJBPaymentTerminal[] memory _terminals,\n string memory _memo\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.RECONFIGURE)\n returns (uint256 configuration)\n {\n // If there is a previous configuration, reconfigureFundingCyclesOf should be called instead\n if (fundingCycleStore.latestConfigurationOf(_projectId) > 0)\n revert FUNDING_CYCLE_ALREADY_LAUNCHED();\n\n // Set this contract as the project's controller in the directory.\n directory.setControllerOf(_projectId, address(this));\n\n // Configure the first funding cycle.\n configuration = _configure(\n _projectId,\n _data,\n _metadata,\n _mustStartAtOrAfter,\n _groupedSplits,\n _fundAccessConstraints\n );\n\n // Add the provided terminals to the list of terminals.\n if (_terminals.length > 0) directory.setTerminalsOf(_projectId, _terminals);\n\n emit LaunchFundingCycles(configuration, _projectId, _memo, msg.sender);\n }\n\n /// @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.\n /// @dev Only a project's owner or a designated operator can configure its funding cycles.\n /// @param _projectId The ID of the project whose funding cycles are being reconfigured.\n /// @param _data Data that defines the funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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`.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return configuration The configuration of the funding cycle that was successfully reconfigured.\n function reconfigureFundingCyclesOf(\n uint256 _projectId,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] calldata _groupedSplits,\n JBFundAccessConstraints[] calldata _fundAccessConstraints,\n string calldata _memo\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.RECONFIGURE)\n returns (uint256 configuration)\n {\n // Configure the next funding cycle.\n configuration = _configure(\n _projectId,\n _data,\n _metadata,\n _mustStartAtOrAfter,\n _groupedSplits,\n _fundAccessConstraints\n );\n\n emit ReconfigureFundingCycles(configuration, _projectId, _memo, msg.sender);\n }\n\n /// @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.\n /// @dev Only a project's owner, a designated operator, one of its terminals, or the current data source can mint its tokens.\n /// @param _projectId The ID of the project to which the tokens being minted belong.\n /// @param _tokenCount The amount of tokens to mint in total, counting however many should be reserved.\n /// @param _beneficiary The account that the tokens are being minted for.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _preferClaimedTokens A flag indicating whether a project's attached token contract should be minted if they have been issued.\n /// @param _useReservedRate Whether to use the current funding cycle's reserved rate in the mint calculation.\n /// @return beneficiaryTokenCount The amount of tokens minted for the beneficiary.\n function mintTokensOf(\n uint256 _projectId,\n uint256 _tokenCount,\n address _beneficiary,\n string calldata _memo,\n bool _preferClaimedTokens,\n bool _useReservedRate\n ) external virtual override returns (uint256 beneficiaryTokenCount) {\n // There should be tokens to mint.\n if (_tokenCount == 0) revert ZERO_TOKENS_TO_MINT();\n\n // Define variables that will be needed outside scoped section below.\n // Keep a reference to the reserved rate to use\n uint256 _reservedRate;\n\n // Scoped section prevents stack too deep. `_fundingCycle` only used within scope.\n {\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Minting limited to: project owner, authorized callers, project terminal and current funding cycle data source\n _requirePermissionAllowingOverride(\n projects.ownerOf(_projectId),\n _projectId,\n JBOperations.MINT,\n directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender)) ||\n msg.sender == address(_fundingCycle.dataSource())\n );\n\n // If the message sender is not a terminal or a datasource, the current funding cycle must allow minting.\n if (\n !_fundingCycle.mintingAllowed() &&\n !directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender)) &&\n msg.sender != address(_fundingCycle.dataSource())\n ) revert MINT_NOT_ALLOWED_AND_NOT_TERMINAL_DELEGATE();\n\n // Determine the reserved rate to use.\n _reservedRate = _useReservedRate ? _fundingCycle.reservedRate() : 0;\n\n // Override the claimed token preference with the funding cycle value.\n _preferClaimedTokens = _preferClaimedTokens == true\n ? _preferClaimedTokens\n : _fundingCycle.preferClaimedTokenOverride();\n }\n\n if (_reservedRate != JBConstants.MAX_RESERVED_RATE) {\n // The unreserved token count that will be minted for the beneficiary.\n beneficiaryTokenCount = PRBMath.mulDiv(\n _tokenCount,\n JBConstants.MAX_RESERVED_RATE - _reservedRate,\n JBConstants.MAX_RESERVED_RATE\n );\n\n // Mint the tokens.\n tokenStore.mintFor(_beneficiary, _projectId, beneficiaryTokenCount, _preferClaimedTokens);\n }\n\n // Add reserved tokens if needed\n if (_reservedRate > 0)\n _reservedTokenBalanceOf[_projectId] += _tokenCount - beneficiaryTokenCount;\n\n emit MintTokens(\n _beneficiary,\n _projectId,\n _tokenCount,\n beneficiaryTokenCount,\n _memo,\n _reservedRate,\n msg.sender\n );\n }\n\n /// @notice Burns a token holder's supply.\n /// @dev Only a token's holder, a designated operator, or a project's terminal can burn it.\n /// @param _holder The account that is having its tokens burned.\n /// @param _projectId The ID of the project to which the tokens being burned belong.\n /// @param _tokenCount The number of tokens to burn.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _preferClaimedTokens A flag indicating whether a project's attached token contract should be burned first if they have been issued.\n function burnTokensOf(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n string calldata _memo,\n bool _preferClaimedTokens\n )\n external\n virtual\n override\n requirePermissionAllowingOverride(\n _holder,\n _projectId,\n JBOperations.BURN,\n directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender))\n )\n {\n // There should be tokens to burn\n if (_tokenCount == 0) revert NO_BURNABLE_TOKENS();\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // If the message sender is a terminal, the current funding cycle must not be paused.\n if (\n _fundingCycle.burnPaused() &&\n !directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender))\n ) revert BURN_PAUSED_AND_SENDER_NOT_VALID_TERMINAL_DELEGATE();\n\n // Burn the tokens.\n tokenStore.burnFrom(_holder, _projectId, _tokenCount, _preferClaimedTokens);\n\n emit BurnTokens(_holder, _projectId, _tokenCount, _memo, msg.sender);\n }\n\n /// @notice Distributes all outstanding reserved tokens for a project.\n /// @param _projectId The ID of the project to which the reserved tokens belong.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return The amount of minted reserved tokens.\n function distributeReservedTokensOf(\n uint256 _projectId,\n string calldata _memo\n ) external virtual override returns (uint256) {\n return _distributeReservedTokensOf(_projectId, _memo);\n }\n\n /// @notice Allows other controllers to signal to this one that a migration is expected for the specified project.\n /// @dev This controller should not yet be the project's controller.\n /// @param _projectId The ID of the project that will be migrated to this controller.\n /// @param _from The controller being migrated from.\n function prepForMigrationOf(uint256 _projectId, address _from) external virtual override {\n _projectId; // Prevents unused var compiler and natspec complaints.\n _from; // Prevents unused var compiler and natspec complaints.\n }\n\n /// @notice Allows a project to migrate from this controller to another.\n /// @dev Only a project's owner or a designated operator can migrate it.\n /// @param _projectId The ID of the project that will be migrated from this controller.\n /// @param _to The controller to which the project is migrating.\n function migrate(\n uint256 _projectId,\n IJBMigratable _to\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.MIGRATE_CONTROLLER)\n {\n // Keep a reference to the directory.\n IJBDirectory _directory = directory;\n\n // This controller must be the project's current controller.\n if (_directory.controllerOf(_projectId) != address(this)) revert NOT_CURRENT_CONTROLLER();\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Migration must be allowed.\n if (!_fundingCycle.controllerMigrationAllowed()) revert MIGRATION_NOT_ALLOWED();\n\n // All reserved tokens must be minted before migrating.\n if (_reservedTokenBalanceOf[_projectId] != 0) _distributeReservedTokensOf(_projectId, '');\n\n // Make sure the new controller is prepped for the migration.\n _to.prepForMigrationOf(_projectId, address(this));\n\n // Set the new controller.\n _directory.setControllerOf(_projectId, address(_to));\n\n emit Migrate(_projectId, _to, msg.sender);\n }\n\n //*********************************************************************//\n // ------------------------ internal functions ----------------------- //\n //*********************************************************************//\n\n /// @notice Distributes all outstanding reserved tokens for a project.\n /// @param _projectId The ID of the project to which the reserved tokens belong.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return tokenCount The amount of minted reserved tokens.\n function _distributeReservedTokensOf(\n uint256 _projectId,\n string memory _memo\n ) internal returns (uint256 tokenCount) {\n // Keep a reference to the token store.\n IJBTokenStore _tokenStore = tokenStore;\n\n // Get the current funding cycle to read the reserved rate from.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Get a reference to the number of tokens that need to be minted.\n tokenCount = _reservedTokenBalanceOf[_projectId];\n\n // Reset the reserved token balance\n _reservedTokenBalanceOf[_projectId] = 0;\n\n // Get a reference to the project owner.\n address _owner = projects.ownerOf(_projectId);\n\n // Distribute tokens to splits and get a reference to the leftover amount to mint after all splits have gotten their share.\n uint256 _leftoverTokenCount = tokenCount == 0\n ? 0\n : _distributeToReservedTokenSplitsOf(\n _projectId,\n _fundingCycle.configuration,\n JBSplitsGroups.RESERVED_TOKENS,\n tokenCount\n );\n\n // Mint any leftover tokens to the project owner.\n if (_leftoverTokenCount > 0)\n _tokenStore.mintFor(_owner, _projectId, _leftoverTokenCount, false);\n\n emit DistributeReservedTokens(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _owner,\n tokenCount,\n _leftoverTokenCount,\n _memo,\n msg.sender\n );\n }\n\n /// @notice Distribute tokens to the splits according to the specified funding cycle configuration.\n /// @param _projectId The ID of the project for which reserved token splits are being distributed.\n /// @param _domain The domain of the splits to distribute the reserved tokens between.\n /// @param _group The group of the splits to distribute the reserved tokens between.\n /// @param _amount The total amount of tokens to mint.\n /// @return leftoverAmount If the splits percents dont add up to 100%, the leftover amount is returned.\n function _distributeToReservedTokenSplitsOf(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group,\n uint256 _amount\n ) internal returns (uint256 leftoverAmount) {\n // Keep a reference to the token store.\n IJBTokenStore _tokenStore = tokenStore;\n\n // Set the leftover amount to the initial amount.\n leftoverAmount = _amount;\n\n // Get a reference to the project's reserved token splits.\n JBSplit[] memory _splits = splitsStore.splitsOf(_projectId, _domain, _group);\n\n //Transfer between all splits.\n for (uint256 _i; _i < _splits.length; ) {\n // Get a reference to the split being iterated on.\n JBSplit memory _split = _splits[_i];\n\n // The amount to send towards the split.\n uint256 _tokenCount = PRBMath.mulDiv(\n _amount,\n _split.percent,\n JBConstants.SPLITS_TOTAL_PERCENT\n );\n\n // Mints tokens for the split if needed.\n if (_tokenCount > 0) {\n _tokenStore.mintFor(\n // If an allocator is set in the splits, set it as the beneficiary.\n // Otherwise if a projectId is set in the split, set the project's owner as the beneficiary.\n // If the split has a beneficiary send to the split's beneficiary. Otherwise send to the msg.sender.\n _split.allocator != IJBSplitAllocator(address(0))\n ? address(_split.allocator)\n : _split.projectId != 0\n ? projects.ownerOf(_split.projectId)\n : _split.beneficiary != address(0)\n ? _split.beneficiary\n : msg.sender,\n _projectId,\n _tokenCount,\n _split.preferClaimed\n );\n\n // If there's an allocator set, trigger its `allocate` function.\n if (_split.allocator != IJBSplitAllocator(address(0)))\n _split.allocator.allocate(\n JBSplitAllocationData(\n address(_tokenStore.tokenOf(_projectId)),\n _tokenCount,\n 18,\n _projectId,\n _group,\n _split\n )\n );\n\n // Subtract from the amount to be sent to the beneficiary.\n leftoverAmount = leftoverAmount - _tokenCount;\n }\n\n emit DistributeToReservedTokenSplit(\n _projectId,\n _domain,\n _group,\n _split,\n _tokenCount,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n\n /// @notice Configures a funding cycle and stores information pertinent to the configuration.\n /// @param _projectId The ID of the project whose funding cycles are being reconfigured.\n /// @param _data Data that defines the funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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.\n /// @return configuration The configuration of the funding cycle that was successfully reconfigured.\n function _configure(\n uint256 _projectId,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] memory _groupedSplits,\n JBFundAccessConstraints[] memory _fundAccessConstraints\n ) internal returns (uint256) {\n // Make sure the provided reserved rate is valid.\n if (_metadata.reservedRate > JBConstants.MAX_RESERVED_RATE) revert INVALID_RESERVED_RATE();\n\n // Make sure the provided redemption rate is valid.\n if (_metadata.redemptionRate > JBConstants.MAX_REDEMPTION_RATE)\n revert INVALID_REDEMPTION_RATE();\n\n // Make sure the provided ballot redemption rate is valid.\n if (_metadata.ballotRedemptionRate > JBConstants.MAX_REDEMPTION_RATE)\n revert INVALID_BALLOT_REDEMPTION_RATE();\n\n // Configure the funding cycle's properties.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.configureFor(\n _projectId,\n _data,\n JBFundingCycleMetadataResolver.packFundingCycleMetadata(_metadata),\n _mustStartAtOrAfter\n );\n\n // Set splits for the group.\n splitsStore.set(_projectId, _fundingCycle.configuration, _groupedSplits);\n\n // Set distribution limits if there are any.\n for (uint256 _i; _i < _fundAccessConstraints.length; ) {\n JBFundAccessConstraints memory _constraints = _fundAccessConstraints[_i];\n\n // If distribution limit value is larger than 232 bits, revert.\n if (_constraints.distributionLimit > type(uint232).max) revert INVALID_DISTRIBUTION_LIMIT();\n\n // If distribution limit currency value is larger than 24 bits, revert.\n if (_constraints.distributionLimitCurrency > type(uint24).max)\n revert INVALID_DISTRIBUTION_LIMIT_CURRENCY();\n\n // If overflow allowance value is larger than 232 bits, revert.\n if (_constraints.overflowAllowance > type(uint232).max) revert INVALID_OVERFLOW_ALLOWANCE();\n\n // If overflow allowance currency value is larger than 24 bits, revert.\n if (_constraints.overflowAllowanceCurrency > type(uint24).max)\n revert INVALID_OVERFLOW_ALLOWANCE_CURRENCY();\n\n // Set the distribution limit if there is one.\n if (_constraints.distributionLimit > 0)\n _packedDistributionLimitDataOf[_projectId][_fundingCycle.configuration][\n _constraints.terminal\n ][_constraints.token] =\n _constraints.distributionLimit |\n (_constraints.distributionLimitCurrency << 232);\n\n // Set the overflow allowance if there is one.\n if (_constraints.overflowAllowance > 0)\n _packedOverflowAllowanceDataOf[_projectId][_fundingCycle.configuration][\n _constraints.terminal\n ][_constraints.token] =\n _constraints.overflowAllowance |\n (_constraints.overflowAllowanceCurrency << 232);\n\n emit SetFundAccessConstraints(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _constraints,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n\n return _fundingCycle.configuration;\n }\n}\n" + }, + "contracts/JBProjects.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';\nimport {ERC721Votes, ERC721, EIP712} from '@openzeppelin/contracts/token/ERC721/extensions/draft-ERC721Votes.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBOperatable} from './abstract/JBOperatable.sol';\nimport {IJBOperatable} from './interfaces/IJBOperatable.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {IJBTokenUriResolver} from './interfaces/IJBTokenUriResolver.sol';\nimport {JBOperations} from './libraries/JBOperations.sol';\nimport {JBProjectMetadata} from './structs/JBProjectMetadata.sol';\n\n/// @notice Stores project ownership and metadata.\n/// @dev Projects are represented as ERC-721's.\ncontract JBProjects is JBOperatable, ERC721Votes, Ownable, IJBProjects {\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The number of projects that have been created using this contract.\n /// @dev The count is incremented with each new project created.\n /// @dev The resulting ERC-721 token ID for each project is the newly incremented count value.\n uint256 public override count = 0;\n\n /// @notice The metadata for each project, which can be used across several domains.\n /// @custom:param _projectId The ID of the project to which the metadata belongs.\n /// @custom:param _domain The domain within which the metadata applies. Applications can use the domain namespace as they wish.\n mapping(uint256 => mapping(uint256 => string)) public override metadataContentOf;\n\n /// @notice The contract resolving each project ID to its ERC721 URI.\n IJBTokenUriResolver public override tokenUriResolver;\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice Returns the URI where the ERC-721 standard JSON of a project is hosted.\n /// @param _projectId The ID of the project to get a URI of.\n /// @return The token URI to use for the provided `_projectId`.\n function tokenURI(uint256 _projectId) public view override returns (string memory) {\n // Keep a reference to the resolver.\n IJBTokenUriResolver _tokenUriResolver = tokenUriResolver;\n\n // If there's no resolver, there's no URI.\n if (_tokenUriResolver == IJBTokenUriResolver(address(0))) return '';\n\n // Return the resolved URI.\n return _tokenUriResolver.getUri(_projectId);\n }\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if the provided interface ID is supported.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(IERC165, ERC721) returns (bool) {\n return\n _interfaceId == type(IJBProjects).interfaceId ||\n _interfaceId == type(IJBOperatable).interfaceId ||\n super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _operatorStore A contract storing operator assignments.\n constructor(\n IJBOperatorStore _operatorStore\n )\n ERC721('Juicebox Projects', 'JUICEBOX')\n EIP712('Juicebox Projects', '1')\n JBOperatable(_operatorStore)\n // solhint-disable-next-line no-empty-blocks\n {\n\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Create a new project for the specified owner, which mints an NFT (ERC-721) into their wallet.\n /// @dev Anyone can create a project on an owner's behalf.\n /// @param _owner The address that will be the owner of the project.\n /// @param _metadata A struct containing metadata content about the project, and domain within which the metadata applies.\n /// @return projectId The token ID of the newly created project.\n function createFor(\n address _owner,\n JBProjectMetadata calldata _metadata\n ) external override returns (uint256 projectId) {\n // Increment the count, which will be used as the ID.\n projectId = ++count;\n\n // Mint the project.\n _safeMint(_owner, projectId);\n\n // Set the metadata if one was provided.\n if (bytes(_metadata.content).length > 0)\n metadataContentOf[projectId][_metadata.domain] = _metadata.content;\n\n emit Create(projectId, _owner, _metadata, msg.sender);\n }\n\n /// @notice Allows a project owner to set the project's metadata content for a particular domain namespace.\n /// @dev Only a project's owner or operator can set its metadata.\n /// @dev Applications can use the domain namespace as they wish.\n /// @param _projectId The ID of the project who's metadata is being changed.\n /// @param _metadata A struct containing metadata content, and domain within which the metadata applies.\n function setMetadataOf(\n uint256 _projectId,\n JBProjectMetadata calldata _metadata\n )\n external\n override\n requirePermission(ownerOf(_projectId), _projectId, JBOperations.SET_METADATA)\n {\n // Set the project's new metadata content within the specified domain.\n metadataContentOf[_projectId][_metadata.domain] = _metadata.content;\n\n emit SetMetadata(_projectId, _metadata, msg.sender);\n }\n\n /// @notice Sets the address of the resolver used to retrieve the tokenURI of projects.\n /// @param _newResolver The address of the new resolver.\n function setTokenUriResolver(IJBTokenUriResolver _newResolver) external override onlyOwner {\n // Store the new resolver.\n tokenUriResolver = _newResolver;\n\n emit SetTokenUriResolver(_newResolver, msg.sender);\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC721/extensions/draft-ERC721Votes.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (token/ERC721/extensions/draft-ERC721Votes.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../ERC721.sol\";\nimport \"../../../governance/utils/Votes.sol\";\n\n/**\n * @dev Extension of ERC721 to support voting and delegation as implemented by {Votes}, where each individual NFT counts\n * as 1 vote unit.\n *\n * Tokens do not count as votes until they are delegated, because votes must be tracked which incurs an additional cost\n * on every transfer. Token holders can either delegate to a trusted representative who will decide how to make use of\n * the votes in governance decisions, or they can delegate to themselves to be their own representative.\n *\n * _Available since v4.5._\n */\nabstract contract ERC721Votes is ERC721, Votes {\n /**\n * @dev Adjusts votes when tokens are transferred.\n *\n * Emits a {Votes-DelegateVotesChanged} event.\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 tokenId\n ) internal virtual override {\n _transferVotingUnits(from, to, 1);\n super._afterTokenTransfer(from, to, tokenId);\n }\n\n /**\n * @dev Returns the balance of `account`.\n */\n function _getVotingUnits(address account) internal virtual override returns (uint256) {\n return balanceOf(account);\n }\n}\n" + }, + "@openzeppelin/contracts/token/ERC721/ERC721.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (token/ERC721/ERC721.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC721.sol\";\nimport \"./IERC721Receiver.sol\";\nimport \"./extensions/IERC721Metadata.sol\";\nimport \"../../utils/Address.sol\";\nimport \"../../utils/Context.sol\";\nimport \"../../utils/Strings.sol\";\nimport \"../../utils/introspection/ERC165.sol\";\n\n/**\n * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including\n * the Metadata extension, but not including the Enumerable extension, which is available separately as\n * {ERC721Enumerable}.\n */\ncontract ERC721 is Context, ERC165, IERC721, IERC721Metadata {\n using Address for address;\n using Strings for uint256;\n\n // Token name\n string private _name;\n\n // Token symbol\n string private _symbol;\n\n // Mapping from token ID to owner address\n mapping(uint256 => address) private _owners;\n\n // Mapping owner address to token count\n mapping(address => uint256) private _balances;\n\n // Mapping from token ID to approved address\n mapping(uint256 => address) private _tokenApprovals;\n\n // Mapping from owner to operator approvals\n mapping(address => mapping(address => bool)) private _operatorApprovals;\n\n /**\n * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {\n return\n interfaceId == type(IERC721).interfaceId ||\n interfaceId == type(IERC721Metadata).interfaceId ||\n super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev See {IERC721-balanceOf}.\n */\n function balanceOf(address owner) public view virtual override returns (uint256) {\n require(owner != address(0), \"ERC721: balance query for the zero address\");\n return _balances[owner];\n }\n\n /**\n * @dev See {IERC721-ownerOf}.\n */\n function ownerOf(uint256 tokenId) public view virtual override returns (address) {\n address owner = _owners[tokenId];\n require(owner != address(0), \"ERC721: owner query for nonexistent token\");\n return owner;\n }\n\n /**\n * @dev See {IERC721Metadata-name}.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev See {IERC721Metadata-symbol}.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev See {IERC721Metadata-tokenURI}.\n */\n function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {\n require(_exists(tokenId), \"ERC721Metadata: URI query for nonexistent token\");\n\n string memory baseURI = _baseURI();\n return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : \"\";\n }\n\n /**\n * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each\n * token will be the concatenation of the `baseURI` and the `tokenId`. Empty\n * by default, can be overriden in child contracts.\n */\n function _baseURI() internal view virtual returns (string memory) {\n return \"\";\n }\n\n /**\n * @dev See {IERC721-approve}.\n */\n function approve(address to, uint256 tokenId) public virtual override {\n address owner = ERC721.ownerOf(tokenId);\n require(to != owner, \"ERC721: approval to current owner\");\n\n require(\n _msgSender() == owner || isApprovedForAll(owner, _msgSender()),\n \"ERC721: approve caller is not owner nor approved for all\"\n );\n\n _approve(to, tokenId);\n }\n\n /**\n * @dev See {IERC721-getApproved}.\n */\n function getApproved(uint256 tokenId) public view virtual override returns (address) {\n require(_exists(tokenId), \"ERC721: approved query for nonexistent token\");\n\n return _tokenApprovals[tokenId];\n }\n\n /**\n * @dev See {IERC721-setApprovalForAll}.\n */\n function setApprovalForAll(address operator, bool approved) public virtual override {\n _setApprovalForAll(_msgSender(), operator, approved);\n }\n\n /**\n * @dev See {IERC721-isApprovedForAll}.\n */\n function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {\n return _operatorApprovals[owner][operator];\n }\n\n /**\n * @dev See {IERC721-transferFrom}.\n */\n function transferFrom(\n address from,\n address to,\n uint256 tokenId\n ) public virtual override {\n //solhint-disable-next-line max-line-length\n require(_isApprovedOrOwner(_msgSender(), tokenId), \"ERC721: transfer caller is not owner nor approved\");\n\n _transfer(from, to, tokenId);\n }\n\n /**\n * @dev See {IERC721-safeTransferFrom}.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId\n ) public virtual override {\n safeTransferFrom(from, to, tokenId, \"\");\n }\n\n /**\n * @dev See {IERC721-safeTransferFrom}.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId,\n bytes memory _data\n ) public virtual override {\n require(_isApprovedOrOwner(_msgSender(), tokenId), \"ERC721: transfer caller is not owner nor approved\");\n _safeTransfer(from, to, tokenId, _data);\n }\n\n /**\n * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\n * are aware of the ERC721 protocol to prevent tokens from being forever locked.\n *\n * `_data` is additional data, it has no specified format and it is sent in call to `to`.\n *\n * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.\n * implement alternative mechanisms to perform token transfer, such as signature-based.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must exist and be owned by `from`.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function _safeTransfer(\n address from,\n address to,\n uint256 tokenId,\n bytes memory _data\n ) internal virtual {\n _transfer(from, to, tokenId);\n require(_checkOnERC721Received(from, to, tokenId, _data), \"ERC721: transfer to non ERC721Receiver implementer\");\n }\n\n /**\n * @dev Returns whether `tokenId` exists.\n *\n * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.\n *\n * Tokens start existing when they are minted (`_mint`),\n * and stop existing when they are burned (`_burn`).\n */\n function _exists(uint256 tokenId) internal view virtual returns (bool) {\n return _owners[tokenId] != address(0);\n }\n\n /**\n * @dev Returns whether `spender` is allowed to manage `tokenId`.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n */\n function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {\n require(_exists(tokenId), \"ERC721: operator query for nonexistent token\");\n address owner = ERC721.ownerOf(tokenId);\n return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));\n }\n\n /**\n * @dev Safely mints `tokenId` and transfers it to `to`.\n *\n * Requirements:\n *\n * - `tokenId` must not exist.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function _safeMint(address to, uint256 tokenId) internal virtual {\n _safeMint(to, tokenId, \"\");\n }\n\n /**\n * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is\n * forwarded in {IERC721Receiver-onERC721Received} to contract recipients.\n */\n function _safeMint(\n address to,\n uint256 tokenId,\n bytes memory _data\n ) internal virtual {\n _mint(to, tokenId);\n require(\n _checkOnERC721Received(address(0), to, tokenId, _data),\n \"ERC721: transfer to non ERC721Receiver implementer\"\n );\n }\n\n /**\n * @dev Mints `tokenId` and transfers it to `to`.\n *\n * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible\n *\n * Requirements:\n *\n * - `tokenId` must not exist.\n * - `to` cannot be the zero address.\n *\n * Emits a {Transfer} event.\n */\n function _mint(address to, uint256 tokenId) internal virtual {\n require(to != address(0), \"ERC721: mint to the zero address\");\n require(!_exists(tokenId), \"ERC721: token already minted\");\n\n _beforeTokenTransfer(address(0), to, tokenId);\n\n _balances[to] += 1;\n _owners[tokenId] = to;\n\n emit Transfer(address(0), to, tokenId);\n\n _afterTokenTransfer(address(0), to, tokenId);\n }\n\n /**\n * @dev Destroys `tokenId`.\n * The approval is cleared when the token is burned.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n *\n * Emits a {Transfer} event.\n */\n function _burn(uint256 tokenId) internal virtual {\n address owner = ERC721.ownerOf(tokenId);\n\n _beforeTokenTransfer(owner, address(0), tokenId);\n\n // Clear approvals\n _approve(address(0), tokenId);\n\n _balances[owner] -= 1;\n delete _owners[tokenId];\n\n emit Transfer(owner, address(0), tokenId);\n\n _afterTokenTransfer(owner, address(0), tokenId);\n }\n\n /**\n * @dev Transfers `tokenId` from `from` to `to`.\n * As opposed to {transferFrom}, this imposes no restrictions on msg.sender.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - `tokenId` token must be owned by `from`.\n *\n * Emits a {Transfer} event.\n */\n function _transfer(\n address from,\n address to,\n uint256 tokenId\n ) internal virtual {\n require(ERC721.ownerOf(tokenId) == from, \"ERC721: transfer from incorrect owner\");\n require(to != address(0), \"ERC721: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, tokenId);\n\n // Clear approvals from the previous owner\n _approve(address(0), tokenId);\n\n _balances[from] -= 1;\n _balances[to] += 1;\n _owners[tokenId] = to;\n\n emit Transfer(from, to, tokenId);\n\n _afterTokenTransfer(from, to, tokenId);\n }\n\n /**\n * @dev Approve `to` to operate on `tokenId`\n *\n * Emits a {Approval} event.\n */\n function _approve(address to, uint256 tokenId) internal virtual {\n _tokenApprovals[tokenId] = to;\n emit Approval(ERC721.ownerOf(tokenId), to, tokenId);\n }\n\n /**\n * @dev Approve `operator` to operate on all of `owner` tokens\n *\n * Emits a {ApprovalForAll} event.\n */\n function _setApprovalForAll(\n address owner,\n address operator,\n bool approved\n ) internal virtual {\n require(owner != operator, \"ERC721: approve to caller\");\n _operatorApprovals[owner][operator] = approved;\n emit ApprovalForAll(owner, operator, approved);\n }\n\n /**\n * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.\n * The call is not executed if the target address is not a contract.\n *\n * @param from address representing the previous owner of the given token ID\n * @param to target address that will receive the tokens\n * @param tokenId uint256 ID of the token to be transferred\n * @param _data bytes optional data to send along with the call\n * @return bool whether the call correctly returned the expected magic value\n */\n function _checkOnERC721Received(\n address from,\n address to,\n uint256 tokenId,\n bytes memory _data\n ) private returns (bool) {\n if (to.isContract()) {\n try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) {\n return retval == IERC721Receiver.onERC721Received.selector;\n } catch (bytes memory reason) {\n if (reason.length == 0) {\n revert(\"ERC721: transfer to non ERC721Receiver implementer\");\n } else {\n assembly {\n revert(add(32, reason), mload(reason))\n }\n }\n }\n } else {\n return true;\n }\n }\n\n /**\n * @dev Hook that is called before any token transfer. This includes minting\n * and burning.\n *\n * Calling conditions:\n *\n * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be\n * transferred to `to`.\n * - When `from` is zero, `tokenId` will be minted for `to`.\n * - When `to` is zero, ``from``'s `tokenId` will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 tokenId\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 tokenId\n ) internal virtual {}\n}\n" + }, + "@openzeppelin/contracts/governance/utils/Votes.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (governance/utils/Votes.sol)\npragma solidity ^0.8.0;\n\nimport \"../../utils/Context.sol\";\nimport \"../../utils/Counters.sol\";\nimport \"../../utils/Checkpoints.sol\";\nimport \"../../utils/cryptography/draft-EIP712.sol\";\nimport \"./IVotes.sol\";\n\n/**\n * @dev This is a base abstract contract that tracks voting units, which are a measure of voting power that can be\n * transferred, and provides a system of vote delegation, where an account can delegate its voting units to a sort of\n * \"representative\" that will pool delegated voting units from different accounts and can then use it to vote in\n * decisions. In fact, voting units _must_ be delegated in order to count as actual votes, and an account has to\n * delegate those votes to itself if it wishes to participate in decisions and does not have a trusted representative.\n *\n * This contract is often combined with a token contract such that voting units correspond to token units. For an\n * example, see {ERC721Votes}.\n *\n * The full history of delegate votes is tracked on-chain so that governance protocols can consider votes as distributed\n * at a particular block number to protect against flash loans and double voting. The opt-in delegate system makes the\n * cost of this history tracking optional.\n *\n * When using this module the derived contract must implement {_getVotingUnits} (for example, make it return\n * {ERC721-balanceOf}), and can use {_transferVotingUnits} to track a change in the distribution of those units (in the\n * previous example, it would be included in {ERC721-_beforeTokenTransfer}).\n *\n * _Available since v4.5._\n */\nabstract contract Votes is IVotes, Context, EIP712 {\n using Checkpoints for Checkpoints.History;\n using Counters for Counters.Counter;\n\n bytes32 private constant _DELEGATION_TYPEHASH =\n keccak256(\"Delegation(address delegatee,uint256 nonce,uint256 expiry)\");\n\n mapping(address => address) private _delegation;\n mapping(address => Checkpoints.History) private _delegateCheckpoints;\n Checkpoints.History private _totalCheckpoints;\n\n mapping(address => Counters.Counter) private _nonces;\n\n /**\n * @dev Returns the current amount of votes that `account` has.\n */\n function getVotes(address account) public view virtual override returns (uint256) {\n return _delegateCheckpoints[account].latest();\n }\n\n /**\n * @dev Returns the amount of votes that `account` had at the end of a past block (`blockNumber`).\n *\n * Requirements:\n *\n * - `blockNumber` must have been already mined\n */\n function getPastVotes(address account, uint256 blockNumber) public view virtual override returns (uint256) {\n return _delegateCheckpoints[account].getAtBlock(blockNumber);\n }\n\n /**\n * @dev Returns the total supply of votes available at the end of a past block (`blockNumber`).\n *\n * NOTE: This value is the sum of all available votes, which is not necessarily the sum of all delegated votes.\n * Votes that have not been delegated are still part of total supply, even though they would not participate in a\n * vote.\n *\n * Requirements:\n *\n * - `blockNumber` must have been already mined\n */\n function getPastTotalSupply(uint256 blockNumber) public view virtual override returns (uint256) {\n require(blockNumber < block.number, \"Votes: block not yet mined\");\n return _totalCheckpoints.getAtBlock(blockNumber);\n }\n\n /**\n * @dev Returns the current total supply of votes.\n */\n function _getTotalSupply() internal view virtual returns (uint256) {\n return _totalCheckpoints.latest();\n }\n\n /**\n * @dev Returns the delegate that `account` has chosen.\n */\n function delegates(address account) public view virtual override returns (address) {\n return _delegation[account];\n }\n\n /**\n * @dev Delegates votes from the sender to `delegatee`.\n */\n function delegate(address delegatee) public virtual override {\n address account = _msgSender();\n _delegate(account, delegatee);\n }\n\n /**\n * @dev Delegates votes from signer to `delegatee`.\n */\n function delegateBySig(\n address delegatee,\n uint256 nonce,\n uint256 expiry,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) public virtual override {\n require(block.timestamp <= expiry, \"Votes: signature expired\");\n address signer = ECDSA.recover(\n _hashTypedDataV4(keccak256(abi.encode(_DELEGATION_TYPEHASH, delegatee, nonce, expiry))),\n v,\n r,\n s\n );\n require(nonce == _useNonce(signer), \"Votes: invalid nonce\");\n _delegate(signer, delegatee);\n }\n\n /**\n * @dev Delegate all of `account`'s voting units to `delegatee`.\n *\n * Emits events {DelegateChanged} and {DelegateVotesChanged}.\n */\n function _delegate(address account, address delegatee) internal virtual {\n address oldDelegate = delegates(account);\n _delegation[account] = delegatee;\n\n emit DelegateChanged(account, oldDelegate, delegatee);\n _moveDelegateVotes(oldDelegate, delegatee, _getVotingUnits(account));\n }\n\n /**\n * @dev Transfers, mints, or burns voting units. To register a mint, `from` should be zero. To register a burn, `to`\n * should be zero. Total supply of voting units will be adjusted with mints and burns.\n */\n function _transferVotingUnits(\n address from,\n address to,\n uint256 amount\n ) internal virtual {\n if (from == address(0)) {\n _totalCheckpoints.push(_add, amount);\n }\n if (to == address(0)) {\n _totalCheckpoints.push(_subtract, amount);\n }\n _moveDelegateVotes(delegates(from), delegates(to), amount);\n }\n\n /**\n * @dev Moves delegated votes from one delegate to another.\n */\n function _moveDelegateVotes(\n address from,\n address to,\n uint256 amount\n ) private {\n if (from != to && amount > 0) {\n if (from != address(0)) {\n (uint256 oldValue, uint256 newValue) = _delegateCheckpoints[from].push(_subtract, amount);\n emit DelegateVotesChanged(from, oldValue, newValue);\n }\n if (to != address(0)) {\n (uint256 oldValue, uint256 newValue) = _delegateCheckpoints[to].push(_add, amount);\n emit DelegateVotesChanged(to, oldValue, newValue);\n }\n }\n }\n\n function _add(uint256 a, uint256 b) private pure returns (uint256) {\n return a + b;\n }\n\n function _subtract(uint256 a, uint256 b) private pure returns (uint256) {\n return a - b;\n }\n\n /**\n * @dev Consumes a nonce.\n *\n * Returns the current value and increments nonce.\n */\n function _useNonce(address owner) internal virtual returns (uint256 current) {\n Counters.Counter storage nonce = _nonces[owner];\n current = nonce.current();\n nonce.increment();\n }\n\n /**\n * @dev Returns an address nonce.\n */\n function nonces(address owner) public view virtual returns (uint256) {\n return _nonces[owner].current();\n }\n\n /**\n * @dev Returns the contract's {EIP712} domain separator.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32) {\n return _domainSeparatorV4();\n }\n\n /**\n * @dev Must return the voting units held by an account.\n */\n function _getVotingUnits(address) internal virtual returns (uint256);\n}\n" + }, + "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721Receiver.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @title ERC721 token receiver interface\n * @dev Interface for any contract that wants to support safeTransfers\n * from ERC721 asset contracts.\n */\ninterface IERC721Receiver {\n /**\n * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}\n * by `operator` from `from`, this function is called.\n *\n * It must return its Solidity selector to confirm the token transfer.\n * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.\n *\n * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`.\n */\n function onERC721Received(\n address operator,\n address from,\n uint256 tokenId,\n bytes calldata data\n ) external returns (bytes4);\n}\n" + }, + "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC721.sol\";\n\n/**\n * @title ERC-721 Non-Fungible Token Standard, optional metadata extension\n * @dev See https://eips.ethereum.org/EIPS/eip-721\n */\ninterface IERC721Metadata is IERC721 {\n /**\n * @dev Returns the token collection name.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the token collection symbol.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.\n */\n function tokenURI(uint256 tokenId) external view returns (string memory);\n}\n" + }, + "@openzeppelin/contracts/utils/Checkpoints.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (utils/Checkpoints.sol)\npragma solidity ^0.8.0;\n\nimport \"./math/Math.sol\";\nimport \"./math/SafeCast.sol\";\n\n/**\n * @dev This library defines the `History` struct, for checkpointing values as they change at different points in\n * time, and later looking up past values by block number. See {Votes} as an example.\n *\n * To create a history of checkpoints define a variable type `Checkpoints.History` in your contract, and store a new\n * checkpoint for the current transaction block using the {push} function.\n *\n * _Available since v4.5._\n */\nlibrary Checkpoints {\n struct Checkpoint {\n uint32 _blockNumber;\n uint224 _value;\n }\n\n struct History {\n Checkpoint[] _checkpoints;\n }\n\n /**\n * @dev Returns the value in the latest checkpoint, or zero if there are no checkpoints.\n */\n function latest(History storage self) internal view returns (uint256) {\n uint256 pos = self._checkpoints.length;\n return pos == 0 ? 0 : self._checkpoints[pos - 1]._value;\n }\n\n /**\n * @dev Returns the value at a given block number. If a checkpoint is not available at that block, the closest one\n * before it is returned, or zero otherwise.\n */\n function getAtBlock(History storage self, uint256 blockNumber) internal view returns (uint256) {\n require(blockNumber < block.number, \"Checkpoints: block not yet mined\");\n\n uint256 high = self._checkpoints.length;\n uint256 low = 0;\n while (low < high) {\n uint256 mid = Math.average(low, high);\n if (self._checkpoints[mid]._blockNumber > blockNumber) {\n high = mid;\n } else {\n low = mid + 1;\n }\n }\n return high == 0 ? 0 : self._checkpoints[high - 1]._value;\n }\n\n /**\n * @dev Pushes a value onto a History so that it is stored as the checkpoint for the current block.\n *\n * Returns previous value and new value.\n */\n function push(History storage self, uint256 value) internal returns (uint256, uint256) {\n uint256 pos = self._checkpoints.length;\n uint256 old = latest(self);\n if (pos > 0 && self._checkpoints[pos - 1]._blockNumber == block.number) {\n self._checkpoints[pos - 1]._value = SafeCast.toUint224(value);\n } else {\n self._checkpoints.push(\n Checkpoint({_blockNumber: SafeCast.toUint32(block.number), _value: SafeCast.toUint224(value)})\n );\n }\n return (old, value);\n }\n\n /**\n * @dev Pushes a value onto a History, by updating the latest value using binary operation `op`. The new value will\n * be set to `op(latest, delta)`.\n *\n * Returns previous value and new value.\n */\n function push(\n History storage self,\n function(uint256, uint256) view returns (uint256) op,\n uint256 delta\n ) internal returns (uint256, uint256) {\n return push(self, op(latest(self), delta));\n }\n}\n" + }, + "contracts/JBDirectory.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';\nimport {JBOperatable} from './abstract/JBOperatable.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {JBFundingCycleMetadataResolver} from './libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBOperations} from './libraries/JBOperations.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\n\n/// @notice Keeps a reference of which terminal contracts each project is currently accepting funds through, and which controller contract is managing each project's tokens and funding cycles.\ncontract JBDirectory is JBOperatable, Ownable, IJBDirectory {\n // A library that parses the packed funding cycle metadata into a friendlier format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error DUPLICATE_TERMINALS();\n error INVALID_PROJECT_ID_IN_DIRECTORY();\n error SET_CONTROLLER_NOT_ALLOWED();\n error SET_TERMINALS_NOT_ALLOWED();\n error TOKEN_NOT_ACCEPTED();\n\n //*********************************************************************//\n // --------------------- private stored properties ------------------- //\n //*********************************************************************//\n\n /// @notice For each project ID, the terminals that are currently managing its funds.\n /// @custom:member _projectId The ID of the project to get terminals of.\n mapping(uint256 => IJBPaymentTerminal[]) private _terminalsOf;\n\n /// @notice The project's primary terminal for a token.\n /// @custom:member _projectId The ID of the project to get the primary terminal of.\n /// @custom:member _token The token to get the project's primary terminal of.\n mapping(uint256 => mapping(address => IJBPaymentTerminal)) private _primaryTerminalOf;\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice Mints ERC-721's that represent project ownership and transfers.\n IJBProjects public immutable override projects;\n\n /// @notice The contract storing all funding cycle configurations.\n IJBFundingCycleStore public immutable override fundingCycleStore;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice For each project ID, the controller that manages how terminals interact with tokens and funding cycles.\n /// @custom:member _projectId The ID of the project to get the controller of.\n mapping(uint256 => address) public override controllerOf;\n\n /// @notice Addresses that can set a project's first controller on their behalf. These addresses/contracts have been vetted and verified by this contract's owner.\n /// @custom:param _address The address that is either allowed or not.\n mapping(address => bool) public override isAllowedToSetFirstController;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice For each project ID, the terminals that are currently managing its funds.\n /// @param _projectId The ID of the project to get terminals of.\n /// @return An array of terminal addresses.\n function terminalsOf(uint256 _projectId)\n external\n view\n override\n returns (IJBPaymentTerminal[] memory)\n {\n return _terminalsOf[_projectId];\n }\n\n /// @notice The primary terminal that is managing funds for a project for a specified token.\n /// @dev The zero address is returned if a terminal isn't found for the specified token.\n /// @param _projectId The ID of the project to get a terminal for.\n /// @param _token The token the terminal accepts.\n /// @return The primary terminal for the project for the specified token.\n function primaryTerminalOf(uint256 _projectId, address _token)\n external\n view\n override\n returns (IJBPaymentTerminal)\n {\n // Keep a reference to the primary terminal for the provided project ID and token.\n IJBPaymentTerminal _primaryTerminal = _primaryTerminalOf[_projectId][_token];\n\n // If a primary terminal for the token was specifically set and it's one of the project's terminals, return it.\n if (\n _primaryTerminal != IJBPaymentTerminal(address(0)) &&\n isTerminalOf(_projectId, _primaryTerminal)\n ) return _primaryTerminal;\n\n // Keep a reference to the number of terminals the project has.\n uint256 _numberOfTerminals = _terminalsOf[_projectId].length;\n\n // Return the first terminal which accepts the specified token.\n for (uint256 _i; _i < _numberOfTerminals; ) {\n // Keep a reference to the terminal being iterated on.\n IJBPaymentTerminal _terminal = _terminalsOf[_projectId][_i];\n\n // If the terminal accepts the specified token, return it.\n if (_terminal.acceptsToken(_token, _projectId)) return _terminal;\n\n unchecked {\n ++_i;\n }\n }\n\n // Not found.\n return IJBPaymentTerminal(address(0));\n }\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice Whether or not a specified terminal is a terminal of the specified project.\n /// @param _projectId The ID of the project to check within.\n /// @param _terminal The address of the terminal to check for.\n /// @return A flag indicating whether or not the specified terminal is a terminal of the specified project.\n function isTerminalOf(uint256 _projectId, IJBPaymentTerminal _terminal)\n public\n view\n override\n returns (bool)\n {\n // Keep a reference to the number of terminals the project has.\n uint256 _numberOfTerminals = _terminalsOf[_projectId].length;\n\n // Loop through and return true if the terminal is contained.\n for (uint256 _i; _i < _numberOfTerminals; ) {\n // If the terminal being iterated on matches the provided terminal, return true.\n if (_terminalsOf[_projectId][_i] == _terminal) return true;\n\n unchecked {\n ++_i;\n }\n }\n\n // Otherwise, return false.\n return false;\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _fundingCycleStore A contract storing all funding cycle configurations.\n /// @param _owner The address that will own the contract.\n constructor(\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBFundingCycleStore _fundingCycleStore,\n address _owner\n ) JBOperatable(_operatorStore) {\n projects = _projects;\n fundingCycleStore = _fundingCycleStore;\n\n _transferOwnership(_owner);\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Update the controller that manages how terminals interact with the ecosystem.\n /// @dev A controller can be set if:\n /// @dev - the message sender is the project owner or an operator having the correct authorization.\n /// @dev - the message sender is the project's current controller.\n /// @dev - or, an allowedlisted address is setting a controller for a project that doesn't already have a controller.\n /// @param _projectId The ID of the project to set a new controller for.\n /// @param _controller The new controller to set.\n function setControllerOf(uint256 _projectId, address _controller)\n external\n override\n requirePermissionAllowingOverride(\n projects.ownerOf(_projectId),\n _projectId,\n JBOperations.SET_CONTROLLER,\n (msg.sender == address(controllerOf[_projectId]) ||\n (isAllowedToSetFirstController[msg.sender] && controllerOf[_projectId] == address(0)))\n )\n {\n // The project must exist.\n if (projects.count() < _projectId) revert INVALID_PROJECT_ID_IN_DIRECTORY();\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Setting controller is allowed if called from the current controller, or if the project doesn't have a current controller, or if the project's funding cycle allows setting the controller. Revert otherwise.\n if (\n msg.sender != address(controllerOf[_projectId]) &&\n controllerOf[_projectId] != address(0) &&\n !_fundingCycle.global().allowSetController\n ) revert SET_CONTROLLER_NOT_ALLOWED();\n\n // Set the new controller.\n controllerOf[_projectId] = _controller;\n\n emit SetController(_projectId, _controller, msg.sender);\n }\n\n /// @notice Set a project's terminals.\n /// @dev Only a project owner, an operator, or its controller can set its terminals.\n /// @param _projectId The ID of the project having terminals set.\n /// @param _terminals The terminal to set.\n function setTerminalsOf(uint256 _projectId, IJBPaymentTerminal[] calldata _terminals)\n external\n override\n requirePermissionAllowingOverride(\n projects.ownerOf(_projectId),\n _projectId,\n JBOperations.SET_TERMINALS,\n msg.sender == address(controllerOf[_projectId])\n )\n {\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Setting terminals must be allowed if not called from the current controller.\n if (\n msg.sender != address(controllerOf[_projectId]) && !_fundingCycle.global().allowSetTerminals\n ) revert SET_TERMINALS_NOT_ALLOWED();\n\n // Set the stored terminals for the project.\n _terminalsOf[_projectId] = _terminals;\n\n // Make sure duplicates were not added.\n if (_terminals.length > 1) {\n for (uint256 _i; _i < _terminals.length; ) {\n for (uint256 _j = _i + 1; _j < _terminals.length; ) {\n if (_terminals[_i] == _terminals[_j]) revert DUPLICATE_TERMINALS();\n\n unchecked {\n ++_j;\n }\n }\n\n unchecked {\n ++_i;\n }\n }\n }\n emit SetTerminals(_projectId, _terminals, msg.sender);\n }\n\n /// @notice Project's can set which terminal should be their primary for a particular token. \n /// @dev This is useful in case a project has several terminals connected for a particular token.\n /// @dev The terminal will be set as the primary terminal where ecosystem contracts should route tokens.\n /// @dev If setting a newly added terminal and the funding cycle doesn't allow new terminals, the caller must be the current controller.\n /// @param _projectId The ID of the project for which a primary token is being set.\n /// @param _token The token to set the primary terminal of.\n /// @param _terminal The terminal to make primary.\n function setPrimaryTerminalOf(\n uint256 _projectId,\n address _token,\n IJBPaymentTerminal _terminal\n )\n external\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.SET_PRIMARY_TERMINAL)\n {\n // Can't set the primary terminal for a token if it doesn't accept the token.\n if (!_terminal.acceptsToken(_token, _projectId)) revert TOKEN_NOT_ACCEPTED();\n\n // Add the terminal to the project if it hasn't been already.\n _addTerminalIfNeeded(_projectId, _terminal);\n\n // Store the terminal as the primary for the particular token.\n _primaryTerminalOf[_projectId][_token] = _terminal;\n\n emit SetPrimaryTerminal(_projectId, _token, _terminal, msg.sender);\n }\n\n /// @notice Set a contract to the list of trusted addresses that can set a first controller for any project.\t\n /// @dev The owner can add addresses which are allowed to change projects' first controllers. \n /// @dev These addresses are known and vetted controllers as well as contracts designed to launch new projects. \n /// @dev A project can set its own controller without it being on the allow list.\n /// @dev If you would like an address/contract allowlisted, please reach out to the contract owner.\n /// @param _address The address to allow or revoke allowance from.\n /// @param _flag Whether allowance is being added or revoked.\n function setIsAllowedToSetFirstController(address _address, bool _flag)\n external\n override\n onlyOwner\n {\n // Set the flag in the allowlist.\n isAllowedToSetFirstController[_address] = _flag;\n\n emit SetIsAllowedToSetFirstController(_address, _flag, msg.sender);\n }\n\n //*********************************************************************//\n // --------------------- private helper functions -------------------- //\n //*********************************************************************//\n\n /// @notice Add a terminal to a project's list of terminals if it hasn't been already.\n /// @param _projectId The ID of the project having a terminal added.\n /// @param _terminal The terminal to add.\n function _addTerminalIfNeeded(uint256 _projectId, IJBPaymentTerminal _terminal) private {\n // Check that the terminal has not already been added.\n if (isTerminalOf(_projectId, _terminal)) return;\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Setting terminals must be allowed if not called from the current controller.\n if (\n msg.sender != address(controllerOf[_projectId]) && !_fundingCycle.global().allowSetTerminals\n ) revert SET_TERMINALS_NOT_ALLOWED();\n\n // Add the new terminal.\n _terminalsOf[_projectId].push(_terminal);\n\n emit AddTerminal(_projectId, _terminal, msg.sender);\n }\n}\n" + }, + "contracts/JBSingleTokenPaymentTerminalStore3_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {ReentrancyGuard} from '@openzeppelin/contracts/security/ReentrancyGuard.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {JBBallotState} from './enums/JBBallotState.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBController3_1} from './interfaces/IJBController3_1.sol';\nimport {IJBFundingCycleDataSource} from './interfaces/IJBFundingCycleDataSource.sol';\nimport {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol';\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\nimport {IJBSingleTokenPaymentTerminal} from './interfaces/IJBSingleTokenPaymentTerminal.sol';\nimport {IJBSingleTokenPaymentTerminalStore} from './interfaces/IJBSingleTokenPaymentTerminalStore.sol';\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\nimport {JBConstants} from './libraries/JBConstants.sol';\nimport {JBCurrencies} from './libraries/JBCurrencies.sol';\nimport {JBFixedPointNumber} from './libraries/JBFixedPointNumber.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\nimport {JBFundingCycleMetadataResolver} from './libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBPayDelegateAllocation} from './structs/JBPayDelegateAllocation.sol';\nimport {JBPayParamsData} from './structs/JBPayParamsData.sol';\nimport {JBRedeemParamsData} from './structs/JBRedeemParamsData.sol';\nimport {JBRedemptionDelegateAllocation} from './structs/JBRedemptionDelegateAllocation.sol';\nimport {JBTokenAmount} from './structs/JBTokenAmount.sol';\n\n/// @notice Manages all bookkeeping for inflows and outflows of funds from any ISingleTokenPaymentTerminal.\n/// @dev This Store expects a project's controller to be an IJBController3_1. This is the only difference between this version and the original.\ncontract JBSingleTokenPaymentTerminalStore3_1 is\n ReentrancyGuard,\n IJBSingleTokenPaymentTerminalStore\n{\n // A library that parses the packed funding cycle metadata into a friendlier format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error INVALID_AMOUNT_TO_SEND_DELEGATE();\n error CURRENCY_MISMATCH();\n error DISTRIBUTION_AMOUNT_LIMIT_REACHED();\n error FUNDING_CYCLE_PAYMENT_PAUSED();\n error FUNDING_CYCLE_DISTRIBUTION_PAUSED();\n error FUNDING_CYCLE_REDEEM_PAUSED();\n error INADEQUATE_CONTROLLER_ALLOWANCE();\n error INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n error INSUFFICIENT_TOKENS();\n error INVALID_FUNDING_CYCLE();\n error PAYMENT_TERMINAL_MIGRATION_NOT_ALLOWED();\n\n //*********************************************************************//\n // -------------------------- private constants ---------------------- //\n //*********************************************************************//\n\n /// @notice Ensures a maximum number of decimal points of persisted fidelity on mulDiv operations of fixed point numbers.\n uint256 private constant _MAX_FIXED_POINT_FIDELITY = 18;\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n /// @notice The contract storing all funding cycle configurations.\n IJBFundingCycleStore public immutable override fundingCycleStore;\n\n /// @notice The contract that exposes price feeds.\n IJBPrices public immutable override prices;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The amount of tokens that each project has for each terminal, in terms of the terminal's token.\n /// @dev The used distribution limit is represented as a fixed point number with the same amount of decimals as its relative terminal.\n /// @custom:param _terminal The terminal to which the balance applies.\n /// @custom:param _projectId The ID of the project to get the balance of.\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => uint256)) public override balanceOf;\n\n /// @notice The amount of funds that a project has distributed from its limit during the current funding cycle for each terminal, in terms of the distribution limit's currency.\n /// @dev Increases as projects use their preconfigured distribution limits.\n /// @dev The used distribution limit is represented as a fixed point number with the same amount of decimals as its relative terminal.\n /// @custom:param _terminal The terminal to which the used distribution limit applies.\n /// @custom:param _projectId The ID of the project to get the used distribution limit of.\n /// @custom:param _fundingCycleNumber The number of the funding cycle during which the distribution limit was used.\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => mapping(uint256 => uint256)))\n public\n override usedDistributionLimitOf;\n\n /// @notice The amount of funds that a project has used from its allowance during the current funding cycle configuration for each terminal, in terms of the overflow allowance's currency.\n /// @dev Increases as projects use their allowance.\n /// @dev The used allowance is represented as a fixed point number with the same amount of decimals as its relative terminal.\n /// @custom:param _terminal The terminal to which the overflow allowance applies.\n /// @custom:param _projectId The ID of the project to get the used overflow allowance of.\n /// @custom:param _configuration The configuration of the during which the allowance was used.\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => mapping(uint256 => uint256)))\n public\n override usedOverflowAllowanceOf;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Gets the current overflowed amount in a terminal for a specified project.\n /// @dev The current overflow is represented as a fixed point number with the same amount of decimals as the specified terminal.\n /// @param _terminal The terminal for which the overflow is being calculated.\n /// @param _projectId The ID of the project to get overflow for.\n /// @return The current amount of overflow that project has in the specified terminal.\n function currentOverflowOf(\n IJBSingleTokenPaymentTerminal _terminal,\n uint256 _projectId\n ) external view override returns (uint256) {\n // Return the overflow during the project's current funding cycle.\n return\n _overflowDuring(\n _terminal,\n _projectId,\n fundingCycleStore.currentOf(_projectId),\n _terminal.currency()\n );\n }\n\n /// @notice Gets the current overflowed amount for a specified project across all terminals.\n /// @param _projectId The ID of the project to get total overflow for.\n /// @param _decimals The number of decimals that the fixed point overflow should include.\n /// @param _currency The currency that the total overflow should be in terms of.\n /// @return The current total amount of overflow that project has across all terminals.\n function currentTotalOverflowOf(\n uint256 _projectId,\n uint256 _decimals,\n uint256 _currency\n ) external view override returns (uint256) {\n return _currentTotalOverflowOf(_projectId, _decimals, _currency);\n }\n\n /// @notice The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the total token supply and overflow in the ecosystem.\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\n /// @dev The current reclaimable overflow is returned in terms of the specified terminal's currency.\n /// @dev The reclaimable overflow is represented as a fixed point number with the same amount of decimals as the specified terminal.\n /// @param _terminal The terminal from which the reclaimable amount would come.\n /// @param _projectId The ID of the project to get the reclaimable overflow amount for.\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _useTotalOverflow A flag indicating whether the overflow used in the calculation should be summed from all of the project's terminals. If false, overflow should be limited to the amount in the specified `_terminal`.\n /// @return The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_terminal`.\n function currentReclaimableOverflowOf(\n IJBSingleTokenPaymentTerminal _terminal,\n uint256 _projectId,\n uint256 _tokenCount,\n bool _useTotalOverflow\n ) external view override returns (uint256) {\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Get the amount of current overflow.\n // Use the project's total overflow across all of its terminals if the flag species specifies so. Otherwise, use the overflow local to the specified terminal.\n uint256 _currentOverflow = _useTotalOverflow\n ? _currentTotalOverflowOf(_projectId, _terminal.decimals(), _terminal.currency())\n : _overflowDuring(_terminal, _projectId, _fundingCycle, _terminal.currency());\n\n // If there's no overflow, there's no reclaimable overflow.\n if (_currentOverflow == 0) return 0;\n\n // Get the number of outstanding tokens the project has.\n uint256 _totalSupply = IJBController3_1(directory.controllerOf(_projectId))\n .totalOutstandingTokensOf(_projectId);\n\n // Can't redeem more tokens that is in the supply.\n if (_tokenCount > _totalSupply) return 0;\n\n // Return the reclaimable overflow amount.\n return\n _reclaimableOverflowDuring(\n _projectId,\n _fundingCycle,\n _tokenCount,\n _totalSupply,\n _currentOverflow\n );\n }\n\n /// @notice The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the specified total token supply and overflow amounts.\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\n /// @param _projectId The ID of the project to get the reclaimable overflow amount for.\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _totalSupply The total number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _overflow The amount of overflow to make the calculation with, as a fixed point number.\n /// @return The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_overflow`.\n function currentReclaimableOverflowOf(\n uint256 _projectId,\n uint256 _tokenCount,\n uint256 _totalSupply,\n uint256 _overflow\n ) external view override returns (uint256) {\n // If there's no overflow, there's no reclaimable overflow.\n if (_overflow == 0) return 0;\n\n // Can't redeem more tokens that is in the supply.\n if (_tokenCount > _totalSupply) return 0;\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Return the reclaimable overflow amount.\n return\n _reclaimableOverflowDuring(_projectId, _fundingCycle, _tokenCount, _totalSupply, _overflow);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _fundingCycleStore A contract storing all funding cycle configurations.\n /// @param _prices A contract that exposes price feeds.\n constructor(IJBDirectory _directory, IJBFundingCycleStore _fundingCycleStore, IJBPrices _prices) {\n directory = _directory;\n fundingCycleStore = _fundingCycleStore;\n prices = _prices;\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Records newly contributed tokens to a project.\n /// @dev Mints the project's tokens according to values provided by a configured data source. If no data source is configured, mints tokens proportional to the amount of the contribution.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.sender's tokens.\n /// @param _payer The original address that sent the payment to the terminal.\n /// @param _amount The amount of tokens being paid. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\n /// @param _projectId The ID of the project being paid.\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _beneficiary The specified address that should be the beneficiary of anything that results from the payment.\n /// @param _memo A memo to pass along to the emitted event, and passed along to the funding cycle's data source.\n /// @param _metadata Bytes to send along to the data source, if one is provided.\n /// @return fundingCycle The project's funding cycle during which payment was made.\n /// @return tokenCount The number of project tokens that were minted, as a fixed point number with 18 decimals.\n /// @return delegateAllocations The amount to send to delegates instead of adding to the local balance.\n /// @return memo A memo that should be passed along to the emitted event.\n function recordPaymentFrom(\n address _payer,\n JBTokenAmount calldata _amount,\n uint256 _projectId,\n uint256 _baseWeightCurrency,\n address _beneficiary,\n string calldata _memo,\n bytes memory _metadata\n )\n external\n override\n nonReentrant\n returns (\n JBFundingCycle memory fundingCycle,\n uint256 tokenCount,\n JBPayDelegateAllocation[] memory delegateAllocations,\n string memory memo\n )\n {\n // Get a reference to the current funding cycle for the project.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // The project must have a funding cycle configured.\n if (fundingCycle.number == 0) revert INVALID_FUNDING_CYCLE();\n\n // Must not be paused.\n if (fundingCycle.payPaused()) revert FUNDING_CYCLE_PAYMENT_PAUSED();\n\n // The weight according to which new token supply is to be minted, as a fixed point number with 18 decimals.\n uint256 _weight;\n\n // If the funding cycle has configured a data source, use it to derive a weight and memo.\n if (fundingCycle.useDataSourceForPay() && fundingCycle.dataSource() != address(0)) {\n // Create the params that'll be sent to the data source.\n JBPayParamsData memory _data = JBPayParamsData(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _payer,\n _amount,\n _projectId,\n fundingCycle.configuration,\n _beneficiary,\n fundingCycle.weight,\n fundingCycle.reservedRate(),\n _memo,\n _metadata\n );\n (_weight, memo, delegateAllocations) = IJBFundingCycleDataSource(fundingCycle.dataSource())\n .payParams(_data);\n }\n // Otherwise use the funding cycle's weight\n else {\n _weight = fundingCycle.weight;\n memo = _memo;\n }\n\n // Scoped section prevents stack too deep. `_balanceDiff` only used within scope.\n {\n // Keep a reference to the amount that should be added to the project's balance.\n uint256 _balanceDiff = _amount.value;\n\n // Validate all delegated amounts. This needs to be done before returning the delegate allocations to ensure valid delegated amounts.\n if (delegateAllocations.length != 0) {\n for (uint256 _i; _i < delegateAllocations.length; ) {\n // Get a reference to the amount to be delegated.\n uint256 _delegatedAmount = delegateAllocations[_i].amount;\n\n // Validate if non-zero.\n if (_delegatedAmount != 0) {\n // Can't delegate more than was paid.\n if (_delegatedAmount > _balanceDiff) revert INVALID_AMOUNT_TO_SEND_DELEGATE();\n\n // Decrement the total amount being added to the balance.\n _balanceDiff = _balanceDiff - _delegatedAmount;\n }\n\n unchecked {\n ++_i;\n }\n }\n }\n\n // If there's no amount being recorded, there's nothing left to do.\n if (_amount.value == 0) return (fundingCycle, 0, delegateAllocations, memo);\n\n // Add the correct balance difference to the token balance of the project.\n if (_balanceDiff != 0)\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] +\n _balanceDiff;\n }\n\n // If there's no weight, token count must be 0 so there's nothing left to do.\n if (_weight == 0) return (fundingCycle, 0, delegateAllocations, memo);\n\n // Get a reference to the number of decimals in the amount. (prevents stack too deep).\n uint256 _decimals = _amount.decimals;\n\n // If the terminal should base its weight on a different currency from the terminal's currency, determine the factor.\n // The weight is always a fixed point mumber with 18 decimals. To ensure this, the ratio should use the same number of decimals as the `_amount`.\n uint256 _weightRatio = _amount.currency == _baseWeightCurrency\n ? 10 ** _decimals\n : prices.priceFor(_amount.currency, _baseWeightCurrency, _decimals);\n\n // Find the number of tokens to mint, as a fixed point number with as many decimals as `weight` has.\n tokenCount = PRBMath.mulDiv(_amount.value, _weight, _weightRatio);\n }\n\n /// @notice Records newly redeemed tokens of a project.\n /// @dev Redeems the project's tokens according to values provided by a configured data source. If no data source is configured, redeems tokens along a redemption bonding curve that is a function of the number of tokens being burned.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.senders tokens.\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the data source, if one is provided.\n /// @return fundingCycle The funding cycle during which the redemption was made.\n /// @return reclaimAmount The amount of terminal tokens reclaimed, as a fixed point number with 18 decimals.\n /// @return delegateAllocations The amount to send to delegates instead of sending to the beneficiary.\n /// @return memo A memo that should be passed along to the emitted event.\n function recordRedemptionFor(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n string memory _memo,\n bytes memory _metadata\n )\n external\n override\n nonReentrant\n returns (\n JBFundingCycle memory fundingCycle,\n uint256 reclaimAmount,\n JBRedemptionDelegateAllocation[] memory delegateAllocations,\n string memory memo\n )\n {\n // Get a reference to the project's current funding cycle.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // The current funding cycle must not be paused.\n if (fundingCycle.redeemPaused()) revert FUNDING_CYCLE_REDEEM_PAUSED();\n\n // Scoped section prevents stack too deep. `_reclaimedTokenAmount`, `_currentOverflow`, and `_totalSupply` only used within scope.\n {\n // Get a reference to the reclaimed token amount struct, the current overflow, and the total token supply.\n JBTokenAmount memory _reclaimedTokenAmount;\n uint256 _currentOverflow;\n uint256 _totalSupply;\n\n // Another scoped section prevents stack too deep. `_token`, `_decimals`, and `_currency` only used within scope.\n {\n // Get a reference to the terminal's tokens.\n address _token = IJBSingleTokenPaymentTerminal(msg.sender).token();\n\n // Get a reference to the terminal's decimals.\n uint256 _decimals = IJBSingleTokenPaymentTerminal(msg.sender).decimals();\n\n // Get areference to the terminal's currency.\n uint256 _currency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\n\n // Get the amount of current overflow.\n // Use the local overflow if the funding cycle specifies that it should be used. Otherwise, use the project's total overflow across all of its terminals.\n _currentOverflow = fundingCycle.useTotalOverflowForRedemptions()\n ? _currentTotalOverflowOf(_projectId, _decimals, _currency)\n : _overflowDuring(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _projectId,\n fundingCycle,\n _currency\n );\n\n // Get the number of outstanding tokens the project has.\n _totalSupply = IJBController3_1(directory.controllerOf(_projectId))\n .totalOutstandingTokensOf(_projectId);\n\n // Can't redeem more tokens that is in the supply.\n if (_tokenCount > _totalSupply) revert INSUFFICIENT_TOKENS();\n\n if (_currentOverflow != 0)\n // Calculate reclaim amount using the current overflow amount.\n reclaimAmount = _reclaimableOverflowDuring(\n _projectId,\n fundingCycle,\n _tokenCount,\n _totalSupply,\n _currentOverflow\n );\n\n _reclaimedTokenAmount = JBTokenAmount(_token, reclaimAmount, _decimals, _currency);\n }\n\n // If the funding cycle has configured a data source, use it to derive a claim amount and memo.\n if (fundingCycle.useDataSourceForRedeem() && fundingCycle.dataSource() != address(0)) {\n // Yet another scoped section prevents stack too deep. `_state` only used within scope.\n {\n // Get a reference to the ballot state.\n JBBallotState _state = fundingCycleStore.currentBallotStateOf(_projectId);\n\n // Create the params that'll be sent to the data source.\n JBRedeemParamsData memory _data = JBRedeemParamsData(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _holder,\n _projectId,\n fundingCycle.configuration,\n _tokenCount,\n _totalSupply,\n _currentOverflow,\n _reclaimedTokenAmount,\n fundingCycle.useTotalOverflowForRedemptions(),\n _state == JBBallotState.Active\n ? fundingCycle.ballotRedemptionRate()\n : fundingCycle.redemptionRate(),\n _memo,\n _metadata\n );\n (reclaimAmount, memo, delegateAllocations) = IJBFundingCycleDataSource(\n fundingCycle.dataSource()\n ).redeemParams(_data);\n }\n } else {\n memo = _memo;\n }\n }\n\n // Keep a reference to the amount that should be subtracted from the project's balance.\n uint256 _balanceDiff = reclaimAmount;\n\n if (delegateAllocations.length != 0) {\n // Validate all delegated amounts.\n for (uint256 _i; _i < delegateAllocations.length; ) {\n // Get a reference to the amount to be delegated.\n uint256 _delegatedAmount = delegateAllocations[_i].amount;\n\n // Validate if non-zero.\n if (_delegatedAmount != 0)\n // Increment the total amount being subtracted from the balance.\n _balanceDiff = _balanceDiff + _delegatedAmount;\n\n unchecked {\n ++_i;\n }\n }\n }\n\n // The amount being reclaimed must be within the project's balance.\n if (_balanceDiff > balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId])\n revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n\n // Remove the reclaimed funds from the project's balance.\n if (_balanceDiff != 0) {\n unchecked {\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\n _balanceDiff;\n }\n }\n }\n\n /// @notice Records newly distributed funds for a project.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\n /// @param _projectId The ID of the project that is having funds distributed.\n /// @param _amount The amount to use from the distribution limit, as a fixed point number.\n /// @param _currency The currency of the `_amount`. This must match the project's current funding cycle's currency.\n /// @return fundingCycle The funding cycle during which the distribution was made.\n /// @return distributedAmount The amount of terminal tokens distributed, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordDistributionFor(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency\n )\n external\n override\n nonReentrant\n returns (JBFundingCycle memory fundingCycle, uint256 distributedAmount)\n {\n // Get a reference to the project's current funding cycle.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // The funding cycle must not be configured to have distributions paused.\n if (fundingCycle.distributionsPaused()) revert FUNDING_CYCLE_DISTRIBUTION_PAUSED();\n\n // The new total amount that has been distributed during this funding cycle.\n uint256 _newUsedDistributionLimitOf = usedDistributionLimitOf[\n IJBSingleTokenPaymentTerminal(msg.sender)\n ][_projectId][fundingCycle.number] + _amount;\n\n // Amount must be within what is still distributable.\n (uint256 _distributionLimitOf, uint256 _distributionLimitCurrencyOf) = IJBController3_1(\n directory.controllerOf(_projectId)\n ).fundAccessConstraintsStore().distributionLimitOf(\n _projectId,\n fundingCycle.configuration,\n IJBSingleTokenPaymentTerminal(msg.sender),\n IJBSingleTokenPaymentTerminal(msg.sender).token()\n );\n\n // Make sure the new used amount is within the distribution limit.\n if (_newUsedDistributionLimitOf > _distributionLimitOf || _distributionLimitOf == 0)\n revert DISTRIBUTION_AMOUNT_LIMIT_REACHED();\n\n // Make sure the currencies match.\n if (_currency != _distributionLimitCurrencyOf) revert CURRENCY_MISMATCH();\n\n // Get a reference to the terminal's currency.\n uint256 _balanceCurrency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\n\n // Convert the amount to the balance's currency.\n distributedAmount = (_currency == _balanceCurrency)\n ? _amount\n : PRBMath.mulDiv(\n _amount,\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\n prices.priceFor(_currency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\n );\n\n // The amount being distributed must be available.\n if (distributedAmount > balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId])\n revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n\n // Store the new amount.\n usedDistributionLimitOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId][\n fundingCycle.number\n ] = _newUsedDistributionLimitOf;\n\n // Removed the distributed funds from the project's token balance.\n unchecked {\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\n distributedAmount;\n }\n }\n\n /// @notice Records newly used allowance funds of a project.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\n /// @param _projectId The ID of the project to use the allowance of.\n /// @param _amount The amount to use from the allowance, as a fixed point number.\n /// @param _currency The currency of the `_amount`. Must match the currency of the overflow allowance.\n /// @return fundingCycle The funding cycle during which the overflow allowance is being used.\n /// @return usedAmount The amount of terminal tokens used, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordUsedAllowanceOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency\n )\n external\n override\n nonReentrant\n returns (JBFundingCycle memory fundingCycle, uint256 usedAmount)\n {\n // Get a reference to the project's current funding cycle.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Get a reference to the new used overflow allowance for this funding cycle configuration.\n uint256 _newUsedOverflowAllowanceOf = usedOverflowAllowanceOf[\n IJBSingleTokenPaymentTerminal(msg.sender)\n ][_projectId][fundingCycle.configuration] + _amount;\n\n // There must be sufficient allowance available.\n (uint256 _overflowAllowanceOf, uint256 _overflowAllowanceCurrency) = IJBController3_1(\n directory.controllerOf(_projectId)\n ).fundAccessConstraintsStore().overflowAllowanceOf(\n _projectId,\n fundingCycle.configuration,\n IJBSingleTokenPaymentTerminal(msg.sender),\n IJBSingleTokenPaymentTerminal(msg.sender).token()\n );\n\n // Make sure the new used amount is within the allowance.\n if (_newUsedOverflowAllowanceOf > _overflowAllowanceOf || _overflowAllowanceOf == 0)\n revert INADEQUATE_CONTROLLER_ALLOWANCE();\n\n // Make sure the currencies match.\n if (_currency != _overflowAllowanceCurrency) revert CURRENCY_MISMATCH();\n\n // Get a reference to the terminal's currency.\n uint256 _balanceCurrency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\n\n // Convert the amount to this store's terminal's token.\n usedAmount = (_currency == _balanceCurrency)\n ? _amount\n : PRBMath.mulDiv(\n _amount,\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\n prices.priceFor(_currency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\n );\n\n // The amount being distributed must be available in the overflow.\n if (\n usedAmount >\n _overflowDuring(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _projectId,\n fundingCycle,\n _balanceCurrency\n )\n ) revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n\n // Store the incremented value.\n usedOverflowAllowanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId][\n fundingCycle.configuration\n ] = _newUsedOverflowAllowanceOf;\n\n // Update the project's balance.\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\n usedAmount;\n }\n\n /// @notice Records newly added funds for the project.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\n /// @param _projectId The ID of the project to which the funds being added belong.\n /// @param _amount The amount of terminal tokens added, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordAddedBalanceFor(uint256 _projectId, uint256 _amount) external override {\n // Increment the balance.\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] +\n _amount;\n }\n\n /// @notice Records the migration of funds from this store.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount returned is in terms of the msg.senders tokens.\n /// @param _projectId The ID of the project being migrated.\n /// @return balance The project's migrated balance, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordMigration(\n uint256 _projectId\n ) external override nonReentrant returns (uint256 balance) {\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n // Migration must be allowed.\n if (!_fundingCycle.terminalMigrationAllowed()) revert PAYMENT_TERMINAL_MIGRATION_NOT_ALLOWED();\n\n // Return the current balance.\n balance = balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId];\n\n // Set the balance to 0.\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] = 0;\n }\n\n //*********************************************************************//\n // --------------------- private helper functions -------------------- //\n //*********************************************************************//\n\n /// @notice The amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens when measured from the specified.\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\n /// @param _projectId The ID of the project to get the reclaimable overflow amount for.\n /// @param _fundingCycle The funding cycle during which reclaimable overflow is being calculated.\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _totalSupply The total supply of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _overflow The amount of overflow to make the calculation with.\n /// @return The amount of overflowed tokens that can be reclaimed.\n function _reclaimableOverflowDuring(\n uint256 _projectId,\n JBFundingCycle memory _fundingCycle,\n uint256 _tokenCount,\n uint256 _totalSupply,\n uint256 _overflow\n ) private view returns (uint256) {\n // If the amount being redeemed is the total supply, return the rest of the overflow.\n if (_tokenCount == _totalSupply) return _overflow;\n\n // Use the ballot redemption rate if the queued cycle is pending approval according to the previous funding cycle's ballot.\n uint256 _redemptionRate = fundingCycleStore.currentBallotStateOf(_projectId) ==\n JBBallotState.Active\n ? _fundingCycle.ballotRedemptionRate()\n : _fundingCycle.redemptionRate();\n\n // If the redemption rate is 0, nothing is claimable.\n if (_redemptionRate == 0) return 0;\n\n // Get a reference to the linear proportion.\n uint256 _base = PRBMath.mulDiv(_overflow, _tokenCount, _totalSupply);\n\n // These conditions are all part of the same curve. Edge conditions are separated because fewer operation are necessary.\n if (_redemptionRate == JBConstants.MAX_REDEMPTION_RATE) return _base;\n\n return\n PRBMath.mulDiv(\n _base,\n _redemptionRate +\n PRBMath.mulDiv(\n _tokenCount,\n JBConstants.MAX_REDEMPTION_RATE - _redemptionRate,\n _totalSupply\n ),\n JBConstants.MAX_REDEMPTION_RATE\n );\n }\n\n /// @notice Gets the amount that is overflowing when measured from the specified funding cycle.\n /// @dev This amount changes as the value of the balance changes in relation to the currency being used to measure the distribution limit.\n /// @param _terminal The terminal for which the overflow is being calculated.\n /// @param _fundingCycle The ID of the funding cycle to base the overflow on.\n /// @param _balanceCurrency The currency that the stored balance is expected to be in terms of.\n /// @return overflow The overflow of funds, as a fixed point number with 18 decimals.\n function _overflowDuring(\n IJBSingleTokenPaymentTerminal _terminal,\n uint256 _projectId,\n JBFundingCycle memory _fundingCycle,\n uint256 _balanceCurrency\n ) private view returns (uint256) {\n // Get the current balance of the project.\n uint256 _balanceOf = balanceOf[_terminal][_projectId];\n\n // If there's no balance, there's no overflow.\n if (_balanceOf == 0) return 0;\n\n // Get a reference to the distribution limit during the funding cycle.\n (uint256 _distributionLimit, uint256 _distributionLimitCurrency) = IJBController3_1(\n directory.controllerOf(_projectId)\n ).fundAccessConstraintsStore().distributionLimitOf(\n _projectId,\n _fundingCycle.configuration,\n _terminal,\n _terminal.token()\n );\n\n // Get a reference to the amount still distributable during the funding cycle.\n uint256 _distributionLimitRemaining = _distributionLimit -\n usedDistributionLimitOf[_terminal][_projectId][_fundingCycle.number];\n\n // Convert the _distributionRemaining to be in terms of the provided currency.\n if (_distributionLimitRemaining != 0 && _distributionLimitCurrency != _balanceCurrency)\n _distributionLimitRemaining = PRBMath.mulDiv(\n _distributionLimitRemaining,\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\n prices.priceFor(_distributionLimitCurrency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\n );\n\n // Overflow is the balance of this project minus the amount that can still be distributed.\n unchecked {\n return\n _balanceOf > _distributionLimitRemaining ? _balanceOf - _distributionLimitRemaining : 0;\n }\n }\n\n /// @notice Gets the amount that is currently overflowing across all of a project's terminals.\n /// @dev This amount changes as the value of the balances changes in relation to the currency being used to measure the project's distribution limits.\n /// @param _projectId The ID of the project to get the total overflow for.\n /// @param _decimals The number of decimals that the fixed point overflow should include.\n /// @param _currency The currency that the overflow should be in terms of.\n /// @return overflow The total overflow of a project's funds.\n function _currentTotalOverflowOf(\n uint256 _projectId,\n uint256 _decimals,\n uint256 _currency\n ) private view returns (uint256) {\n // Get a reference to the project's terminals.\n IJBPaymentTerminal[] memory _terminals = directory.terminalsOf(_projectId);\n\n // Keep a reference to the ETH overflow across all terminals, as a fixed point number with 18 decimals.\n uint256 _ethOverflow;\n\n // Add the current ETH overflow for each terminal.\n for (uint256 _i; _i < _terminals.length; ) {\n _ethOverflow = _ethOverflow + _terminals[_i].currentEthOverflowOf(_projectId);\n unchecked {\n ++_i;\n }\n }\n\n // Convert the ETH overflow to the specified currency if needed, maintaining a fixed point number with 18 decimals.\n uint256 _totalOverflow18Decimal = _currency == JBCurrencies.ETH\n ? _ethOverflow\n : PRBMath.mulDiv(_ethOverflow, 10 ** 18, prices.priceFor(JBCurrencies.ETH, _currency, 18));\n\n // Adjust the decimals of the fixed point number if needed to match the target decimals.\n return\n (_decimals == 18)\n ? _totalOverflow18Decimal\n : JBFixedPointNumber.adjustDecimals(_totalOverflow18Decimal, 18, _decimals);\n }\n}\n" + }, + "contracts/interfaces/IJBFundingCycleDataSource.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBPayDelegateAllocation} from './../structs/JBPayDelegateAllocation.sol';\nimport {JBPayParamsData} from './../structs/JBPayParamsData.sol';\nimport {JBRedeemParamsData} from './../structs/JBRedeemParamsData.sol';\nimport {JBRedemptionDelegateAllocation} from './../structs/JBRedemptionDelegateAllocation.sol';\n\n/// @title Datasource\n/// @notice The datasource is called by JBPayoutRedemptionPaymentTerminals on pay and redemption, and provide an extra layer of logic to use a custom weight, a custom memo and/or a pay/redeem delegate\ninterface IJBFundingCycleDataSource is IERC165 {\n /// @notice The datasource implementation for JBPaymentTerminal.pay(..)\n /// @param data the data passed to the data source in terminal.pay(..), as a JBPayParamsData struct:\n /// @return weight the weight to use to override the funding cycle weight\n /// @return memo the memo to override the pay(..) memo\n /// @return delegateAllocations The amount to send to delegates instead of adding to the local balance.\n function payParams(\n JBPayParamsData calldata data\n )\n external\n returns (\n uint256 weight,\n string memory memo,\n JBPayDelegateAllocation[] memory delegateAllocations\n );\n\n /// @notice The datasource implementation for JBPaymentTerminal.redeemTokensOf(..)\n /// @param data the data passed to the data source in terminal.redeemTokensOf(..), as a JBRedeemParamsData struct:\n /// @return reclaimAmount The amount to claim, overriding the terminal logic.\n /// @return memo The memo to override the redeemTokensOf(..) memo.\n /// @return delegateAllocations The amount to send to delegates instead of adding to the beneficiary.\n function redeemParams(\n JBRedeemParamsData calldata data\n )\n external\n returns (\n uint256 reclaimAmount,\n string memory memo,\n JBRedemptionDelegateAllocation[] memory delegateAllocations\n );\n}\n" + }, + "contracts/interfaces/IJBSingleTokenPaymentTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\n\ninterface IJBSingleTokenPaymentTerminal is IJBPaymentTerminal {\n function token() external view returns (address);\n\n function currency() external view returns (uint256);\n\n function decimals() external view returns (uint256);\n}\n" + }, + "contracts/interfaces/IJBSingleTokenPaymentTerminalStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\nimport {JBPayDelegateAllocation} from './../structs/JBPayDelegateAllocation.sol';\nimport {JBRedemptionDelegateAllocation} from './../structs/JBRedemptionDelegateAllocation.sol';\nimport {JBTokenAmount} from './../structs/JBTokenAmount.sol';\nimport {IJBDirectory} from './IJBDirectory.sol';\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\nimport {IJBPrices} from './IJBPrices.sol';\nimport {IJBSingleTokenPaymentTerminal} from './IJBSingleTokenPaymentTerminal.sol';\n\ninterface IJBSingleTokenPaymentTerminalStore {\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\n\n function directory() external view returns (IJBDirectory);\n\n function prices() external view returns (IJBPrices);\n\n function balanceOf(\n IJBSingleTokenPaymentTerminal terminal,\n uint256 projectId\n ) external view returns (uint256);\n\n function usedDistributionLimitOf(\n IJBSingleTokenPaymentTerminal terminal,\n uint256 projectId,\n uint256 fundingCycleNumber\n ) external view returns (uint256);\n\n function usedOverflowAllowanceOf(\n IJBSingleTokenPaymentTerminal terminal,\n uint256 projectId,\n uint256 fundingCycleConfiguration\n ) external view returns (uint256);\n\n function currentOverflowOf(\n IJBSingleTokenPaymentTerminal terminal,\n uint256 projectId\n ) external view returns (uint256);\n\n function currentTotalOverflowOf(\n uint256 projectId,\n uint256 decimals,\n uint256 currency\n ) external view returns (uint256);\n\n function currentReclaimableOverflowOf(\n IJBSingleTokenPaymentTerminal terminal,\n uint256 projectId,\n uint256 tokenCount,\n bool useTotalOverflow\n ) external view returns (uint256);\n\n function currentReclaimableOverflowOf(\n uint256 projectId,\n uint256 tokenCount,\n uint256 totalSupply,\n uint256 overflow\n ) external view returns (uint256);\n\n function recordPaymentFrom(\n address payer,\n JBTokenAmount memory amount,\n uint256 projectId,\n uint256 baseWeightCurrency,\n address beneficiary,\n string calldata inputMemo,\n bytes calldata metadata\n )\n external\n returns (\n JBFundingCycle memory fundingCycle,\n uint256 tokenCount,\n JBPayDelegateAllocation[] memory delegateAllocations,\n string memory outputMemo\n );\n\n function recordRedemptionFor(\n address holder,\n uint256 projectId,\n uint256 tokenCount,\n string calldata inputMemo,\n bytes calldata metadata\n )\n external\n returns (\n JBFundingCycle memory fundingCycle,\n uint256 reclaimAmount,\n JBRedemptionDelegateAllocation[] memory delegateAllocations,\n string memory outputMemo\n );\n\n function recordDistributionFor(\n uint256 projectId,\n uint256 amount,\n uint256 currency\n ) external returns (JBFundingCycle memory fundingCycle, uint256 distributedAmount);\n\n function recordUsedAllowanceOf(\n uint256 projectId,\n uint256 amount,\n uint256 currency\n ) external returns (JBFundingCycle memory fundingCycle, uint256 withdrawnAmount);\n\n function recordAddedBalanceFor(uint256 projectId, uint256 amount) external;\n\n function recordMigration(uint256 projectId) external returns (uint256 balance);\n}\n" + }, + "contracts/interfaces/IJBPrices.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBPriceFeed} from './IJBPriceFeed.sol';\n\ninterface IJBPrices {\n event AddFeed(uint256 indexed currency, uint256 indexed base, IJBPriceFeed feed);\n\n function feedFor(uint256 currency, uint256 base) external view returns (IJBPriceFeed);\n\n function priceFor(\n uint256 currency,\n uint256 base,\n uint256 decimals\n ) external view returns (uint256);\n\n function addFeedFor(uint256 currency, uint256 base, IJBPriceFeed priceFeed) external;\n}\n" + }, + "contracts/libraries/JBCurrencies.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nlibrary JBCurrencies {\n uint256 public constant ETH = 1;\n uint256 public constant USD = 2;\n}\n" + }, + "contracts/libraries/JBFixedPointNumber.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nlibrary JBFixedPointNumber {\n function adjustDecimals(\n uint256 _value,\n uint256 _decimals,\n uint256 _targetDecimals\n ) internal pure returns (uint256) {\n // If decimals need adjusting, multiply or divide the price by the decimal adjuster to get the normalized result.\n if (_targetDecimals == _decimals) return _value;\n else if (_targetDecimals > _decimals) return _value * 10**(_targetDecimals - _decimals);\n else return _value / 10**(_decimals - _targetDecimals);\n }\n}\n" + }, + "contracts/structs/JBPayDelegateAllocation.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBPayDelegate} from '../interfaces/IJBPayDelegate.sol';\n\n/// @custom:member delegate A delegate contract to use for subsequent calls.\n/// @custom:member amount The amount to send to the delegate.\nstruct JBPayDelegateAllocation {\n IJBPayDelegate delegate;\n uint256 amount;\n}\n" + }, + "contracts/structs/JBPayParamsData.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\nimport {JBTokenAmount} from './JBTokenAmount.sol';\n\n/// @custom:member terminal The terminal that is facilitating the payment.\n/// @custom:member payer The address from which the payment originated.\n/// @custom:member amount The amount of the payment. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\n/// @custom:member projectId The ID of the project being paid.\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the payment is being made.\n/// @custom:member beneficiary The specified address that should be the beneficiary of anything that results from the payment.\n/// @custom:member weight The weight of the funding cycle during which the payment is being made.\n/// @custom:member reservedRate The reserved rate of the funding cycle during which the payment is being made.\n/// @custom:member memo The memo that was sent alongside the payment.\n/// @custom:member metadata Extra data provided by the payer.\nstruct JBPayParamsData {\n IJBPaymentTerminal terminal;\n address payer;\n JBTokenAmount amount;\n uint256 projectId;\n uint256 currentFundingCycleConfiguration;\n address beneficiary;\n uint256 weight;\n uint256 reservedRate;\n string memo;\n bytes metadata;\n}\n" + }, + "contracts/structs/JBRedeemParamsData.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\nimport {JBTokenAmount} from './JBTokenAmount.sol';\n\n/// @custom:member terminal The terminal that is facilitating the redemption.\n/// @custom:member holder The holder of the tokens being redeemed.\n/// @custom:member projectId The ID of the project whos tokens are being redeemed.\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the redemption is being made.\n/// @custom:member tokenCount The proposed number of tokens being redeemed, as a fixed point number with 18 decimals.\n/// @custom:member totalSupply The total supply of tokens used in the calculation, as a fixed point number with 18 decimals.\n/// @custom:member overflow The amount of overflow used in the reclaim amount calculation.\n/// @custom:member reclaimAmount The amount that should be reclaimed by the redeemer using the protocol's standard bonding curve redemption formula. Includes the token being reclaimed, the reclaim value, the number of decimals included, and the currency of the reclaim amount.\n/// @custom:member useTotalOverflow If overflow across all of a project's terminals is being used when making redemptions.\n/// @custom:member redemptionRate The redemption rate of the funding cycle during which the redemption is being made.\n/// @custom:member memo The proposed memo that is being emitted alongside the redemption.\n/// @custom:member metadata Extra data provided by the redeemer.\nstruct JBRedeemParamsData {\n IJBPaymentTerminal terminal;\n address holder;\n uint256 projectId;\n uint256 currentFundingCycleConfiguration;\n uint256 tokenCount;\n uint256 totalSupply;\n uint256 overflow;\n JBTokenAmount reclaimAmount;\n bool useTotalOverflow;\n uint256 redemptionRate;\n string memo;\n bytes metadata;\n}\n" + }, + "contracts/structs/JBRedemptionDelegateAllocation.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBRedemptionDelegate} from '../interfaces/IJBRedemptionDelegate.sol';\n\n/// @custom:member delegate A delegate contract to use for subsequent calls.\n/// @custom:member amount The amount to send to the delegate.\nstruct JBRedemptionDelegateAllocation {\n IJBRedemptionDelegate delegate;\n uint256 amount;\n}\n" + }, + "contracts/structs/JBTokenAmount.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @custom:member token The token the payment was made in.\n/// @custom:member value The amount of tokens that was paid, as a fixed point number.\n/// @custom:member decimals The number of decimals included in the value fixed point number.\n/// @custom:member currency The expected currency of the value.\nstruct JBTokenAmount {\n address token;\n uint256 value;\n uint256 decimals;\n uint256 currency;\n}\n" + }, + "contracts/interfaces/IJBPayDelegate.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBDidPayData} from './../structs/JBDidPayData.sol';\n\n/// @title Pay delegate\n/// @notice Delegate called after JBTerminal.pay(..) logic completion (if passed by the funding cycle datasource)\ninterface IJBPayDelegate is IERC165 {\n /// @notice This function is called by JBPaymentTerminal.pay(..), after the execution of its logic\n /// @dev Critical business logic should be protected by an appropriate access control\n /// @param data the data passed by the terminal, as a JBDidPayData struct:\n function didPay(JBDidPayData calldata data) external payable;\n}\n" + }, + "contracts/structs/JBDidPayData.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBTokenAmount} from './JBTokenAmount.sol';\n\n/// @custom:member payer The address from which the payment originated.\n/// @custom:member projectId The ID of the project for which the payment was made.\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the payment is being made.\n/// @custom:member amount The amount of the payment. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\n/// @custom:member forwardedAmount The amount of the payment that is being sent to the delegate. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\n/// @custom:member projectTokenCount The number of project tokens minted for the beneficiary.\n/// @custom:member beneficiary The address to which the tokens were minted.\n/// @custom:member preferClaimedTokens A flag indicating whether the request prefered to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract.\n/// @custom:member memo The memo that is being emitted alongside the payment.\n/// @custom:member metadata Extra data to send to the delegate.\nstruct JBDidPayData {\n address payer;\n uint256 projectId;\n uint256 currentFundingCycleConfiguration;\n JBTokenAmount amount;\n JBTokenAmount forwardedAmount;\n uint256 projectTokenCount;\n address beneficiary;\n bool preferClaimedTokens;\n string memo;\n bytes metadata;\n}\n" + }, + "contracts/interfaces/IJBRedemptionDelegate.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBDidRedeemData} from './../structs/JBDidRedeemData.sol';\n\n/// @title Redemption delegate\n/// @notice Delegate called after JBTerminal.redeemTokensOf(..) logic completion (if passed by the funding cycle datasource)\ninterface IJBRedemptionDelegate is IERC165 {\n /// @notice This function is called by JBPaymentTerminal.redeemTokensOf(..), after the execution of its logic\n /// @dev Critical business logic should be protected by an appropriate access control\n /// @param data the data passed by the terminal, as a JBDidRedeemData struct:\n function didRedeem(JBDidRedeemData calldata data) external payable;\n}\n" + }, + "contracts/structs/JBDidRedeemData.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBTokenAmount} from './JBTokenAmount.sol';\n\n/// @custom:member holder The holder of the tokens being redeemed.\n/// @custom:member projectId The ID of the project with which the redeemed tokens are associated.\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the redemption is being made.\n/// @custom:member projectTokenCount The number of project tokens being redeemed.\n/// @custom:member reclaimedAmount The amount reclaimed from the treasury. Includes the token being reclaimed, the value, the number of decimals included, and the currency of the amount.\n/// @custom:member forwardedAmount The amount of the payment that is being sent to the delegate. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\n/// @custom:member beneficiary The address to which the reclaimed amount will be sent.\n/// @custom:member memo The memo that is being emitted alongside the redemption.\n/// @custom:member metadata Extra data to send to the delegate.\nstruct JBDidRedeemData {\n address holder;\n uint256 projectId;\n uint256 currentFundingCycleConfiguration;\n uint256 projectTokenCount;\n JBTokenAmount reclaimedAmount;\n JBTokenAmount forwardedAmount;\n address payable beneficiary;\n string memo;\n bytes metadata;\n}\n" + }, + "contracts/interfaces/IJBPriceFeed.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBPriceFeed {\n function currentPrice(uint256 targetDecimals) external view returns (uint256);\n}\n" + }, + "contracts/JBSingleTokenPaymentTerminalStore3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {ReentrancyGuard} from '@openzeppelin/contracts/security/ReentrancyGuard.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {JBBallotState} from './enums/JBBallotState.sol';\nimport {IJBController3_1} from './interfaces/IJBController3_1.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBFundingCycleDataSource3_1_1} from './interfaces/IJBFundingCycleDataSource3_1_1.sol';\nimport {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol';\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\nimport {IJBSingleTokenPaymentTerminal} from './interfaces/IJBSingleTokenPaymentTerminal.sol';\nimport {IJBSingleTokenPaymentTerminalStore3_1_1} from './interfaces/IJBSingleTokenPaymentTerminalStore3_1_1.sol';\nimport {JBConstants} from './libraries/JBConstants.sol';\nimport {JBCurrencies} from './libraries/JBCurrencies.sol';\nimport {JBFixedPointNumber} from './libraries/JBFixedPointNumber.sol';\nimport {JBFundingCycleMetadataResolver} from './libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\nimport {JBPayDelegateAllocation3_1_1} from './structs/JBPayDelegateAllocation3_1_1.sol';\nimport {JBPayParamsData} from './structs/JBPayParamsData.sol';\nimport {JBRedeemParamsData} from './structs/JBRedeemParamsData.sol';\nimport {JBRedemptionDelegateAllocation3_1_1} from './structs/JBRedemptionDelegateAllocation3_1_1.sol';\nimport {JBTokenAmount} from './structs/JBTokenAmount.sol';\n\n/// @notice Manages all bookkeeping for inflows and outflows of funds from any ISingleTokenPaymentTerminal.\n/// @dev This Store expects a project's controller to be an IJBController3_1.\ncontract JBSingleTokenPaymentTerminalStore3_1_1 is\n ReentrancyGuard,\n IJBSingleTokenPaymentTerminalStore3_1_1\n{\n // A library that parses the packed funding cycle metadata into a friendlier format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error INVALID_AMOUNT_TO_SEND_DELEGATE();\n error CURRENCY_MISMATCH();\n error DISTRIBUTION_AMOUNT_LIMIT_REACHED();\n error FUNDING_CYCLE_PAYMENT_PAUSED();\n error FUNDING_CYCLE_DISTRIBUTION_PAUSED();\n error FUNDING_CYCLE_REDEEM_PAUSED();\n error INADEQUATE_CONTROLLER_ALLOWANCE();\n error INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n error INSUFFICIENT_TOKENS();\n error INVALID_FUNDING_CYCLE();\n error PAYMENT_TERMINAL_MIGRATION_NOT_ALLOWED();\n\n //*********************************************************************//\n // -------------------------- private constants ---------------------- //\n //*********************************************************************//\n\n /// @notice Ensures a maximum number of decimal points of persisted fidelity on mulDiv operations of fixed point numbers.\n uint256 private constant _MAX_FIXED_POINT_FIDELITY = 18;\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n /// @notice The contract storing all funding cycle configurations.\n IJBFundingCycleStore public immutable override fundingCycleStore;\n\n /// @notice The contract that exposes price feeds.\n IJBPrices public immutable override prices;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The amount of tokens that each project has for each terminal, in terms of the terminal's token.\n /// @dev The balance is represented as a fixed point number with the same amount of decimals as its relative terminal.\n /// @custom:param _terminal The terminal to which the balance applies.\n /// @custom:param _projectId The ID of the project to get the balance of.\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => uint256)) public override balanceOf;\n\n /// @notice The amount of funds that a project has distributed from its limit during the current funding cycle for each terminal, in terms of the distribution limit's currency.\n /// @dev Increases as projects use their preconfigured distribution limits.\n /// @dev The used distribution limit is represented as a fixed point number with the same amount of decimals as its relative terminal.\n /// @custom:param _terminal The terminal to which the used distribution limit applies.\n /// @custom:param _projectId The ID of the project to get the used distribution limit of.\n /// @custom:param _fundingCycleNumber The number of the funding cycle during which the distribution limit was used.\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => mapping(uint256 => uint256)))\n public\n override usedDistributionLimitOf;\n\n /// @notice The amount of funds that a project has used from its allowance during the current funding cycle configuration for each terminal, in terms of the overflow allowance's currency.\n /// @dev Increases as projects use their allowance.\n /// @dev The used allowance is represented as a fixed point number with the same amount of decimals as its relative terminal.\n /// @custom:param _terminal The terminal to which the overflow allowance applies.\n /// @custom:param _projectId The ID of the project to get the used overflow allowance of.\n /// @custom:param _configuration The configuration of the during which the allowance was used.\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => mapping(uint256 => uint256)))\n public\n override usedOverflowAllowanceOf;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Gets the current overflowed amount in a terminal for a specified project.\n /// @dev The current overflow is represented as a fixed point number with the same amount of decimals as the specified terminal.\n /// @param _terminal The terminal for which the overflow is being calculated.\n /// @param _projectId The ID of the project to get overflow for.\n /// @return The current amount of overflow that project has in the specified terminal.\n function currentOverflowOf(\n IJBSingleTokenPaymentTerminal _terminal,\n uint256 _projectId\n ) external view override returns (uint256) {\n // Return the overflow during the project's current funding cycle.\n return\n _overflowDuring(\n _terminal,\n _projectId,\n fundingCycleStore.currentOf(_projectId),\n _terminal.currency()\n );\n }\n\n /// @notice Gets the current overflowed amount for a specified project across all terminals.\n /// @param _projectId The ID of the project to get total overflow for.\n /// @param _decimals The number of decimals that the fixed point overflow should include.\n /// @param _currency The currency that the total overflow should be in terms of.\n /// @return The current total amount of overflow that project has across all terminals.\n function currentTotalOverflowOf(\n uint256 _projectId,\n uint256 _decimals,\n uint256 _currency\n ) external view override returns (uint256) {\n return _currentTotalOverflowOf(_projectId, _decimals, _currency);\n }\n\n /// @notice The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the total token supply and overflow in the ecosystem.\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\n /// @dev The current reclaimable overflow is returned in terms of the specified terminal's currency.\n /// @dev The reclaimable overflow is represented as a fixed point number with the same amount of decimals as the specified terminal.\n /// @param _terminal The terminal from which the reclaimable amount would come.\n /// @param _projectId The ID of the project to get the reclaimable overflow amount for.\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _useTotalOverflow A flag indicating whether the overflow used in the calculation should be summed from all of the project's terminals. If false, overflow should be limited to the amount in the specified `_terminal`.\n /// @return The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_terminal`.\n function currentReclaimableOverflowOf(\n IJBSingleTokenPaymentTerminal _terminal,\n uint256 _projectId,\n uint256 _tokenCount,\n bool _useTotalOverflow\n ) external view override returns (uint256) {\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Get the amount of current overflow.\n // Use the project's total overflow across all of its terminals if the flag species specifies so. Otherwise, use the overflow local to the specified terminal.\n uint256 _currentOverflow = _useTotalOverflow\n ? _currentTotalOverflowOf(_projectId, _terminal.decimals(), _terminal.currency())\n : _overflowDuring(_terminal, _projectId, _fundingCycle, _terminal.currency());\n\n // If there's no overflow, there's no reclaimable overflow.\n if (_currentOverflow == 0) return 0;\n\n // Get the number of outstanding tokens the project has.\n uint256 _totalSupply = IJBController3_1(directory.controllerOf(_projectId))\n .totalOutstandingTokensOf(_projectId);\n\n // Can't redeem more tokens that is in the supply.\n if (_tokenCount > _totalSupply) return 0;\n\n // Return the reclaimable overflow amount.\n return\n _reclaimableOverflowDuring(\n _projectId,\n _fundingCycle,\n _tokenCount,\n _totalSupply,\n _currentOverflow\n );\n }\n\n /// @notice The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the specified total token supply and overflow amounts.\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\n /// @param _projectId The ID of the project to get the reclaimable overflow amount for.\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _totalSupply The total number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _overflow The amount of overflow to make the calculation with, as a fixed point number.\n /// @return The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_overflow`.\n function currentReclaimableOverflowOf(\n uint256 _projectId,\n uint256 _tokenCount,\n uint256 _totalSupply,\n uint256 _overflow\n ) external view override returns (uint256) {\n // If there's no overflow, there's no reclaimable overflow.\n if (_overflow == 0) return 0;\n\n // Can't redeem more tokens that is in the supply.\n if (_tokenCount > _totalSupply) return 0;\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Return the reclaimable overflow amount.\n return\n _reclaimableOverflowDuring(_projectId, _fundingCycle, _tokenCount, _totalSupply, _overflow);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _fundingCycleStore A contract storing all funding cycle configurations.\n /// @param _prices A contract that exposes price feeds.\n constructor(IJBDirectory _directory, IJBFundingCycleStore _fundingCycleStore, IJBPrices _prices) {\n directory = _directory;\n fundingCycleStore = _fundingCycleStore;\n prices = _prices;\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Records newly contributed tokens to a project.\n /// @dev Mints the project's tokens according to values provided by a configured data source. If no data source is configured, mints tokens proportional to the amount of the contribution.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.sender's tokens.\n /// @param _payer The original address that sent the payment to the terminal.\n /// @param _amount The amount of tokens being paid. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\n /// @param _projectId The ID of the project being paid.\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _beneficiary The specified address that should be the beneficiary of anything that results from the payment.\n /// @param _memo A memo to pass along to the emitted event, and passed along to the funding cycle's data source.\n /// @param _metadata Bytes to send along to the data source, if one is provided.\n /// @return fundingCycle The project's funding cycle during which payment was made.\n /// @return tokenCount The number of project tokens that were minted, as a fixed point number with 18 decimals.\n /// @return delegateAllocations The amount to send to delegates instead of adding to the local balance.\n /// @return memo A memo that should be passed along to the emitted event.\n function recordPaymentFrom(\n address _payer,\n JBTokenAmount calldata _amount,\n uint256 _projectId,\n uint256 _baseWeightCurrency,\n address _beneficiary,\n string calldata _memo,\n bytes memory _metadata\n )\n external\n override\n nonReentrant\n returns (\n JBFundingCycle memory fundingCycle,\n uint256 tokenCount,\n JBPayDelegateAllocation3_1_1[] memory delegateAllocations,\n string memory memo\n )\n {\n // Get a reference to the current funding cycle for the project.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // The project must have a funding cycle configured.\n if (fundingCycle.number == 0) revert INVALID_FUNDING_CYCLE();\n\n // Must not be paused.\n if (fundingCycle.payPaused()) revert FUNDING_CYCLE_PAYMENT_PAUSED();\n\n // The weight according to which new token supply is to be minted, as a fixed point number with 18 decimals.\n uint256 _weight;\n\n // If the funding cycle has configured a data source, use it to derive a weight and memo.\n if (fundingCycle.useDataSourceForPay() && fundingCycle.dataSource() != address(0)) {\n // Create the params that'll be sent to the data source.\n JBPayParamsData memory _data = JBPayParamsData(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _payer,\n _amount,\n _projectId,\n fundingCycle.configuration,\n _beneficiary,\n fundingCycle.weight,\n fundingCycle.reservedRate(),\n _memo,\n _metadata\n );\n (_weight, memo, delegateAllocations) = IJBFundingCycleDataSource3_1_1(\n fundingCycle.dataSource()\n ).payParams(_data);\n }\n // Otherwise use the funding cycle's weight\n else {\n _weight = fundingCycle.weight;\n memo = _memo;\n }\n\n // Scoped section prevents stack too deep. `_balanceDiff` only used within scope.\n {\n // Keep a reference to the amount that should be added to the project's balance.\n uint256 _balanceDiff = _amount.value;\n\n // Validate all delegated amounts. This needs to be done before returning the delegate allocations to ensure valid delegated amounts.\n if (delegateAllocations.length != 0) {\n for (uint256 _i; _i < delegateAllocations.length; ) {\n // Get a reference to the amount to be delegated.\n uint256 _delegatedAmount = delegateAllocations[_i].amount;\n\n // Validate if non-zero.\n if (_delegatedAmount != 0) {\n // Can't delegate more than was paid.\n if (_delegatedAmount > _balanceDiff) revert INVALID_AMOUNT_TO_SEND_DELEGATE();\n\n // Decrement the total amount being added to the balance.\n _balanceDiff = _balanceDiff - _delegatedAmount;\n }\n\n unchecked {\n ++_i;\n }\n }\n }\n\n // If there's no amount being recorded, there's nothing left to do.\n if (_amount.value == 0) return (fundingCycle, 0, delegateAllocations, memo);\n\n // Add the correct balance difference to the token balance of the project.\n if (_balanceDiff != 0)\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] +\n _balanceDiff;\n }\n\n // If there's no weight, token count must be 0 so there's nothing left to do.\n if (_weight == 0) return (fundingCycle, 0, delegateAllocations, memo);\n\n // Get a reference to the number of decimals in the amount. (prevents stack too deep).\n uint256 _decimals = _amount.decimals;\n\n // If the terminal should base its weight on a different currency from the terminal's currency, determine the factor.\n // The weight is always a fixed point mumber with 18 decimals. To ensure this, the ratio should use the same number of decimals as the `_amount`.\n uint256 _weightRatio = _amount.currency == _baseWeightCurrency\n ? 10 ** _decimals\n : prices.priceFor(_amount.currency, _baseWeightCurrency, _decimals);\n\n // Find the number of tokens to mint, as a fixed point number with as many decimals as `weight` has.\n tokenCount = PRBMath.mulDiv(_amount.value, _weight, _weightRatio);\n }\n\n /// @notice Records newly redeemed tokens of a project.\n /// @dev Redeems the project's tokens according to values provided by a configured data source. If no data source is configured, redeems tokens along a redemption bonding curve that is a function of the number of tokens being burned.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.senders tokens.\n /// @param _holder The account that is having its tokens redeemed.\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\n /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the data source, if one is provided.\n /// @return fundingCycle The funding cycle during which the redemption was made.\n /// @return reclaimAmount The amount of terminal tokens reclaimed, as a fixed point number with 18 decimals.\n /// @return delegateAllocations The amount to send to delegates instead of sending to the beneficiary.\n /// @return memo A memo that should be passed along to the emitted event.\n function recordRedemptionFor(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n string memory _memo,\n bytes memory _metadata\n )\n external\n override\n nonReentrant\n returns (\n JBFundingCycle memory fundingCycle,\n uint256 reclaimAmount,\n JBRedemptionDelegateAllocation3_1_1[] memory delegateAllocations,\n string memory memo\n )\n {\n // Get a reference to the project's current funding cycle.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // The current funding cycle must not be paused.\n if (fundingCycle.redeemPaused()) revert FUNDING_CYCLE_REDEEM_PAUSED();\n\n // Scoped section prevents stack too deep. `_reclaimedTokenAmount`, `_currentOverflow`, and `_totalSupply` only used within scope.\n {\n // Get a reference to the reclaimed token amount struct, the current overflow, and the total token supply.\n JBTokenAmount memory _reclaimedTokenAmount;\n uint256 _currentOverflow;\n uint256 _totalSupply;\n\n // Another scoped section prevents stack too deep. `_token`, `_decimals`, and `_currency` only used within scope.\n {\n // Get a reference to the terminal's tokens.\n address _token = IJBSingleTokenPaymentTerminal(msg.sender).token();\n\n // Get a reference to the terminal's decimals.\n uint256 _decimals = IJBSingleTokenPaymentTerminal(msg.sender).decimals();\n\n // Get areference to the terminal's currency.\n uint256 _currency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\n\n // Get the amount of current overflow.\n // Use the local overflow if the funding cycle specifies that it should be used. Otherwise, use the project's total overflow across all of its terminals.\n _currentOverflow = fundingCycle.useTotalOverflowForRedemptions()\n ? _currentTotalOverflowOf(_projectId, _decimals, _currency)\n : _overflowDuring(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _projectId,\n fundingCycle,\n _currency\n );\n\n // Get the number of outstanding tokens the project has.\n _totalSupply = IJBController3_1(directory.controllerOf(_projectId))\n .totalOutstandingTokensOf(_projectId);\n\n // Can't redeem more tokens that is in the supply.\n if (_tokenCount > _totalSupply) revert INSUFFICIENT_TOKENS();\n\n if (_currentOverflow != 0)\n // Calculate reclaim amount using the current overflow amount.\n reclaimAmount = _reclaimableOverflowDuring(\n _projectId,\n fundingCycle,\n _tokenCount,\n _totalSupply,\n _currentOverflow\n );\n\n _reclaimedTokenAmount = JBTokenAmount(_token, reclaimAmount, _decimals, _currency);\n }\n\n // If the funding cycle has configured a data source, use it to derive a claim amount and memo.\n if (fundingCycle.useDataSourceForRedeem() && fundingCycle.dataSource() != address(0)) {\n // Yet another scoped section prevents stack too deep. `_state` only used within scope.\n {\n // Get a reference to the ballot state.\n JBBallotState _state = fundingCycleStore.currentBallotStateOf(_projectId);\n\n // Create the params that'll be sent to the data source.\n JBRedeemParamsData memory _data = JBRedeemParamsData(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _holder,\n _projectId,\n fundingCycle.configuration,\n _tokenCount,\n _totalSupply,\n _currentOverflow,\n _reclaimedTokenAmount,\n fundingCycle.useTotalOverflowForRedemptions(),\n _state == JBBallotState.Active\n ? fundingCycle.ballotRedemptionRate()\n : fundingCycle.redemptionRate(),\n _memo,\n _metadata\n );\n (reclaimAmount, memo, delegateAllocations) = IJBFundingCycleDataSource3_1_1(\n fundingCycle.dataSource()\n ).redeemParams(_data);\n }\n } else {\n memo = _memo;\n }\n }\n\n // Keep a reference to the amount that should be subtracted from the project's balance.\n uint256 _balanceDiff = reclaimAmount;\n\n if (delegateAllocations.length != 0) {\n // Validate all delegated amounts.\n for (uint256 _i; _i < delegateAllocations.length; ) {\n // Get a reference to the amount to be delegated.\n uint256 _delegatedAmount = delegateAllocations[_i].amount;\n\n // Validate if non-zero.\n if (_delegatedAmount != 0)\n // Increment the total amount being subtracted from the balance.\n _balanceDiff = _balanceDiff + _delegatedAmount;\n\n unchecked {\n ++_i;\n }\n }\n }\n\n // The amount being reclaimed must be within the project's balance.\n if (_balanceDiff > balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId])\n revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n\n // Remove the reclaimed funds from the project's balance.\n if (_balanceDiff != 0) {\n unchecked {\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\n _balanceDiff;\n }\n }\n }\n\n /// @notice Records newly distributed funds for a project.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\n /// @param _projectId The ID of the project that is having funds distributed.\n /// @param _amount The amount to use from the distribution limit, as a fixed point number.\n /// @param _currency The currency of the `_amount`. This must match the project's current funding cycle's currency.\n /// @return fundingCycle The funding cycle during which the distribution was made.\n /// @return distributedAmount The amount of terminal tokens distributed, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordDistributionFor(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency\n )\n external\n override\n nonReentrant\n returns (JBFundingCycle memory fundingCycle, uint256 distributedAmount)\n {\n // Get a reference to the project's current funding cycle.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // The funding cycle must not be configured to have distributions paused.\n if (fundingCycle.distributionsPaused()) revert FUNDING_CYCLE_DISTRIBUTION_PAUSED();\n\n // The new total amount that has been distributed during this funding cycle.\n uint256 _newUsedDistributionLimitOf = usedDistributionLimitOf[\n IJBSingleTokenPaymentTerminal(msg.sender)\n ][_projectId][fundingCycle.number] + _amount;\n\n // Amount must be within what is still distributable.\n (uint256 _distributionLimitOf, uint256 _distributionLimitCurrencyOf) = IJBController3_1(\n directory.controllerOf(_projectId)\n ).fundAccessConstraintsStore().distributionLimitOf(\n _projectId,\n fundingCycle.configuration,\n IJBSingleTokenPaymentTerminal(msg.sender),\n IJBSingleTokenPaymentTerminal(msg.sender).token()\n );\n\n // Make sure the new used amount is within the distribution limit.\n if (_newUsedDistributionLimitOf > _distributionLimitOf || _distributionLimitOf == 0)\n revert DISTRIBUTION_AMOUNT_LIMIT_REACHED();\n\n // Make sure the currencies match.\n if (_currency != _distributionLimitCurrencyOf) revert CURRENCY_MISMATCH();\n\n // Get a reference to the terminal's currency.\n uint256 _balanceCurrency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\n\n // Convert the amount to the balance's currency.\n distributedAmount = (_currency == _balanceCurrency)\n ? _amount\n : PRBMath.mulDiv(\n _amount,\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\n prices.priceFor(_currency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\n );\n\n // The amount being distributed must be available.\n if (distributedAmount > balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId])\n revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n\n // Store the new amount.\n usedDistributionLimitOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId][\n fundingCycle.number\n ] = _newUsedDistributionLimitOf;\n\n // Removed the distributed funds from the project's token balance.\n unchecked {\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\n distributedAmount;\n }\n }\n\n /// @notice Records newly used allowance funds of a project.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\n /// @param _projectId The ID of the project to use the allowance of.\n /// @param _amount The amount to use from the allowance, as a fixed point number.\n /// @param _currency The currency of the `_amount`. Must match the currency of the overflow allowance.\n /// @return fundingCycle The funding cycle during which the overflow allowance is being used.\n /// @return usedAmount The amount of terminal tokens used, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordUsedAllowanceOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency\n )\n external\n override\n nonReentrant\n returns (JBFundingCycle memory fundingCycle, uint256 usedAmount)\n {\n // Get a reference to the project's current funding cycle.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Get a reference to the new used overflow allowance for this funding cycle configuration.\n uint256 _newUsedOverflowAllowanceOf = usedOverflowAllowanceOf[\n IJBSingleTokenPaymentTerminal(msg.sender)\n ][_projectId][fundingCycle.configuration] + _amount;\n\n // There must be sufficient allowance available.\n (uint256 _overflowAllowanceOf, uint256 _overflowAllowanceCurrency) = IJBController3_1(\n directory.controllerOf(_projectId)\n ).fundAccessConstraintsStore().overflowAllowanceOf(\n _projectId,\n fundingCycle.configuration,\n IJBSingleTokenPaymentTerminal(msg.sender),\n IJBSingleTokenPaymentTerminal(msg.sender).token()\n );\n\n // Make sure the new used amount is within the allowance.\n if (_newUsedOverflowAllowanceOf > _overflowAllowanceOf || _overflowAllowanceOf == 0)\n revert INADEQUATE_CONTROLLER_ALLOWANCE();\n\n // Make sure the currencies match.\n if (_currency != _overflowAllowanceCurrency) revert CURRENCY_MISMATCH();\n\n // Get a reference to the terminal's currency.\n uint256 _balanceCurrency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\n\n // Convert the amount to this store's terminal's token.\n usedAmount = (_currency == _balanceCurrency)\n ? _amount\n : PRBMath.mulDiv(\n _amount,\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\n prices.priceFor(_currency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\n );\n\n // The amount being distributed must be available in the overflow.\n if (\n usedAmount >\n _overflowDuring(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _projectId,\n fundingCycle,\n _balanceCurrency\n )\n ) revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n\n // Store the incremented value.\n usedOverflowAllowanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId][\n fundingCycle.configuration\n ] = _newUsedOverflowAllowanceOf;\n\n // Update the project's balance.\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\n usedAmount;\n }\n\n /// @notice Records newly added funds for the project.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\n /// @param _projectId The ID of the project to which the funds being added belong.\n /// @param _amount The amount of terminal tokens added, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordAddedBalanceFor(uint256 _projectId, uint256 _amount) external override {\n // Increment the balance.\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] +\n _amount;\n }\n\n /// @notice Records the migration of funds from this store.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount returned is in terms of the msg.senders tokens.\n /// @param _projectId The ID of the project being migrated.\n /// @return balance The project's migrated balance, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordMigration(\n uint256 _projectId\n ) external override nonReentrant returns (uint256 balance) {\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Migration must be allowed.\n if (!_fundingCycle.terminalMigrationAllowed()) revert PAYMENT_TERMINAL_MIGRATION_NOT_ALLOWED();\n\n // Return the current balance.\n balance = balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId];\n\n // Set the balance to 0.\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] = 0;\n }\n\n //*********************************************************************//\n // --------------------- private helper functions -------------------- //\n //*********************************************************************//\n\n /// @notice The amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens when measured from the specified.\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\n /// @param _projectId The ID of the project to get the reclaimable overflow amount for.\n /// @param _fundingCycle The funding cycle during which reclaimable overflow is being calculated.\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _totalSupply The total supply of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _overflow The amount of overflow to make the calculation with.\n /// @return The amount of overflowed tokens that can be reclaimed.\n function _reclaimableOverflowDuring(\n uint256 _projectId,\n JBFundingCycle memory _fundingCycle,\n uint256 _tokenCount,\n uint256 _totalSupply,\n uint256 _overflow\n ) private view returns (uint256) {\n // If the amount being redeemed is the total supply, return the rest of the overflow.\n if (_tokenCount == _totalSupply) return _overflow;\n\n // Use the ballot redemption rate if the queued cycle is pending approval according to the previous funding cycle's ballot.\n uint256 _redemptionRate = fundingCycleStore.currentBallotStateOf(_projectId) ==\n JBBallotState.Active\n ? _fundingCycle.ballotRedemptionRate()\n : _fundingCycle.redemptionRate();\n\n // If the redemption rate is 0, nothing is claimable.\n if (_redemptionRate == 0) return 0;\n\n // Get a reference to the linear proportion.\n uint256 _base = PRBMath.mulDiv(_overflow, _tokenCount, _totalSupply);\n\n // These conditions are all part of the same curve. Edge conditions are separated because fewer operation are necessary.\n if (_redemptionRate == JBConstants.MAX_REDEMPTION_RATE) return _base;\n\n return\n PRBMath.mulDiv(\n _base,\n _redemptionRate +\n PRBMath.mulDiv(\n _tokenCount,\n JBConstants.MAX_REDEMPTION_RATE - _redemptionRate,\n _totalSupply\n ),\n JBConstants.MAX_REDEMPTION_RATE\n );\n }\n\n /// @notice Gets the amount that is overflowing when measured from the specified funding cycle.\n /// @dev This amount changes as the value of the balance changes in relation to the currency being used to measure the distribution limit.\n /// @param _terminal The terminal for which the overflow is being calculated.\n /// @param _projectId The ID of the project to get overflow for.\n /// @param _fundingCycle The ID of the funding cycle to base the overflow on.\n /// @param _balanceCurrency The currency that the stored balance is expected to be in terms of.\n /// @return overflow The overflow of funds, as a fixed point number with 18 decimals.\n function _overflowDuring(\n IJBSingleTokenPaymentTerminal _terminal,\n uint256 _projectId,\n JBFundingCycle memory _fundingCycle,\n uint256 _balanceCurrency\n ) private view returns (uint256) {\n // Get the current balance of the project.\n uint256 _balanceOf = balanceOf[_terminal][_projectId];\n\n // If there's no balance, there's no overflow.\n if (_balanceOf == 0) return 0;\n\n // Get a reference to the distribution limit during the funding cycle.\n (uint256 _distributionLimit, uint256 _distributionLimitCurrency) = IJBController3_1(\n directory.controllerOf(_projectId)\n ).fundAccessConstraintsStore().distributionLimitOf(\n _projectId,\n _fundingCycle.configuration,\n _terminal,\n _terminal.token()\n );\n\n // Get a reference to the amount still distributable during the funding cycle.\n uint256 _distributionLimitRemaining = _distributionLimit -\n usedDistributionLimitOf[_terminal][_projectId][_fundingCycle.number];\n\n // Convert the _distributionRemaining to be in terms of the provided currency.\n if (_distributionLimitRemaining != 0 && _distributionLimitCurrency != _balanceCurrency)\n _distributionLimitRemaining = PRBMath.mulDiv(\n _distributionLimitRemaining,\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\n prices.priceFor(_distributionLimitCurrency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\n );\n\n // Overflow is the balance of this project minus the amount that can still be distributed.\n unchecked {\n return\n _balanceOf > _distributionLimitRemaining ? _balanceOf - _distributionLimitRemaining : 0;\n }\n }\n\n /// @notice Gets the amount that is currently overflowing across all of a project's terminals.\n /// @dev This amount changes as the value of the balances changes in relation to the currency being used to measure the project's distribution limits.\n /// @param _projectId The ID of the project to get the total overflow for.\n /// @param _decimals The number of decimals that the fixed point overflow should include.\n /// @param _currency The currency that the overflow should be in terms of.\n /// @return overflow The total overflow of a project's funds.\n function _currentTotalOverflowOf(\n uint256 _projectId,\n uint256 _decimals,\n uint256 _currency\n ) private view returns (uint256) {\n // Get a reference to the project's terminals.\n IJBPaymentTerminal[] memory _terminals = directory.terminalsOf(_projectId);\n\n // Keep a reference to the ETH overflow across all terminals, as a fixed point number with 18 decimals.\n uint256 _ethOverflow;\n\n // Add the current ETH overflow for each terminal.\n for (uint256 _i; _i < _terminals.length; ) {\n _ethOverflow = _ethOverflow + _terminals[_i].currentEthOverflowOf(_projectId);\n unchecked {\n ++_i;\n }\n }\n\n // Convert the ETH overflow to the specified currency if needed, maintaining a fixed point number with 18 decimals.\n uint256 _totalOverflow18Decimal = _currency == JBCurrencies.ETH\n ? _ethOverflow\n : PRBMath.mulDiv(_ethOverflow, 10 ** 18, prices.priceFor(JBCurrencies.ETH, _currency, 18));\n\n // Adjust the decimals of the fixed point number if needed to match the target decimals.\n return\n (_decimals == 18)\n ? _totalOverflow18Decimal\n : JBFixedPointNumber.adjustDecimals(_totalOverflow18Decimal, 18, _decimals);\n }\n}\n" + }, + "contracts/interfaces/IJBFundingCycleDataSource3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBPayDelegateAllocation3_1_1} from './../structs/JBPayDelegateAllocation3_1_1.sol';\nimport {JBPayParamsData} from './../structs/JBPayParamsData.sol';\nimport {JBRedeemParamsData} from './../structs/JBRedeemParamsData.sol';\nimport {JBRedemptionDelegateAllocation3_1_1} from './../structs/JBRedemptionDelegateAllocation3_1_1.sol';\n\n/// @title Datasource\n/// @notice The datasource is called by JBPayoutRedemptionPaymentTerminals on pay and redemption, and provide an extra layer of logic to use a custom weight, a custom memo and/or a pay/redeem delegate\ninterface IJBFundingCycleDataSource3_1_1 is IERC165 {\n /// @notice The datasource implementation for JBPaymentTerminal.pay(..)\n /// @param data the data passed to the data source in terminal.pay(..), as a JBPayParamsData struct:\n /// @return weight the weight to use to override the funding cycle weight\n /// @return memo the memo to override the pay(..) memo\n /// @return delegateAllocations The amount to send to delegates instead of adding to the local balance.\n function payParams(\n JBPayParamsData calldata data\n )\n external\n returns (\n uint256 weight,\n string memory memo,\n JBPayDelegateAllocation3_1_1[] memory delegateAllocations\n );\n\n /// @notice The datasource implementation for JBPaymentTerminal.redeemTokensOf(..)\n /// @param data the data passed to the data source in terminal.redeemTokensOf(..), as a JBRedeemParamsData struct:\n /// @return reclaimAmount The amount to claim, overriding the terminal logic.\n /// @return memo The memo to override the redeemTokensOf(..) memo.\n /// @return delegateAllocations The amount to send to delegates instead of adding to the beneficiary.\n function redeemParams(\n JBRedeemParamsData calldata data\n )\n external\n returns (\n uint256 reclaimAmount,\n string memory memo,\n JBRedemptionDelegateAllocation3_1_1[] memory delegateAllocations\n );\n}\n" + }, + "contracts/interfaces/IJBSingleTokenPaymentTerminalStore3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\nimport {JBPayDelegateAllocation3_1_1} from './../structs/JBPayDelegateAllocation3_1_1.sol';\nimport {JBRedemptionDelegateAllocation3_1_1} from './../structs/JBRedemptionDelegateAllocation3_1_1.sol';\nimport {JBTokenAmount} from './../structs/JBTokenAmount.sol';\nimport {IJBDirectory} from './IJBDirectory.sol';\nimport {IJBFundingCycleStore} from './IJBFundingCycleStore.sol';\nimport {IJBPrices} from './IJBPrices.sol';\nimport {IJBSingleTokenPaymentTerminal} from './IJBSingleTokenPaymentTerminal.sol';\n\ninterface IJBSingleTokenPaymentTerminalStore3_1_1 {\n function fundingCycleStore() external view returns (IJBFundingCycleStore);\n\n function directory() external view returns (IJBDirectory);\n\n function prices() external view returns (IJBPrices);\n\n function balanceOf(\n IJBSingleTokenPaymentTerminal terminal,\n uint256 projectId\n ) external view returns (uint256);\n\n function usedDistributionLimitOf(\n IJBSingleTokenPaymentTerminal terminal,\n uint256 projectId,\n uint256 fundingCycleNumber\n ) external view returns (uint256);\n\n function usedOverflowAllowanceOf(\n IJBSingleTokenPaymentTerminal terminal,\n uint256 projectId,\n uint256 fundingCycleConfiguration\n ) external view returns (uint256);\n\n function currentOverflowOf(\n IJBSingleTokenPaymentTerminal terminal,\n uint256 projectId\n ) external view returns (uint256);\n\n function currentTotalOverflowOf(\n uint256 projectId,\n uint256 decimals,\n uint256 currency\n ) external view returns (uint256);\n\n function currentReclaimableOverflowOf(\n IJBSingleTokenPaymentTerminal terminal,\n uint256 projectId,\n uint256 tokenCount,\n bool useTotalOverflow\n ) external view returns (uint256);\n\n function currentReclaimableOverflowOf(\n uint256 projectId,\n uint256 tokenCount,\n uint256 totalSupply,\n uint256 overflow\n ) external view returns (uint256);\n\n function recordPaymentFrom(\n address payer,\n JBTokenAmount memory amount,\n uint256 projectId,\n uint256 baseWeightCurrency,\n address beneficiary,\n string calldata inputMemo,\n bytes calldata metadata\n )\n external\n returns (\n JBFundingCycle memory fundingCycle,\n uint256 tokenCount,\n JBPayDelegateAllocation3_1_1[] memory delegateAllocations,\n string memory outputMemo\n );\n\n function recordRedemptionFor(\n address holder,\n uint256 projectId,\n uint256 tokenCount,\n string calldata inputMemo,\n bytes calldata metadata\n )\n external\n returns (\n JBFundingCycle memory fundingCycle,\n uint256 reclaimAmount,\n JBRedemptionDelegateAllocation3_1_1[] memory delegateAllocations,\n string memory outputMemo\n );\n\n function recordDistributionFor(\n uint256 projectId,\n uint256 amount,\n uint256 currency\n ) external returns (JBFundingCycle memory fundingCycle, uint256 distributedAmount);\n\n function recordUsedAllowanceOf(\n uint256 projectId,\n uint256 amount,\n uint256 currency\n ) external returns (JBFundingCycle memory fundingCycle, uint256 withdrawnAmount);\n\n function recordAddedBalanceFor(uint256 projectId, uint256 amount) external;\n\n function recordMigration(uint256 projectId) external returns (uint256 balance);\n}\n" + }, + "contracts/structs/JBPayDelegateAllocation3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBPayDelegate3_1_1} from '../interfaces/IJBPayDelegate3_1_1.sol';\n\n/// @custom:member delegate A delegate contract to use for subsequent calls.\n/// @custom:member amount The amount to send to the delegate.\n/// @custom:member metadata Metadata to pass the delegate.\nstruct JBPayDelegateAllocation3_1_1 {\n IJBPayDelegate3_1_1 delegate;\n uint256 amount;\n bytes metadata;\n}\n" + }, + "contracts/structs/JBRedemptionDelegateAllocation3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBRedemptionDelegate3_1_1} from '../interfaces/IJBRedemptionDelegate3_1_1.sol';\n\n/// @custom:member delegate A delegate contract to use for subsequent calls.\n/// @custom:member amount The amount to send to the delegate.\n/// @custom:member metadata Metadata to pass the delegate.\nstruct JBRedemptionDelegateAllocation3_1_1 {\n IJBRedemptionDelegate3_1_1 delegate;\n uint256 amount;\n bytes metadata;\n}\n" + }, + "contracts/interfaces/IJBPayDelegate3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBDidPayData3_1_1} from './../structs/JBDidPayData3_1_1.sol';\n\n/// @title Pay delegate\n/// @notice Delegate called after JBTerminal.pay(..) logic completion (if passed by the funding cycle datasource)\ninterface IJBPayDelegate3_1_1 is IERC165 {\n /// @notice This function is called by JBPaymentTerminal.pay(..), after the execution of its logic\n /// @dev Critical business logic should be protected by an appropriate access control\n /// @param data the data passed by the terminal, as a JBDidPayData3_1_1 struct:\n function didPay(JBDidPayData3_1_1 calldata data) external payable;\n}\n" + }, + "contracts/structs/JBDidPayData3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBTokenAmount} from './JBTokenAmount.sol';\n\n/// @custom:member payer The address from which the payment originated.\n/// @custom:member projectId The ID of the project for which the payment was made.\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the payment is being made.\n/// @custom:member amount The amount of the payment. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\n/// @custom:member forwardedAmount The amount of the payment that is being sent to the delegate. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\n/// @custom:member projectTokenCount The number of project tokens minted for the beneficiary.\n/// @custom:member beneficiary The address to which the tokens were minted.\n/// @custom:member preferClaimedTokens A flag indicating whether the request prefered to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract.\n/// @custom:member memo The memo that is being emitted alongside the payment.\n/// @custom:member dataSourceMetadata Extra data to send to the delegate sent by the data source.\n/// @custom:member payerMetadata Extra data to send to the delegate sent by the payer.\nstruct JBDidPayData3_1_1 {\n address payer;\n uint256 projectId;\n uint256 currentFundingCycleConfiguration;\n JBTokenAmount amount;\n JBTokenAmount forwardedAmount;\n uint256 projectTokenCount;\n address beneficiary;\n bool preferClaimedTokens;\n string memo;\n bytes dataSourceMetadata;\n bytes payerMetadata;\n}\n" + }, + "contracts/interfaces/IJBRedemptionDelegate3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBDidRedeemData3_1_1} from './../structs/JBDidRedeemData3_1_1.sol';\n\n/// @title Redemption delegate\n/// @notice Delegate called after JBTerminal.redeemTokensOf(..) logic completion (if passed by the funding cycle datasource)\ninterface IJBRedemptionDelegate3_1_1 is IERC165 {\n /// @notice This function is called by JBPaymentTerminal.redeemTokensOf(..), after the execution of its logic\n /// @dev Critical business logic should be protected by an appropriate access control\n /// @param data the data passed by the terminal, as a JBDidRedeemData struct:\n function didRedeem(JBDidRedeemData3_1_1 calldata data) external payable;\n}\n" + }, + "contracts/structs/JBDidRedeemData3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBTokenAmount} from './JBTokenAmount.sol';\n\n/// @custom:member holder The holder of the tokens being redeemed.\n/// @custom:member projectId The ID of the project with which the redeemed tokens are associated.\n/// @custom:member currentFundingCycleConfiguration The configuration of the funding cycle during which the redemption is being made.\n/// @custom:member projectTokenCount The number of project tokens being redeemed.\n/// @custom:member reclaimedAmount The amount reclaimed from the treasury. Includes the token being reclaimed, the value, the number of decimals included, and the currency of the amount.\n/// @custom:member forwardedAmount The amount of the payment that is being sent to the delegate. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\n/// @custom:member beneficiary The address to which the reclaimed amount will be sent.\n/// @custom:member memo The memo that is being emitted alongside the redemption.\n/// @custom:member dataSourceMetadata Extra data to send to the delegate sent by the data source.\n/// @custom:member redeemerMetadata Extra data to send to the delegate sent by the redeemer.\nstruct JBDidRedeemData3_1_1 {\n address holder;\n uint256 projectId;\n uint256 currentFundingCycleConfiguration;\n uint256 projectTokenCount;\n JBTokenAmount reclaimedAmount;\n JBTokenAmount forwardedAmount;\n address payable beneficiary;\n string memo;\n bytes dataSourceMetadata;\n bytes redeemerMetadata;\n}\n" + }, + "contracts/JBSingleTokenPaymentTerminalStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {ReentrancyGuard} from '@openzeppelin/contracts/security/ReentrancyGuard.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {JBBallotState} from './enums/JBBallotState.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBController} from './interfaces/IJBController.sol';\nimport {IJBFundingCycleDataSource} from './interfaces/IJBFundingCycleDataSource.sol';\nimport {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol';\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\nimport {IJBSingleTokenPaymentTerminal} from './interfaces/IJBSingleTokenPaymentTerminal.sol';\nimport {IJBSingleTokenPaymentTerminalStore} from './interfaces/IJBSingleTokenPaymentTerminalStore.sol';\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\nimport {JBConstants} from './libraries/JBConstants.sol';\nimport {JBCurrencies} from './libraries/JBCurrencies.sol';\nimport {JBFixedPointNumber} from './libraries/JBFixedPointNumber.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\nimport {JBFundingCycleMetadataResolver} from './libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBPayDelegateAllocation} from './structs/JBPayDelegateAllocation.sol';\nimport {JBPayParamsData} from './structs/JBPayParamsData.sol';\nimport {JBRedeemParamsData} from './structs/JBRedeemParamsData.sol';\nimport {JBRedemptionDelegateAllocation} from './structs/JBRedemptionDelegateAllocation.sol';\nimport {JBTokenAmount} from './structs/JBTokenAmount.sol';\n\n/// @notice Manages all bookkeeping for inflows and outflows of funds from any ISingleTokenPaymentTerminal.\ncontract JBSingleTokenPaymentTerminalStore is ReentrancyGuard, IJBSingleTokenPaymentTerminalStore {\n // A library that parses the packed funding cycle metadata into a friendlier format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error INVALID_AMOUNT_TO_SEND_DELEGATE();\n error CURRENCY_MISMATCH();\n error DISTRIBUTION_AMOUNT_LIMIT_REACHED();\n error FUNDING_CYCLE_PAYMENT_PAUSED();\n error FUNDING_CYCLE_DISTRIBUTION_PAUSED();\n error FUNDING_CYCLE_REDEEM_PAUSED();\n error INADEQUATE_CONTROLLER_ALLOWANCE();\n error INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n error INSUFFICIENT_TOKENS();\n error INVALID_FUNDING_CYCLE();\n error PAYMENT_TERMINAL_MIGRATION_NOT_ALLOWED();\n\n //*********************************************************************//\n // -------------------------- private constants ---------------------- //\n //*********************************************************************//\n\n /// @notice Ensures a maximum number of decimal points of persisted fidelity on mulDiv operations of fixed point numbers.\n uint256 private constant _MAX_FIXED_POINT_FIDELITY = 18;\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n /// @notice The contract storing all funding cycle configurations.\n IJBFundingCycleStore public immutable override fundingCycleStore;\n\n /// @notice The contract that exposes price feeds.\n IJBPrices public immutable override prices;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The amount of tokens that each project has for each terminal, in terms of the terminal's token.\n /// @dev The used distribution limit is represented as a fixed point number with the same amount of decimals as its relative terminal.\n /// @custom:param _terminal The terminal to which the balance applies.\n /// @custom:param _projectId The ID of the project to get the balance of.\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => uint256)) public override balanceOf;\n\n /// @notice The amount of funds that a project has distributed from its limit during the current funding cycle for each terminal, in terms of the distribution limit's currency.\n /// @dev Increases as projects use their preconfigured distribution limits.\n /// @dev The used distribution limit is represented as a fixed point number with the same amount of decimals as its relative terminal.\n /// @custom:param _terminal The terminal to which the used distribution limit applies.\n /// @custom:param _projectId The ID of the project to get the used distribution limit of.\n /// @custom:param _fundingCycleNumber The number of the funding cycle during which the distribution limit was used.\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => mapping(uint256 => uint256)))\n public\n override usedDistributionLimitOf;\n\n /// @notice The amount of funds that a project has used from its allowance during the current funding cycle configuration for each terminal, in terms of the overflow allowance's currency.\n /// @dev Increases as projects use their allowance.\n /// @dev The used allowance is represented as a fixed point number with the same amount of decimals as its relative terminal.\n /// @custom:param _terminal The terminal to which the overflow allowance applies.\n /// @custom:param _projectId The ID of the project to get the used overflow allowance of.\n /// @custom:param _configuration The configuration of the during which the allowance was used.\n mapping(IJBSingleTokenPaymentTerminal => mapping(uint256 => mapping(uint256 => uint256)))\n public\n override usedOverflowAllowanceOf;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Gets the current overflowed amount in a terminal for a specified project.\n /// @dev The current overflow is represented as a fixed point number with the same amount of decimals as the specified terminal.\n /// @param _terminal The terminal for which the overflow is being calculated.\n /// @param _projectId The ID of the project to get overflow for.\n /// @return The current amount of overflow that project has in the specified terminal.\n function currentOverflowOf(\n IJBSingleTokenPaymentTerminal _terminal,\n uint256 _projectId\n ) external view override returns (uint256) {\n // Return the overflow during the project's current funding cycle.\n return\n _overflowDuring(\n _terminal,\n _projectId,\n fundingCycleStore.currentOf(_projectId),\n _terminal.currency()\n );\n }\n\n /// @notice Gets the current overflowed amount for a specified project across all terminals.\n /// @param _projectId The ID of the project to get total overflow for.\n /// @param _decimals The number of decimals that the fixed point overflow should include.\n /// @param _currency The currency that the total overflow should be in terms of.\n /// @return The current total amount of overflow that project has across all terminals.\n function currentTotalOverflowOf(\n uint256 _projectId,\n uint256 _decimals,\n uint256 _currency\n ) external view override returns (uint256) {\n return _currentTotalOverflowOf(_projectId, _decimals, _currency);\n }\n\n /// @notice The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the total token supply and overflow in the ecosystem.\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\n /// @dev The current reclaimable overflow is returned in terms of the specified terminal's currency.\n /// @dev The reclaimable overflow is represented as a fixed point number with the same amount of decimals as the specified terminal.\n /// @param _terminal The terminal from which the reclaimable amount would come.\n /// @param _projectId The ID of the project to get the reclaimable overflow amount for.\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _useTotalOverflow A flag indicating whether the overflow used in the calculation should be summed from all of the project's terminals. If false, overflow should be limited to the amount in the specified `_terminal`.\n /// @return The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_terminal`.\n function currentReclaimableOverflowOf(\n IJBSingleTokenPaymentTerminal _terminal,\n uint256 _projectId,\n uint256 _tokenCount,\n bool _useTotalOverflow\n ) external view override returns (uint256) {\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Get the amount of current overflow.\n // Use the project's total overflow across all of its terminals if the flag species specifies so. Otherwise, use the overflow local to the specified terminal.\n uint256 _currentOverflow = _useTotalOverflow\n ? _currentTotalOverflowOf(_projectId, _terminal.decimals(), _terminal.currency())\n : _overflowDuring(_terminal, _projectId, _fundingCycle, _terminal.currency());\n\n // If there's no overflow, there's no reclaimable overflow.\n if (_currentOverflow == 0) return 0;\n\n // Get the number of outstanding tokens the project has.\n uint256 _totalSupply = IJBController(directory.controllerOf(_projectId))\n .totalOutstandingTokensOf(_projectId, _fundingCycle.reservedRate());\n\n // Can't redeem more tokens that is in the supply.\n if (_tokenCount > _totalSupply) return 0;\n\n // Return the reclaimable overflow amount.\n return\n _reclaimableOverflowDuring(\n _projectId,\n _fundingCycle,\n _tokenCount,\n _totalSupply,\n _currentOverflow\n );\n }\n\n /// @notice The current amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens, using the specified total token supply and overflow amounts.\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\n /// @param _projectId The ID of the project for which the reclaimable overflow applies.\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _totalSupply The total number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _overflow The amount of overflow to make the calculation with, as a fixed point number.\n /// @return The amount of overflowed tokens that can be reclaimed, as a fixed point number with the same number of decimals as the provided `_overflow`.\n function currentReclaimableOverflowOf(\n uint256 _projectId,\n uint256 _tokenCount,\n uint256 _totalSupply,\n uint256 _overflow\n ) external view override returns (uint256) {\n // If there's no overflow, there's no reclaimable overflow.\n if (_overflow == 0) return 0;\n\n // Can't redeem more tokens that is in the supply.\n if (_tokenCount > _totalSupply) return 0;\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Return the reclaimable overflow amount.\n return\n _reclaimableOverflowDuring(_projectId, _fundingCycle, _tokenCount, _totalSupply, _overflow);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _fundingCycleStore A contract storing all funding cycle configurations.\n /// @param _prices A contract that exposes price feeds.\n constructor(IJBDirectory _directory, IJBFundingCycleStore _fundingCycleStore, IJBPrices _prices) {\n directory = _directory;\n fundingCycleStore = _fundingCycleStore;\n prices = _prices;\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Records newly contributed tokens to a project.\n /// @dev Mints the project's tokens according to values provided by a configured data source. If no data source is configured, mints tokens proportional to the amount of the contribution.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.sender's tokens.\n /// @param _payer The original address that sent the payment to the terminal.\n /// @param _amount The amount of tokens being paid. Includes the token being paid, the value, the number of decimals included, and the currency of the amount.\n /// @param _projectId The ID of the project being paid.\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _beneficiary The specified address that should be the beneficiary of anything that results from the payment.\n /// @param _memo A memo to pass along to the emitted event, and passed along to the funding cycle's data source.\n /// @param _metadata Bytes to send along to the data source, if one is provided.\n /// @return fundingCycle The project's funding cycle during which payment was made.\n /// @return tokenCount The number of project tokens that were minted, as a fixed point number with 18 decimals.\n /// @return delegateAllocations The amount to send to delegates instead of adding to the local balance.\n /// @return memo A memo that should be passed along to the emitted event.\n function recordPaymentFrom(\n address _payer,\n JBTokenAmount calldata _amount,\n uint256 _projectId,\n uint256 _baseWeightCurrency,\n address _beneficiary,\n string calldata _memo,\n bytes memory _metadata\n )\n external\n override\n nonReentrant\n returns (\n JBFundingCycle memory fundingCycle,\n uint256 tokenCount,\n JBPayDelegateAllocation[] memory delegateAllocations,\n string memory memo\n )\n {\n // Get a reference to the current funding cycle for the project.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // The project must have a funding cycle configured.\n if (fundingCycle.number == 0) revert INVALID_FUNDING_CYCLE();\n\n // Must not be paused.\n if (fundingCycle.payPaused()) revert FUNDING_CYCLE_PAYMENT_PAUSED();\n\n // The weight according to which new token supply is to be minted, as a fixed point number with 18 decimals.\n uint256 _weight;\n\n // If the funding cycle has configured a data source, use it to derive a weight and memo.\n if (fundingCycle.useDataSourceForPay() && fundingCycle.dataSource() != address(0)) {\n // Create the params that'll be sent to the data source.\n JBPayParamsData memory _data = JBPayParamsData(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _payer,\n _amount,\n _projectId,\n fundingCycle.configuration,\n _beneficiary,\n fundingCycle.weight,\n fundingCycle.reservedRate(),\n _memo,\n _metadata\n );\n (_weight, memo, delegateAllocations) = IJBFundingCycleDataSource(fundingCycle.dataSource())\n .payParams(_data);\n }\n // Otherwise use the funding cycle's weight\n else {\n _weight = fundingCycle.weight;\n memo = _memo;\n }\n\n // Scoped section prevents stack too deep. `_balanceDiff` only used within scope.\n {\n // Keep a reference to the amount that should be added to the project's balance.\n uint256 _balanceDiff = _amount.value;\n\n // Validate all delegated amounts. This needs to be done before returning the delegate allocations to ensure valid delegated amounts.\n if (delegateAllocations.length != 0) {\n for (uint256 _i; _i < delegateAllocations.length; ) {\n // Get a reference to the amount to be delegated.\n uint256 _delegatedAmount = delegateAllocations[_i].amount;\n\n // Validate if non-zero.\n if (_delegatedAmount != 0) {\n // Can't delegate more than was paid.\n if (_delegatedAmount > _balanceDiff) revert INVALID_AMOUNT_TO_SEND_DELEGATE();\n\n // Decrement the total amount being added to the balance.\n _balanceDiff = _balanceDiff - _delegatedAmount;\n }\n\n unchecked {\n ++_i;\n }\n }\n }\n\n // If there's no amount being recorded, there's nothing left to do.\n if (_amount.value == 0) return (fundingCycle, 0, delegateAllocations, memo);\n\n // Add the correct balance difference to the token balance of the project.\n if (_balanceDiff != 0)\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] +\n _balanceDiff;\n }\n\n // If there's no weight, token count must be 0 so there's nothing left to do.\n if (_weight == 0) return (fundingCycle, 0, delegateAllocations, memo);\n\n // Get a reference to the number of decimals in the amount. (prevents stack too deep).\n uint256 _decimals = _amount.decimals;\n\n // If the terminal should base its weight on a different currency from the terminal's currency, determine the factor.\n // The weight is always a fixed point mumber with 18 decimals. To ensure this, the ratio should use the same number of decimals as the `_amount`.\n uint256 _weightRatio = _amount.currency == _baseWeightCurrency\n ? 10 ** _decimals\n : prices.priceFor(_amount.currency, _baseWeightCurrency, _decimals);\n\n // Find the number of tokens to mint, as a fixed point number with as many decimals as `weight` has.\n tokenCount = PRBMath.mulDiv(_amount.value, _weight, _weightRatio);\n }\n\n /// @notice Records newly redeemed tokens of a project.\n /// @dev Redeems the project's tokens according to values provided by a configured data source. If no data source is configured, redeems tokens along a redemption bonding curve that is a function of the number of tokens being burned.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount specified in the params is in terms of the msg.senders tokens.\n /// @param _holder The account that is having its tokens redeemed.\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\n /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the data source, if one is provided.\n /// @return fundingCycle The funding cycle during which the redemption was made.\n /// @return reclaimAmount The amount of terminal tokens reclaimed, as a fixed point number with 18 decimals.\n /// @return delegateAllocations The amount to send to delegates instead of sending to the beneficiary.\n /// @return memo A memo that should be passed along to the emitted event.\n function recordRedemptionFor(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n string memory _memo,\n bytes memory _metadata\n )\n external\n override\n nonReentrant\n returns (\n JBFundingCycle memory fundingCycle,\n uint256 reclaimAmount,\n JBRedemptionDelegateAllocation[] memory delegateAllocations,\n string memory memo\n )\n {\n // Get a reference to the project's current funding cycle.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // The current funding cycle must not be paused.\n if (fundingCycle.redeemPaused()) revert FUNDING_CYCLE_REDEEM_PAUSED();\n\n // Scoped section prevents stack too deep. `_reclaimedTokenAmount`, `_currentOverflow`, and `_totalSupply` only used within scope.\n {\n // Get a reference to the reclaimed token amount struct, the current overflow, and the total token supply.\n JBTokenAmount memory _reclaimedTokenAmount;\n uint256 _currentOverflow;\n uint256 _totalSupply;\n\n // Another scoped section prevents stack too deep. `_token`, `_decimals`, and `_currency` only used within scope.\n {\n // Get a reference to the terminal's tokens.\n address _token = IJBSingleTokenPaymentTerminal(msg.sender).token();\n\n // Get a reference to the terminal's decimals.\n uint256 _decimals = IJBSingleTokenPaymentTerminal(msg.sender).decimals();\n\n // Get areference to the terminal's currency.\n uint256 _currency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\n\n // Get the amount of current overflow.\n // Use the local overflow if the funding cycle specifies that it should be used. Otherwise, use the project's total overflow across all of its terminals.\n _currentOverflow = fundingCycle.useTotalOverflowForRedemptions()\n ? _currentTotalOverflowOf(_projectId, _decimals, _currency)\n : _overflowDuring(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _projectId,\n fundingCycle,\n _currency\n );\n\n // Get the number of outstanding tokens the project has.\n _totalSupply = IJBController(directory.controllerOf(_projectId)).totalOutstandingTokensOf(\n _projectId,\n fundingCycle.reservedRate()\n );\n\n // Can't redeem more tokens that is in the supply.\n if (_tokenCount > _totalSupply) revert INSUFFICIENT_TOKENS();\n\n if (_currentOverflow != 0)\n // Calculate reclaim amount using the current overflow amount.\n reclaimAmount = _reclaimableOverflowDuring(\n _projectId,\n fundingCycle,\n _tokenCount,\n _totalSupply,\n _currentOverflow\n );\n\n _reclaimedTokenAmount = JBTokenAmount(_token, reclaimAmount, _decimals, _currency);\n }\n\n // If the funding cycle has configured a data source, use it to derive a claim amount and memo.\n if (fundingCycle.useDataSourceForRedeem() && fundingCycle.dataSource() != address(0)) {\n // Yet another scoped section prevents stack too deep. `_state` only used within scope.\n {\n // Get a reference to the ballot state.\n JBBallotState _state = fundingCycleStore.currentBallotStateOf(_projectId);\n\n // Create the params that'll be sent to the data source.\n JBRedeemParamsData memory _data = JBRedeemParamsData(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _holder,\n _projectId,\n fundingCycle.configuration,\n _tokenCount,\n _totalSupply,\n _currentOverflow,\n _reclaimedTokenAmount,\n fundingCycle.useTotalOverflowForRedemptions(),\n _state == JBBallotState.Active\n ? fundingCycle.ballotRedemptionRate()\n : fundingCycle.redemptionRate(),\n _memo,\n _metadata\n );\n (reclaimAmount, memo, delegateAllocations) = IJBFundingCycleDataSource(\n fundingCycle.dataSource()\n ).redeemParams(_data);\n }\n } else {\n memo = _memo;\n }\n }\n\n // Keep a reference to the amount that should be subtracted from the project's balance.\n uint256 _balanceDiff = reclaimAmount;\n\n if (delegateAllocations.length != 0) {\n // Validate all delegated amounts.\n for (uint256 _i; _i < delegateAllocations.length; ) {\n // Get a reference to the amount to be delegated.\n uint256 _delegatedAmount = delegateAllocations[_i].amount;\n\n // Validate if non-zero.\n if (_delegatedAmount != 0)\n // Increment the total amount being subtracted from the balance.\n _balanceDiff = _balanceDiff + _delegatedAmount;\n\n unchecked {\n ++_i;\n }\n }\n }\n\n // The amount being reclaimed must be within the project's balance.\n if (_balanceDiff > balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId])\n revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n\n // Remove the reclaimed funds from the project's balance.\n if (_balanceDiff != 0) {\n unchecked {\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\n _balanceDiff;\n }\n }\n }\n\n /// @notice Records newly distributed funds for a project.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\n /// @param _projectId The ID of the project that is having funds distributed.\n /// @param _amount The amount to use from the distribution limit, as a fixed point number.\n /// @param _currency The currency of the `_amount`. This must match the project's current funding cycle's currency.\n /// @return fundingCycle The funding cycle during which the distribution was made.\n /// @return distributedAmount The amount of terminal tokens distributed, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordDistributionFor(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency\n )\n external\n override\n nonReentrant\n returns (JBFundingCycle memory fundingCycle, uint256 distributedAmount)\n {\n // Get a reference to the project's current funding cycle.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // The funding cycle must not be configured to have distributions paused.\n if (fundingCycle.distributionsPaused()) revert FUNDING_CYCLE_DISTRIBUTION_PAUSED();\n\n // The new total amount that has been distributed during this funding cycle.\n uint256 _newUsedDistributionLimitOf = usedDistributionLimitOf[\n IJBSingleTokenPaymentTerminal(msg.sender)\n ][_projectId][fundingCycle.number] + _amount;\n\n // Amount must be within what is still distributable.\n (uint256 _distributionLimitOf, uint256 _distributionLimitCurrencyOf) = IJBController(\n directory.controllerOf(_projectId)\n ).distributionLimitOf(\n _projectId,\n fundingCycle.configuration,\n IJBSingleTokenPaymentTerminal(msg.sender),\n IJBSingleTokenPaymentTerminal(msg.sender).token()\n );\n\n // Make sure the new used amount is within the distribution limit.\n if (_newUsedDistributionLimitOf > _distributionLimitOf || _distributionLimitOf == 0)\n revert DISTRIBUTION_AMOUNT_LIMIT_REACHED();\n\n // Make sure the currencies match.\n if (_currency != _distributionLimitCurrencyOf) revert CURRENCY_MISMATCH();\n\n // Get a reference to the terminal's currency.\n uint256 _balanceCurrency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\n\n // Convert the amount to the balance's currency.\n distributedAmount = (_currency == _balanceCurrency)\n ? _amount\n : PRBMath.mulDiv(\n _amount,\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\n prices.priceFor(_currency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\n );\n\n // The amount being distributed must be available.\n if (distributedAmount > balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId])\n revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n\n // Store the new amount.\n usedDistributionLimitOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId][\n fundingCycle.number\n ] = _newUsedDistributionLimitOf;\n\n // Removed the distributed funds from the project's token balance.\n unchecked {\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\n distributedAmount;\n }\n }\n\n /// @notice Records newly used allowance funds of a project.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\n /// @param _projectId The ID of the project to use the allowance of.\n /// @param _amount The amount to use from the allowance, as a fixed point number.\n /// @param _currency The currency of the `_amount`. Must match the currency of the overflow allowance.\n /// @return fundingCycle The funding cycle during which the overflow allowance is being used.\n /// @return usedAmount The amount of terminal tokens used, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordUsedAllowanceOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency\n )\n external\n override\n nonReentrant\n returns (JBFundingCycle memory fundingCycle, uint256 usedAmount)\n {\n // Get a reference to the project's current funding cycle.\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Get a reference to the new used overflow allowance for this funding cycle configuration.\n uint256 _newUsedOverflowAllowanceOf = usedOverflowAllowanceOf[\n IJBSingleTokenPaymentTerminal(msg.sender)\n ][_projectId][fundingCycle.configuration] + _amount;\n\n // There must be sufficient allowance available.\n (uint256 _overflowAllowanceOf, uint256 _overflowAllowanceCurrency) = IJBController(\n directory.controllerOf(_projectId)\n ).overflowAllowanceOf(\n _projectId,\n fundingCycle.configuration,\n IJBSingleTokenPaymentTerminal(msg.sender),\n IJBSingleTokenPaymentTerminal(msg.sender).token()\n );\n\n // Make sure the new used amount is within the allowance.\n if (_newUsedOverflowAllowanceOf > _overflowAllowanceOf || _overflowAllowanceOf == 0)\n revert INADEQUATE_CONTROLLER_ALLOWANCE();\n\n // Make sure the currencies match.\n if (_currency != _overflowAllowanceCurrency) revert CURRENCY_MISMATCH();\n\n // Get a reference to the terminal's currency.\n uint256 _balanceCurrency = IJBSingleTokenPaymentTerminal(msg.sender).currency();\n\n // Convert the amount to this store's terminal's token.\n usedAmount = (_currency == _balanceCurrency)\n ? _amount\n : PRBMath.mulDiv(\n _amount,\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\n prices.priceFor(_currency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\n );\n\n // The amount being distributed must be available in the overflow.\n if (\n usedAmount >\n _overflowDuring(\n IJBSingleTokenPaymentTerminal(msg.sender),\n _projectId,\n fundingCycle,\n _balanceCurrency\n )\n ) revert INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE();\n\n // Store the incremented value.\n usedOverflowAllowanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId][\n fundingCycle.configuration\n ] = _newUsedOverflowAllowanceOf;\n\n // Update the project's balance.\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] -\n usedAmount;\n }\n\n /// @notice Records newly added funds for the project.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal.\n /// @param _projectId The ID of the project to which the funds being added belong.\n /// @param _amount The amount of terminal tokens added, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordAddedBalanceFor(uint256 _projectId, uint256 _amount) external override {\n // Increment the balance.\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] =\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] +\n _amount;\n }\n\n /// @notice Records the migration of funds from this store.\n /// @dev The msg.sender must be an IJBSingleTokenPaymentTerminal. The amount returned is in terms of the msg.senders tokens.\n /// @param _projectId The ID of the project being migrated.\n /// @return balance The project's migrated balance, as a fixed point number with the same amount of decimals as its relative terminal.\n function recordMigration(\n uint256 _projectId\n ) external override nonReentrant returns (uint256 balance) {\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Migration must be allowed.\n if (!_fundingCycle.terminalMigrationAllowed()) revert PAYMENT_TERMINAL_MIGRATION_NOT_ALLOWED();\n\n // Return the current balance.\n balance = balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId];\n\n // Set the balance to 0.\n balanceOf[IJBSingleTokenPaymentTerminal(msg.sender)][_projectId] = 0;\n }\n\n //*********************************************************************//\n // --------------------- private helper functions -------------------- //\n //*********************************************************************//\n\n /// @notice The amount of overflowed tokens from a terminal that can be reclaimed by the specified number of tokens when measured from the specified.\n /// @dev If the project has an active funding cycle reconfiguration ballot, the project's ballot redemption rate is used.\n /// @param _projectId The ID of the project to get the reclaimable overflow amount for.\n /// @param _fundingCycle The funding cycle during which reclaimable overflow is being calculated.\n /// @param _tokenCount The number of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _totalSupply The total supply of tokens to make the calculation with, as a fixed point number with 18 decimals.\n /// @param _overflow The amount of overflow to make the calculation with.\n /// @return The amount of overflowed tokens that can be reclaimed.\n function _reclaimableOverflowDuring(\n uint256 _projectId,\n JBFundingCycle memory _fundingCycle,\n uint256 _tokenCount,\n uint256 _totalSupply,\n uint256 _overflow\n ) private view returns (uint256) {\n // If the amount being redeemed is the total supply, return the rest of the overflow.\n if (_tokenCount == _totalSupply) return _overflow;\n\n // Use the ballot redemption rate if the queued cycle is pending approval according to the previous funding cycle's ballot.\n uint256 _redemptionRate = fundingCycleStore.currentBallotStateOf(_projectId) ==\n JBBallotState.Active\n ? _fundingCycle.ballotRedemptionRate()\n : _fundingCycle.redemptionRate();\n\n // If the redemption rate is 0, nothing is claimable.\n if (_redemptionRate == 0) return 0;\n\n // Get a reference to the linear proportion.\n uint256 _base = PRBMath.mulDiv(_overflow, _tokenCount, _totalSupply);\n\n // These conditions are all part of the same curve. Edge conditions are separated because fewer operation are necessary.\n if (_redemptionRate == JBConstants.MAX_REDEMPTION_RATE) return _base;\n\n return\n PRBMath.mulDiv(\n _base,\n _redemptionRate +\n PRBMath.mulDiv(\n _tokenCount,\n JBConstants.MAX_REDEMPTION_RATE - _redemptionRate,\n _totalSupply\n ),\n JBConstants.MAX_REDEMPTION_RATE\n );\n }\n\n /// @notice Gets the amount that is overflowing when measured from the specified funding cycle.\n /// @dev This amount changes as the value of the balance changes in relation to the currency being used to measure the distribution limit.\n /// @param _terminal The terminal for which the overflow is being calculated.\n /// @param _projectId The ID of the project to get overflow for.\n /// @param _fundingCycle The ID of the funding cycle to base the overflow on.\n /// @param _balanceCurrency The currency that the stored balance is expected to be in terms of.\n /// @return overflow The overflow of funds, as a fixed point number with 18 decimals.\n function _overflowDuring(\n IJBSingleTokenPaymentTerminal _terminal,\n uint256 _projectId,\n JBFundingCycle memory _fundingCycle,\n uint256 _balanceCurrency\n ) private view returns (uint256) {\n // Get the current balance of the project.\n uint256 _balanceOf = balanceOf[_terminal][_projectId];\n\n // If there's no balance, there's no overflow.\n if (_balanceOf == 0) return 0;\n\n // Get a reference to the distribution limit during the funding cycle.\n (uint256 _distributionLimit, uint256 _distributionLimitCurrency) = IJBController(\n directory.controllerOf(_projectId)\n ).distributionLimitOf(_projectId, _fundingCycle.configuration, _terminal, _terminal.token());\n\n // Get a reference to the amount still distributable during the funding cycle.\n uint256 _distributionLimitRemaining = _distributionLimit -\n usedDistributionLimitOf[_terminal][_projectId][_fundingCycle.number];\n\n // Convert the _distributionRemaining to be in terms of the provided currency.\n if (_distributionLimitRemaining != 0 && _distributionLimitCurrency != _balanceCurrency)\n _distributionLimitRemaining = PRBMath.mulDiv(\n _distributionLimitRemaining,\n 10 ** _MAX_FIXED_POINT_FIDELITY, // Use _MAX_FIXED_POINT_FIDELITY to keep as much of the `_amount.value`'s fidelity as possible when converting.\n prices.priceFor(_distributionLimitCurrency, _balanceCurrency, _MAX_FIXED_POINT_FIDELITY)\n );\n\n // Overflow is the balance of this project minus the amount that can still be distributed.\n unchecked {\n return\n _balanceOf > _distributionLimitRemaining ? _balanceOf - _distributionLimitRemaining : 0;\n }\n }\n\n /// @notice Gets the amount that is currently overflowing across all of a project's terminals.\n /// @dev This amount changes as the value of the balances changes in relation to the currency being used to measure the project's distribution limits.\n /// @param _projectId The ID of the project to get the total overflow for.\n /// @param _decimals The number of decimals that the fixed point overflow should include.\n /// @param _currency The currency that the overflow should be in terms of.\n /// @return overflow The total overflow of a project's funds.\n function _currentTotalOverflowOf(\n uint256 _projectId,\n uint256 _decimals,\n uint256 _currency\n ) private view returns (uint256) {\n // Get a reference to the project's terminals.\n IJBPaymentTerminal[] memory _terminals = directory.terminalsOf(_projectId);\n\n // Keep a reference to the ETH overflow across all terminals, as a fixed point number with 18 decimals.\n uint256 _ethOverflow;\n\n // Add the current ETH overflow for each terminal.\n for (uint256 _i; _i < _terminals.length; ) {\n _ethOverflow = _ethOverflow + _terminals[_i].currentEthOverflowOf(_projectId);\n unchecked {\n ++_i;\n }\n }\n\n // Convert the ETH overflow to the specified currency if needed, maintaining a fixed point number with 18 decimals.\n uint256 _totalOverflow18Decimal = _currency == JBCurrencies.ETH\n ? _ethOverflow\n : PRBMath.mulDiv(_ethOverflow, 10 ** 18, prices.priceFor(JBCurrencies.ETH, _currency, 18));\n\n // Adjust the decimals of the fixed point number if needed to match the target decimals.\n return\n (_decimals == 18)\n ? _totalOverflow18Decimal\n : JBFixedPointNumber.adjustDecimals(_totalOverflow18Decimal, 18, _decimals);\n }\n}\n" + }, + "contracts/JBMigrationOperator.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {IJBController} from './interfaces/IJBController.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBMigratable} from './interfaces/IJBMigratable.sol';\nimport {IJBPayoutRedemptionPaymentTerminal} from './interfaces/IJBPayoutRedemptionPaymentTerminal.sol';\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\n\n/// @notice Allows projects to migrate their controller & terminal to 3.1 version\ncontract JBMigrationOperator {\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error UNAUTHORIZED();\n\n //*********************************************************************//\n // --------------- public immutable stored properties ---------------- //\n //*********************************************************************//\n\n /// @notice directory instance which keeps a track of which controller is linked to which project.\n IJBDirectory public immutable directory;\n\n /// @notice The NFT granting ownership to a Juicebox project\n IJBProjects public immutable projects;\n\n //*********************************************************************//\n // ---------------------------- constructor -------------------------- //\n //*********************************************************************//\n\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n constructor(IJBDirectory _directory) {\n directory = _directory;\n projects = IJBProjects(_directory.projects());\n }\n\n //*********************************************************************//\n // --------------------- external transactions ----------------------- //\n //*********************************************************************//\n\n /// @notice Allows project owners to migrate the controller & terminal linked to their project to the latest version.\n /// @param _projectId The project id whose controller & terminal are to be migrated\n /// @param _newController Controller 3.1 address to migrate to.\n /// @param _newJbTerminal Terminal 3.1 address to migrate to.\n /// @param _oldJbTerminal Old terminal address to migrate from.\n function migrate(\n uint256 _projectId,\n IJBMigratable _newController,\n IJBPaymentTerminal _newJbTerminal,\n IJBPayoutRedemptionPaymentTerminal _oldJbTerminal\n ) external {\n // Only allow the project owner to migrate\n if (projects.ownerOf(_projectId) != msg.sender) revert UNAUTHORIZED();\n\n // controller migration\n address _oldController = directory.controllerOf(_projectId);\n\n // assuming the project owner has reconfigured the funding cycle with allowControllerMigration\n IJBController(_oldController).migrate(_projectId, _newController);\n\n // terminal migration\n IJBPaymentTerminal[] memory _newTerminals = new IJBPaymentTerminal[](1);\n _newTerminals[0] = IJBPaymentTerminal(address(_newJbTerminal));\n\n // assuming the project owner has reconfigured the funding cycle with allowTerminalMigration & global.allowSetTerminals\n directory.setTerminalsOf(_projectId, _newTerminals);\n _oldJbTerminal.migrate(_projectId, _newJbTerminal);\n }\n}\n" + }, + "contracts/interfaces/IJBPayoutRedemptionPaymentTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBFee} from './../structs/JBFee.sol';\nimport {IJBAllowanceTerminal} from './IJBAllowanceTerminal.sol';\nimport {IJBDirectory} from './IJBDirectory.sol';\nimport {IJBPayDelegate} from './IJBPayDelegate.sol';\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\nimport {IJBPayoutTerminal} from './IJBPayoutTerminal.sol';\nimport {IJBPrices} from './IJBPrices.sol';\nimport {IJBProjects} from './IJBProjects.sol';\nimport {IJBRedemptionDelegate} from './IJBRedemptionDelegate.sol';\nimport {IJBRedemptionTerminal} from './IJBRedemptionTerminal.sol';\nimport {IJBSplitsStore} from './IJBSplitsStore.sol';\nimport {JBDidPayData} from './../structs/JBDidPayData.sol';\nimport {JBDidRedeemData} from './../structs/JBDidRedeemData.sol';\nimport {JBSplit} from './../structs/JBSplit.sol';\n\ninterface IJBPayoutRedemptionPaymentTerminal is\n IJBPaymentTerminal,\n IJBPayoutTerminal,\n IJBAllowanceTerminal,\n IJBRedemptionTerminal\n{\n event AddToBalance(\n uint256 indexed projectId,\n uint256 amount,\n uint256 refundedFees,\n string memo,\n bytes metadata,\n address caller\n );\n\n event Migrate(\n uint256 indexed projectId,\n IJBPaymentTerminal indexed to,\n uint256 amount,\n address caller\n );\n\n event DistributePayouts(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n address beneficiary,\n uint256 amount,\n uint256 distributedAmount,\n uint256 fee,\n uint256 beneficiaryDistributionAmount,\n string memo,\n address caller\n );\n\n event UseAllowance(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n address beneficiary,\n uint256 amount,\n uint256 distributedAmount,\n uint256 netDistributedamount,\n string memo,\n address caller\n );\n\n event HoldFee(\n uint256 indexed projectId,\n uint256 indexed amount,\n uint256 indexed fee,\n uint256 feeDiscount,\n address beneficiary,\n address caller\n );\n\n event ProcessFee(\n uint256 indexed projectId,\n uint256 indexed amount,\n bool indexed wasHeld,\n address beneficiary,\n address caller\n );\n\n event RefundHeldFees(\n uint256 indexed projectId,\n uint256 indexed amount,\n uint256 indexed refundedFees,\n uint256 leftoverAmount,\n address caller\n );\n\n event Pay(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n address payer,\n address beneficiary,\n uint256 amount,\n uint256 beneficiaryTokenCount,\n string memo,\n bytes metadata,\n address caller\n );\n\n event DelegateDidPay(\n IJBPayDelegate indexed delegate,\n JBDidPayData data,\n uint256 delegatedAmount,\n address caller\n );\n\n event RedeemTokens(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n address holder,\n address beneficiary,\n uint256 tokenCount,\n uint256 reclaimedAmount,\n string memo,\n bytes metadata,\n address caller\n );\n\n event DelegateDidRedeem(\n IJBRedemptionDelegate indexed delegate,\n JBDidRedeemData data,\n uint256 delegatedAmount,\n address caller\n );\n\n event DistributeToPayoutSplit(\n uint256 indexed projectId,\n uint256 indexed domain,\n uint256 indexed group,\n JBSplit split,\n uint256 amount,\n address caller\n );\n\n event SetFee(uint256 fee, address caller);\n\n event SetFeeGauge(address indexed feeGauge, address caller);\n\n event SetFeelessAddress(address indexed addrs, bool indexed flag, address caller);\n\n function projects() external view returns (IJBProjects);\n\n function splitsStore() external view returns (IJBSplitsStore);\n\n function directory() external view returns (IJBDirectory);\n\n function prices() external view returns (IJBPrices);\n\n function store() external view returns (address);\n\n function baseWeightCurrency() external view returns (uint256);\n\n function payoutSplitsGroup() external view returns (uint256);\n\n function heldFeesOf(uint256 projectId) external view returns (JBFee[] memory);\n\n function fee() external view returns (uint256);\n\n function feeGauge() external view returns (address);\n\n function isFeelessAddress(address account) external view returns (bool);\n\n function migrate(uint256 projectId, IJBPaymentTerminal _to) external returns (uint256 balance);\n\n function processFees(uint256 projectId) external;\n\n function setFee(uint256 fee) external;\n\n function setFeeGauge(address feeGauge) external;\n\n function setFeelessAddress(address account, bool flag) external;\n}\n" + }, + "contracts/structs/JBFee.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/// @custom:member amount The total amount the fee was taken from, as a fixed point number with the same number of decimals as the terminal in which this struct was created.\n/// @custom:member fee The percent of the fee, out of MAX_FEE.\n/// @custom:member feeDiscount The discount of the fee.\n/// @custom:member beneficiary The address that will receive the tokens that are minted as a result of the fee payment.\nstruct JBFee {\n uint256 amount;\n uint32 fee;\n uint32 feeDiscount;\n address beneficiary;\n}\n" + }, + "contracts/interfaces/IJBAllowanceTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBAllowanceTerminal {\n function useAllowanceOf(\n uint256 projectId,\n uint256 amount,\n uint256 currency,\n address token,\n uint256 minReturnedTokens,\n address payable beneficiary,\n string calldata memo\n ) external returns (uint256 netDistributedAmount);\n}\n" + }, + "contracts/interfaces/IJBPayoutTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBPayoutTerminal {\n function distributePayoutsOf(\n uint256 projectId,\n uint256 amount,\n uint256 currency,\n address token,\n uint256 minReturnedTokens,\n string calldata memo\n ) external returns (uint256 netLeftoverDistributionAmount);\n}\n" + }, + "contracts/interfaces/IJBRedemptionTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBRedemptionTerminal {\n function redeemTokensOf(\n address holder,\n uint256 projectId,\n uint256 tokenCount,\n address token,\n uint256 minReturnedTokens,\n address payable beneficiary,\n string calldata memo,\n bytes calldata metadata\n ) external returns (uint256 reclaimAmount);\n}\n" + }, + "contracts/JBETHPaymentTerminal3_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Address} from '@openzeppelin/contracts/utils/Address.sol';\nimport {JBPayoutRedemptionPaymentTerminal3_1} from './abstract/JBPayoutRedemptionPaymentTerminal3_1.sol';\nimport {JBSplitsGroups} from './libraries/JBSplitsGroups.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {JBCurrencies} from './libraries/JBCurrencies.sol';\nimport {JBTokens} from './libraries/JBTokens.sol';\n\n/// @notice Manages all inflows and outflows of ETH funds into the protocol ecosystem.\ncontract JBETHPaymentTerminal3_1 is JBPayoutRedemptionPaymentTerminal3_1 {\n //*********************************************************************//\n // -------------------------- internal views ------------------------- //\n //*********************************************************************//\n\n /// @notice Checks the balance of tokens in this contract.\n /// @return The contract's balance, as a fixed point number with the same amount of decimals as this terminal.\n function _balance() internal view override returns (uint256) {\n return address(this).balance;\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _prices A contract that exposes price feeds.\n /// @param _store A contract that stores the terminal's data.\n /// @param _owner The address that will own this contract.\n constructor(\n uint256 _baseWeightCurrency,\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBSplitsStore _splitsStore,\n IJBPrices _prices,\n address _store,\n address _owner\n )\n JBPayoutRedemptionPaymentTerminal3_1(\n JBTokens.ETH,\n 18, // 18 decimals.\n JBCurrencies.ETH,\n _baseWeightCurrency,\n JBSplitsGroups.ETH_PAYOUT,\n _operatorStore,\n _projects,\n _directory,\n _splitsStore,\n _prices,\n _store,\n _owner\n )\n // solhint-disable-next-line no-empty-blocks\n {\n\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Transfers tokens.\n /// @param _from The address from which the transfer should originate.\n /// @param _to The address to which the transfer should go.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _transferFrom(address _from, address payable _to, uint256 _amount) internal override {\n _from; // Prevents unused var compiler and natspec complaints.\n\n Address.sendValue(_to, _amount);\n }\n}\n" + }, + "contracts/abstract/JBPayoutRedemptionPaymentTerminal3_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {ERC165Checker} from '@openzeppelin/contracts/utils/introspection/ERC165Checker.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {IJBAllowanceTerminal3_1} from './../interfaces/IJBAllowanceTerminal3_1.sol';\nimport {IJBController} from './../interfaces/IJBController.sol';\nimport {IJBDirectory} from './../interfaces/IJBDirectory.sol';\nimport {IJBFeeGauge} from './../interfaces/IJBFeeGauge.sol';\nimport {IJBPayoutRedemptionPaymentTerminal3_1} from './../interfaces/IJBPayoutRedemptionPaymentTerminal3_1.sol';\nimport {IJBSplitAllocator} from './../interfaces/IJBSplitAllocator.sol';\nimport {IJBOperatable} from './../interfaces/IJBOperatable.sol';\nimport {IJBOperatorStore} from './../interfaces/IJBOperatorStore.sol';\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\nimport {IJBPayoutTerminal3_1} from './../interfaces/IJBPayoutTerminal3_1.sol';\nimport {IJBPrices} from './../interfaces/IJBPrices.sol';\nimport {IJBProjects} from './../interfaces/IJBProjects.sol';\nimport {IJBRedemptionTerminal} from './../interfaces/IJBRedemptionTerminal.sol';\nimport {IJBSingleTokenPaymentTerminalStore} from './../interfaces/IJBSingleTokenPaymentTerminalStore.sol';\nimport {IJBSplitsStore} from './../interfaces/IJBSplitsStore.sol';\nimport {JBConstants} from './../libraries/JBConstants.sol';\nimport {JBCurrencies} from './../libraries/JBCurrencies.sol';\nimport {JBFixedPointNumber} from './../libraries/JBFixedPointNumber.sol';\nimport {JBFundingCycleMetadataResolver} from './../libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBOperations} from './../libraries/JBOperations.sol';\nimport {JBTokens} from './../libraries/JBTokens.sol';\nimport {JBDidPayData} from './../structs/JBDidPayData.sol';\nimport {JBDidRedeemData} from './../structs/JBDidRedeemData.sol';\nimport {JBFee} from './../structs/JBFee.sol';\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\nimport {JBPayDelegateAllocation} from './../structs/JBPayDelegateAllocation.sol';\nimport {JBTokenAmount} from './../structs/JBTokenAmount.sol';\nimport {JBRedemptionDelegateAllocation} from './../structs/JBRedemptionDelegateAllocation.sol';\nimport {JBSplit} from './../structs/JBSplit.sol';\nimport {JBSplitAllocationData} from './../structs/JBSplitAllocationData.sol';\nimport {JBOperatable} from './JBOperatable.sol';\nimport {JBSingleTokenPaymentTerminal} from './JBSingleTokenPaymentTerminal.sol';\n\n/// @notice Generic terminal managing all inflows and outflows of funds into the protocol ecosystem.\nabstract contract JBPayoutRedemptionPaymentTerminal3_1 is\n JBSingleTokenPaymentTerminal,\n JBOperatable,\n Ownable,\n IJBPayoutRedemptionPaymentTerminal3_1\n{\n // A library that parses the packed funding cycle metadata into a friendlier format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error FEE_TOO_HIGH();\n error INADEQUATE_DISTRIBUTION_AMOUNT();\n error INADEQUATE_RECLAIM_AMOUNT();\n error INADEQUATE_TOKEN_COUNT();\n error NO_MSG_VALUE_ALLOWED();\n error PAY_TO_ZERO_ADDRESS();\n error PROJECT_TERMINAL_MISMATCH();\n error REDEEM_TO_ZERO_ADDRESS();\n error TERMINAL_IN_SPLIT_ZERO_ADDRESS();\n error TERMINAL_TOKENS_INCOMPATIBLE();\n\n //*********************************************************************//\n // ---------------------------- modifiers ---------------------------- //\n //*********************************************************************//\n\n /// @notice A modifier that verifies this terminal is a terminal of provided project ID.\n modifier isTerminalOf(uint256 _projectId) {\n if (!directory.isTerminalOf(_projectId, this)) revert PROJECT_TERMINAL_MISMATCH();\n _;\n }\n\n //*********************************************************************//\n // --------------------- internal stored constants ------------------- //\n //*********************************************************************//\n\n /// @notice Maximum fee that can be set for a funding cycle configuration.\n /// @dev Out of MAX_FEE (50_000_000 / 1_000_000_000).\n uint256 internal constant _FEE_CAP = 50_000_000;\n\n /// @notice The fee beneficiary project ID is 1, as it should be the first project launched during the deployment process.\n uint256 internal constant _FEE_BENEFICIARY_PROJECT_ID = 1;\n\n //*********************************************************************//\n // --------------------- internal stored properties ------------------ //\n //*********************************************************************//\n\n /// @notice Fees that are being held to be processed later.\n /// @custom:param _projectId The ID of the project for which fees are being held.\n mapping(uint256 => JBFee[]) internal _heldFeesOf;\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice Mints ERC-721's that represent project ownership and transfers.\n IJBProjects public immutable override projects;\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n /// @notice The contract that stores splits for each project.\n IJBSplitsStore public immutable override splitsStore;\n\n /// @notice The contract that exposes price feeds.\n IJBPrices public immutable override prices;\n\n /// @notice The contract that stores and manages the terminal's data.\n address public immutable override store;\n\n /// @notice The currency to base token issuance on.\n /// @dev If this differs from `currency`, there must be a price feed available to convert `currency` to `baseWeightCurrency`.\n uint256 public immutable override baseWeightCurrency;\n\n /// @notice The group that payout splits coming from this terminal are identified by.\n uint256 public immutable override payoutSplitsGroup;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The platform fee percent.\n /// @dev Out of MAX_FEE (25_000_000 / 1_000_000_000)\n uint256 public override fee = 25_000_000; // 2.5%\n\n /// @notice The data source that returns a discount to apply to a project's fee.\n address public override feeGauge;\n\n /// @notice Addresses that can be paid towards from this terminal without incurring a fee.\n /// @dev Only addresses that are considered to be contained within the ecosystem can be feeless. Funds sent outside the ecosystem may incur fees despite being stored as feeless.\n /// @custom:param _address The address that can be paid toward.\n mapping(address => bool) public override isFeelessAddress;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Gets the current overflowed amount in this terminal for a specified project, in terms of ETH.\n /// @dev The current overflow is represented as a fixed point number with 18 decimals.\n /// @param _projectId The ID of the project to get overflow for.\n /// @return The current amount of ETH overflow that project has in this terminal, as a fixed point number with 18 decimals.\n function currentEthOverflowOf(\n uint256 _projectId\n ) external view virtual override returns (uint256) {\n // Get this terminal's current overflow.\n uint256 _overflow = IJBSingleTokenPaymentTerminalStore(store).currentOverflowOf(\n this,\n _projectId\n );\n\n // Adjust the decimals of the fixed point number if needed to have 18 decimals.\n uint256 _adjustedOverflow = (decimals == 18)\n ? _overflow\n : JBFixedPointNumber.adjustDecimals(_overflow, decimals, 18);\n\n // Return the amount converted to ETH.\n return\n (currency == JBCurrencies.ETH)\n ? _adjustedOverflow\n : PRBMath.mulDiv(\n _adjustedOverflow,\n 10 ** decimals,\n prices.priceFor(currency, JBCurrencies.ETH, decimals)\n );\n }\n\n /// @notice The fees that are currently being held to be processed later for each project.\n /// @param _projectId The ID of the project for which fees are being held.\n /// @return An array of fees that are being held.\n function heldFeesOf(uint256 _projectId) external view override returns (JBFee[] memory) {\n return _heldFeesOf[_projectId];\n }\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if the provided interface ID is supported.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(JBSingleTokenPaymentTerminal, IERC165) returns (bool) {\n return\n _interfaceId == type(IJBPayoutRedemptionPaymentTerminal3_1).interfaceId ||\n _interfaceId == type(IJBPayoutTerminal3_1).interfaceId ||\n _interfaceId == type(IJBAllowanceTerminal3_1).interfaceId ||\n _interfaceId == type(IJBRedemptionTerminal).interfaceId ||\n _interfaceId == type(IJBOperatable).interfaceId ||\n super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // -------------------------- internal views ------------------------- //\n //*********************************************************************//\n\n /// @notice Checks the balance of tokens in this contract.\n /// @return The contract's balance.\n function _balance() internal view virtual returns (uint256);\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _decimals The number of decimals the token fixed point amounts are expected to have.\n /// @param _currency The currency that this terminal's token adheres to for price feeds.\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _payoutSplitsGroup The group that denotes payout splits from this terminal in the splits store.\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _prices A contract that exposes price feeds.\n /// @param _store A contract that stores the terminal's data.\n /// @param _owner The address that will own this contract.\n constructor(\n // payable constructor save the gas used to check msg.value==0\n address _token,\n uint256 _decimals,\n uint256 _currency,\n uint256 _baseWeightCurrency,\n uint256 _payoutSplitsGroup,\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBSplitsStore _splitsStore,\n IJBPrices _prices,\n address _store,\n address _owner\n )\n payable\n JBSingleTokenPaymentTerminal(_token, _decimals, _currency)\n JBOperatable(_operatorStore)\n {\n baseWeightCurrency = _baseWeightCurrency;\n payoutSplitsGroup = _payoutSplitsGroup;\n projects = _projects;\n directory = _directory;\n splitsStore = _splitsStore;\n prices = _prices;\n store = _store;\n\n transferOwnership(_owner);\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Contribute tokens to a project.\n /// @param _projectId The ID of the project being paid.\n /// @param _amount The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place.\n /// @param _token The token being paid. This terminal ignores this property since it only manages one token.\n /// @param _beneficiary The address to mint tokens for and pass along to the funding cycle's data source and delegate.\n /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\n /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals.\n function pay(\n uint256 _projectId,\n uint256 _amount,\n address _token,\n address _beneficiary,\n uint256 _minReturnedTokens,\n bool _preferClaimedTokens,\n string calldata _memo,\n bytes calldata _metadata\n ) external payable virtual override isTerminalOf(_projectId) returns (uint256) {\n _token; // Prevents unused var compiler and natspec complaints.\n\n // ETH shouldn't be sent if this terminal's token isn't ETH.\n if (token != JBTokens.ETH) {\n if (msg.value > 0) revert NO_MSG_VALUE_ALLOWED();\n\n // Get a reference to the balance before receiving tokens.\n uint256 _balanceBefore = _balance();\n\n // Transfer tokens to this terminal from the msg sender.\n _transferFrom(msg.sender, payable(address(this)), _amount);\n\n // The amount should reflect the change in balance.\n _amount = _balance() - _balanceBefore;\n }\n // If this terminal's token is ETH, override _amount with msg.value.\n else _amount = msg.value;\n\n return\n _pay(\n _amount,\n msg.sender,\n _projectId,\n _beneficiary,\n _minReturnedTokens,\n _preferClaimedTokens,\n _memo,\n _metadata\n );\n }\n\n /// @notice Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source.\n /// @dev Only a token holder or a designated operator can redeem its tokens.\n /// @param _holder The account to redeem tokens for.\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\n /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals.\n /// @param _token The token being reclaimed. This terminal ignores this property since it only manages one token.\n /// @param _minReturnedTokens The minimum amount of terminal tokens expected in return, as a fixed point number with the same amount of decimals as the terminal.\n /// @param _beneficiary The address to send the terminal tokens to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return reclaimAmount The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals.\n function redeemTokensOf(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n address _token,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo,\n bytes memory _metadata\n )\n external\n virtual\n override\n requirePermission(_holder, _projectId, JBOperations.REDEEM)\n returns (uint256 reclaimAmount)\n {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return\n _redeemTokensOf(\n _holder,\n _projectId,\n _tokenCount,\n _minReturnedTokens,\n _beneficiary,\n _memo,\n _metadata\n );\n }\n\n /// @notice Distributes payouts for a project with the distribution limit of its current funding cycle.\n /// @dev Payouts are sent to the preprogrammed splits. Any leftover is sent to the project's owner.\n /// @dev 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.\n /// @dev All funds distributed outside of this contract or any feeless terminals incure the protocol fee.\n /// @param _projectId The ID of the project having its payouts distributed.\n /// @param _amount The amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency.\n /// @param _token The token being distributed. This terminal ignores this property since it only manages one token.\n /// @param _minReturnedTokens 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.\n /// @param _metadata Bytes to send along to the emitted event, if provided.\n /// @return netLeftoverDistributionAmount The amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal.\n function distributePayoutsOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n address _token,\n uint256 _minReturnedTokens,\n bytes calldata _metadata\n ) external virtual override returns (uint256 netLeftoverDistributionAmount) {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return _distributePayoutsOf(_projectId, _amount, _currency, _minReturnedTokens, _metadata);\n }\n\n /// @notice Only a project's owner or a designated operator can use its allowance.\n /// @dev Incurs the protocol fee.\n /// @param _projectId The ID of the project to use the allowance of.\n /// @param _amount The amount of terminal tokens to use from this project's current allowance, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's overflow allowance currency.\n /// @param _token The token being distributed. This terminal ignores this property since it only manages one token.\n /// @param _minReturnedTokens The minimum number of tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with 18 decimals.\n /// @param _beneficiary The address to send the funds to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the emitted event, if provided.\n /// @return netDistributedAmount The amount of tokens that was distributed to the beneficiary, as a fixed point number with the same amount of decimals as the terminal.\n function useAllowanceOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n address _token,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo,\n bytes calldata _metadata\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.USE_ALLOWANCE)\n returns (uint256 netDistributedAmount)\n {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return\n _useAllowanceOf(\n _projectId,\n _amount,\n _currency,\n _minReturnedTokens,\n _beneficiary,\n _memo,\n _metadata\n );\n }\n\n /// @notice Allows a project owner to migrate its funds and operations to a new terminal that accepts the same token type.\n /// @dev Only a project's owner or a designated operator can migrate it.\n /// @param _projectId The ID of the project being migrated.\n /// @param _to The terminal contract that will gain the project's funds.\n /// @return balance The amount of funds that were migrated, as a fixed point number with the same amount of decimals as this terminal.\n function migrate(\n uint256 _projectId,\n IJBPaymentTerminal _to\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.MIGRATE_TERMINAL)\n returns (uint256 balance)\n {\n // The terminal being migrated to must accept the same token as this terminal.\n if (!_to.acceptsToken(token, _projectId)) revert TERMINAL_TOKENS_INCOMPATIBLE();\n\n // Record the migration in the store.\n balance = IJBSingleTokenPaymentTerminalStore(store).recordMigration(_projectId);\n\n // Transfer the balance if needed.\n if (balance > 0) {\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_to), balance);\n\n // If this terminal's token is ETH, send it in msg.value.\n uint256 _payableValue = token == JBTokens.ETH ? balance : 0;\n\n // Withdraw the balance to transfer to the new terminal;\n _to.addToBalanceOf{value: _payableValue}(_projectId, balance, token, '', bytes(''));\n }\n\n emit Migrate(_projectId, _to, balance, msg.sender);\n }\n\n /// @notice Receives funds belonging to the specified project.\n /// @param _projectId The ID of the project to which the funds received belong.\n /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\n /// @param _token The token being paid. This terminal ignores this property since it only manages one currency.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the emitted event.\n function addToBalanceOf(\n uint256 _projectId,\n uint256 _amount,\n address _token,\n string calldata _memo,\n bytes calldata _metadata\n ) external payable virtual override isTerminalOf(_projectId) {\n // Do not refund held fees by default.\n addToBalanceOf(_projectId, _amount, _token, false, _memo, _metadata);\n }\n\n /// @notice Process any fees that are being held for the project.\n /// @dev Only a project owner, an operator, or the contract's owner can process held fees.\n /// @param _projectId The ID of the project whos held fees should be processed.\n function processFees(\n uint256 _projectId\n )\n external\n virtual\n override\n requirePermissionAllowingOverride(\n projects.ownerOf(_projectId),\n _projectId,\n JBOperations.PROCESS_FEES,\n msg.sender == owner()\n )\n {\n // Get a reference to the project's held fees.\n JBFee[] memory _heldFees = _heldFeesOf[_projectId];\n\n // Delete the held fees.\n delete _heldFeesOf[_projectId];\n\n // Push array length in stack\n uint256 _heldFeeLength = _heldFees.length;\n\n // Process each fee.\n for (uint256 _i; _i < _heldFeeLength; ) {\n // Get the fee amount.\n uint256 _amount = _feeAmount(\n _heldFees[_i].amount,\n _heldFees[_i].fee,\n _heldFees[_i].feeDiscount\n );\n\n // Process the fee.\n _processFee(_amount, _heldFees[_i].beneficiary, _projectId);\n\n emit ProcessFee(_projectId, _amount, true, _heldFees[_i].beneficiary, msg.sender);\n\n unchecked {\n ++_i;\n }\n }\n }\n\n /// @notice Allows the fee to be updated.\n /// @dev Only the owner of this contract can change the fee.\n /// @param _fee The new fee, out of MAX_FEE.\n function setFee(uint256 _fee) external virtual override onlyOwner {\n // The provided fee must be within the max.\n if (_fee > _FEE_CAP) revert FEE_TOO_HIGH();\n\n // Store the new fee.\n fee = _fee;\n\n emit SetFee(_fee, msg.sender);\n }\n\n /// @notice Allows the fee gauge to be updated.\n /// @dev Only the owner of this contract can change the fee gauge.\n /// @param _feeGauge The new fee gauge.\n function setFeeGauge(address _feeGauge) external virtual override onlyOwner {\n // Store the new fee gauge.\n feeGauge = _feeGauge;\n\n emit SetFeeGauge(_feeGauge, msg.sender);\n }\n\n /// @notice Sets whether projects operating on this terminal can pay towards the specified address without incurring a fee.\n /// @param _address The address that can be paid towards while still bypassing fees.\n /// @param _flag A flag indicating whether the terminal should be feeless or not.\n function setFeelessAddress(address _address, bool _flag) external virtual override onlyOwner {\n // Set the flag value.\n isFeelessAddress[_address] = _flag;\n\n emit SetFeelessAddress(_address, _flag, msg.sender);\n }\n\n //*********************************************************************//\n // ----------------------- public transactions ----------------------- //\n //*********************************************************************//\n\n /// @notice Receives funds belonging to the specified project.\n /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\n /// @param _token The token being paid. This terminal ignores this property since it only manages one currency.\n /// @param _shouldRefundHeldFees A flag indicating if held fees should be refunded based on the amount being added.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the emitted event.\n function addToBalanceOf(\n uint256 _projectId,\n uint256 _amount,\n address _token,\n bool _shouldRefundHeldFees,\n string calldata _memo,\n bytes calldata _metadata\n ) public payable virtual override isTerminalOf(_projectId) {\n _token; // Prevents unused var compiler and natspec complaints.\n\n // If this terminal's token isn't ETH, make sure no msg.value was sent, then transfer the tokens in from msg.sender.\n if (token != JBTokens.ETH) {\n // Amount must be greater than 0.\n if (msg.value > 0) revert NO_MSG_VALUE_ALLOWED();\n\n // Get a reference to the balance before receiving tokens.\n uint256 _balanceBefore = _balance();\n\n // Transfer tokens to this terminal from the msg sender.\n _transferFrom(msg.sender, payable(address(this)), _amount);\n\n // The amount should reflect the change in balance.\n _amount = _balance() - _balanceBefore;\n }\n // If the terminal's token is ETH, override `_amount` with msg.value.\n else _amount = msg.value;\n\n // Add to balance.\n _addToBalanceOf(_projectId, _amount, _shouldRefundHeldFees, _memo, _metadata);\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Transfers tokens.\n /// @param _from The address from which the transfer should originate.\n /// @param _to The address to which the transfer should go.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _transferFrom(address _from, address payable _to, uint256 _amount) internal virtual {\n _from; // Prevents unused var compiler and natspec complaints.\n _to; // Prevents unused var compiler and natspec complaints.\n _amount; // Prevents unused var compiler and natspec complaints.\n }\n\n /// @notice Logic to be triggered before transferring tokens from this terminal.\n /// @param _to The address to which the transfer is going.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _beforeTransferTo(address _to, uint256 _amount) internal virtual {\n _to; // Prevents unused var compiler and natspec complaints.\n _amount; // Prevents unused var compiler and natspec complaints.\n }\n\n /// @notice Logic to be triggered if a transfer should be undone\n /// @param _to The address to which the transfer went.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _cancelTransferTo(address _to, uint256 _amount) internal virtual {\n _to; // Prevents unused var compiler and natspec complaints.\n _amount; // Prevents unused var compiler and natspec complaints.\n }\n\n /// @notice Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source.\n /// @dev Only a token holder or a designated operator can redeem its tokens.\n /// @param _holder The account to redeem tokens for.\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\n /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals.\n /// @param _minReturnedTokens The minimum amount of terminal tokens expected in return, as a fixed point number with the same amount of decimals as the terminal.\n /// @param _beneficiary The address to send the terminal tokens to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return reclaimAmount The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals.\n function _redeemTokensOf(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo,\n bytes memory _metadata\n ) internal returns (uint256 reclaimAmount) {\n // Can't send reclaimed funds to the zero address.\n if (_beneficiary == address(0)) revert REDEEM_TO_ZERO_ADDRESS();\n\n // Define variables that will be needed outside the scoped section below.\n // Keep a reference to the funding cycle during which the redemption is being made.\n JBFundingCycle memory _fundingCycle;\n\n // Scoped section prevents stack too deep. `_delegateAllocations` only used within scope.\n {\n JBRedemptionDelegateAllocation[] memory _delegateAllocations;\n\n // Record the redemption.\n (\n _fundingCycle,\n reclaimAmount,\n _delegateAllocations,\n _memo\n ) = IJBSingleTokenPaymentTerminalStore(store).recordRedemptionFor(\n _holder,\n _projectId,\n _tokenCount,\n _memo,\n _metadata\n );\n\n // The amount being reclaimed must be at least as much as was expected.\n if (reclaimAmount < _minReturnedTokens) revert INADEQUATE_RECLAIM_AMOUNT();\n\n // Burn the project tokens.\n if (_tokenCount > 0)\n IJBController(directory.controllerOf(_projectId)).burnTokensOf(\n _holder,\n _projectId,\n _tokenCount,\n '',\n false\n );\n\n // If delegate allocations were specified by the data source, fulfill them.\n if (_delegateAllocations.length != 0) {\n // Keep a reference to the token amount being forwarded to the delegate.\n JBTokenAmount memory _forwardedAmount = JBTokenAmount(token, 0, decimals, currency);\n\n JBDidRedeemData memory _data = JBDidRedeemData(\n _holder,\n _projectId,\n _fundingCycle.configuration,\n _tokenCount,\n JBTokenAmount(token, reclaimAmount, decimals, currency),\n _forwardedAmount,\n _beneficiary,\n _memo,\n _metadata\n );\n\n uint256 _numDelegates = _delegateAllocations.length;\n\n for (uint256 _i; _i < _numDelegates; ) {\n // Get a reference to the delegate being iterated on.\n JBRedemptionDelegateAllocation memory _delegateAllocation = _delegateAllocations[_i];\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_delegateAllocation.delegate), _delegateAllocation.amount);\n\n // Keep track of the msg.value to use in the delegate call\n uint256 _payableValue;\n\n // If this terminal's token is ETH, send it in msg.value.\n if (token == JBTokens.ETH) _payableValue = _delegateAllocation.amount;\n\n // Pass the correct token forwardedAmount to the delegate\n _data.forwardedAmount.value = _delegateAllocation.amount;\n\n _delegateAllocation.delegate.didRedeem{value: _payableValue}(_data);\n\n emit DelegateDidRedeem(\n _delegateAllocation.delegate,\n _data,\n _delegateAllocation.amount,\n msg.sender\n );\n unchecked {\n ++_i;\n }\n }\n }\n }\n\n // Send the reclaimed funds to the beneficiary.\n if (reclaimAmount > 0) _transferFrom(address(this), _beneficiary, reclaimAmount);\n\n emit RedeemTokens(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _holder,\n _beneficiary,\n _tokenCount,\n reclaimAmount,\n _memo,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Distributes payouts for a project with the distribution limit of its current funding cycle.\n /// @dev Payouts are sent to the preprogrammed splits. Any leftover is sent to the project's owner.\n /// @dev 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.\n /// @dev All funds distributed outside of this contract or any feeless terminals incure the protocol fee.\n /// @param _projectId The ID of the project having its payouts distributed.\n /// @param _amount The amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency.\n /// @param _minReturnedTokens 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.\n /// @param _metadata Bytes to send along to the emitted event, if provided.\n /// @return netLeftoverDistributionAmount The amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal.\n function _distributePayoutsOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n uint256 _minReturnedTokens,\n bytes calldata _metadata\n ) internal returns (uint256 netLeftoverDistributionAmount) {\n // Record the distribution.\n (\n JBFundingCycle memory _fundingCycle,\n uint256 _distributedAmount\n ) = IJBSingleTokenPaymentTerminalStore(store).recordDistributionFor(\n _projectId,\n _amount,\n _currency\n );\n\n // The amount being distributed must be at least as much as was expected.\n if (_distributedAmount < _minReturnedTokens) revert INADEQUATE_DISTRIBUTION_AMOUNT();\n\n // Get a reference to the project owner, which will receive tokens from paying the platform fee\n // and receive any extra distributable funds not allocated to payout splits.\n address payable _projectOwner = payable(projects.ownerOf(_projectId));\n\n // Define variables that will be needed outside the scoped section below.\n // Keep a reference to the fee amount that was paid.\n uint256 _fee;\n\n // Scoped section prevents stack too deep. `_feeDiscount`, `_feeEligibleDistributionAmount`, and `_leftoverDistributionAmount` only used within scope.\n {\n // Get the amount of discount that should be applied to any fees taken.\n // If the fee is zero, set the discount to 100% for convenience.\n uint256 _feeDiscount = fee == 0\n ? JBConstants.MAX_FEE_DISCOUNT\n : _currentFeeDiscount(_projectId);\n\n // The amount distributed that is eligible for incurring fees.\n uint256 _feeEligibleDistributionAmount;\n\n // The amount leftover after distributing to the splits.\n uint256 _leftoverDistributionAmount;\n\n // Payout to splits and get a reference to the leftover transfer amount after all splits have been paid.\n // Also get a reference to the amount that was distributed to splits from which fees should be taken.\n (_leftoverDistributionAmount, _feeEligibleDistributionAmount) = _distributeToPayoutSplitsOf(\n _projectId,\n _fundingCycle.configuration,\n payoutSplitsGroup,\n _distributedAmount,\n _feeDiscount\n );\n\n if (_feeDiscount != JBConstants.MAX_FEE_DISCOUNT) {\n // Leftover distribution amount is also eligible for a fee since the funds are going out of the ecosystem to _beneficiary.\n unchecked {\n _feeEligibleDistributionAmount += _leftoverDistributionAmount;\n }\n }\n\n // Take the fee.\n _fee = _feeEligibleDistributionAmount != 0\n ? _takeFeeFrom(\n _projectId,\n _fundingCycle,\n _feeEligibleDistributionAmount,\n _projectOwner,\n _feeDiscount\n )\n : 0;\n\n // Transfer any remaining balance to the project owner and update returned leftover accordingly.\n if (_leftoverDistributionAmount != 0) {\n // Subtract the fee from the net leftover amount.\n netLeftoverDistributionAmount =\n _leftoverDistributionAmount -\n _feeAmount(_leftoverDistributionAmount, fee, _feeDiscount);\n\n // Transfer the amount to the project owner.\n _transferFrom(address(this), _projectOwner, netLeftoverDistributionAmount);\n }\n }\n\n emit DistributePayouts(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _projectOwner,\n _amount,\n _distributedAmount,\n _fee,\n netLeftoverDistributionAmount,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Allows a project to send funds from its overflow up to the preconfigured allowance.\n /// @dev Only a project's owner or a designated operator can use its allowance.\n /// @dev Incurs the protocol fee.\n /// @param _projectId The ID of the project to use the allowance of.\n /// @param _amount The amount of terminal tokens to use from this project's current allowance, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's overflow allowance currency.\n /// @param _minReturnedTokens The minimum number of tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with 18 decimals.\n /// @param _beneficiary The address to send the funds to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the emitted event, if provided.\n /// @return netDistributedAmount The amount of tokens that was distributed to the beneficiary, as a fixed point number with the same amount of decimals as the terminal.\n function _useAllowanceOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo,\n bytes calldata _metadata\n ) internal returns (uint256 netDistributedAmount) {\n // Record the use of the allowance.\n (\n JBFundingCycle memory _fundingCycle,\n uint256 _distributedAmount\n ) = IJBSingleTokenPaymentTerminalStore(store).recordUsedAllowanceOf(\n _projectId,\n _amount,\n _currency\n );\n\n // The amount being withdrawn must be at least as much as was expected.\n if (_distributedAmount < _minReturnedTokens) revert INADEQUATE_DISTRIBUTION_AMOUNT();\n\n // Scoped section prevents stack too deep. `_fee`, `_projectOwner`, `_feeDiscount`, and `_netAmount` only used within scope.\n {\n // Keep a reference to the fee amount that was paid.\n uint256 _fee;\n\n // Get a reference to the project owner, which will receive tokens from paying the platform fee.\n address _projectOwner = projects.ownerOf(_projectId);\n\n // Get the amount of discount that should be applied to any fees taken.\n // 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.\n uint256 _feeDiscount = fee == 0 || isFeelessAddress[msg.sender]\n ? JBConstants.MAX_FEE_DISCOUNT\n : _currentFeeDiscount(_projectId);\n\n // Take a fee from the `_distributedAmount`, if needed.\n _fee = _feeDiscount == JBConstants.MAX_FEE_DISCOUNT\n ? 0\n : _takeFeeFrom(_projectId, _fundingCycle, _distributedAmount, _projectOwner, _feeDiscount);\n\n unchecked {\n // The net amount is the withdrawn amount without the fee.\n netDistributedAmount = _distributedAmount - _fee;\n }\n\n // Transfer any remaining balance to the beneficiary.\n if (netDistributedAmount > 0)\n _transferFrom(address(this), _beneficiary, netDistributedAmount);\n }\n\n emit UseAllowance(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _beneficiary,\n _amount,\n _distributedAmount,\n netDistributedAmount,\n _memo,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Pays out splits for a project's funding cycle configuration.\n /// @param _projectId The ID of the project for which payout splits are being distributed.\n /// @param _domain The domain of the splits to distribute the payout between.\n /// @param _group The group of the splits to distribute the payout between.\n /// @param _amount The total amount being distributed, as a fixed point number with the same number of decimals as this terminal.\n /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE.\n /// @return leftoverAmount If the leftover amount if the splits don't add up to 100%.\n /// @return feeEligibleDistributionAmount The total amount of distributions that are eligible to have fees taken from.\n function _distributeToPayoutSplitsOf(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group,\n uint256 _amount,\n uint256 _feeDiscount\n ) internal returns (uint256 leftoverAmount, uint256 feeEligibleDistributionAmount) {\n // Set the leftover amount to the initial amount.\n leftoverAmount = _amount;\n // The total percentage available to split\n uint256 leftoverPercentage = JBConstants.SPLITS_TOTAL_PERCENT;\n\n // Get a reference to the project's payout splits.\n JBSplit[] memory _splits = splitsStore.splitsOf(_projectId, _domain, _group);\n\n // Transfer between all splits.\n for (uint256 _i; _i < _splits.length; ) {\n // Get a reference to the split being iterated on.\n JBSplit memory _split = _splits[_i];\n\n // The amount to send towards the split.\n uint256 _payoutAmount = _split.percent == leftoverPercentage\n ? leftoverAmount\n : PRBMath.mulDiv(_amount, _split.percent, JBConstants.SPLITS_TOTAL_PERCENT);\n\n // Decrement the leftover percentage.\n leftoverPercentage -= _split.percent;\n\n // The payout amount substracting any applicable incurred fees.\n uint256 _netPayoutAmount = _distributeToPayoutSplit(\n _split,\n _projectId,\n _group,\n _payoutAmount,\n _feeDiscount\n );\n\n // If the split allocator is set as feeless, this distribution is not eligible for a fee.\n if (_netPayoutAmount != 0 && _netPayoutAmount != _payoutAmount)\n feeEligibleDistributionAmount += _payoutAmount;\n\n if (_payoutAmount > 0) {\n // Subtract from the amount to be sent to the beneficiary.\n unchecked {\n leftoverAmount = leftoverAmount - _payoutAmount;\n }\n }\n\n emit DistributeToPayoutSplit(\n _projectId,\n _domain,\n _group,\n _split,\n _payoutAmount,\n _netPayoutAmount,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n\n /// @notice Pays out a split for a project's funding cycle configuration.\n /// @param _split The split to distribute payouts to.\n /// @param _amount The total amount being distributed to the split, as a fixed point number with the same number of decimals as this terminal.\n /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE.\n /// @return netPayoutAmount The amount sent to the split after subtracting fees.\n function _distributeToPayoutSplit(\n JBSplit memory _split,\n uint256 _projectId,\n uint256 _group,\n uint256 _amount,\n uint256 _feeDiscount\n ) internal returns (uint256 netPayoutAmount) {\n // If there's an allocator set, transfer to its `allocate` function.\n if (_split.allocator != IJBSplitAllocator(address(0))) {\n // If the split allocator is set as feeless, this distribution is not eligible for a fee.\n if (\n _feeDiscount == JBConstants.MAX_FEE_DISCOUNT || isFeelessAddress[address(_split.allocator)]\n )\n netPayoutAmount = _amount;\n // This distribution is eligible for a fee since the funds are leaving this contract and the allocator isn't listed as feeless.\n else {\n unchecked {\n netPayoutAmount = _amount - _feeAmount(_amount, fee, _feeDiscount);\n }\n }\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_split.allocator), netPayoutAmount);\n\n // Create the data to send to the allocator.\n JBSplitAllocationData memory _data = JBSplitAllocationData(\n token,\n netPayoutAmount,\n decimals,\n _projectId,\n _group,\n _split\n );\n\n // Trigger the allocator's `allocate` function.\n uint256 _error;\n bytes memory _reason;\n\n if (\n ERC165Checker.supportsInterface(\n address(_split.allocator),\n type(IJBSplitAllocator).interfaceId\n )\n )\n // If this terminal's token is ETH, send it in msg.value.\n try\n _split.allocator.allocate{value: token == JBTokens.ETH ? netPayoutAmount : 0}(_data)\n {} catch (bytes memory reason) {\n _reason = reason;\n _error = 1;\n }\n else _error = 2;\n\n if (_error != 0) {\n // Trigger any inhereted post-transfer cancelation logic.\n _cancelTransferTo(address(_split.allocator), netPayoutAmount);\n\n // Set the net payout amount to 0 to signal the reversion.\n netPayoutAmount = 0;\n\n // Add undistributed amount back to project's balance.\n IJBSingleTokenPaymentTerminalStore(store).recordAddedBalanceFor(_projectId, _amount);\n\n emit PayoutReverted(\n _projectId,\n _split,\n _amount,\n _error == 1 ? _reason : abi.encode('IERC165 fail'),\n msg.sender\n );\n }\n\n // Otherwise, if a project is specified, make a payment to it.\n } else if (_split.projectId != 0) {\n // Get a reference to the Juicebox terminal being used.\n IJBPaymentTerminal _terminal = directory.primaryTerminalOf(_split.projectId, token);\n\n // The project must have a terminal to send funds to.\n if (_terminal == IJBPaymentTerminal(address(0))) revert TERMINAL_IN_SPLIT_ZERO_ADDRESS();\n\n // If the terminal is set as feeless, this distribution is not eligible for a fee.\n if (\n _terminal == this ||\n _feeDiscount == JBConstants.MAX_FEE_DISCOUNT ||\n isFeelessAddress[address(_terminal)]\n )\n netPayoutAmount = _amount;\n // This distribution is eligible for a fee since the funds are leaving this contract and the terminal isn't listed as feeless.\n else {\n unchecked {\n netPayoutAmount = _amount - _feeAmount(_amount, fee, _feeDiscount);\n }\n }\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_terminal), netPayoutAmount);\n\n // Send the projectId in the metadata.\n bytes memory _projectMetadata = new bytes(32);\n _projectMetadata = bytes(abi.encodePacked(_projectId));\n\n // Add to balance if prefered.\n if (_split.preferAddToBalance)\n try\n _terminal.addToBalanceOf{value: token == JBTokens.ETH ? netPayoutAmount : 0}(\n _split.projectId,\n netPayoutAmount,\n token,\n '',\n _projectMetadata\n )\n {} catch (bytes memory reason) {\n // Trigger any inhereted post-transfer cancelation logic.\n _cancelTransferTo(address(_terminal), netPayoutAmount);\n\n // Set the net payout amount to 0 to signal the reversion.\n netPayoutAmount = 0;\n\n // Add undistributed amount back to project's balance.\n IJBSingleTokenPaymentTerminalStore(store).recordAddedBalanceFor(_projectId, _amount);\n\n emit PayoutReverted(_projectId, _split, _amount, reason, msg.sender);\n }\n else\n try\n _terminal.pay{value: token == JBTokens.ETH ? netPayoutAmount : 0}(\n _split.projectId,\n netPayoutAmount,\n token,\n _split.beneficiary != address(0) ? _split.beneficiary : msg.sender,\n 0,\n _split.preferClaimed,\n '',\n _projectMetadata\n )\n {} catch (bytes memory reason) {\n // Trigger any inhereted post-transfer cancelation logic.\n _cancelTransferTo(address(_terminal), netPayoutAmount);\n\n // Set the net payout amount to 0 to signal the reversion.\n netPayoutAmount = 0;\n\n // Add undistributed amount back to project's balance.\n IJBSingleTokenPaymentTerminalStore(store).recordAddedBalanceFor(_projectId, _amount);\n\n emit PayoutReverted(_projectId, _split, _amount, reason, msg.sender);\n }\n } else {\n // Keep a reference to the beneficiary.\n address payable _beneficiary = _split.beneficiary != address(0)\n ? _split.beneficiary\n : payable(msg.sender);\n\n // If there's a full discount, this distribution is not eligible for a fee.\n // Don't enforce feeless address for the beneficiary since the funds are leaving the ecosystem.\n if (_feeDiscount == JBConstants.MAX_FEE_DISCOUNT)\n netPayoutAmount = _amount;\n // This distribution is eligible for a fee since the funds are leaving this contract and the beneficiary isn't listed as feeless.\n else {\n unchecked {\n netPayoutAmount = _amount - _feeAmount(_amount, fee, _feeDiscount);\n }\n }\n\n // If there's a beneficiary, send the funds directly to the beneficiary. Otherwise send to the msg.sender.\n _transferFrom(address(this), _beneficiary, netPayoutAmount);\n }\n }\n\n /// @notice Takes a fee into the platform's project, which has an id of _FEE_BENEFICIARY_PROJECT_ID.\n /// @param _projectId The ID of the project having fees taken from.\n /// @param _fundingCycle The funding cycle during which the fee is being taken.\n /// @param _amount The amount of the fee to take, as a floating point number with 18 decimals.\n /// @param _beneficiary The address to mint the platforms tokens for.\n /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE.\n /// @return feeAmount The amount of the fee taken.\n function _takeFeeFrom(\n uint256 _projectId,\n JBFundingCycle memory _fundingCycle,\n uint256 _amount,\n address _beneficiary,\n uint256 _feeDiscount\n ) internal returns (uint256 feeAmount) {\n feeAmount = _feeAmount(_amount, fee, _feeDiscount);\n\n if (_fundingCycle.shouldHoldFees()) {\n // Store the held fee.\n _heldFeesOf[_projectId].push(JBFee(_amount, uint32(fee), uint32(_feeDiscount), _beneficiary));\n\n emit HoldFee(_projectId, _amount, fee, _feeDiscount, _beneficiary, msg.sender);\n } else {\n // Process the fee.\n _processFee(feeAmount, _beneficiary, _projectId); // Take the fee.\n\n emit ProcessFee(_projectId, feeAmount, false, _beneficiary, msg.sender);\n }\n }\n\n /// @notice Process a fee of the specified amount.\n /// @param _amount The fee amount, as a floating point number with 18 decimals.\n /// @param _beneficiary The address to mint the platform's tokens for.\n /// @param _from The project ID the fee is being paid from.\n function _processFee(uint256 _amount, address _beneficiary, uint256 _from) internal {\n // Get the terminal for the protocol project.\n IJBPaymentTerminal _terminal = directory.primaryTerminalOf(_FEE_BENEFICIARY_PROJECT_ID, token);\n\n // If this terminal's token is ETH, send it in msg.value.\n uint256 _payableValue = token == JBTokens.ETH ? _amount : 0;\n\n // Send the projectId in the metadata.\n bytes memory _projectMetadata = new bytes(32);\n _projectMetadata = bytes(abi.encodePacked(_from));\n\n // Trigger any inherited pre-transfer logic if funds will be transferred.\n if (address(_terminal) != address(this)) _beforeTransferTo(address(_terminal), _amount);\n\n try\n // Send the fee.\n _terminal.pay{value: _payableValue}(\n _FEE_BENEFICIARY_PROJECT_ID,\n _amount,\n token,\n _beneficiary,\n 0,\n false,\n '',\n _projectMetadata\n )\n {} catch (bytes memory reason) {\n // Trigger any inhereted post-transfer cancelation logic if the pre-transfer logic was triggered.\n if (address(_terminal) != address(this)) _cancelTransferTo(address(_terminal), _amount);\n\n // Add fee amount back to project's balance.\n IJBSingleTokenPaymentTerminalStore(store).recordAddedBalanceFor(_from, _amount);\n\n emit FeeReverted(_from, _FEE_BENEFICIARY_PROJECT_ID, _amount, reason, msg.sender);\n }\n }\n\n /// @notice Contribute tokens to a project.\n /// @param _amount The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place.\n /// @param _payer The address making the payment.\n /// @param _projectId The ID of the project being paid.\n /// @param _beneficiary The address to mint tokens for and pass along to the funding cycle's data source and delegate.\n /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\n /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return beneficiaryTokenCount The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals.\n function _pay(\n uint256 _amount,\n address _payer,\n uint256 _projectId,\n address _beneficiary,\n uint256 _minReturnedTokens,\n bool _preferClaimedTokens,\n string memory _memo,\n bytes memory _metadata\n ) internal returns (uint256 beneficiaryTokenCount) {\n // Cant send tokens to the zero address.\n if (_beneficiary == address(0)) revert PAY_TO_ZERO_ADDRESS();\n\n // Define variables that will be needed outside the scoped section below.\n // Keep a reference to the funding cycle during which the payment is being made.\n JBFundingCycle memory _fundingCycle;\n\n // Scoped section prevents stack too deep. `_delegateAllocations` and `_tokenCount` only used within scope.\n {\n JBPayDelegateAllocation[] memory _delegateAllocations;\n uint256 _tokenCount;\n\n // Bundle the amount info into a JBTokenAmount struct.\n JBTokenAmount memory _bundledAmount = JBTokenAmount(token, _amount, decimals, currency);\n\n // Record the payment.\n (\n _fundingCycle,\n _tokenCount,\n _delegateAllocations,\n _memo\n ) = IJBSingleTokenPaymentTerminalStore(store).recordPaymentFrom(\n _payer,\n _bundledAmount,\n _projectId,\n baseWeightCurrency,\n _beneficiary,\n _memo,\n _metadata\n );\n\n // Mint the tokens if needed.\n if (_tokenCount > 0)\n // Set token count to be the number of tokens minted for the beneficiary instead of the total amount.\n beneficiaryTokenCount = IJBController(directory.controllerOf(_projectId)).mintTokensOf(\n _projectId,\n _tokenCount,\n _beneficiary,\n '',\n _preferClaimedTokens,\n true\n );\n\n // The token count for the beneficiary must be greater than or equal to the minimum expected.\n if (beneficiaryTokenCount < _minReturnedTokens) revert INADEQUATE_TOKEN_COUNT();\n\n // If delegate allocations were specified by the data source, fulfill them.\n if (_delegateAllocations.length != 0) {\n // Keep a reference to the token amount being forwarded to the delegate.\n JBTokenAmount memory _forwardedAmount = JBTokenAmount(token, _amount, decimals, currency);\n\n JBDidPayData memory _data = JBDidPayData(\n _payer,\n _projectId,\n _fundingCycle.configuration,\n _bundledAmount,\n _forwardedAmount,\n beneficiaryTokenCount,\n _beneficiary,\n _preferClaimedTokens,\n _memo,\n _metadata\n );\n\n // Get a reference to the number of delegates to allocate to.\n uint256 _numDelegates = _delegateAllocations.length;\n\n for (uint256 _i; _i < _numDelegates; ) {\n // Get a reference to the delegate being iterated on.\n JBPayDelegateAllocation memory _delegateAllocation = _delegateAllocations[_i];\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_delegateAllocation.delegate), _delegateAllocation.amount);\n\n // Keep track of the msg.value to use in the delegate call\n uint256 _payableValue;\n\n // If this terminal's token is ETH, send it in msg.value.\n if (token == JBTokens.ETH) _payableValue = _delegateAllocation.amount;\n\n // Pass the correct token forwardedAmount to the delegate\n _data.forwardedAmount.value = _delegateAllocation.amount;\n\n _delegateAllocation.delegate.didPay{value: _payableValue}(_data);\n\n emit DelegateDidPay(\n _delegateAllocation.delegate,\n _data,\n _delegateAllocation.amount,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n }\n\n emit Pay(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _payer,\n _beneficiary,\n _amount,\n beneficiaryTokenCount,\n _memo,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Receives funds belonging to the specified project.\n /// @param _projectId The ID of the project to which the funds received belong.\n /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\n /// @param _shouldRefundHeldFees A flag indicating if held fees should be refunded based on the amount being added.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the emitted event.\n function _addToBalanceOf(\n uint256 _projectId,\n uint256 _amount,\n bool _shouldRefundHeldFees,\n string memory _memo,\n bytes memory _metadata\n ) internal {\n // Refund any held fees to make sure the project doesn't pay double for funds going in and out of the protocol.\n uint256 _refundedFees = _shouldRefundHeldFees ? _refundHeldFees(_projectId, _amount) : 0;\n\n // Record the added funds with any refunded fees.\n IJBSingleTokenPaymentTerminalStore(store).recordAddedBalanceFor(\n _projectId,\n _amount + _refundedFees\n );\n\n emit AddToBalance(_projectId, _amount, _refundedFees, _memo, _metadata, msg.sender);\n }\n\n /// @notice Refund fees based on the specified amount.\n /// @param _projectId The project for which fees are being refunded.\n /// @param _amount The amount to base the refund on, as a fixed point number with the same amount of decimals as this terminal.\n /// @return refundedFees How much fees were refunded, as a fixed point number with the same number of decimals as this terminal\n function _refundHeldFees(\n uint256 _projectId,\n uint256 _amount\n ) internal returns (uint256 refundedFees) {\n // Get a reference to the project's held fees.\n JBFee[] memory _heldFees = _heldFeesOf[_projectId];\n\n // Delete the current held fees.\n delete _heldFeesOf[_projectId];\n\n // Get a reference to the leftover amount once all fees have been settled.\n uint256 leftoverAmount = _amount;\n\n // Push length in stack\n uint256 _heldFeesLength = _heldFees.length;\n\n // Process each fee.\n for (uint256 _i; _i < _heldFeesLength; ) {\n if (leftoverAmount == 0) _heldFeesOf[_projectId].push(_heldFees[_i]);\n else if (leftoverAmount >= _heldFees[_i].amount) {\n unchecked {\n leftoverAmount = leftoverAmount - _heldFees[_i].amount;\n refundedFees += _feeAmount(\n _heldFees[_i].amount,\n _heldFees[_i].fee,\n _heldFees[_i].feeDiscount\n );\n }\n } else {\n unchecked {\n _heldFeesOf[_projectId].push(\n JBFee(\n _heldFees[_i].amount - leftoverAmount,\n _heldFees[_i].fee,\n _heldFees[_i].feeDiscount,\n _heldFees[_i].beneficiary\n )\n );\n refundedFees += _feeAmount(leftoverAmount, _heldFees[_i].fee, _heldFees[_i].feeDiscount);\n }\n leftoverAmount = 0;\n }\n\n unchecked {\n ++_i;\n }\n }\n\n emit RefundHeldFees(_projectId, _amount, refundedFees, leftoverAmount, msg.sender);\n }\n\n /// @notice Returns the fee amount based on the provided amount for the specified project.\n /// @param _amount The amount that the fee is based on, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _fee The percentage of the fee, out of MAX_FEE.\n /// @param _feeDiscount The percentage discount that should be applied out of the max amount, out of MAX_FEE_DISCOUNT.\n /// @return The amount of the fee, as a fixed point number with the same amount of decimals as this terminal.\n function _feeAmount(\n uint256 _amount,\n uint256 _fee,\n uint256 _feeDiscount\n ) internal pure returns (uint256) {\n // Calculate the discounted fee.\n uint256 _discountedFee = _fee -\n PRBMath.mulDiv(_fee, _feeDiscount, JBConstants.MAX_FEE_DISCOUNT);\n\n // The amount of tokens from the `_amount` to pay as a fee.\n return\n _amount - PRBMath.mulDiv(_amount, JBConstants.MAX_FEE, _discountedFee + JBConstants.MAX_FEE);\n }\n\n /// @notice Get the fee discount from the fee gauge for the specified project.\n /// @param _projectId The ID of the project to get a fee discount for.\n /// @return feeDiscount The fee discount, which should be interpreted as a percentage out MAX_FEE_DISCOUNT.\n function _currentFeeDiscount(uint256 _projectId) internal view returns (uint256) {\n // Can't take a fee if the protocol project doesn't have a terminal that accepts the token.\n if (\n directory.primaryTerminalOf(_FEE_BENEFICIARY_PROJECT_ID, token) ==\n IJBPaymentTerminal(address(0))\n ) return JBConstants.MAX_FEE_DISCOUNT;\n\n // Get the fee discount.\n if (feeGauge != address(0))\n // If the guage reverts, keep the discount at 0.\n try IJBFeeGauge(feeGauge).currentDiscountFor(_projectId) returns (uint256 discount) {\n // If the fee discount is greater than the max, we ignore the return value\n if (discount <= JBConstants.MAX_FEE_DISCOUNT) return discount;\n } catch {\n return 0;\n }\n\n return 0;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165Checker.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC165.sol\";\n\n/**\n * @dev Library used to query support of an interface declared via {IERC165}.\n *\n * Note that these functions return the actual result of the query: they do not\n * `revert` if an interface is not supported. It is up to the caller to decide\n * what to do in these cases.\n */\nlibrary ERC165Checker {\n // As per the EIP-165 spec, no interface should ever match 0xffffffff\n bytes4 private constant _INTERFACE_ID_INVALID = 0xffffffff;\n\n /**\n * @dev Returns true if `account` supports the {IERC165} interface,\n */\n function supportsERC165(address account) internal view returns (bool) {\n // Any contract that implements ERC165 must explicitly indicate support of\n // InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid\n return\n _supportsERC165Interface(account, type(IERC165).interfaceId) &&\n !_supportsERC165Interface(account, _INTERFACE_ID_INVALID);\n }\n\n /**\n * @dev Returns true if `account` supports the interface defined by\n * `interfaceId`. Support for {IERC165} itself is queried automatically.\n *\n * See {IERC165-supportsInterface}.\n */\n function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) {\n // query support of both ERC165 as per the spec and support of _interfaceId\n return supportsERC165(account) && _supportsERC165Interface(account, interfaceId);\n }\n\n /**\n * @dev Returns a boolean array where each value corresponds to the\n * interfaces passed in and whether they're supported or not. This allows\n * you to batch check interfaces for a contract where your expectation\n * is that some interfaces may not be supported.\n *\n * See {IERC165-supportsInterface}.\n *\n * _Available since v3.4._\n */\n function getSupportedInterfaces(address account, bytes4[] memory interfaceIds)\n internal\n view\n returns (bool[] memory)\n {\n // an array of booleans corresponding to interfaceIds and whether they're supported or not\n bool[] memory interfaceIdsSupported = new bool[](interfaceIds.length);\n\n // query support of ERC165 itself\n if (supportsERC165(account)) {\n // query support of each interface in interfaceIds\n for (uint256 i = 0; i < interfaceIds.length; i++) {\n interfaceIdsSupported[i] = _supportsERC165Interface(account, interfaceIds[i]);\n }\n }\n\n return interfaceIdsSupported;\n }\n\n /**\n * @dev Returns true if `account` supports all the interfaces defined in\n * `interfaceIds`. Support for {IERC165} itself is queried automatically.\n *\n * Batch-querying can lead to gas savings by skipping repeated checks for\n * {IERC165} support.\n *\n * See {IERC165-supportsInterface}.\n */\n function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) {\n // query support of ERC165 itself\n if (!supportsERC165(account)) {\n return false;\n }\n\n // query support of each interface in _interfaceIds\n for (uint256 i = 0; i < interfaceIds.length; i++) {\n if (!_supportsERC165Interface(account, interfaceIds[i])) {\n return false;\n }\n }\n\n // all interfaces supported\n return true;\n }\n\n /**\n * @notice Query if a contract implements an interface, does not check ERC165 support\n * @param account The address of the contract to query for support of an interface\n * @param interfaceId The interface identifier, as specified in ERC-165\n * @return true if the contract at account indicates support of the interface with\n * identifier interfaceId, false otherwise\n * @dev Assumes that account contains a contract that supports ERC165, otherwise\n * the behavior of this method is undefined. This precondition can be checked\n * with {supportsERC165}.\n * Interface identification is specified in ERC-165.\n */\n function _supportsERC165Interface(address account, bytes4 interfaceId) private view returns (bool) {\n bytes memory encodedParams = abi.encodeWithSelector(IERC165.supportsInterface.selector, interfaceId);\n (bool success, bytes memory result) = account.staticcall{gas: 30000}(encodedParams);\n if (result.length < 32) return false;\n return success && abi.decode(result, (bool));\n }\n}\n" + }, + "contracts/interfaces/IJBAllowanceTerminal3_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBAllowanceTerminal3_1 {\n function useAllowanceOf(\n uint256 projectId,\n uint256 amount,\n uint256 currency,\n address token,\n uint256 minReturnedTokens,\n address payable beneficiary,\n string calldata memo,\n bytes calldata metadata\n ) external returns (uint256 netDistributedAmount);\n}\n" + }, + "contracts/interfaces/IJBFeeGauge.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBFeeGauge {\n function currentDiscountFor(uint256 projectId) external view returns (uint256);\n}\n" + }, + "contracts/interfaces/IJBPayoutRedemptionPaymentTerminal3_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBFee} from './../structs/JBFee.sol';\nimport {IJBAllowanceTerminal3_1} from './IJBAllowanceTerminal3_1.sol';\nimport {IJBDirectory} from './IJBDirectory.sol';\nimport {IJBFeeHoldingTerminal} from './IJBFeeHoldingTerminal.sol';\nimport {IJBPayDelegate} from './IJBPayDelegate.sol';\nimport {IJBPaymentTerminal} from './IJBPaymentTerminal.sol';\nimport {IJBPayoutTerminal3_1} from './IJBPayoutTerminal3_1.sol';\nimport {IJBPrices} from './IJBPrices.sol';\nimport {IJBProjects} from './IJBProjects.sol';\nimport {IJBRedemptionDelegate} from './IJBRedemptionDelegate.sol';\nimport {IJBRedemptionTerminal} from './IJBRedemptionTerminal.sol';\nimport {IJBSplitsStore} from './IJBSplitsStore.sol';\nimport {JBDidPayData} from './../structs/JBDidPayData.sol';\nimport {JBDidRedeemData} from './../structs/JBDidRedeemData.sol';\nimport {JBSplit} from './../structs/JBSplit.sol';\n\ninterface IJBPayoutRedemptionPaymentTerminal3_1 is\n IJBPaymentTerminal,\n IJBPayoutTerminal3_1,\n IJBAllowanceTerminal3_1,\n IJBRedemptionTerminal,\n IJBFeeHoldingTerminal\n{\n event AddToBalance(\n uint256 indexed projectId,\n uint256 amount,\n uint256 refundedFees,\n string memo,\n bytes metadata,\n address caller\n );\n\n event Migrate(\n uint256 indexed projectId,\n IJBPaymentTerminal indexed to,\n uint256 amount,\n address caller\n );\n\n event DistributePayouts(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n address beneficiary,\n uint256 amount,\n uint256 distributedAmount,\n uint256 fee,\n uint256 beneficiaryDistributionAmount,\n bytes metadata,\n address caller\n );\n\n event UseAllowance(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n address beneficiary,\n uint256 amount,\n uint256 distributedAmount,\n uint256 netDistributedamount,\n string memo,\n bytes metadata,\n address caller\n );\n\n event HoldFee(\n uint256 indexed projectId,\n uint256 indexed amount,\n uint256 indexed fee,\n uint256 feeDiscount,\n address beneficiary,\n address caller\n );\n\n event ProcessFee(\n uint256 indexed projectId,\n uint256 indexed amount,\n bool indexed wasHeld,\n address beneficiary,\n address caller\n );\n\n event RefundHeldFees(\n uint256 indexed projectId,\n uint256 indexed amount,\n uint256 indexed refundedFees,\n uint256 leftoverAmount,\n address caller\n );\n\n event Pay(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n address payer,\n address beneficiary,\n uint256 amount,\n uint256 beneficiaryTokenCount,\n string memo,\n bytes metadata,\n address caller\n );\n\n event DelegateDidPay(\n IJBPayDelegate indexed delegate,\n JBDidPayData data,\n uint256 delegatedAmount,\n address caller\n );\n\n event RedeemTokens(\n uint256 indexed fundingCycleConfiguration,\n uint256 indexed fundingCycleNumber,\n uint256 indexed projectId,\n address holder,\n address beneficiary,\n uint256 tokenCount,\n uint256 reclaimedAmount,\n string memo,\n bytes metadata,\n address caller\n );\n\n event DelegateDidRedeem(\n IJBRedemptionDelegate indexed delegate,\n JBDidRedeemData data,\n uint256 delegatedAmount,\n address caller\n );\n\n event DistributeToPayoutSplit(\n uint256 indexed projectId,\n uint256 indexed domain,\n uint256 indexed group,\n JBSplit split,\n uint256 amount,\n uint256 netAmount,\n address caller\n );\n\n event SetFee(uint256 fee, address caller);\n\n event SetFeeGauge(address indexed feeGauge, address caller);\n\n event SetFeelessAddress(address indexed addrs, bool indexed flag, address caller);\n\n event PayoutReverted(\n uint256 indexed projectId,\n JBSplit split,\n uint256 amount,\n bytes reason,\n address caller\n );\n\n event FeeReverted(\n uint256 indexed projectId,\n uint256 indexed feeProjectId,\n uint256 amount,\n bytes reason,\n address caller\n );\n\n function projects() external view returns (IJBProjects);\n\n function splitsStore() external view returns (IJBSplitsStore);\n\n function directory() external view returns (IJBDirectory);\n\n function prices() external view returns (IJBPrices);\n\n function store() external view returns (address);\n\n function baseWeightCurrency() external view returns (uint256);\n\n function payoutSplitsGroup() external view returns (uint256);\n\n function heldFeesOf(uint256 projectId) external view returns (JBFee[] memory);\n\n function fee() external view returns (uint256);\n\n function feeGauge() external view returns (address);\n\n function isFeelessAddress(address account) external view returns (bool);\n\n function migrate(uint256 projectId, IJBPaymentTerminal to) external returns (uint256 balance);\n\n function processFees(uint256 projectId) external;\n\n function setFee(uint256 fee) external;\n\n function setFeeGauge(address feeGauge) external;\n\n function setFeelessAddress(address account, bool flag) external;\n}\n" + }, + "contracts/interfaces/IJBPayoutTerminal3_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBPayoutTerminal3_1 {\n function distributePayoutsOf(\n uint256 projectId,\n uint256 amount,\n uint256 currency,\n address token,\n uint256 minReturnedTokens,\n bytes calldata metadata\n ) external returns (uint256 netLeftoverDistributionAmount);\n}\n" + }, + "contracts/abstract/JBSingleTokenPaymentTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {ERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol';\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\nimport {IJBSingleTokenPaymentTerminal} from './../interfaces/IJBSingleTokenPaymentTerminal.sol';\n\n/// @notice Generic terminal managing all inflows of funds into the protocol ecosystem for one token.\nabstract contract JBSingleTokenPaymentTerminal is ERC165, IJBSingleTokenPaymentTerminal {\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice The token that this terminal accepts.\n address public immutable override token;\n\n /// @notice The number of decimals the token fixed point amounts are expected to have.\n uint256 public immutable override decimals;\n\n /// @notice The currency to use when resolving price feeds for this terminal.\n uint256 public immutable override currency;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice A flag indicating if this terminal accepts the specified token.\n /// @param _token The token to check if this terminal accepts or not.\n /// @param _projectId The project ID to check for token acceptance.\n /// @return The flag.\n function acceptsToken(address _token, uint256 _projectId) external view override returns (bool) {\n _projectId; // Prevents unused var compiler and natspec complaints.\n\n return _token == token;\n }\n\n /// @notice The decimals that should be used in fixed number accounting for the specified token.\n /// @param _token The token to check for the decimals of.\n /// @return The number of decimals for the token.\n function decimalsForToken(address _token) external view override returns (uint256) {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return decimals;\n }\n\n /// @notice The currency that should be used for the specified token.\n /// @param _token The token to check for the currency of.\n /// @return The currency index.\n function currencyForToken(address _token) external view override returns (uint256) {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return currency;\n }\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if the provided interface ID is supported.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(ERC165, IERC165) returns (bool) {\n return\n _interfaceId == type(IJBPaymentTerminal).interfaceId ||\n _interfaceId == type(IJBSingleTokenPaymentTerminal).interfaceId ||\n super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _token The token that this terminal manages.\n /// @param _decimals The number of decimals the token fixed point amounts are expected to have.\n /// @param _currency The currency that this terminal's token adheres to for price feeds.\n constructor(address _token, uint256 _decimals, uint256 _currency) {\n token = _token;\n decimals = _decimals;\n currency = _currency;\n }\n}\n" + }, + "contracts/interfaces/IJBFeeHoldingTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IJBFeeHoldingTerminal {\n function addToBalanceOf(\n uint256 projectId,\n uint256 amount,\n address token,\n bool shouldRefundHeldFees,\n string calldata memo,\n bytes calldata metadata\n ) external payable;\n}\n" + }, + "contracts/JBETHPaymentTerminal3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Address} from '@openzeppelin/contracts/utils/Address.sol';\nimport {JBPayoutRedemptionPaymentTerminal3_1_1} from './abstract/JBPayoutRedemptionPaymentTerminal3_1_1.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\nimport {JBCurrencies} from './libraries/JBCurrencies.sol';\nimport {JBSplitsGroups} from './libraries/JBSplitsGroups.sol';\nimport {JBTokens} from './libraries/JBTokens.sol';\n\n/// @notice Manages all inflows and outflows of ETH funds into the protocol ecosystem.\ncontract JBETHPaymentTerminal3_1_1 is JBPayoutRedemptionPaymentTerminal3_1_1 {\n //*********************************************************************//\n // -------------------------- internal views ------------------------- //\n //*********************************************************************//\n\n /// @notice Checks the balance of tokens in this contract.\n /// @return The contract's balance, as a fixed point number with the same amount of decimals as this terminal.\n function _balance() internal view override returns (uint256) {\n return address(this).balance;\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _prices A contract that exposes price feeds.\n /// @param _store A contract that stores the terminal's data.\n /// @param _owner The address that will own this contract.\n constructor(\n uint256 _baseWeightCurrency,\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBSplitsStore _splitsStore,\n IJBPrices _prices,\n address _store,\n address _owner\n )\n JBPayoutRedemptionPaymentTerminal3_1_1(\n JBTokens.ETH,\n 18, // 18 decimals.\n JBCurrencies.ETH,\n _baseWeightCurrency,\n JBSplitsGroups.ETH_PAYOUT,\n _operatorStore,\n _projects,\n _directory,\n _splitsStore,\n _prices,\n _store,\n _owner\n )\n // solhint-disable-next-line no-empty-blocks\n {\n\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Transfers tokens.\n /// @param _from The address from which the transfer should originate.\n /// @param _to The address to which the transfer should go.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _transferFrom(address _from, address payable _to, uint256 _amount) internal override {\n _from; // Prevents unused var compiler and natspec complaints.\n\n Address.sendValue(_to, _amount);\n }\n}\n" + }, + "contracts/abstract/JBPayoutRedemptionPaymentTerminal3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {ERC165Checker} from '@openzeppelin/contracts/utils/introspection/ERC165Checker.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {JBFeeType} from './../enums/JBFeeType.sol';\nimport {IJBAllowanceTerminal3_1} from './../interfaces/IJBAllowanceTerminal3_1.sol';\nimport {IJBController} from './../interfaces/IJBController.sol';\nimport {IJBDirectory} from './../interfaces/IJBDirectory.sol';\nimport {IJBPayoutRedemptionPaymentTerminal3_1} from './../interfaces/IJBPayoutRedemptionPaymentTerminal3_1.sol';\nimport {IJBPayoutRedemptionPaymentTerminal3_1_1} from './../interfaces/IJBPayoutRedemptionPaymentTerminal3_1_1.sol';\nimport {IJBSplitsStore} from './../interfaces/IJBSplitsStore.sol';\nimport {IJBFeeGauge3_1} from './../interfaces/IJBFeeGauge3_1.sol';\nimport {IJBOperatable} from './../interfaces/IJBOperatable.sol';\nimport {IJBOperatorStore} from './../interfaces/IJBOperatorStore.sol';\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\nimport {IJBPayoutTerminal3_1} from './../interfaces/IJBPayoutTerminal3_1.sol';\nimport {IJBPrices} from './../interfaces/IJBPrices.sol';\nimport {IJBProjects} from './../interfaces/IJBProjects.sol';\nimport {IJBRedemptionTerminal} from './../interfaces/IJBRedemptionTerminal.sol';\nimport {IJBSingleTokenPaymentTerminalStore3_1_1} from './../interfaces/IJBSingleTokenPaymentTerminalStore3_1_1.sol';\nimport {IJBSplitAllocator} from './../interfaces/IJBSplitAllocator.sol';\nimport {JBConstants} from './../libraries/JBConstants.sol';\nimport {JBCurrencies} from './../libraries/JBCurrencies.sol';\nimport {JBFixedPointNumber} from './../libraries/JBFixedPointNumber.sol';\nimport {JBFundingCycleMetadataResolver} from './../libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBOperations} from './../libraries/JBOperations.sol';\nimport {JBTokens} from './../libraries/JBTokens.sol';\nimport {JBDidRedeemData3_1_1} from './../structs/JBDidRedeemData3_1_1.sol';\nimport {JBDidPayData3_1_1} from './../structs/JBDidPayData3_1_1.sol';\nimport {JBFee} from './../structs/JBFee.sol';\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\nimport {JBPayDelegateAllocation3_1_1} from './../structs/JBPayDelegateAllocation3_1_1.sol';\nimport {JBRedemptionDelegateAllocation3_1_1} from './../structs/JBRedemptionDelegateAllocation3_1_1.sol';\nimport {JBSplit} from './../structs/JBSplit.sol';\nimport {JBSplitAllocationData} from './../structs/JBSplitAllocationData.sol';\nimport {JBTokenAmount} from './../structs/JBTokenAmount.sol';\nimport {JBOperatable} from './JBOperatable.sol';\nimport {JBSingleTokenPaymentTerminal} from './JBSingleTokenPaymentTerminal.sol';\n\n/// @notice Generic terminal managing all inflows and outflows of funds into the protocol ecosystem.\nabstract contract JBPayoutRedemptionPaymentTerminal3_1_1 is\n JBSingleTokenPaymentTerminal,\n JBOperatable,\n Ownable,\n IJBPayoutRedemptionPaymentTerminal3_1,\n IJBPayoutRedemptionPaymentTerminal3_1_1\n{\n // A library that parses the packed funding cycle metadata into a friendlier format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error FEE_TOO_HIGH();\n error INADEQUATE_DISTRIBUTION_AMOUNT();\n error INADEQUATE_RECLAIM_AMOUNT();\n error INADEQUATE_TOKEN_COUNT();\n error NO_MSG_VALUE_ALLOWED();\n error PAY_TO_ZERO_ADDRESS();\n error PROJECT_TERMINAL_MISMATCH();\n error REDEEM_TO_ZERO_ADDRESS();\n error TERMINAL_TOKENS_INCOMPATIBLE();\n\n //*********************************************************************//\n // --------------------- internal stored constants ------------------- //\n //*********************************************************************//\n\n /// @notice Maximum fee that can be set for a funding cycle configuration.\n /// @dev Out of MAX_FEE (50_000_000 / 1_000_000_000).\n uint256 internal constant _FEE_CAP = 50_000_000;\n\n /// @notice The fee beneficiary project ID is 1, as it should be the first project launched during the deployment process.\n uint256 internal constant _FEE_BENEFICIARY_PROJECT_ID = 1;\n\n //*********************************************************************//\n // --------------------- internal stored properties ------------------ //\n //*********************************************************************//\n\n /// @notice Fees that are being held to be processed later.\n /// @custom:param _projectId The ID of the project for which fees are being held.\n mapping(uint256 => JBFee[]) internal _heldFeesOf;\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice Mints ERC-721's that represent project ownership and transfers.\n IJBProjects public immutable override projects;\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n /// @notice The contract that stores splits for each project.\n IJBSplitsStore public immutable override splitsStore;\n\n /// @notice The contract that exposes price feeds.\n IJBPrices public immutable override prices;\n\n /// @notice The contract that stores and manages the terminal's data.\n address public immutable override store;\n\n /// @notice The currency to base token issuance on.\n /// @dev If this differs from `currency`, there must be a price feed available to convert `currency` to `baseWeightCurrency`.\n uint256 public immutable override baseWeightCurrency;\n\n /// @notice The group that payout splits coming from this terminal are identified by.\n uint256 public immutable override payoutSplitsGroup;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The platform fee percent.\n /// @dev Out of MAX_FEE (25_000_000 / 1_000_000_000)\n uint256 public override fee = 25_000_000; // 2.5%\n\n /// @notice The data source that returns a discount to apply to a project's fee.\n address public override feeGauge;\n\n /// @notice Addresses that can be paid towards from this terminal without incurring a fee.\n /// @dev Only addresses that are considered to be contained within the ecosystem can be feeless. Funds sent outside the ecosystem may incur fees despite being stored as feeless.\n /// @custom:param _address The address that can be paid toward.\n mapping(address => bool) public override isFeelessAddress;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Gets the current overflowed amount in this terminal for a specified project, in terms of ETH.\n /// @dev The current overflow is represented as a fixed point number with 18 decimals.\n /// @param _projectId The ID of the project to get overflow for.\n /// @return The current amount of ETH overflow that project has in this terminal, as a fixed point number with 18 decimals.\n function currentEthOverflowOf(\n uint256 _projectId\n ) external view virtual override returns (uint256) {\n // Get this terminal's current overflow.\n uint256 _overflow = IJBSingleTokenPaymentTerminalStore3_1_1(store).currentOverflowOf(\n this,\n _projectId\n );\n\n // Adjust the decimals of the fixed point number if needed to have 18 decimals.\n uint256 _adjustedOverflow = (decimals == 18)\n ? _overflow\n : JBFixedPointNumber.adjustDecimals(_overflow, decimals, 18);\n\n // Return the amount converted to ETH.\n return\n (currency == JBCurrencies.ETH)\n ? _adjustedOverflow\n : PRBMath.mulDiv(\n _adjustedOverflow,\n 10 ** decimals,\n prices.priceFor(currency, JBCurrencies.ETH, decimals)\n );\n }\n\n /// @notice The fees that are currently being held to be processed later for each project.\n /// @param _projectId The ID of the project for which fees are being held.\n /// @return An array of fees that are being held.\n function heldFeesOf(uint256 _projectId) external view override returns (JBFee[] memory) {\n return _heldFeesOf[_projectId];\n }\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if the provided interface ID is supported.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(JBSingleTokenPaymentTerminal, IERC165) returns (bool) {\n return\n _interfaceId == type(IJBPayoutRedemptionPaymentTerminal3_1_1).interfaceId ||\n _interfaceId == type(IJBPayoutRedemptionPaymentTerminal3_1).interfaceId ||\n _interfaceId == type(IJBPayoutTerminal3_1).interfaceId ||\n _interfaceId == type(IJBAllowanceTerminal3_1).interfaceId ||\n _interfaceId == type(IJBRedemptionTerminal).interfaceId ||\n _interfaceId == type(IJBOperatable).interfaceId ||\n super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // -------------------------- internal views ------------------------- //\n //*********************************************************************//\n\n /// @notice Checks the balance of tokens in this contract.\n /// @return The contract's balance.\n function _balance() internal view virtual returns (uint256);\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _token The token that this terminal manages.\n /// @param _decimals The number of decimals the token fixed point amounts are expected to have.\n /// @param _currency The currency that this terminal's token adheres to for price feeds.\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _payoutSplitsGroup The group that denotes payout splits from this terminal in the splits store.\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _prices A contract that exposes price feeds.\n /// @param _store A contract that stores the terminal's data.\n /// @param _owner The address that will own this contract.\n constructor(\n // payable constructor save the gas used to check msg.value==0\n address _token,\n uint256 _decimals,\n uint256 _currency,\n uint256 _baseWeightCurrency,\n uint256 _payoutSplitsGroup,\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBSplitsStore _splitsStore,\n IJBPrices _prices,\n address _store,\n address _owner\n )\n payable\n JBSingleTokenPaymentTerminal(_token, _decimals, _currency)\n JBOperatable(_operatorStore)\n {\n baseWeightCurrency = _baseWeightCurrency;\n payoutSplitsGroup = _payoutSplitsGroup;\n projects = _projects;\n directory = _directory;\n splitsStore = _splitsStore;\n prices = _prices;\n store = _store;\n\n transferOwnership(_owner);\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Contribute tokens to a project.\n /// @param _projectId The ID of the project being paid.\n /// @param _amount The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place.\n /// @param _token The token being paid. This terminal ignores this property since it only manages one token.\n /// @param _beneficiary The address to mint tokens for and pass along to the funding cycle's data source and delegate.\n /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\n /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals.\n function pay(\n uint256 _projectId,\n uint256 _amount,\n address _token,\n address _beneficiary,\n uint256 _minReturnedTokens,\n bool _preferClaimedTokens,\n string calldata _memo,\n bytes calldata _metadata\n ) external payable virtual override returns (uint256) {\n _token; // Prevents unused var compiler and natspec complaints.\n\n // valid terminal check\n _isTerminalOf(_projectId);\n\n // ETH shouldn't be sent if this terminal's token isn't ETH.\n if (token != JBTokens.ETH) {\n if (msg.value != 0) revert NO_MSG_VALUE_ALLOWED();\n\n // Get a reference to the balance before receiving tokens.\n uint256 _balanceBefore = _balance();\n\n // Transfer tokens to this terminal from the msg sender.\n _transferFrom(msg.sender, payable(address(this)), _amount);\n\n // The amount should reflect the change in balance.\n _amount = _balance() - _balanceBefore;\n }\n // If this terminal's token is ETH, override _amount with msg.value.\n else _amount = msg.value;\n\n return\n _pay(\n _amount,\n msg.sender,\n _projectId,\n _beneficiary,\n _minReturnedTokens,\n _preferClaimedTokens,\n _memo,\n _metadata\n );\n }\n\n /// @notice Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source.\n /// @dev Only a token holder or a designated operator can redeem its tokens.\n /// @param _holder The account to redeem tokens for.\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\n /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals.\n /// @param _token The token being reclaimed. This terminal ignores this property since it only manages one token.\n /// @param _minReturnedTokens The minimum amount of terminal tokens expected in return, as a fixed point number with the same amount of decimals as the terminal.\n /// @param _beneficiary The address to send the terminal tokens to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return reclaimAmount The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals.\n function redeemTokensOf(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n address _token,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo,\n bytes memory _metadata\n )\n external\n virtual\n override\n requirePermission(_holder, _projectId, JBOperations.REDEEM)\n returns (uint256 reclaimAmount)\n {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return\n _redeemTokensOf(\n _holder,\n _projectId,\n _tokenCount,\n _minReturnedTokens,\n _beneficiary,\n _memo,\n _metadata\n );\n }\n\n /// @notice Distributes payouts for a project with the distribution limit of its current funding cycle.\n /// @dev Payouts are sent to the preprogrammed splits. Any leftover is sent to the project's owner.\n /// @dev 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.\n /// @dev All funds distributed outside of this contract or any feeless terminals incure the protocol fee.\n /// @param _projectId The ID of the project having its payouts distributed.\n /// @param _amount The amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency.\n /// @param _token The token being distributed. This terminal ignores this property since it only manages one token.\n /// @param _minReturnedTokens 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.\n /// @param _metadata Bytes to send along to the emitted event, if provided.\n /// @return netLeftoverDistributionAmount The amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal.\n function distributePayoutsOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n address _token,\n uint256 _minReturnedTokens,\n bytes calldata _metadata\n ) external virtual override returns (uint256 netLeftoverDistributionAmount) {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return _distributePayoutsOf(_projectId, _amount, _currency, _minReturnedTokens, _metadata);\n }\n\n /// @notice Allows a project to send funds from its overflow up to the preconfigured allowance.\n /// @dev Only a project's owner or a designated operator can use its allowance.\n /// @dev Incurs the protocol fee.\n /// @param _projectId The ID of the project to use the allowance of.\n /// @param _amount The amount of terminal tokens to use from this project's current allowance, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's overflow allowance currency.\n /// @param _token The token being distributed. This terminal ignores this property since it only manages one token.\n /// @param _minReturnedTokens The minimum number of tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with 18 decimals.\n /// @param _beneficiary The address to send the funds to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the emitted event, if provided.\n /// @return netDistributedAmount The amount of tokens that was distributed to the beneficiary, as a fixed point number with the same amount of decimals as the terminal.\n function useAllowanceOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n address _token,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo,\n bytes calldata _metadata\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.USE_ALLOWANCE)\n returns (uint256 netDistributedAmount)\n {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return\n _useAllowanceOf(\n _projectId,\n _amount,\n _currency,\n _minReturnedTokens,\n _beneficiary,\n _memo,\n _metadata\n );\n }\n\n /// @notice Allows a project owner to migrate its funds and operations to a new terminal that accepts the same token type.\n /// @dev Only a project's owner or a designated operator can migrate it.\n /// @param _projectId The ID of the project being migrated.\n /// @param _to The terminal contract that will gain the project's funds.\n /// @return balance The amount of funds that were migrated, as a fixed point number with the same amount of decimals as this terminal.\n function migrate(\n uint256 _projectId,\n IJBPaymentTerminal _to\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.MIGRATE_TERMINAL)\n returns (uint256 balance)\n {\n // The terminal being migrated to must accept the same token as this terminal.\n if (!_to.acceptsToken(token, _projectId)) revert TERMINAL_TOKENS_INCOMPATIBLE();\n\n // Record the migration in the store.\n balance = IJBSingleTokenPaymentTerminalStore3_1_1(store).recordMigration(_projectId);\n\n // Transfer the balance if needed.\n if (balance != 0) {\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_to), balance);\n\n // If this terminal's token is ETH, send it in msg.value.\n uint256 _payableValue = token == JBTokens.ETH ? balance : 0;\n\n // Withdraw the balance to transfer to the new terminal;\n _to.addToBalanceOf{value: _payableValue}(_projectId, balance, token, '', bytes(''));\n }\n\n emit Migrate(_projectId, _to, balance, msg.sender);\n }\n\n /// @notice Receives funds belonging to the specified project.\n /// @param _projectId The ID of the project to which the funds received belong.\n /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\n /// @param _token The token being paid. This terminal ignores this property since it only manages one currency.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the emitted event.\n function addToBalanceOf(\n uint256 _projectId,\n uint256 _amount,\n address _token,\n string calldata _memo,\n bytes calldata _metadata\n ) external payable virtual override {\n // valid terminal check\n _isTerminalOf(_projectId);\n\n // Do not refund held fees by default.\n addToBalanceOf(_projectId, _amount, _token, false, _memo, _metadata);\n }\n\n /// @notice Process any fees that are being held for the project.\n /// @dev Only a project owner, an operator, or the contract's owner can process held fees.\n /// @param _projectId The ID of the project whos held fees should be processed.\n function processFees(\n uint256 _projectId\n )\n external\n virtual\n override\n requirePermissionAllowingOverride(\n projects.ownerOf(_projectId),\n _projectId,\n JBOperations.PROCESS_FEES,\n msg.sender == owner()\n )\n {\n // Get a reference to the project's held fees.\n JBFee[] memory _heldFees = _heldFeesOf[_projectId];\n\n // Delete the held fees.\n delete _heldFeesOf[_projectId];\n\n // Push array length in stack\n uint256 _heldFeeLength = _heldFees.length;\n\n // Keep a reference to the amount.\n uint256 _amount;\n\n // Process each fee.\n for (uint256 _i; _i < _heldFeeLength; ) {\n // Get the fee amount.\n _amount = (\n _heldFees[_i].fee == 0 || _heldFees[_i].feeDiscount == JBConstants.MAX_FEE_DISCOUNT\n ? 0\n : _feeAmount(_heldFees[_i].amount, _heldFees[_i].fee, _heldFees[_i].feeDiscount)\n );\n\n // Process the fee.\n _processFee(_amount, _heldFees[_i].beneficiary, _projectId);\n\n emit ProcessFee(_projectId, _amount, true, _heldFees[_i].beneficiary, msg.sender);\n\n unchecked {\n ++_i;\n }\n }\n }\n\n /// @notice Allows the fee to be updated.\n /// @dev Only the owner of this contract can change the fee.\n /// @param _fee The new fee, out of MAX_FEE.\n function setFee(uint256 _fee) external virtual override onlyOwner {\n // The provided fee must be within the max.\n if (_fee > _FEE_CAP) revert FEE_TOO_HIGH();\n\n // Store the new fee.\n fee = _fee;\n\n emit SetFee(_fee, msg.sender);\n }\n\n /// @notice Allows the fee gauge to be updated.\n /// @dev Only the owner of this contract can change the fee gauge.\n /// @param _feeGauge The new fee gauge.\n function setFeeGauge(address _feeGauge) external virtual override onlyOwner {\n // Store the new fee gauge.\n feeGauge = _feeGauge;\n\n emit SetFeeGauge(_feeGauge, msg.sender);\n }\n\n /// @notice Sets whether projects operating on this terminal can pay towards the specified address without incurring a fee.\n /// @dev Only the owner of this contract can set addresses as feeless.\n /// @param _address The address that can be paid towards while still bypassing fees.\n /// @param _flag A flag indicating whether the terminal should be feeless or not.\n function setFeelessAddress(address _address, bool _flag) external virtual override onlyOwner {\n // Set the flag value.\n isFeelessAddress[_address] = _flag;\n\n emit SetFeelessAddress(_address, _flag, msg.sender);\n }\n\n //*********************************************************************//\n // ----------------------- public transactions ----------------------- //\n //*********************************************************************//\n\n /// @notice Receives funds belonging to the specified project.\n /// @param _projectId The ID of the project to which the funds received belong.\n /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\n /// @param _token The token being paid. This terminal ignores this property since it only manages one currency.\n /// @param _shouldRefundHeldFees A flag indicating if held fees should be refunded based on the amount being added.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the emitted event.\n function addToBalanceOf(\n uint256 _projectId,\n uint256 _amount,\n address _token,\n bool _shouldRefundHeldFees,\n string calldata _memo,\n bytes calldata _metadata\n ) public payable virtual override {\n // valid terminal check\n _isTerminalOf(_projectId);\n\n _token; // Prevents unused var compiler and natspec complaints.\n\n // If this terminal's token isn't ETH, make sure no msg.value was sent, then transfer the tokens in from msg.sender.\n if (token != JBTokens.ETH) {\n // Amount must be greater than 0.\n if (msg.value != 0) revert NO_MSG_VALUE_ALLOWED();\n\n // Get a reference to the balance before receiving tokens.\n uint256 _balanceBefore = _balance();\n\n // Transfer tokens to this terminal from the msg sender.\n _transferFrom(msg.sender, payable(address(this)), _amount);\n\n // The amount should reflect the change in balance.\n _amount = _balance() - _balanceBefore;\n }\n // If the terminal's token is ETH, override `_amount` with msg.value.\n else _amount = msg.value;\n\n // Add to balance.\n _addToBalanceOf(_projectId, _amount, _shouldRefundHeldFees, _memo, _metadata);\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Transfers tokens.\n /// @param _from The address from which the transfer should originate.\n /// @param _to The address to which the transfer should go.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _transferFrom(address _from, address payable _to, uint256 _amount) internal virtual {\n _from; // Prevents unused var compiler and natspec complaints.\n _to; // Prevents unused var compiler and natspec complaints.\n _amount; // Prevents unused var compiler and natspec complaints.\n }\n\n /// @notice Logic to be triggered before transferring tokens from this terminal.\n /// @param _to The address to which the transfer is going.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _beforeTransferTo(address _to, uint256 _amount) internal virtual {\n _to; // Prevents unused var compiler and natspec complaints.\n _amount; // Prevents unused var compiler and natspec complaints.\n }\n\n /// @notice Logic to be triggered if a transfer should be undone\n /// @param _to The address to which the transfer went.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _cancelTransferTo(address _to, uint256 _amount) internal virtual {\n _to; // Prevents unused var compiler and natspec complaints.\n _amount; // Prevents unused var compiler and natspec complaints.\n }\n\n /// @notice Verifies this terminal is a terminal of provided project ID.\n /// @param _projectId The ID of the project to check if this contract is a terminal of.\n function _isTerminalOf(uint256 _projectId) internal view {\n if (!directory.isTerminalOf(_projectId, this)) revert PROJECT_TERMINAL_MISMATCH();\n }\n\n /// @notice Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source.\n /// @dev Only a token holder or a designated operator can redeem its tokens.\n /// @param _holder The account to redeem tokens for.\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\n /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals.\n /// @param _minReturnedTokens The minimum amount of terminal tokens expected in return, as a fixed point number with the same amount of decimals as the terminal.\n /// @param _beneficiary The address to send the terminal tokens to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return reclaimAmount The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals.\n function _redeemTokensOf(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo,\n bytes memory _metadata\n ) internal returns (uint256 reclaimAmount) {\n // Can't send reclaimed funds to the zero address.\n if (_beneficiary == address(0)) revert REDEEM_TO_ZERO_ADDRESS();\n\n // Define variables that will be needed outside the scoped section below.\n // Keep a reference to the funding cycle during which the redemption is being made.\n JBFundingCycle memory _fundingCycle;\n\n // Scoped section prevents stack too deep. `_feeEligibleDistributionAmount`, `_feeDiscount` and `_feePercent` only used within scope.\n {\n // Keep a reference to the amount being reclaimed that should have fees withheld from.\n uint256 _feeEligibleDistributionAmount;\n\n // Keep a reference to the amount of discount to apply to the fee.\n uint256 _feeDiscount;\n\n // Keep a reference to the fee.\n uint256 _feePercent = fee;\n\n // Scoped section prevents stack too deep. `_delegateAllocations` only used within scope.\n {\n JBRedemptionDelegateAllocation3_1_1[] memory _delegateAllocations;\n\n // Record the redemption.\n (\n _fundingCycle,\n reclaimAmount,\n _delegateAllocations,\n _memo\n ) = IJBSingleTokenPaymentTerminalStore3_1_1(store).recordRedemptionFor(\n _holder,\n _projectId,\n _tokenCount,\n _memo,\n _metadata\n );\n\n // Set the reference to the fee discount to apply. No fee if the beneficiary is feeless or if the redemption rate is at its max.\n _feeDiscount = isFeelessAddress[_beneficiary] ||\n (_fundingCycle.redemptionRate() == JBConstants.MAX_REDEMPTION_RATE &&\n _fundingCycle.ballotRedemptionRate() == JBConstants.MAX_REDEMPTION_RATE) ||\n _feePercent == 0\n ? JBConstants.MAX_FEE_DISCOUNT\n : _currentFeeDiscount(_projectId, JBFeeType.REDEMPTION);\n\n // The amount being reclaimed must be at least as much as was expected.\n if (reclaimAmount < _minReturnedTokens) revert INADEQUATE_RECLAIM_AMOUNT();\n\n // Burn the project tokens.\n if (_tokenCount != 0)\n IJBController(directory.controllerOf(_projectId)).burnTokensOf(\n _holder,\n _projectId,\n _tokenCount,\n '',\n false\n );\n\n // If delegate allocations were specified by the data source, fulfill them.\n if (_delegateAllocations.length != 0) {\n JBDidRedeemData3_1_1 memory _data = JBDidRedeemData3_1_1(\n _holder,\n _projectId,\n _fundingCycle.configuration,\n _tokenCount,\n JBTokenAmount(token, reclaimAmount, decimals, currency),\n JBTokenAmount(token, 0, decimals, currency),\n _beneficiary,\n _memo,\n bytes(''),\n _metadata\n );\n\n // Keep a reference to the allocation.\n JBRedemptionDelegateAllocation3_1_1 memory _delegateAllocation;\n\n // Keep a reference to the fee.\n uint256 _delegatedAmountFee;\n\n // Keep a reference to the number of allocations.\n uint256 _numDelegates = _delegateAllocations.length;\n\n for (uint256 _i; _i < _numDelegates; ) {\n // Get a reference to the delegate being iterated on.\n _delegateAllocation = _delegateAllocations[_i];\n\n // Get the fee for the delegated amount.\n _delegatedAmountFee = _feePercent == 0\n ? 0\n : _feeAmount(_delegateAllocation.amount, _feePercent, _feeDiscount);\n\n // Add the delegated amount to the amount eligible for having a fee taken.\n if (_delegatedAmountFee != 0) {\n _feeEligibleDistributionAmount += _delegateAllocation.amount;\n _delegateAllocation.amount -= _delegatedAmountFee;\n }\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_delegateAllocation.delegate), _delegateAllocation.amount);\n\n // Pass the correct token forwardedAmount to the delegate\n _data.forwardedAmount.value = _delegateAllocation.amount;\n\n // Pass the correct metadata from the data source.\n _data.dataSourceMetadata = _delegateAllocation.metadata;\n\n _delegateAllocation.delegate.didRedeem{\n value: token == JBTokens.ETH ? _delegateAllocation.amount : 0\n }(_data);\n\n emit DelegateDidRedeem(\n _delegateAllocation.delegate,\n _data,\n _delegateAllocation.amount,\n _delegatedAmountFee,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n }\n\n // Send the reclaimed funds to the beneficiary.\n if (reclaimAmount != 0) {\n // Get the fee for the reclaimed amount.\n uint256 _reclaimAmountFee = _feeDiscount == JBConstants.MAX_FEE_DISCOUNT\n ? 0\n : _feeAmount(reclaimAmount, _feePercent, _feeDiscount);\n\n if (_reclaimAmountFee != 0) {\n _feeEligibleDistributionAmount += reclaimAmount;\n reclaimAmount -= _reclaimAmountFee;\n }\n\n // Subtract the fee from the reclaim amount.\n if (reclaimAmount != 0) _transferFrom(address(this), _beneficiary, reclaimAmount);\n }\n\n // Take the fee from all outbound reclaimations.\n _feeEligibleDistributionAmount != 0\n ? _takeFeeFrom(\n _projectId,\n false,\n _feeEligibleDistributionAmount,\n _feePercent,\n _beneficiary,\n _feeDiscount\n )\n : 0;\n }\n\n emit RedeemTokens(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _holder,\n _beneficiary,\n _tokenCount,\n reclaimAmount,\n _memo,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Distributes payouts for a project with the distribution limit of its current funding cycle.\n /// @dev Payouts are sent to the preprogrammed splits. Any leftover is sent to the project's owner.\n /// @dev 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.\n /// @dev All funds distributed outside of this contract or any feeless terminals incure the protocol fee.\n /// @param _projectId The ID of the project having its payouts distributed.\n /// @param _amount The amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency.\n /// @param _minReturnedTokens 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.\n /// @param _metadata Bytes to send along to the emitted event, if provided.\n /// @return netLeftoverDistributionAmount The amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal.\n function _distributePayoutsOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n uint256 _minReturnedTokens,\n bytes calldata _metadata\n ) internal returns (uint256 netLeftoverDistributionAmount) {\n // Record the distribution.\n (\n JBFundingCycle memory _fundingCycle,\n uint256 _distributedAmount\n ) = IJBSingleTokenPaymentTerminalStore3_1_1(store).recordDistributionFor(\n _projectId,\n _amount,\n _currency\n );\n\n // The amount being distributed must be at least as much as was expected.\n if (_distributedAmount < _minReturnedTokens) revert INADEQUATE_DISTRIBUTION_AMOUNT();\n\n // Get a reference to the project owner, which will receive tokens from paying the platform fee\n // and receive any extra distributable funds not allocated to payout splits.\n address payable _projectOwner = payable(projects.ownerOf(_projectId));\n\n // Define variables that will be needed outside the scoped section below.\n // Keep a reference to the fee amount that was paid.\n uint256 _feeTaken;\n\n // Scoped section prevents stack too deep. `_feePercent`, `_feeDiscount`, `_feeEligibleDistributionAmount`, and `_leftoverDistributionAmount` only used within scope.\n {\n // Keep a reference to the fee.\n uint256 _feePercent = fee;\n\n // Get the amount of discount that should be applied to any fees taken.\n // If the fee is zero, set the discount to 100% for convenience.\n uint256 _feeDiscount = _feePercent == 0\n ? JBConstants.MAX_FEE_DISCOUNT\n : _currentFeeDiscount(_projectId, JBFeeType.PAYOUT);\n\n // The amount distributed that is eligible for incurring fees.\n uint256 _feeEligibleDistributionAmount;\n\n // The amount leftover after distributing to the splits.\n uint256 _leftoverDistributionAmount;\n\n // Payout to splits and get a reference to the leftover transfer amount after all splits have been paid.\n // Also get a reference to the amount that was distributed to splits from which fees should be taken.\n (_leftoverDistributionAmount, _feeEligibleDistributionAmount) = _distributeToPayoutSplitsOf(\n _projectId,\n _fundingCycle.configuration,\n payoutSplitsGroup,\n _distributedAmount,\n _feePercent,\n _feeDiscount\n );\n\n if (_feeDiscount != JBConstants.MAX_FEE_DISCOUNT) {\n // Leftover distribution amount is also eligible for a fee since the funds are going out of the ecosystem to _beneficiary.\n unchecked {\n _feeEligibleDistributionAmount += _leftoverDistributionAmount;\n }\n }\n\n // Take the fee.\n _feeTaken = _feeEligibleDistributionAmount != 0\n ? _takeFeeFrom(\n _projectId,\n _fundingCycle.shouldHoldFees(),\n _feeEligibleDistributionAmount,\n _feePercent,\n _projectOwner,\n _feeDiscount\n )\n : 0;\n\n // Transfer any remaining balance to the project owner and update returned leftover accordingly.\n if (_leftoverDistributionAmount != 0) {\n // Subtract the fee from the net leftover amount.\n netLeftoverDistributionAmount =\n _leftoverDistributionAmount -\n (\n _feeDiscount == JBConstants.MAX_FEE_DISCOUNT\n ? 0\n : _feeAmount(_leftoverDistributionAmount, _feePercent, _feeDiscount)\n );\n\n // Transfer the amount to the project owner.\n _transferFrom(address(this), _projectOwner, netLeftoverDistributionAmount);\n }\n }\n\n emit DistributePayouts(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _projectOwner,\n _amount,\n _distributedAmount,\n _feeTaken,\n netLeftoverDistributionAmount,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Allows a project to send funds from its overflow up to the preconfigured allowance.\n /// @dev Only a project's owner or a designated operator can use its allowance.\n /// @dev Incurs the protocol fee.\n /// @param _projectId The ID of the project to use the allowance of.\n /// @param _amount The amount of terminal tokens to use from this project's current allowance, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's overflow allowance currency.\n /// @param _minReturnedTokens The minimum number of tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with 18 decimals.\n /// @param _beneficiary The address to send the funds to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the emitted event, if provided.\n /// @return netDistributedAmount The amount of tokens that was distributed to the beneficiary, as a fixed point number with the same amount of decimals as the terminal.\n function _useAllowanceOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo,\n bytes calldata _metadata\n ) internal returns (uint256 netDistributedAmount) {\n // Record the use of the allowance.\n (\n JBFundingCycle memory _fundingCycle,\n uint256 _distributedAmount\n ) = IJBSingleTokenPaymentTerminalStore3_1_1(store).recordUsedAllowanceOf(\n _projectId,\n _amount,\n _currency\n );\n\n // The amount being withdrawn must be at least as much as was expected.\n if (_distributedAmount < _minReturnedTokens) revert INADEQUATE_DISTRIBUTION_AMOUNT();\n\n // Scoped section prevents stack too deep. `_fee`, `_projectOwner`, `_feeDiscount`, and `_netAmount` only used within scope.\n {\n // Keep a reference to the fee amount that was paid.\n uint256 _feeTaken;\n\n // Keep a reference to the fee.\n uint256 _feePercent = fee;\n\n // Get a reference to the project owner, which will receive tokens from paying the platform fee.\n address _projectOwner = projects.ownerOf(_projectId);\n\n // Get the amount of discount that should be applied to any fees taken.\n // 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.\n uint256 _feeDiscount = _feePercent == 0 || isFeelessAddress[msg.sender]\n ? JBConstants.MAX_FEE_DISCOUNT\n : _currentFeeDiscount(_projectId, JBFeeType.ALLOWANCE);\n\n // Take a fee from the `_distributedAmount`, if needed.\n _feeTaken = _feeDiscount == JBConstants.MAX_FEE_DISCOUNT\n ? 0\n : _takeFeeFrom(\n _projectId,\n _fundingCycle.shouldHoldFees(),\n _distributedAmount,\n _feePercent,\n _projectOwner,\n _feeDiscount\n );\n\n unchecked {\n // The net amount is the withdrawn amount without the fee.\n netDistributedAmount = _distributedAmount - _feeTaken;\n }\n\n // Transfer any remaining balance to the beneficiary.\n if (netDistributedAmount != 0)\n _transferFrom(address(this), _beneficiary, netDistributedAmount);\n }\n\n emit UseAllowance(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _beneficiary,\n _amount,\n _distributedAmount,\n netDistributedAmount,\n _memo,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Pays out splits for a project's funding cycle configuration.\n /// @param _projectId The ID of the project for which payout splits are being distributed.\n /// @param _domain The domain of the splits to distribute the payout between.\n /// @param _group The group of the splits to distribute the payout between.\n /// @param _amount The total amount being distributed, as a fixed point number with the same number of decimals as this terminal.\n /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE.\n /// @param _feePercent The percent of fees to take, out of MAX_FEE.\n /// @return If the leftover amount if the splits don't add up to 100%.\n /// @return feeEligibleDistributionAmount The total amount of distributions that are eligible to have fees taken from.\n function _distributeToPayoutSplitsOf(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group,\n uint256 _amount,\n uint256 _feePercent,\n uint256 _feeDiscount\n ) internal returns (uint256, uint256 feeEligibleDistributionAmount) {\n // The total percentage available to split\n uint256 _leftoverPercentage = JBConstants.SPLITS_TOTAL_PERCENT;\n\n // Get a reference to the project's payout splits.\n JBSplit[] memory _splits = splitsStore.splitsOf(_projectId, _domain, _group);\n\n // Keep a reference to the split being iterated on.\n JBSplit memory _split;\n\n // Transfer between all splits.\n for (uint256 _i; _i < _splits.length; ) {\n // Get a reference to the split being iterated on.\n _split = _splits[_i];\n\n // The amount to send towards the split.\n uint256 _payoutAmount = PRBMath.mulDiv(_amount, _split.percent, _leftoverPercentage);\n\n // The payout amount substracting any applicable incurred fees.\n uint256 _netPayoutAmount = _distributeToPayoutSplit(\n _split,\n _projectId,\n _group,\n _payoutAmount,\n _feePercent,\n _feeDiscount\n );\n\n // If the split allocator is set as feeless, this distribution is not eligible for a fee.\n if (_netPayoutAmount != 0 && _netPayoutAmount != _payoutAmount)\n feeEligibleDistributionAmount += _payoutAmount;\n\n if (_payoutAmount != 0) {\n // Subtract from the amount to be sent to the beneficiary.\n unchecked {\n _amount -= _payoutAmount;\n }\n }\n\n unchecked {\n // Decrement the leftover percentage.\n _leftoverPercentage -= _split.percent;\n }\n\n emit DistributeToPayoutSplit(\n _projectId,\n _domain,\n _group,\n _split,\n _payoutAmount,\n _netPayoutAmount,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n\n return (_amount, feeEligibleDistributionAmount);\n }\n\n /// @notice Pays out a split for a project's funding cycle configuration.\n /// @param _split The split to distribute payouts to.\n /// @param _amount The total amount being distributed to the split, as a fixed point number with the same number of decimals as this terminal.\n /// @param _feePercent The percent of fees to take, out of MAX_FEE.\n /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE.\n /// @return netPayoutAmount The amount sent to the split after subtracting fees.\n function _distributeToPayoutSplit(\n JBSplit memory _split,\n uint256 _projectId,\n uint256 _group,\n uint256 _amount,\n uint256 _feePercent,\n uint256 _feeDiscount\n ) internal returns (uint256 netPayoutAmount) {\n // By default, the net payout amount is the full amount. This will be adjusted if fees are taken.\n netPayoutAmount = _amount;\n\n // If there's an allocator set, transfer to its `allocate` function.\n if (_split.allocator != IJBSplitAllocator(address(0))) {\n // This distribution is eligible for a fee since the funds are leaving this contract and the allocator isn't listed as feeless.\n if (\n _feeDiscount != JBConstants.MAX_FEE_DISCOUNT && !isFeelessAddress[address(_split.allocator)]\n ) {\n unchecked {\n netPayoutAmount -= _feeAmount(_amount, _feePercent, _feeDiscount);\n }\n }\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_split.allocator), netPayoutAmount);\n\n // Create the data to send to the allocator.\n JBSplitAllocationData memory _data = JBSplitAllocationData(\n token,\n netPayoutAmount,\n decimals,\n _projectId,\n _group,\n _split\n );\n\n // Trigger the allocator's `allocate` function.\n bytes memory _reason;\n\n if (\n ERC165Checker.supportsInterface(\n address(_split.allocator),\n type(IJBSplitAllocator).interfaceId\n )\n )\n // If this terminal's token is ETH, send it in msg.value.\n try\n _split.allocator.allocate{value: token == JBTokens.ETH ? netPayoutAmount : 0}(_data)\n {} catch (bytes memory __reason) {\n _reason = __reason.length == 0 ? abi.encode('Allocate fail') : __reason;\n }\n else {\n _reason = abi.encode('IERC165 fail');\n }\n\n if (_reason.length != 0) {\n // Revert the payout.\n _revertTransferFrom(_projectId, address(_split.allocator), netPayoutAmount, _amount);\n\n // Set the net payout amount to 0 to signal the reversion.\n netPayoutAmount = 0;\n\n emit PayoutReverted(_projectId, _split, _amount, _reason, msg.sender);\n }\n\n // Otherwise, if a project is specified, make a payment to it.\n } else if (_split.projectId != 0) {\n // Get a reference to the Juicebox terminal being used.\n IJBPaymentTerminal _terminal = directory.primaryTerminalOf(_split.projectId, token);\n\n // The project must have a terminal to send funds to.\n if (_terminal == IJBPaymentTerminal(address(0))) {\n // Set the net payout amount to 0 to signal the reversion.\n netPayoutAmount = 0;\n\n // Revert the payout.\n _revertTransferFrom(_projectId, address(0), 0, _amount);\n\n emit PayoutReverted(_projectId, _split, _amount, 'Terminal not found', msg.sender);\n } else {\n // This distribution is eligible for a fee since the funds are leaving this contract and the terminal isn't listed as feeless.\n if (\n _terminal != this &&\n _feeDiscount != JBConstants.MAX_FEE_DISCOUNT &&\n !isFeelessAddress[address(_terminal)]\n ) {\n unchecked {\n netPayoutAmount -= _feeAmount(_amount, _feePercent, _feeDiscount);\n }\n }\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_terminal), netPayoutAmount);\n\n // Add to balance if prefered.\n if (_split.preferAddToBalance)\n try\n _terminal.addToBalanceOf{value: token == JBTokens.ETH ? netPayoutAmount : 0}(\n _split.projectId,\n netPayoutAmount,\n token,\n '',\n // Send the projectId in the metadata as a referral.\n bytes(abi.encodePacked(_projectId))\n )\n {} catch (bytes memory _reason) {\n // Revert the payout.\n _revertTransferFrom(_projectId, address(_terminal), netPayoutAmount, _amount);\n\n // Set the net payout amount to 0 to signal the reversion.\n netPayoutAmount = 0;\n\n emit PayoutReverted(_projectId, _split, _amount, _reason, msg.sender);\n }\n else\n try\n _terminal.pay{value: token == JBTokens.ETH ? netPayoutAmount : 0}(\n _split.projectId,\n netPayoutAmount,\n token,\n _split.beneficiary != address(0) ? _split.beneficiary : msg.sender,\n 0,\n _split.preferClaimed,\n '',\n // Send the projectId in the metadata as a referral.\n bytes(abi.encodePacked(_projectId))\n )\n {} catch (bytes memory _reason) {\n // Revert the payout.\n _revertTransferFrom(_projectId, address(_terminal), netPayoutAmount, _amount);\n\n // Set the net payout amount to 0 to signal the reversion.\n netPayoutAmount = 0;\n\n emit PayoutReverted(_projectId, _split, _amount, _reason, msg.sender);\n }\n }\n } else {\n // This distribution is eligible for a fee since the funds are leaving this contract and the beneficiary isn't listed as feeless.\n // Don't enforce feeless address for the beneficiary since the funds are leaving the ecosystem.\n if (_feeDiscount != JBConstants.MAX_FEE_DISCOUNT) {\n unchecked {\n netPayoutAmount -= _feeAmount(_amount, _feePercent, _feeDiscount);\n }\n }\n\n // If there's a beneficiary, send the funds directly to the beneficiary. Otherwise send to the msg.sender.\n _transferFrom(\n address(this),\n _split.beneficiary != address(0) ? _split.beneficiary : payable(msg.sender),\n netPayoutAmount\n );\n }\n }\n\n /// @notice Takes a fee into the platform's project, which has an id of _FEE_BENEFICIARY_PROJECT_ID.\n /// @param _projectId The ID of the project having fees taken from.\n /// @param _shouldHoldFees If fees should be tracked and held back.\n /// @param _feePercent The percent of fees to take, out of MAX_FEE.\n /// @param _amount The amount of the fee to take, as a floating point number with 18 decimals.\n /// @param _beneficiary The address to mint the platforms tokens for.\n /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE.\n /// @return feeAmount The amount of the fee taken.\n function _takeFeeFrom(\n uint256 _projectId,\n bool _shouldHoldFees,\n uint256 _amount,\n uint256 _feePercent,\n address _beneficiary,\n uint256 _feeDiscount\n ) internal returns (uint256 feeAmount) {\n feeAmount = _feeAmount(_amount, _feePercent, _feeDiscount);\n\n if (_shouldHoldFees) {\n // Store the held fee.\n _heldFeesOf[_projectId].push(JBFee(_amount, uint32(fee), uint32(_feeDiscount), _beneficiary));\n\n emit HoldFee(_projectId, _amount, _feePercent, _feeDiscount, _beneficiary, msg.sender);\n } else {\n // Process the fee.\n _processFee(feeAmount, _beneficiary, _projectId); // Take the fee.\n\n emit ProcessFee(_projectId, feeAmount, false, _beneficiary, msg.sender);\n }\n }\n\n /// @notice Process a fee of the specified amount.\n /// @param _amount The fee amount, as a floating point number with 18 decimals.\n /// @param _beneficiary The address to mint the platform's tokens for.\n /// @param _from The project ID the fee is being paid from.\n function _processFee(uint256 _amount, address _beneficiary, uint256 _from) internal {\n // Get the terminal for the protocol project.\n IJBPaymentTerminal _terminal = directory.primaryTerminalOf(_FEE_BENEFICIARY_PROJECT_ID, token);\n\n // Trigger any inherited pre-transfer logic if funds will be transferred.\n if (address(_terminal) != address(this)) _beforeTransferTo(address(_terminal), _amount);\n\n try\n // Send the fee.\n // If this terminal's token is ETH, send it in msg.value.\n _terminal.pay{value: token == JBTokens.ETH ? _amount : 0}(\n _FEE_BENEFICIARY_PROJECT_ID,\n _amount,\n token,\n _beneficiary,\n 0,\n false,\n '',\n // Send the projectId in the metadata.\n bytes(abi.encodePacked(_from))\n )\n {} catch (bytes memory _reason) {\n _revertTransferFrom(\n _from,\n address(_terminal) != address(this) ? address(_terminal) : address(0),\n address(_terminal) != address(this) ? _amount : 0,\n _amount\n );\n emit FeeReverted(_from, _FEE_BENEFICIARY_PROJECT_ID, _amount, _reason, msg.sender);\n }\n }\n\n /// @notice Reverts an expected payout.\n /// @param _projectId The ID of the project having paying out.\n /// @param _expectedDestination The address the payout was expected to go to.\n /// @param _allowanceAmount The amount that the destination has been allowed to use.\n /// @param _depositAmount The amount of the payout as debited from the project's balance.\n function _revertTransferFrom(\n uint256 _projectId,\n address _expectedDestination,\n uint256 _allowanceAmount,\n uint256 _depositAmount\n ) internal {\n // Cancel allowance if needed.\n if (_allowanceAmount != 0) _cancelTransferTo(_expectedDestination, _allowanceAmount);\n\n // Add undistributed amount back to project's balance.\n IJBSingleTokenPaymentTerminalStore3_1_1(store).recordAddedBalanceFor(\n _projectId,\n _depositAmount\n );\n }\n\n /// @notice Contribute tokens to a project.\n /// @param _amount The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place.\n /// @param _payer The address making the payment.\n /// @param _projectId The ID of the project being paid.\n /// @param _beneficiary The address to mint tokens for and pass along to the funding cycle's data source and delegate.\n /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\n /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return beneficiaryTokenCount The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals.\n function _pay(\n uint256 _amount,\n address _payer,\n uint256 _projectId,\n address _beneficiary,\n uint256 _minReturnedTokens,\n bool _preferClaimedTokens,\n string memory _memo,\n bytes memory _metadata\n ) internal returns (uint256 beneficiaryTokenCount) {\n // Cant send tokens to the zero address.\n if (_beneficiary == address(0)) revert PAY_TO_ZERO_ADDRESS();\n\n // Define variables that will be needed outside the scoped section below.\n // Keep a reference to the funding cycle during which the payment is being made.\n JBFundingCycle memory _fundingCycle;\n\n // Scoped section prevents stack too deep. `_delegateAllocations` and `_tokenCount` only used within scope.\n {\n JBPayDelegateAllocation3_1_1[] memory _delegateAllocations;\n uint256 _tokenCount;\n\n // Bundle the amount info into a JBTokenAmount struct.\n JBTokenAmount memory _bundledAmount = JBTokenAmount(token, _amount, decimals, currency);\n\n // Record the payment.\n (\n _fundingCycle,\n _tokenCount,\n _delegateAllocations,\n _memo\n ) = IJBSingleTokenPaymentTerminalStore3_1_1(store).recordPaymentFrom(\n _payer,\n _bundledAmount,\n _projectId,\n baseWeightCurrency,\n _beneficiary,\n _memo,\n _metadata\n );\n\n // Mint the tokens if needed.\n if (_tokenCount != 0)\n // Set token count to be the number of tokens minted for the beneficiary instead of the total amount.\n beneficiaryTokenCount = IJBController(directory.controllerOf(_projectId)).mintTokensOf(\n _projectId,\n _tokenCount,\n _beneficiary,\n '',\n _preferClaimedTokens,\n true\n );\n\n // The token count for the beneficiary must be greater than or equal to the minimum expected.\n if (beneficiaryTokenCount < _minReturnedTokens) revert INADEQUATE_TOKEN_COUNT();\n\n // If delegate allocations were specified by the data source, fulfill them.\n if (_delegateAllocations.length != 0) {\n JBDidPayData3_1_1 memory _data = JBDidPayData3_1_1(\n _payer,\n _projectId,\n _fundingCycle.configuration,\n _bundledAmount,\n JBTokenAmount(token, 0, decimals, currency),\n beneficiaryTokenCount,\n _beneficiary,\n _preferClaimedTokens,\n _memo,\n bytes(''),\n _metadata\n );\n\n // Get a reference to the number of delegates to allocate to.\n uint256 _numDelegates = _delegateAllocations.length;\n\n // Keep a reference to the allocation.\n JBPayDelegateAllocation3_1_1 memory _delegateAllocation;\n\n for (uint256 _i; _i < _numDelegates; ) {\n // Get a reference to the delegate being iterated on.\n _delegateAllocation = _delegateAllocations[_i];\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_delegateAllocation.delegate), _delegateAllocation.amount);\n\n // Pass the correct token forwardedAmount to the delegate\n _data.forwardedAmount.value = _delegateAllocation.amount;\n\n // Pass the correct metadata from the data source.\n _data.dataSourceMetadata = _delegateAllocation.metadata;\n\n _delegateAllocation.delegate.didPay{\n value: token == JBTokens.ETH ? _delegateAllocation.amount : 0\n }(_data);\n\n emit DelegateDidPay(\n _delegateAllocation.delegate,\n _data,\n _delegateAllocation.amount,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n }\n\n emit Pay(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _payer,\n _beneficiary,\n _amount,\n beneficiaryTokenCount,\n _memo,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Receives funds belonging to the specified project.\n /// @param _projectId The ID of the project to which the funds received belong.\n /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\n /// @param _shouldRefundHeldFees A flag indicating if held fees should be refunded based on the amount being added.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the emitted event.\n function _addToBalanceOf(\n uint256 _projectId,\n uint256 _amount,\n bool _shouldRefundHeldFees,\n string memory _memo,\n bytes memory _metadata\n ) internal {\n // Refund any held fees to make sure the project doesn't pay double for funds going in and out of the protocol.\n uint256 _refundedFees = _shouldRefundHeldFees ? _refundHeldFees(_projectId, _amount) : 0;\n\n // Record the added funds with any refunded fees.\n IJBSingleTokenPaymentTerminalStore3_1_1(store).recordAddedBalanceFor(\n _projectId,\n _amount + _refundedFees\n );\n\n emit AddToBalance(_projectId, _amount, _refundedFees, _memo, _metadata, msg.sender);\n }\n\n /// @notice Refund fees based on the specified amount.\n /// @param _projectId The project for which fees are being refunded.\n /// @param _amount The amount to base the refund on, as a fixed point number with the same amount of decimals as this terminal.\n /// @return refundedFees How much fees were refunded, as a fixed point number with the same number of decimals as this terminal\n function _refundHeldFees(\n uint256 _projectId,\n uint256 _amount\n ) internal returns (uint256 refundedFees) {\n // Get a reference to the project's held fees.\n JBFee[] memory _heldFees = _heldFeesOf[_projectId];\n\n // Delete the current held fees.\n delete _heldFeesOf[_projectId];\n\n // Get a reference to the leftover amount once all fees have been settled.\n uint256 leftoverAmount = _amount;\n\n // Push length in stack\n uint256 _heldFeesLength = _heldFees.length;\n\n // Process each fee.\n for (uint256 _i; _i < _heldFeesLength; ) {\n if (leftoverAmount == 0) _heldFeesOf[_projectId].push(_heldFees[_i]);\n else if (leftoverAmount >= _heldFees[_i].amount) {\n unchecked {\n leftoverAmount = leftoverAmount - _heldFees[_i].amount;\n refundedFees += (\n _heldFees[_i].fee == 0 || _heldFees[_i].feeDiscount == JBConstants.MAX_FEE_DISCOUNT\n ? 0\n : _feeAmount(_heldFees[_i].amount, _heldFees[_i].fee, _heldFees[_i].feeDiscount)\n );\n }\n } else {\n unchecked {\n _heldFeesOf[_projectId].push(\n JBFee(\n _heldFees[_i].amount - leftoverAmount,\n _heldFees[_i].fee,\n _heldFees[_i].feeDiscount,\n _heldFees[_i].beneficiary\n )\n );\n refundedFees += (\n _heldFees[_i].fee == 0 || _heldFees[_i].feeDiscount == JBConstants.MAX_FEE_DISCOUNT\n ? 0\n : _feeAmount(leftoverAmount, _heldFees[_i].fee, _heldFees[_i].feeDiscount)\n );\n }\n leftoverAmount = 0;\n }\n\n unchecked {\n ++_i;\n }\n }\n\n emit RefundHeldFees(_projectId, _amount, refundedFees, leftoverAmount, msg.sender);\n }\n\n /// @notice Returns the fee amount based on the provided amount for the specified project.\n /// @param _amount The amount that the fee is based on, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _fee The percentage of the fee, out of MAX_FEE.\n /// @param _feeDiscount The percentage discount that should be applied out of the max amount, out of MAX_FEE_DISCOUNT.\n /// @return The amount of the fee, as a fixed point number with the same amount of decimals as this terminal.\n function _feeAmount(\n uint256 _amount,\n uint256 _fee,\n uint256 _feeDiscount\n ) internal pure returns (uint256) {\n // Calculate the discounted fee.\n uint256 _discountedFee = _fee -\n PRBMath.mulDiv(_fee, _feeDiscount, JBConstants.MAX_FEE_DISCOUNT);\n\n // The amount of tokens from the `_amount` to pay as a fee.\n return\n _amount - PRBMath.mulDiv(_amount, JBConstants.MAX_FEE, _discountedFee + JBConstants.MAX_FEE);\n }\n\n /// @notice Get the fee discount from the fee gauge for the specified project.\n /// @param _projectId The ID of the project to get a fee discount for.\n /// @param _feeType The type of fee the discount is being applied to.\n /// @return feeDiscount The fee discount, which should be interpreted as a percentage out MAX_FEE_DISCOUNT.\n function _currentFeeDiscount(\n uint256 _projectId,\n JBFeeType _feeType\n ) internal view returns (uint256) {\n // Can't take a fee if the protocol project doesn't have a terminal that accepts the token.\n if (\n directory.primaryTerminalOf(_FEE_BENEFICIARY_PROJECT_ID, token) ==\n IJBPaymentTerminal(address(0))\n ) return JBConstants.MAX_FEE_DISCOUNT;\n\n // Get the fee discount.\n if (feeGauge != address(0))\n // If the guage reverts, keep the discount at 0.\n try IJBFeeGauge3_1(feeGauge).currentDiscountFor(_projectId, _feeType) returns (\n uint256 discount\n ) {\n // If the fee discount is greater than the max, we ignore the return value\n if (discount <= JBConstants.MAX_FEE_DISCOUNT) return discount;\n } catch {\n return 0;\n }\n\n return 0;\n }\n}\n" + }, + "contracts/enums/JBFeeType.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nenum JBFeeType {\n PAYOUT,\n ALLOWANCE,\n REDEMPTION\n}\n" + }, + "contracts/interfaces/IJBPayoutRedemptionPaymentTerminal3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBFee} from './../structs/JBFee.sol';\nimport {JBDidRedeemData3_1_1} from './../structs/JBDidRedeemData3_1_1.sol';\nimport {JBDidPayData3_1_1} from './../structs/JBDidPayData3_1_1.sol';\nimport {IJBPayDelegate3_1_1} from './IJBPayDelegate3_1_1.sol';\nimport {IJBRedemptionDelegate3_1_1} from './IJBRedemptionDelegate3_1_1.sol';\n\ninterface IJBPayoutRedemptionPaymentTerminal3_1_1 {\n event DelegateDidRedeem(\n IJBRedemptionDelegate3_1_1 indexed delegate,\n JBDidRedeemData3_1_1 data,\n uint256 delegatedAmount,\n uint256 fee,\n address caller\n );\n\n event DelegateDidPay(\n IJBPayDelegate3_1_1 indexed delegate,\n JBDidPayData3_1_1 data,\n uint256 delegatedAmount,\n address caller\n );\n}\n" + }, + "contracts/interfaces/IJBFeeGauge3_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {JBFeeType} from './../enums/JBFeeType.sol';\n\ninterface IJBFeeGauge3_1 {\n function currentDiscountFor(uint256 projectId, JBFeeType feeType) external view returns (uint256);\n}\n" + }, + "contracts/JBETHPaymentTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Address} from '@openzeppelin/contracts/utils/Address.sol';\nimport {JBPayoutRedemptionPaymentTerminal} from './abstract/JBPayoutRedemptionPaymentTerminal.sol';\nimport {JBSplitsGroups} from './libraries/JBSplitsGroups.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {JBCurrencies} from './libraries/JBCurrencies.sol';\nimport {JBTokens} from './libraries/JBTokens.sol';\n\n/// @notice Manages all inflows and outflows of ETH funds into the protocol ecosystem.\ncontract JBETHPaymentTerminal is JBPayoutRedemptionPaymentTerminal {\n //*********************************************************************//\n // -------------------------- internal views ------------------------- //\n //*********************************************************************//\n\n /// @notice Checks the balance of tokens in this contract.\n /// @return The contract's balance, as a fixed point number with the same amount of decimals as this terminal.\n function _balance() internal view override returns (uint256) {\n return address(this).balance;\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _prices A contract that exposes price feeds.\n /// @param _store A contract that stores the terminal's data.\n /// @param _owner The address that will own this contract.\n constructor(\n uint256 _baseWeightCurrency,\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBSplitsStore _splitsStore,\n IJBPrices _prices,\n address _store,\n address _owner\n )\n JBPayoutRedemptionPaymentTerminal(\n JBTokens.ETH,\n 18, // 18 decimals.\n JBCurrencies.ETH,\n _baseWeightCurrency,\n JBSplitsGroups.ETH_PAYOUT,\n _operatorStore,\n _projects,\n _directory,\n _splitsStore,\n _prices,\n _store,\n _owner\n )\n // solhint-disable-next-line no-empty-blocks\n {\n\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Transfers tokens.\n /// @param _from The address from which the transfer should originate.\n /// @param _to The address to which the transfer should go.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _transferFrom(address _from, address payable _to, uint256 _amount) internal override {\n _from; // Prevents unused var compiler and natspec complaints.\n\n Address.sendValue(_to, _amount);\n }\n}\n" + }, + "contracts/abstract/JBPayoutRedemptionPaymentTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {IJBAllowanceTerminal} from './../interfaces/IJBAllowanceTerminal.sol';\nimport {IJBController} from './../interfaces/IJBController.sol';\nimport {IJBDirectory} from './../interfaces/IJBDirectory.sol';\nimport {IJBPayoutRedemptionPaymentTerminal} from './../interfaces/IJBPayoutRedemptionPaymentTerminal.sol';\nimport {IJBSplitAllocator} from './../interfaces/IJBSplitAllocator.sol';\nimport {IJBFeeGauge} from './../interfaces/IJBFeeGauge.sol';\nimport {IJBOperatable} from './../interfaces/IJBOperatable.sol';\nimport {IJBOperatorStore} from './../interfaces/IJBOperatorStore.sol';\nimport {IJBPaymentTerminal} from './../interfaces/IJBPaymentTerminal.sol';\nimport {IJBPayoutTerminal} from './../interfaces/IJBPayoutTerminal.sol';\nimport {IJBPrices} from './../interfaces/IJBPrices.sol';\nimport {IJBProjects} from './../interfaces/IJBProjects.sol';\nimport {IJBRedemptionTerminal} from './../interfaces/IJBRedemptionTerminal.sol';\nimport {IJBSingleTokenPaymentTerminalStore} from './../interfaces/IJBSingleTokenPaymentTerminalStore.sol';\nimport {IJBSplitsStore} from './../interfaces/IJBSplitsStore.sol';\nimport {JBConstants} from './../libraries/JBConstants.sol';\nimport {JBCurrencies} from './../libraries/JBCurrencies.sol';\nimport {JBFixedPointNumber} from './../libraries/JBFixedPointNumber.sol';\nimport {JBFundingCycleMetadataResolver} from './../libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBOperations} from './../libraries/JBOperations.sol';\nimport {JBTokens} from './../libraries/JBTokens.sol';\nimport {JBDidPayData} from './../structs/JBDidPayData.sol';\nimport {JBDidRedeemData} from './../structs/JBDidRedeemData.sol';\nimport {JBFee} from './../structs/JBFee.sol';\nimport {JBFundingCycle} from './../structs/JBFundingCycle.sol';\nimport {JBPayDelegateAllocation} from './../structs/JBPayDelegateAllocation.sol';\nimport {JBTokenAmount} from './../structs/JBTokenAmount.sol';\nimport {JBRedemptionDelegateAllocation} from './../structs/JBRedemptionDelegateAllocation.sol';\nimport {JBSplit} from './../structs/JBSplit.sol';\nimport {JBSplitAllocationData} from './../structs/JBSplitAllocationData.sol';\nimport {JBOperatable} from './JBOperatable.sol';\nimport {JBSingleTokenPaymentTerminal} from './JBSingleTokenPaymentTerminal.sol';\n\n/// @notice Generic terminal managing all inflows and outflows of funds into the protocol ecosystem.\n/// A project can transfer its funds, along with the power to reconfigure and mint/burn their tokens, from this contract to another allowed terminal of the same token type contract at any time.\nabstract contract JBPayoutRedemptionPaymentTerminal is\n JBSingleTokenPaymentTerminal,\n JBOperatable,\n Ownable,\n IJBPayoutRedemptionPaymentTerminal\n{\n // A library that parses the packed funding cycle metadata into a friendlier format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error FEE_TOO_HIGH();\n error INADEQUATE_DISTRIBUTION_AMOUNT();\n error INADEQUATE_RECLAIM_AMOUNT();\n error INADEQUATE_TOKEN_COUNT();\n error NO_MSG_VALUE_ALLOWED();\n error PAY_TO_ZERO_ADDRESS();\n error PROJECT_TERMINAL_MISMATCH();\n error REDEEM_TO_ZERO_ADDRESS();\n error TERMINAL_IN_SPLIT_ZERO_ADDRESS();\n error TERMINAL_TOKENS_INCOMPATIBLE();\n\n //*********************************************************************//\n // ---------------------------- modifiers ---------------------------- //\n //*********************************************************************//\n\n /// @notice A modifier that verifies this terminal is a terminal of provided project ID.\n modifier isTerminalOf(uint256 _projectId) {\n if (!directory.isTerminalOf(_projectId, this)) revert PROJECT_TERMINAL_MISMATCH();\n _;\n }\n\n //*********************************************************************//\n // --------------------- internal stored constants ------------------- //\n //*********************************************************************//\n\n /// @notice Maximum fee that can be set for a funding cycle configuration.\n /// @dev Out of MAX_FEE (50_000_000 / 1_000_000_000).\n uint256 internal constant _FEE_CAP = 50_000_000;\n\n /// @notice The fee beneficiary project ID is 1, as it should be the first project launched during the deployment process.\n uint256 internal constant _FEE_BENEFICIARY_PROJECT_ID = 1;\n\n //*********************************************************************//\n // --------------------- internal stored properties ------------------ //\n //*********************************************************************//\n\n /// @notice Fees that are being held to be processed later.\n /// @custom:param _projectId The ID of the project for which fees are being held.\n mapping(uint256 => JBFee[]) internal _heldFeesOf;\n\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice Mints ERC-721's that represent project ownership and transfers.\n IJBProjects public immutable override projects;\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n /// @notice The contract that stores splits for each project.\n IJBSplitsStore public immutable override splitsStore;\n\n /// @notice The contract that exposes price feeds.\n IJBPrices public immutable override prices;\n\n /// @notice The contract that stores and manages the terminal's data.\n address public immutable override store;\n\n /// @notice The currency to base token issuance on.\n /// @dev If this differs from `currency`, there must be a price feed available to convert `currency` to `baseWeightCurrency`.\n uint256 public immutable override baseWeightCurrency;\n\n /// @notice The group that payout splits coming from this terminal are identified by.\n uint256 public immutable override payoutSplitsGroup;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The platform fee percent.\n /// @dev Out of MAX_FEE (25_000_000 / 1_000_000_000)\n uint256 public override fee = 25_000_000; // 2.5%\n\n /// @notice The data source that returns a discount to apply to a project's fee.\n address public override feeGauge;\n\n /// @notice Addresses that can be paid towards from this terminal without incurring a fee.\n /// @dev Only addresses that are considered to be contained within the ecosystem can be feeless. Funds sent outside the ecosystem may incur fees despite being stored as feeless.\n /// @custom:param _address The address that can be paid toward.\n mapping(address => bool) public override isFeelessAddress;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Gets the current overflowed amount in this terminal for a specified project, in terms of ETH.\n /// @dev The current overflow is represented as a fixed point number with 18 decimals.\n /// @param _projectId The ID of the project to get overflow for.\n /// @return The current amount of ETH overflow that project has in this terminal, as a fixed point number with 18 decimals.\n function currentEthOverflowOf(\n uint256 _projectId\n ) external view virtual override returns (uint256) {\n // Get this terminal's current overflow.\n uint256 _overflow = IJBSingleTokenPaymentTerminalStore(store).currentOverflowOf(\n this,\n _projectId\n );\n\n // Adjust the decimals of the fixed point number if needed to have 18 decimals.\n uint256 _adjustedOverflow = (decimals == 18)\n ? _overflow\n : JBFixedPointNumber.adjustDecimals(_overflow, decimals, 18);\n\n // Return the amount converted to ETH.\n return\n (currency == JBCurrencies.ETH)\n ? _adjustedOverflow\n : PRBMath.mulDiv(\n _adjustedOverflow,\n 10 ** decimals,\n prices.priceFor(currency, JBCurrencies.ETH, decimals)\n );\n }\n\n /// @notice The fees that are currently being held to be processed later for each project.\n /// @param _projectId The ID of the project for which fees are being held.\n /// @return An array of fees that are being held.\n function heldFeesOf(uint256 _projectId) external view override returns (JBFee[] memory) {\n return _heldFeesOf[_projectId];\n }\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if the provided interface ID is supported.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(JBSingleTokenPaymentTerminal, IERC165) returns (bool) {\n return\n _interfaceId == type(IJBPayoutRedemptionPaymentTerminal).interfaceId ||\n _interfaceId == type(IJBPayoutTerminal).interfaceId ||\n _interfaceId == type(IJBAllowanceTerminal).interfaceId ||\n _interfaceId == type(IJBRedemptionTerminal).interfaceId ||\n _interfaceId == type(IJBOperatable).interfaceId ||\n super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // -------------------------- internal views ------------------------- //\n //*********************************************************************//\n\n /// @notice Checks the balance of tokens in this contract.\n /// @return The contract's balance.\n function _balance() internal view virtual returns (uint256);\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _token The token that this terminal manages.\n /// @param _decimals The number of decimals the token fixed point amounts are expected to have.\n /// @param _currency The currency that this terminal's token adheres to for price feeds.\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _payoutSplitsGroup The group that denotes payout splits from this terminal in the splits store.\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _prices A contract that exposes price feeds.\n /// @param _store A contract that stores the terminal's data.\n /// @param _owner The address that will own this contract.\n constructor(\n // payable constructor save the gas used to check msg.value==0\n address _token,\n uint256 _decimals,\n uint256 _currency,\n uint256 _baseWeightCurrency,\n uint256 _payoutSplitsGroup,\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBSplitsStore _splitsStore,\n IJBPrices _prices,\n address _store,\n address _owner\n )\n payable\n JBSingleTokenPaymentTerminal(_token, _decimals, _currency)\n JBOperatable(_operatorStore)\n {\n baseWeightCurrency = _baseWeightCurrency;\n payoutSplitsGroup = _payoutSplitsGroup;\n projects = _projects;\n directory = _directory;\n splitsStore = _splitsStore;\n prices = _prices;\n store = _store;\n\n transferOwnership(_owner);\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Contribute tokens to a project.\n /// @param _projectId The ID of the project being paid.\n /// @param _amount The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place.\n /// @param _token The token being paid. This terminal ignores this property since it only manages one token.\n /// @param _beneficiary The address to mint tokens for and pass along to the funding cycle's data source and delegate.\n /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\n /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals.\n function pay(\n uint256 _projectId,\n uint256 _amount,\n address _token,\n address _beneficiary,\n uint256 _minReturnedTokens,\n bool _preferClaimedTokens,\n string calldata _memo,\n bytes calldata _metadata\n ) external payable virtual override isTerminalOf(_projectId) returns (uint256) {\n _token; // Prevents unused var compiler and natspec complaints.\n\n // ETH shouldn't be sent if this terminal's token isn't ETH.\n if (token != JBTokens.ETH) {\n if (msg.value > 0) revert NO_MSG_VALUE_ALLOWED();\n\n // Get a reference to the balance before receiving tokens.\n uint256 _balanceBefore = _balance();\n\n // Transfer tokens to this terminal from the msg sender.\n _transferFrom(msg.sender, payable(address(this)), _amount);\n\n // The amount should reflect the change in balance.\n _amount = _balance() - _balanceBefore;\n }\n // If this terminal's token is ETH, override _amount with msg.value.\n else _amount = msg.value;\n\n return\n _pay(\n _amount,\n msg.sender,\n _projectId,\n _beneficiary,\n _minReturnedTokens,\n _preferClaimedTokens,\n _memo,\n _metadata\n );\n }\n\n /// @notice Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source.\n /// @dev Only a token holder or a designated operator can redeem its tokens.\n /// @param _holder The account to redeem tokens for.\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\n /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals.\n /// @param _token The token being reclaimed. This terminal ignores this property since it only manages one token.\n /// @param _minReturnedTokens The minimum amount of terminal tokens expected in return, as a fixed point number with the same amount of decimals as the terminal.\n /// @param _beneficiary The address to send the terminal tokens to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return reclaimAmount The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals.\n function redeemTokensOf(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n address _token,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo,\n bytes memory _metadata\n )\n external\n virtual\n override\n requirePermission(_holder, _projectId, JBOperations.REDEEM)\n returns (uint256 reclaimAmount)\n {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return\n _redeemTokensOf(\n _holder,\n _projectId,\n _tokenCount,\n _minReturnedTokens,\n _beneficiary,\n _memo,\n _metadata\n );\n }\n\n /// @notice Distributes payouts for a project with the distribution limit of its current funding cycle.\n /// @dev Payouts are sent to the preprogrammed splits. Any leftover is sent to the project's owner.\n /// @dev 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.\n /// @dev All funds distributed outside of this contract or any feeless terminals incure the protocol fee.\n /// @param _projectId The ID of the project having its payouts distributed.\n /// @param _amount The amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency.\n /// @param _token The token being distributed. This terminal ignores this property since it only manages one token.\n /// @param _minReturnedTokens 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.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return netLeftoverDistributionAmount The amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal.\n function distributePayoutsOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n address _token,\n uint256 _minReturnedTokens,\n string calldata _memo\n ) external virtual override returns (uint256 netLeftoverDistributionAmount) {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return _distributePayoutsOf(_projectId, _amount, _currency, _minReturnedTokens, _memo);\n }\n\n /// @notice Allows a project to send funds from its overflow up to the preconfigured allowance.\n /// @dev Only a project's owner or a designated operator can use its allowance.\n /// @dev Incurs the protocol fee.\n /// @param _projectId The ID of the project to use the allowance of.\n /// @param _amount The amount of terminal tokens to use from this project's current allowance, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's overflow allowance currency.\n /// @param _token The token being distributed. This terminal ignores this property since it only manages one token.\n /// @param _minReturnedTokens The minimum number of tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with 18 decimals.\n /// @param _beneficiary The address to send the funds to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return netDistributedAmount The amount of tokens that was distributed to the beneficiary, as a fixed point number with the same amount of decimals as the terminal.\n function useAllowanceOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n address _token,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.USE_ALLOWANCE)\n returns (uint256 netDistributedAmount)\n {\n _token; // Prevents unused var compiler and natspec complaints.\n\n return _useAllowanceOf(_projectId, _amount, _currency, _minReturnedTokens, _beneficiary, _memo);\n }\n\n /// @notice Allows a project owner to migrate its funds and operations to a new terminal that accepts the same token type.\n /// @dev Only a project's owner or a designated operator can migrate it.\n /// @param _projectId The ID of the project being migrated.\n /// @param _to The terminal contract that will gain the project's funds.\n /// @return balance The amount of funds that were migrated, as a fixed point number with the same amount of decimals as this terminal.\n function migrate(\n uint256 _projectId,\n IJBPaymentTerminal _to\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.MIGRATE_TERMINAL)\n returns (uint256 balance)\n {\n // The terminal being migrated to must accept the same token as this terminal.\n if (!_to.acceptsToken(token, _projectId)) revert TERMINAL_TOKENS_INCOMPATIBLE();\n\n // Record the migration in the store.\n balance = IJBSingleTokenPaymentTerminalStore(store).recordMigration(_projectId);\n\n // Transfer the balance if needed.\n if (balance > 0) {\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_to), balance);\n\n // If this terminal's token is ETH, send it in msg.value.\n uint256 _payableValue = token == JBTokens.ETH ? balance : 0;\n\n // Withdraw the balance to transfer to the new terminal;\n _to.addToBalanceOf{value: _payableValue}(_projectId, balance, token, '', bytes(''));\n }\n\n emit Migrate(_projectId, _to, balance, msg.sender);\n }\n\n /// @notice Receives funds belonging to the specified project.\n /// @param _projectId The ID of the project to which the funds received belong.\n /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\n /// @param _token The token being paid. This terminal ignores this property since it only manages one currency.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the emitted event.\n function addToBalanceOf(\n uint256 _projectId,\n uint256 _amount,\n address _token,\n string calldata _memo,\n bytes calldata _metadata\n ) external payable virtual override isTerminalOf(_projectId) {\n _token; // Prevents unused var compiler and natspec complaints.\n\n // If this terminal's token isn't ETH, make sure no msg.value was sent, then transfer the tokens in from msg.sender.\n if (token != JBTokens.ETH) {\n // Amount must be greater than 0.\n if (msg.value > 0) revert NO_MSG_VALUE_ALLOWED();\n\n // Get a reference to the balance before receiving tokens.\n uint256 _balanceBefore = _balance();\n\n // Transfer tokens to this terminal from the msg sender.\n _transferFrom(msg.sender, payable(address(this)), _amount);\n\n // The amount should reflect the change in balance.\n _amount = _balance() - _balanceBefore;\n }\n // If the terminal's token is ETH, override `_amount` with msg.value.\n else _amount = msg.value;\n\n // Add to balance while only refunding held fees if the funds aren't originating from a feeless terminal.\n _addToBalanceOf(_projectId, _amount, !isFeelessAddress[msg.sender], _memo, _metadata);\n }\n\n /// @notice Process any fees that are being held for the project.\n /// @dev Only a project owner, an operator, or the contract's owner can process held fees.\n /// @param _projectId The ID of the project whos held fees should be processed.\n function processFees(\n uint256 _projectId\n )\n external\n virtual\n override\n requirePermissionAllowingOverride(\n projects.ownerOf(_projectId),\n _projectId,\n JBOperations.PROCESS_FEES,\n msg.sender == owner()\n )\n {\n // Get a reference to the project's held fees.\n JBFee[] memory _heldFees = _heldFeesOf[_projectId];\n\n // Delete the held fees.\n delete _heldFeesOf[_projectId];\n\n // Push array length in stack\n uint256 _heldFeeLength = _heldFees.length;\n\n // Process each fee.\n for (uint256 _i; _i < _heldFeeLength; ) {\n // Get the fee amount.\n uint256 _amount = _feeAmount(\n _heldFees[_i].amount,\n _heldFees[_i].fee,\n _heldFees[_i].feeDiscount\n );\n\n // Process the fee.\n _processFee(_amount, _heldFees[_i].beneficiary);\n\n emit ProcessFee(_projectId, _amount, true, _heldFees[_i].beneficiary, msg.sender);\n\n unchecked {\n ++_i;\n }\n }\n }\n\n /// @notice Allows the fee to be updated.\n /// @dev Only the owner of this contract can change the fee.\n /// @param _fee The new fee, out of MAX_FEE.\n function setFee(uint256 _fee) external virtual override onlyOwner {\n // The provided fee must be within the max.\n if (_fee > _FEE_CAP) revert FEE_TOO_HIGH();\n\n // Store the new fee.\n fee = _fee;\n\n emit SetFee(_fee, msg.sender);\n }\n\n /// @notice Allows the fee gauge to be updated.\n /// @dev Only the owner of this contract can change the fee gauge.\n /// @param _feeGauge The new fee gauge.\n function setFeeGauge(address _feeGauge) external virtual override onlyOwner {\n // Store the new fee gauge.\n feeGauge = _feeGauge;\n\n emit SetFeeGauge(_feeGauge, msg.sender);\n }\n\n /// @notice Sets whether projects operating on this terminal can pay towards the specified address without incurring a fee.\n /// @dev Only the owner of this contract can set addresses as feeless.\n /// @param _address The address that can be paid towards while still bypassing fees.\n /// @param _flag A flag indicating whether the terminal should be feeless or not.\n function setFeelessAddress(address _address, bool _flag) external virtual override onlyOwner {\n // Set the flag value.\n isFeelessAddress[_address] = _flag;\n\n emit SetFeelessAddress(_address, _flag, msg.sender);\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Transfers tokens.\n /// @param _from The address from which the transfer should originate.\n /// @param _to The address to which the transfer should go.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _transferFrom(address _from, address payable _to, uint256 _amount) internal virtual {\n _from; // Prevents unused var compiler and natspec complaints.\n _to; // Prevents unused var compiler and natspec complaints.\n _amount; // Prevents unused var compiler and natspec complaints.\n }\n\n /// @notice Logic to be triggered before transferring tokens from this terminal.\n /// @param _to The address to which the transfer is going.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _beforeTransferTo(address _to, uint256 _amount) internal virtual {\n _to; // Prevents unused var compiler and natspec complaints.\n _amount; // Prevents unused var compiler and natspec complaints.\n }\n\n /// @notice Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source.\n /// @dev Only a token holder or a designated operator can redeem its tokens.\n /// @param _holder The account to redeem tokens for.\n /// @param _projectId The ID of the project to which the tokens being redeemed belong.\n /// @param _tokenCount The number of project tokens to redeem, as a fixed point number with 18 decimals.\n /// @param _minReturnedTokens The minimum amount of terminal tokens expected in return, as a fixed point number with the same amount of decimals as the terminal.\n /// @param _beneficiary The address to send the terminal tokens to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return reclaimAmount The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals.\n function _redeemTokensOf(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo,\n bytes memory _metadata\n ) internal returns (uint256 reclaimAmount) {\n // Can't send reclaimed funds to the zero address.\n if (_beneficiary == address(0)) revert REDEEM_TO_ZERO_ADDRESS();\n\n // Define variables that will be needed outside the scoped section below.\n // Keep a reference to the funding cycle during which the redemption is being made.\n JBFundingCycle memory _fundingCycle;\n\n // Scoped section prevents stack too deep. `_delegateAllocations` only used within scope.\n {\n JBRedemptionDelegateAllocation[] memory _delegateAllocations;\n\n // Record the redemption.\n (\n _fundingCycle,\n reclaimAmount,\n _delegateAllocations,\n _memo\n ) = IJBSingleTokenPaymentTerminalStore(store).recordRedemptionFor(\n _holder,\n _projectId,\n _tokenCount,\n _memo,\n _metadata\n );\n\n // The amount being reclaimed must be at least as much as was expected.\n if (reclaimAmount < _minReturnedTokens) revert INADEQUATE_RECLAIM_AMOUNT();\n\n // Burn the project tokens.\n if (_tokenCount > 0)\n IJBController(directory.controllerOf(_projectId)).burnTokensOf(\n _holder,\n _projectId,\n _tokenCount,\n '',\n false\n );\n\n // If delegate allocations were specified by the data source, fulfill them.\n if (_delegateAllocations.length != 0) {\n // Keep a reference to the token amount being forwarded to the delegate.\n JBTokenAmount memory _forwardedAmount = JBTokenAmount(token, 0, decimals, currency);\n\n JBDidRedeemData memory _data = JBDidRedeemData(\n _holder,\n _projectId,\n _fundingCycle.configuration,\n _tokenCount,\n JBTokenAmount(token, reclaimAmount, decimals, currency),\n _forwardedAmount,\n _beneficiary,\n _memo,\n _metadata\n );\n\n uint256 _numDelegates = _delegateAllocations.length;\n\n for (uint256 _i; _i < _numDelegates; ) {\n // Get a reference to the delegate being iterated on.\n JBRedemptionDelegateAllocation memory _delegateAllocation = _delegateAllocations[_i];\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_delegateAllocation.delegate), _delegateAllocation.amount);\n\n // Keep track of the msg.value to use in the delegate call\n uint256 _payableValue;\n\n // If this terminal's token is ETH, send it in msg.value.\n if (token == JBTokens.ETH) _payableValue = _delegateAllocation.amount;\n\n // Pass the correct token forwardedAmount to the delegate\n _data.forwardedAmount.value = _delegateAllocation.amount;\n\n _delegateAllocation.delegate.didRedeem{value: _payableValue}(_data);\n\n emit DelegateDidRedeem(\n _delegateAllocation.delegate,\n _data,\n _delegateAllocation.amount,\n msg.sender\n );\n unchecked {\n ++_i;\n }\n }\n }\n }\n\n // Send the reclaimed funds to the beneficiary.\n if (reclaimAmount > 0) _transferFrom(address(this), _beneficiary, reclaimAmount);\n\n emit RedeemTokens(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _holder,\n _beneficiary,\n _tokenCount,\n reclaimAmount,\n _memo,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Distributes payouts for a project with the distribution limit of its current funding cycle.\n /// @dev Payouts are sent to the preprogrammed splits. Any leftover is sent to the project's owner.\n /// @dev 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.\n /// @dev All funds distributed outside of this contract or any feeless terminals incure the protocol fee.\n /// @param _projectId The ID of the project having its payouts distributed.\n /// @param _amount The amount of terminal tokens to distribute, as a fixed point number with same number of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's distribution limit currency.\n /// @param _minReturnedTokens 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.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return netLeftoverDistributionAmount The amount that was sent to the project owner, as a fixed point number with the same amount of decimals as this terminal.\n function _distributePayoutsOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n uint256 _minReturnedTokens,\n string calldata _memo\n ) internal returns (uint256 netLeftoverDistributionAmount) {\n // Record the distribution.\n (\n JBFundingCycle memory _fundingCycle,\n uint256 _distributedAmount\n ) = IJBSingleTokenPaymentTerminalStore(store).recordDistributionFor(\n _projectId,\n _amount,\n _currency\n );\n\n // The amount being distributed must be at least as much as was expected.\n if (_distributedAmount < _minReturnedTokens) revert INADEQUATE_DISTRIBUTION_AMOUNT();\n\n // Get a reference to the project owner, which will receive tokens from paying the platform fee\n // and receive any extra distributable funds not allocated to payout splits.\n address payable _projectOwner = payable(projects.ownerOf(_projectId));\n\n // Define variables that will be needed outside the scoped section below.\n // Keep a reference to the fee amount that was paid.\n uint256 _fee;\n\n // Scoped section prevents stack too deep. `_feeDiscount`, `_feeEligibleDistributionAmount`, and `_leftoverDistributionAmount` only used within scope.\n {\n // Get the amount of discount that should be applied to any fees taken.\n // If the fee is zero, set the discount to 100% for convenience.\n uint256 _feeDiscount = fee == 0\n ? JBConstants.MAX_FEE_DISCOUNT\n : _currentFeeDiscount(_projectId);\n\n // The amount distributed that is eligible for incurring fees.\n uint256 _feeEligibleDistributionAmount;\n\n // The amount leftover after distributing to the splits.\n uint256 _leftoverDistributionAmount;\n\n // Payout to splits and get a reference to the leftover transfer amount after all splits have been paid.\n // Also get a reference to the amount that was distributed to splits from which fees should be taken.\n (_leftoverDistributionAmount, _feeEligibleDistributionAmount) = _distributeToPayoutSplitsOf(\n _projectId,\n _fundingCycle.configuration,\n payoutSplitsGroup,\n _distributedAmount,\n _feeDiscount\n );\n\n if (_feeDiscount != JBConstants.MAX_FEE_DISCOUNT) {\n // Leftover distribution amount is also eligible for a fee since the funds are going out of the ecosystem to _beneficiary.\n unchecked {\n _feeEligibleDistributionAmount += _leftoverDistributionAmount;\n }\n }\n\n // Take the fee.\n _fee = _feeEligibleDistributionAmount != 0\n ? _takeFeeFrom(\n _projectId,\n _fundingCycle,\n _feeEligibleDistributionAmount,\n _projectOwner,\n _feeDiscount\n )\n : 0;\n\n // Transfer any remaining balance to the project owner and update returned leftover accordingly.\n if (_leftoverDistributionAmount != 0) {\n // Subtract the fee from the net leftover amount.\n netLeftoverDistributionAmount =\n _leftoverDistributionAmount -\n _feeAmount(_leftoverDistributionAmount, fee, _feeDiscount);\n\n // Transfer the amount to the project owner.\n _transferFrom(address(this), _projectOwner, netLeftoverDistributionAmount);\n }\n }\n\n emit DistributePayouts(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _projectOwner,\n _amount,\n _distributedAmount,\n _fee,\n netLeftoverDistributionAmount,\n _memo,\n msg.sender\n );\n }\n\n /// @notice Allows a project to send funds from its overflow up to the preconfigured allowance.\n /// @dev Only a project's owner or a designated operator can use its allowance.\n /// @dev Incurs the protocol fee.\n /// @param _projectId The ID of the project to use the allowance of.\n /// @param _amount The amount of terminal tokens to use from this project's current allowance, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _currency The expected currency of the amount being distributed. Must match the project's current funding cycle's overflow allowance currency.\n /// @param _minReturnedTokens The minimum number of tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with 18 decimals.\n /// @param _beneficiary The address to send the funds to.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return netDistributedAmount The amount of tokens that was distributed to the beneficiary, as a fixed point number with the same amount of decimals as the terminal.\n function _useAllowanceOf(\n uint256 _projectId,\n uint256 _amount,\n uint256 _currency,\n uint256 _minReturnedTokens,\n address payable _beneficiary,\n string memory _memo\n ) internal returns (uint256 netDistributedAmount) {\n // Record the use of the allowance.\n (\n JBFundingCycle memory _fundingCycle,\n uint256 _distributedAmount\n ) = IJBSingleTokenPaymentTerminalStore(store).recordUsedAllowanceOf(\n _projectId,\n _amount,\n _currency\n );\n\n // The amount being withdrawn must be at least as much as was expected.\n if (_distributedAmount < _minReturnedTokens) revert INADEQUATE_DISTRIBUTION_AMOUNT();\n\n // Scoped section prevents stack too deep. `_fee`, `_projectOwner`, `_feeDiscount`, and `_netAmount` only used within scope.\n {\n // Keep a reference to the fee amount that was paid.\n uint256 _fee;\n\n // Get a reference to the project owner, which will receive tokens from paying the platform fee.\n address _projectOwner = projects.ownerOf(_projectId);\n\n // Get the amount of discount that should be applied to any fees taken.\n // 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.\n uint256 _feeDiscount = fee == 0 || isFeelessAddress[msg.sender]\n ? JBConstants.MAX_FEE_DISCOUNT\n : _currentFeeDiscount(_projectId);\n\n // Take a fee from the `_distributedAmount`, if needed.\n _fee = _feeDiscount == JBConstants.MAX_FEE_DISCOUNT\n ? 0\n : _takeFeeFrom(_projectId, _fundingCycle, _distributedAmount, _projectOwner, _feeDiscount);\n\n unchecked {\n // The net amount is the withdrawn amount without the fee.\n netDistributedAmount = _distributedAmount - _fee;\n }\n\n // Transfer any remaining balance to the beneficiary.\n if (netDistributedAmount > 0)\n _transferFrom(address(this), _beneficiary, netDistributedAmount);\n }\n\n emit UseAllowance(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _beneficiary,\n _amount,\n _distributedAmount,\n netDistributedAmount,\n _memo,\n msg.sender\n );\n }\n\n /// @notice Pays out splits for a project's funding cycle configuration.\n /// @param _projectId The ID of the project for which payout splits are being distributed.\n /// @param _domain The domain of the splits to distribute the payout between.\n /// @param _group The group of the splits to distribute the payout between.\n /// @param _amount The total amount being distributed, as a fixed point number with the same number of decimals as this terminal.\n /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE.\n /// @return leftoverAmount If the leftover amount if the splits don't add up to 100%.\n /// @return feeEligibleDistributionAmount The total amount of distributions that are eligible to have fees taken from.\n function _distributeToPayoutSplitsOf(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group,\n uint256 _amount,\n uint256 _feeDiscount\n ) internal returns (uint256 leftoverAmount, uint256 feeEligibleDistributionAmount) {\n // Set the leftover amount to the initial amount.\n leftoverAmount = _amount;\n // The total percentage available to split\n uint256 leftoverPercentage = JBConstants.SPLITS_TOTAL_PERCENT;\n\n // Get a reference to the project's payout splits.\n JBSplit[] memory _splits = splitsStore.splitsOf(_projectId, _domain, _group);\n\n // Transfer between all splits.\n for (uint256 _i; _i < _splits.length; ) {\n // Get a reference to the split being iterated on.\n JBSplit memory _split = _splits[_i];\n\n // The amount to send towards the split.\n uint256 _payoutAmount = _split.percent == leftoverPercentage\n ? leftoverAmount\n : PRBMath.mulDiv(_amount, _split.percent, JBConstants.SPLITS_TOTAL_PERCENT);\n\n // Decrement the leftover percentage.\n leftoverPercentage -= _split.percent;\n\n // The payout amount substracting any applicable incurred fees.\n uint256 _netPayoutAmount;\n\n if (_payoutAmount > 0) {\n // Transfer tokens to the split.\n // If there's an allocator set, transfer to its `allocate` function.\n if (_split.allocator != IJBSplitAllocator(address(0))) {\n // If the split allocator is set as feeless, this distribution is not eligible for a fee.\n if (\n _feeDiscount == JBConstants.MAX_FEE_DISCOUNT ||\n isFeelessAddress[address(_split.allocator)]\n )\n _netPayoutAmount = _payoutAmount;\n // This distribution is eligible for a fee since the funds are leaving this contract and the allocator isn't listed as feeless.\n else {\n unchecked {\n _netPayoutAmount = _payoutAmount - _feeAmount(_payoutAmount, fee, _feeDiscount);\n }\n\n // This distribution is eligible for a fee since the funds are leaving the ecosystem.\n feeEligibleDistributionAmount += _payoutAmount;\n }\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_split.allocator), _netPayoutAmount);\n\n // Create the data to send to the allocator.\n JBSplitAllocationData memory _data = JBSplitAllocationData(\n token,\n _netPayoutAmount,\n decimals,\n _projectId,\n _group,\n _split\n );\n\n // Trigger the allocator's `allocate` function.\n // If this terminal's token is ETH, send it in msg.value.\n _split.allocator.allocate{value: token == JBTokens.ETH ? _netPayoutAmount : 0}(_data);\n\n // Otherwise, if a project is specified, make a payment to it.\n } else if (_split.projectId != 0) {\n // Get a reference to the Juicebox terminal being used.\n IJBPaymentTerminal _terminal = directory.primaryTerminalOf(_split.projectId, token);\n\n // The project must have a terminal to send funds to.\n if (_terminal == IJBPaymentTerminal(address(0))) revert TERMINAL_IN_SPLIT_ZERO_ADDRESS();\n\n // Save gas if this contract is being used as the terminal.\n if (_terminal == this) {\n // This distribution does not incur a fee.\n _netPayoutAmount = _payoutAmount;\n\n // Send the projectId in the metadata.\n bytes memory _projectMetadata = new bytes(32);\n _projectMetadata = bytes(abi.encodePacked(_projectId));\n\n // Add to balance if prefered.\n if (_split.preferAddToBalance)\n _addToBalanceOf(_split.projectId, _netPayoutAmount, false, '', _projectMetadata);\n else\n _pay(\n _netPayoutAmount,\n address(this),\n _split.projectId,\n (_split.beneficiary != address(0)) ? _split.beneficiary : msg.sender,\n 0,\n _split.preferClaimed,\n '',\n _projectMetadata\n );\n } else {\n // If the terminal is set as feeless, this distribution is not eligible for a fee.\n if (\n _feeDiscount == JBConstants.MAX_FEE_DISCOUNT || isFeelessAddress[address(_terminal)]\n )\n _netPayoutAmount = _payoutAmount;\n // This distribution is eligible for a fee since the funds are leaving this contract and the terminal isn't listed as feeless.\n else {\n unchecked {\n _netPayoutAmount = _payoutAmount - _feeAmount(_payoutAmount, fee, _feeDiscount);\n }\n\n feeEligibleDistributionAmount += _payoutAmount;\n }\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_terminal), _netPayoutAmount);\n\n // If this terminal's token is ETH, send it in msg.value.\n uint256 _payableValue = token == JBTokens.ETH ? _netPayoutAmount : 0;\n\n // Send the projectId in the metadata.\n bytes memory _projectMetadata = new bytes(32);\n _projectMetadata = bytes(abi.encodePacked(_projectId));\n\n // Add to balance if prefered.\n if (_split.preferAddToBalance)\n _terminal.addToBalanceOf{value: _payableValue}(\n _split.projectId,\n _netPayoutAmount,\n token,\n '',\n _projectMetadata\n );\n else\n _terminal.pay{value: _payableValue}(\n _split.projectId,\n _netPayoutAmount,\n token,\n _split.beneficiary != address(0) ? _split.beneficiary : msg.sender,\n 0,\n _split.preferClaimed,\n '',\n _projectMetadata\n );\n }\n } else {\n // Keep a reference to the beneficiary.\n address payable _beneficiary = _split.beneficiary != address(0)\n ? _split.beneficiary\n : payable(msg.sender);\n\n // If there's a full discount, this distribution is not eligible for a fee.\n // Don't enforce feeless address for the beneficiary since the funds are leaving the ecosystem.\n if (_feeDiscount == JBConstants.MAX_FEE_DISCOUNT)\n _netPayoutAmount = _payoutAmount;\n // This distribution is eligible for a fee since the funds are leaving this contract and the beneficiary isn't listed as feeless.\n else {\n unchecked {\n _netPayoutAmount = _payoutAmount - _feeAmount(_payoutAmount, fee, _feeDiscount);\n }\n\n feeEligibleDistributionAmount += _payoutAmount;\n }\n\n // If there's a beneficiary, send the funds directly to the beneficiary. Otherwise send to the msg.sender.\n _transferFrom(address(this), _beneficiary, _netPayoutAmount);\n }\n\n // Subtract from the amount to be sent to the beneficiary.\n unchecked {\n leftoverAmount = leftoverAmount - _payoutAmount;\n }\n }\n\n emit DistributeToPayoutSplit(\n _projectId,\n _domain,\n _group,\n _split,\n _netPayoutAmount,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n\n /// @notice Takes a fee into the platform's project, which has an id of _FEE_BENEFICIARY_PROJECT_ID.\n /// @param _projectId The ID of the project having fees taken from.\n /// @param _fundingCycle The funding cycle during which the fee is being taken.\n /// @param _amount The amount of the fee to take, as a floating point number with 18 decimals.\n /// @param _beneficiary The address to mint the platforms tokens for.\n /// @param _feeDiscount The amount of discount to apply to the fee, out of the MAX_FEE.\n /// @return feeAmount The amount of the fee taken.\n function _takeFeeFrom(\n uint256 _projectId,\n JBFundingCycle memory _fundingCycle,\n uint256 _amount,\n address _beneficiary,\n uint256 _feeDiscount\n ) internal returns (uint256 feeAmount) {\n feeAmount = _feeAmount(_amount, fee, _feeDiscount);\n\n if (_fundingCycle.shouldHoldFees()) {\n // Store the held fee.\n _heldFeesOf[_projectId].push(JBFee(_amount, uint32(fee), uint32(_feeDiscount), _beneficiary));\n\n emit HoldFee(_projectId, _amount, fee, _feeDiscount, _beneficiary, msg.sender);\n } else {\n // Process the fee.\n _processFee(feeAmount, _beneficiary); // Take the fee.\n\n emit ProcessFee(_projectId, feeAmount, false, _beneficiary, msg.sender);\n }\n }\n\n /// @notice Process a fee of the specified amount.\n /// @param _amount The fee amount, as a floating point number with 18 decimals.\n /// @param _beneficiary The address to mint the platform's tokens for.\n function _processFee(uint256 _amount, address _beneficiary) internal {\n // Get the terminal for the protocol project.\n IJBPaymentTerminal _terminal = directory.primaryTerminalOf(_FEE_BENEFICIARY_PROJECT_ID, token);\n\n // When processing the admin fee, save gas if the admin is using this contract as its terminal.\n if (_terminal == this)\n _pay(\n _amount,\n address(this),\n _FEE_BENEFICIARY_PROJECT_ID,\n _beneficiary,\n 0,\n false,\n '',\n bytes('')\n ); // Use the local pay call.\n else {\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_terminal), _amount);\n\n // If this terminal's token is ETH, send it in msg.value.\n uint256 _payableValue = token == JBTokens.ETH ? _amount : 0;\n\n // Send the payment.\n _terminal.pay{value: _payableValue}(\n _FEE_BENEFICIARY_PROJECT_ID,\n _amount,\n token,\n _beneficiary,\n 0,\n false,\n '',\n bytes('')\n ); // Use the external pay call of the correct terminal.\n }\n }\n\n /// @notice Contribute tokens to a project.\n /// @param _amount The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place.\n /// @param _payer The address making the payment.\n /// @param _projectId The ID of the project being paid.\n /// @param _beneficiary The address to mint tokens for and pass along to the funding cycle's data source and delegate.\n /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas.\n /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate.\n /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided.\n /// @return beneficiaryTokenCount The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals.\n function _pay(\n uint256 _amount,\n address _payer,\n uint256 _projectId,\n address _beneficiary,\n uint256 _minReturnedTokens,\n bool _preferClaimedTokens,\n string memory _memo,\n bytes memory _metadata\n ) internal returns (uint256 beneficiaryTokenCount) {\n // Cant send tokens to the zero address.\n if (_beneficiary == address(0)) revert PAY_TO_ZERO_ADDRESS();\n\n // Define variables that will be needed outside the scoped section below.\n // Keep a reference to the funding cycle during which the payment is being made.\n JBFundingCycle memory _fundingCycle;\n\n // Scoped section prevents stack too deep. `_delegateAllocations` and `_tokenCount` only used within scope.\n {\n JBPayDelegateAllocation[] memory _delegateAllocations;\n uint256 _tokenCount;\n\n // Bundle the amount info into a JBTokenAmount struct.\n JBTokenAmount memory _bundledAmount = JBTokenAmount(token, _amount, decimals, currency);\n\n // Record the payment.\n (\n _fundingCycle,\n _tokenCount,\n _delegateAllocations,\n _memo\n ) = IJBSingleTokenPaymentTerminalStore(store).recordPaymentFrom(\n _payer,\n _bundledAmount,\n _projectId,\n baseWeightCurrency,\n _beneficiary,\n _memo,\n _metadata\n );\n\n // Mint the tokens if needed.\n if (_tokenCount > 0)\n // Set token count to be the number of tokens minted for the beneficiary instead of the total amount.\n beneficiaryTokenCount = IJBController(directory.controllerOf(_projectId)).mintTokensOf(\n _projectId,\n _tokenCount,\n _beneficiary,\n '',\n _preferClaimedTokens,\n true\n );\n\n // The token count for the beneficiary must be greater than or equal to the minimum expected.\n if (beneficiaryTokenCount < _minReturnedTokens) revert INADEQUATE_TOKEN_COUNT();\n\n // If delegate allocations were specified by the data source, fulfill them.\n if (_delegateAllocations.length != 0) {\n // Keep a reference to the token amount being forwarded to the delegate.\n JBTokenAmount memory _forwardedAmount = JBTokenAmount(token, _amount, decimals, currency);\n\n JBDidPayData memory _data = JBDidPayData(\n _payer,\n _projectId,\n _fundingCycle.configuration,\n _bundledAmount,\n _forwardedAmount,\n beneficiaryTokenCount,\n _beneficiary,\n _preferClaimedTokens,\n _memo,\n _metadata\n );\n\n // Get a reference to the number of delegates to allocate to.\n uint256 _numDelegates = _delegateAllocations.length;\n\n for (uint256 _i; _i < _numDelegates; ) {\n // Get a reference to the delegate being iterated on.\n JBPayDelegateAllocation memory _delegateAllocation = _delegateAllocations[_i];\n\n // Trigger any inherited pre-transfer logic.\n _beforeTransferTo(address(_delegateAllocation.delegate), _delegateAllocation.amount);\n\n // Keep track of the msg.value to use in the delegate call\n uint256 _payableValue;\n\n // If this terminal's token is ETH, send it in msg.value.\n if (token == JBTokens.ETH) _payableValue = _delegateAllocation.amount;\n\n // Pass the correct token forwardedAmount to the delegate\n _data.forwardedAmount.value = _delegateAllocation.amount;\n\n _delegateAllocation.delegate.didPay{value: _payableValue}(_data);\n\n emit DelegateDidPay(\n _delegateAllocation.delegate,\n _data,\n _delegateAllocation.amount,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n }\n\n emit Pay(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _payer,\n _beneficiary,\n _amount,\n beneficiaryTokenCount,\n _memo,\n _metadata,\n msg.sender\n );\n }\n\n /// @notice Receives funds belonging to the specified project.\n /// @param _projectId The ID of the project to which the funds received belong.\n /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead.\n /// @param _shouldRefundHeldFees A flag indicating if held fees should be refunded based on the amount being added.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _metadata Extra data to pass along to the emitted event.\n function _addToBalanceOf(\n uint256 _projectId,\n uint256 _amount,\n bool _shouldRefundHeldFees,\n string memory _memo,\n bytes memory _metadata\n ) internal {\n // Refund any held fees to make sure the project doesn't pay double for funds going in and out of the protocol.\n uint256 _refundedFees = _shouldRefundHeldFees ? _refundHeldFees(_projectId, _amount) : 0;\n\n // Record the added funds with any refunded fees.\n IJBSingleTokenPaymentTerminalStore(store).recordAddedBalanceFor(\n _projectId,\n _amount + _refundedFees\n );\n\n emit AddToBalance(_projectId, _amount, _refundedFees, _memo, _metadata, msg.sender);\n }\n\n /// @notice Refund fees based on the specified amount.\n /// @param _projectId The project for which fees are being refunded.\n /// @param _amount The amount to base the refund on, as a fixed point number with the same amount of decimals as this terminal.\n /// @return refundedFees How much fees were refunded, as a fixed point number with the same number of decimals as this terminal\n function _refundHeldFees(\n uint256 _projectId,\n uint256 _amount\n ) internal returns (uint256 refundedFees) {\n // Get a reference to the project's held fees.\n JBFee[] memory _heldFees = _heldFeesOf[_projectId];\n\n // Delete the current held fees.\n delete _heldFeesOf[_projectId];\n\n // Get a reference to the leftover amount once all fees have been settled.\n uint256 leftoverAmount = _amount;\n\n // Push length in stack\n uint256 _heldFeesLength = _heldFees.length;\n\n // Process each fee.\n for (uint256 _i; _i < _heldFeesLength; ) {\n if (leftoverAmount == 0) _heldFeesOf[_projectId].push(_heldFees[_i]);\n else if (leftoverAmount >= _heldFees[_i].amount) {\n unchecked {\n leftoverAmount = leftoverAmount - _heldFees[_i].amount;\n refundedFees += _feeAmount(\n _heldFees[_i].amount,\n _heldFees[_i].fee,\n _heldFees[_i].feeDiscount\n );\n }\n } else {\n unchecked {\n _heldFeesOf[_projectId].push(\n JBFee(\n _heldFees[_i].amount - leftoverAmount,\n _heldFees[_i].fee,\n _heldFees[_i].feeDiscount,\n _heldFees[_i].beneficiary\n )\n );\n refundedFees += _feeAmount(leftoverAmount, _heldFees[_i].fee, _heldFees[_i].feeDiscount);\n }\n leftoverAmount = 0;\n }\n\n unchecked {\n ++_i;\n }\n }\n\n emit RefundHeldFees(_projectId, _amount, refundedFees, leftoverAmount, msg.sender);\n }\n\n /// @notice Returns the fee amount based on the provided amount for the specified project.\n /// @param _amount The amount that the fee is based on, as a fixed point number with the same amount of decimals as this terminal.\n /// @param _fee The percentage of the fee, out of MAX_FEE.\n /// @param _feeDiscount The percentage discount that should be applied out of the max amount, out of MAX_FEE_DISCOUNT.\n /// @return The amount of the fee, as a fixed point number with the same amount of decimals as this terminal.\n function _feeAmount(\n uint256 _amount,\n uint256 _fee,\n uint256 _feeDiscount\n ) internal pure returns (uint256) {\n // Calculate the discounted fee.\n uint256 _discountedFee = _fee -\n PRBMath.mulDiv(_fee, _feeDiscount, JBConstants.MAX_FEE_DISCOUNT);\n\n // The amount of tokens from the `_amount` to pay as a fee.\n return\n _amount - PRBMath.mulDiv(_amount, JBConstants.MAX_FEE, _discountedFee + JBConstants.MAX_FEE);\n }\n\n /// @notice Get the fee discount from the fee gauge for the specified project.\n /// @param _projectId The ID of the project to get a fee discount for.\n /// @return feeDiscount The fee discount, which should be interpreted as a percentage out MAX_FEE_DISCOUNT.\n function _currentFeeDiscount(uint256 _projectId) internal view returns (uint256) {\n // Can't take a fee if the protocol project doesn't have a terminal that accepts the token.\n if (\n directory.primaryTerminalOf(_FEE_BENEFICIARY_PROJECT_ID, token) ==\n IJBPaymentTerminal(address(0))\n ) return JBConstants.MAX_FEE_DISCOUNT;\n\n // Get the fee discount.\n if (feeGauge != address(0))\n // If the guage reverts, keep the discount at 0.\n try IJBFeeGauge(feeGauge).currentDiscountFor(_projectId) returns (uint256 discount) {\n // If the fee discount is greater than the max, we ignore the return value\n if (discount <= JBConstants.MAX_FEE_DISCOUNT) return discount;\n } catch {\n return 0;\n }\n\n return 0;\n }\n}\n" + }, + "contracts/JBERC20PaymentTerminal3_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';\nimport {IERC20Metadata} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol';\nimport {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';\nimport {JBPayoutRedemptionPaymentTerminal3_1} from './abstract/JBPayoutRedemptionPaymentTerminal3_1.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\n\n/// @notice Manages the inflows and outflows of an ERC-20 token.\ncontract JBERC20PaymentTerminal3_1 is JBPayoutRedemptionPaymentTerminal3_1 {\n using SafeERC20 for IERC20;\n\n //*********************************************************************//\n // -------------------------- internal views ------------------------- //\n //*********************************************************************//\n\n /// @notice Checks the balance of tokens in this contract.\n /// @return The contract's balance, as a fixed point number with the same amount of decimals as this terminal.\n function _balance() internal view override returns (uint256) {\n return IERC20(token).balanceOf(address(this));\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _token The token that this terminal manages.\n /// @param _currency The currency that this terminal's token adheres to for price feeds.\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _payoutSplitsGroup The group that denotes payout splits from this terminal in the splits store.\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _prices A contract that exposes price feeds.\n /// @param _store A contract that stores the terminal's data.\n /// @param _owner The address that will own this contract.\n constructor(\n IERC20Metadata _token,\n uint256 _currency,\n uint256 _baseWeightCurrency,\n uint256 _payoutSplitsGroup,\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBSplitsStore _splitsStore,\n IJBPrices _prices,\n address _store,\n address _owner\n )\n JBPayoutRedemptionPaymentTerminal3_1(\n address(_token),\n _token.decimals(),\n _currency,\n _baseWeightCurrency,\n _payoutSplitsGroup,\n _operatorStore,\n _projects,\n _directory,\n _splitsStore,\n _prices,\n _store,\n _owner\n )\n // solhint-disable-next-line no-empty-blocks\n {\n\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Transfers tokens.\n /// @param _from The address from which the transfer should originate.\n /// @param _to The address to which the transfer should go.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _transferFrom(address _from, address payable _to, uint256 _amount) internal override {\n _from == address(this)\n ? IERC20(token).safeTransfer(_to, _amount)\n : IERC20(token).safeTransferFrom(_from, _to, _amount);\n }\n\n /// @notice Logic to be triggered before transferring tokens from this terminal.\n /// @param _to The address to which the transfer is going.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _beforeTransferTo(address _to, uint256 _amount) internal override {\n IERC20(token).safeIncreaseAllowance(_to, _amount);\n }\n\n /// @notice Logic to be triggered if a transfer should be undone\n /// @param _to The address to which the transfer went.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _cancelTransferTo(address _to, uint256 _amount) internal override {\n IERC20(token).safeDecreaseAllowance(_to, _amount);\n }\n}\n" + }, + "contracts/JBPrices.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {IJBPriceFeed} from './interfaces/IJBPriceFeed.sol';\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\n\n/// @notice Manages and normalizes price feeds.\ncontract JBPrices is Ownable, IJBPrices {\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error PRICE_FEED_ALREADY_EXISTS();\n error PRICE_FEED_NOT_FOUND();\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The available price feeds.\n /// @dev The feed returns the number of `_currency` units that can be converted to 1 `_base` unit.\n /// @custom:param _currency The currency units the feed's resulting price is in terms of.\n /// @custom:param _base The base currency unit being priced by the feed.\n mapping(uint256 => mapping(uint256 => IJBPriceFeed)) public override feedFor;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Gets the number of `_currency` units that can be converted to 1 `_base` unit.\n /// @param _currency The currency units the resulting price is in terms of.\n /// @param _base The base currency unit being priced.\n /// @param _decimals The number of decimals the returned fixed point price should include.\n /// @return The price of the currency in terms of the base, as a fixed point number with the specified number of decimals.\n function priceFor(\n uint256 _currency,\n uint256 _base,\n uint256 _decimals\n ) external view override returns (uint256) {\n // If the currency is the base, return 1 since they are priced the same. Include the desired number of decimals.\n if (_currency == _base) return 10 ** _decimals;\n\n // Get a reference to the feed.\n IJBPriceFeed _feed = feedFor[_currency][_base];\n\n // If it exists, return the price.\n if (_feed != IJBPriceFeed(address(0))) return _feed.currentPrice(_decimals);\n\n // Get the inverse feed.\n _feed = feedFor[_base][_currency];\n\n // If it exists, return the inverse price.\n if (_feed != IJBPriceFeed(address(0)))\n return PRBMath.mulDiv(10 ** _decimals, 10 ** _decimals, _feed.currentPrice(_decimals));\n\n // No price feed available, revert.\n revert PRICE_FEED_NOT_FOUND();\n }\n\n //*********************************************************************//\n // ---------------------------- constructor -------------------------- //\n //*********************************************************************//\n\n /// @param _owner The address that will own the contract.\n constructor(address _owner) {\n // Transfer the ownership.\n transferOwnership(_owner);\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Add a price feed for a currency in terms of the provided base currency.\n /// @dev Current feeds can't be modified.\n /// @param _currency The currency units the feed's resulting price is in terms of.\n /// @param _base The base currency unit being priced by the feed.\n /// @param _feed The price feed being added.\n function addFeedFor(\n uint256 _currency,\n uint256 _base,\n IJBPriceFeed _feed\n ) external override onlyOwner {\n // There can't already be a feed for the specified currency.\n if (\n feedFor[_currency][_base] != IJBPriceFeed(address(0)) ||\n feedFor[_base][_currency] != IJBPriceFeed(address(0))\n ) revert PRICE_FEED_ALREADY_EXISTS();\n\n // Store the feed.\n feedFor[_currency][_base] = _feed;\n\n emit AddFeed(_currency, _base, _feed);\n }\n}\n" + }, + "contracts/JBChainlinkV3PriceFeed.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {AggregatorV3Interface} from '@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol';\nimport {IJBPriceFeed} from './interfaces/IJBPriceFeed.sol';\nimport {JBFixedPointNumber} from './libraries/JBFixedPointNumber.sol';\n\n/// @notice A generalized price feed for the Chainlink AggregatorV3Interface.\ncontract JBChainlinkV3PriceFeed is IJBPriceFeed {\n // A library that provides utility for fixed point numbers.\n using JBFixedPointNumber for uint256;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error STALE_PRICE();\n error INCOMPLETE_ROUND();\n error NEGATIVE_PRICE();\n\n //*********************************************************************//\n // ---------------- public stored immutable properties --------------- //\n //*********************************************************************//\n\n /// @notice The feed that prices are reported from.\n AggregatorV3Interface public immutable feed;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Gets the current price from the feed, normalized to the specified number of decimals.\n /// @param _decimals The number of decimals the returned fixed point price should include.\n /// @return The current price of the feed, as a fixed point number with the specified number of decimals.\n function currentPrice(uint256 _decimals) external view override returns (uint256) {\n // Get the latest round information.\n (uint80 roundId, int256 _price, , uint256 updatedAt, uint80 answeredInRound) = feed\n .latestRoundData();\n\n // Make sure the price isn't stale.\n if (answeredInRound < roundId) revert STALE_PRICE();\n\n // Make sure the round is finished.\n if (updatedAt == 0) revert INCOMPLETE_ROUND();\n\n // Make sure the price is positive.\n if (_price < 0) revert NEGATIVE_PRICE();\n\n // Get a reference to the number of decimals the feed uses.\n uint256 _feedDecimals = feed.decimals();\n\n // Return the price, adjusted to the target decimals.\n return uint256(_price).adjustDecimals(_feedDecimals, _decimals);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _feed The feed to report prices from.\n constructor(AggregatorV3Interface _feed) {\n feed = _feed;\n }\n}\n" + }, + "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface AggregatorV3Interface {\n\n function decimals()\n external\n view\n returns (\n uint8\n );\n\n function description()\n external\n view\n returns (\n string memory\n );\n\n function version()\n external\n view\n returns (\n uint256\n );\n\n // getRoundData and latestRoundData should both raise \"No data present\"\n // if they do not have data to report, instead of returning unset values\n // which could be misinterpreted as actual reported values.\n function getRoundData(\n uint80 _roundId\n )\n external\n view\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n );\n\n function latestRoundData()\n external\n view\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n );\n\n}\n" + }, + "contracts/JBERC20PaymentTerminal3_1_1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';\nimport {IERC20Metadata} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol';\nimport {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';\nimport {JBPayoutRedemptionPaymentTerminal3_1_1} from './abstract/JBPayoutRedemptionPaymentTerminal3_1_1.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\n\n/// @notice Manages the inflows and outflows of an ERC-20 token.\ncontract JBERC20PaymentTerminal3_1_1 is JBPayoutRedemptionPaymentTerminal3_1_1 {\n using SafeERC20 for IERC20;\n\n //*********************************************************************//\n // -------------------------- internal views ------------------------- //\n //*********************************************************************//\n\n /// @notice Checks the balance of tokens in this contract.\n /// @return The contract's balance, as a fixed point number with the same amount of decimals as this terminal.\n function _balance() internal view override returns (uint256) {\n return IERC20(token).balanceOf(address(this));\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _token The token that this terminal manages.\n /// @param _currency The currency that this terminal's token adheres to for price feeds.\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _payoutSplitsGroup The group that denotes payout splits from this terminal in the splits store.\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _prices A contract that exposes price feeds.\n /// @param _store A contract that stores the terminal's data.\n /// @param _owner The address that will own this contract.\n constructor(\n IERC20Metadata _token,\n uint256 _currency,\n uint256 _baseWeightCurrency,\n uint256 _payoutSplitsGroup,\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBSplitsStore _splitsStore,\n IJBPrices _prices,\n address _store,\n address _owner\n )\n JBPayoutRedemptionPaymentTerminal3_1_1(\n address(_token),\n _token.decimals(),\n _currency,\n _baseWeightCurrency,\n _payoutSplitsGroup,\n _operatorStore,\n _projects,\n _directory,\n _splitsStore,\n _prices,\n _store,\n _owner\n )\n // solhint-disable-next-line no-empty-blocks\n {\n\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Transfers tokens.\n /// @param _from The address from which the transfer should originate.\n /// @param _to The address to which the transfer should go.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _transferFrom(address _from, address payable _to, uint256 _amount) internal override {\n _from == address(this)\n ? IERC20(token).safeTransfer(_to, _amount)\n : IERC20(token).safeTransferFrom(_from, _to, _amount);\n }\n\n /// @notice Logic to be triggered before transferring tokens from this terminal.\n /// @param _to The address to which the transfer is going.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _beforeTransferTo(address _to, uint256 _amount) internal override {\n IERC20(token).safeIncreaseAllowance(_to, _amount);\n }\n\n /// @notice Logic to be triggered if a transfer should be undone\n /// @param _to The address to which the transfer went.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _cancelTransferTo(address _to, uint256 _amount) internal override {\n IERC20(token).safeDecreaseAllowance(_to, _amount);\n }\n}\n" + }, + "contracts/JBERC20PaymentTerminal.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';\nimport {IERC20Metadata} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol';\nimport {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';\nimport {JBPayoutRedemptionPaymentTerminal} from './abstract/JBPayoutRedemptionPaymentTerminal.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {IJBPrices} from './interfaces/IJBPrices.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\n\n/// @notice Manages the inflows and outflows of an ERC-20 token.\ncontract JBERC20PaymentTerminal is JBPayoutRedemptionPaymentTerminal {\n using SafeERC20 for IERC20;\n\n //*********************************************************************//\n // -------------------------- internal views ------------------------- //\n //*********************************************************************//\n\n /// @notice Checks the balance of tokens in this contract.\n /// @return The contract's balance, as a fixed point number with the same amount of decimals as this terminal.\n function _balance() internal view override returns (uint256) {\n return IERC20(token).balanceOf(address(this));\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _token The token that this terminal manages.\n /// @param _currency The currency that this terminal's token adheres to for price feeds.\n /// @param _baseWeightCurrency The currency to base token issuance on.\n /// @param _payoutSplitsGroup The group that denotes payout splits from this terminal in the splits store.\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _splitsStore A contract that stores splits for each project.\n /// @param _prices A contract that exposes price feeds.\n /// @param _store A contract that stores the terminal's data.\n /// @param _owner The address that will own this contract.\n constructor(\n IERC20Metadata _token,\n uint256 _currency,\n uint256 _baseWeightCurrency,\n uint256 _payoutSplitsGroup,\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBSplitsStore _splitsStore,\n IJBPrices _prices,\n address _store,\n address _owner\n )\n JBPayoutRedemptionPaymentTerminal(\n address(_token),\n _token.decimals(),\n _currency,\n _baseWeightCurrency,\n _payoutSplitsGroup,\n _operatorStore,\n _projects,\n _directory,\n _splitsStore,\n _prices,\n _store,\n _owner\n )\n // solhint-disable-next-line no-empty-blocks\n {\n\n }\n\n //*********************************************************************//\n // ---------------------- internal transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Transfers tokens.\n /// @param _from The address from which the transfer should originate.\n /// @param _to The address to which the transfer should go.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _transferFrom(address _from, address payable _to, uint256 _amount) internal override {\n _from == address(this)\n ? IERC20(token).safeTransfer(_to, _amount)\n : IERC20(token).safeTransferFrom(_from, _to, _amount);\n }\n\n /// @notice Logic to be triggered before transferring tokens from this terminal.\n /// @param _to The address to which the transfer is going.\n /// @param _amount The amount of the transfer, as a fixed point number with the same number of decimals as this terminal.\n function _beforeTransferTo(address _to, uint256 _amount) internal override {\n IERC20(token).safeApprove(_to, _amount);\n }\n}\n" + }, + "contracts/JBFundingCycleStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {JBControllerUtility} from './abstract/JBControllerUtility.sol';\nimport {JBBallotState} from './enums/JBBallotState.sol';\nimport {JBConstants} from './libraries/JBConstants.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBFundingCycleBallot} from './interfaces/IJBFundingCycleBallot.sol';\nimport {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\nimport {JBFundingCycleData} from './structs/JBFundingCycleData.sol';\n\n/// @notice Manages funding cycle configurations and scheduling.\ncontract JBFundingCycleStore is JBControllerUtility, IJBFundingCycleStore {\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error INVALID_BALLOT();\n error INVALID_DISCOUNT_RATE();\n error INVALID_DURATION();\n error INVALID_TIMEFRAME();\n error INVALID_WEIGHT();\n error NO_SAME_BLOCK_RECONFIGURATION();\n\n //*********************************************************************//\n // --------------------- private stored properties ------------------- //\n //*********************************************************************//\n\n /// @notice Stores the user defined properties of each funding cycle, packed into one storage slot.\n /// @custom:param _projectId The ID of the project to get properties of.\n /// @custom:param _configuration The funding cycle configuration to get properties of.\n mapping(uint256 => mapping(uint256 => uint256)) private _packedUserPropertiesOf;\n\n /// @notice Stores the properties added by the mechanism to manage and schedule each funding cycle, packed into one storage slot.\n /// @custom:param _projectId The ID of the project to get instrinsic properties of.\n /// @custom:param _configuration The funding cycle configuration to get properties of.\n mapping(uint256 => mapping(uint256 => uint256)) private _packedIntrinsicPropertiesOf;\n\n /// @notice Stores the metadata for each funding cycle configuration, packed into one storage slot.\n /// @custom:param _projectId The ID of the project to get metadata of.\n /// @custom:param _configuration The funding cycle configuration to get metadata of.\n mapping(uint256 => mapping(uint256 => uint256)) private _metadataOf;\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The latest funding cycle configuration for each project.\n /// @custom:param _projectId The ID of the project to get the latest funding cycle configuration of.\n mapping(uint256 => uint256) public override latestConfigurationOf;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Get the funding cycle with the given configuration for the specified project.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @param _configuration The configuration of the funding cycle to get.\n /// @return fundingCycle The funding cycle.\n function get(\n uint256 _projectId,\n uint256 _configuration\n ) external view override returns (JBFundingCycle memory fundingCycle) {\n return _getStructFor(_projectId, _configuration);\n }\n\n /// @notice The latest funding cycle to be configured for the specified project, and its current ballot state.\n /// @param _projectId The ID of the project to get the latest configured funding cycle of.\n /// @return fundingCycle The project's queued funding cycle.\n /// @return ballotState The state of the ballot for the reconfiguration.\n function latestConfiguredOf(\n uint256 _projectId\n ) external view override returns (JBFundingCycle memory fundingCycle, JBBallotState ballotState) {\n // Get a reference to the latest funding cycle configuration.\n uint256 _fundingCycleConfiguration = latestConfigurationOf[_projectId];\n\n // Resolve the funding cycle for the latest configuration.\n fundingCycle = _getStructFor(_projectId, _fundingCycleConfiguration);\n\n // Resolve the ballot state.\n ballotState = _ballotStateOf(\n _projectId,\n fundingCycle.configuration,\n fundingCycle.start,\n fundingCycle.basedOn\n );\n }\n\n /// @notice The funding cycle that's next up for the specified project.\n /// @dev If a queued funding cycle of the project is not found, returns an empty funding cycle with all properties set to 0.\n /// @param _projectId The ID of the project to get the queued funding cycle of.\n /// @return fundingCycle The project's queued funding cycle.\n function queuedOf(\n uint256 _projectId\n ) external view override returns (JBFundingCycle memory fundingCycle) {\n // If the project does not have a funding cycle, return an empty struct.\n if (latestConfigurationOf[_projectId] == 0) return _getStructFor(0, 0);\n\n // Get a reference to the configuration of the standby funding cycle.\n uint256 _standbyFundingCycleConfiguration = _standbyOf(_projectId);\n\n // If it exists, return its funding cycle if it is approved.\n if (_standbyFundingCycleConfiguration > 0) {\n fundingCycle = _getStructFor(_projectId, _standbyFundingCycleConfiguration);\n\n if (_isApproved(_projectId, fundingCycle)) return fundingCycle;\n\n // Resolve the funding cycle for the latest configured funding cycle.\n fundingCycle = _getStructFor(_projectId, fundingCycle.basedOn);\n } else {\n // Resolve the funding cycle for the latest configured funding cycle.\n fundingCycle = _getStructFor(_projectId, latestConfigurationOf[_projectId]);\n\n // If the latest funding cycle starts in the future, it must start in the distant future\n // since its not in standby. In this case base the queued cycles on the base cycle.\n if (fundingCycle.start > block.timestamp)\n fundingCycle = _getStructFor(_projectId, fundingCycle.basedOn);\n }\n\n // There's no queued if the current has a duration of 0.\n if (fundingCycle.duration == 0) return _getStructFor(0, 0);\n\n // Check to see if this funding cycle's ballot is approved.\n // If so, return a funding cycle based on it.\n if (_isApproved(_projectId, fundingCycle)) return _mockFundingCycleBasedOn(fundingCycle, false);\n\n // Get the funding cycle of its base funding cycle, which carries the last approved configuration.\n fundingCycle = _getStructFor(_projectId, fundingCycle.basedOn);\n\n // There's no queued if the base, which must still be the current, has a duration of 0.\n if (fundingCycle.duration == 0) return _getStructFor(0, 0);\n\n // Return a mock of the next up funding cycle.\n return _mockFundingCycleBasedOn(fundingCycle, false);\n }\n\n /// @notice The funding cycle that is currently active for the specified project.\n /// @dev If a current funding cycle of the project is not found, returns an empty funding cycle with all properties set to 0.\n /// @param _projectId The ID of the project to get the current funding cycle of.\n /// @return fundingCycle The project's current funding cycle.\n function currentOf(\n uint256 _projectId\n ) external view override returns (JBFundingCycle memory fundingCycle) {\n // If the project does not have a funding cycle, return an empty struct.\n if (latestConfigurationOf[_projectId] == 0) return _getStructFor(0, 0);\n\n // Get a reference to the configuration of the eligible funding cycle.\n uint256 _fundingCycleConfiguration = _eligibleOf(_projectId);\n\n // Keep a reference to the eligible funding cycle.\n JBFundingCycle memory _fundingCycle;\n\n // If an eligible funding cycle exists...\n if (_fundingCycleConfiguration > 0) {\n // Resolve the funding cycle for the eligible configuration.\n _fundingCycle = _getStructFor(_projectId, _fundingCycleConfiguration);\n\n // Check to see if this funding cycle's ballot is approved.\n // If so, return it.\n if (_isApproved(_projectId, _fundingCycle)) return _fundingCycle;\n\n // If it hasn't been approved, set the funding cycle configuration to be the configuration of the funding cycle that it's based on,\n // which carries the last approved configuration.\n _fundingCycleConfiguration = _fundingCycle.basedOn;\n } else {\n // No upcoming funding cycle found that is eligible to become active,\n // so use the last configuration.\n _fundingCycleConfiguration = latestConfigurationOf[_projectId];\n\n // Get the funding cycle for the latest ID.\n _fundingCycle = _getStructFor(_projectId, _fundingCycleConfiguration);\n\n // If it's not approved or if it hasn't yet started, get a reference to the funding cycle that the latest is based on, which has the latest approved configuration.\n if (!_isApproved(_projectId, _fundingCycle) || block.timestamp < _fundingCycle.start)\n _fundingCycleConfiguration = _fundingCycle.basedOn;\n }\n\n // If there is not funding cycle to base the current one on, there can't be a current one.\n if (_fundingCycleConfiguration == 0) return _getStructFor(0, 0);\n\n // The funding cycle to base a current one on.\n _fundingCycle = _getStructFor(_projectId, _fundingCycleConfiguration);\n\n // If the base has no duration, it's still the current one.\n if (_fundingCycle.duration == 0) return _fundingCycle;\n\n // Return a mock of the current funding cycle.\n return _mockFundingCycleBasedOn(_fundingCycle, true);\n }\n\n /// @notice The current ballot state of the project.\n /// @param _projectId The ID of the project to check the ballot state of.\n /// @return The project's current ballot's state.\n function currentBallotStateOf(uint256 _projectId) external view override returns (JBBallotState) {\n // Get a reference to the latest funding cycle configuration.\n uint256 _fundingCycleConfiguration = latestConfigurationOf[_projectId];\n\n // Resolve the funding cycle for the latest configuration.\n JBFundingCycle memory _fundingCycle = _getStructFor(_projectId, _fundingCycleConfiguration);\n\n return\n _ballotStateOf(\n _projectId,\n _fundingCycle.configuration,\n _fundingCycle.start,\n _fundingCycle.basedOn\n );\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n // solhint-disable-next-line no-empty-blocks\n constructor(IJBDirectory _directory) JBControllerUtility(_directory) {}\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Configures the next eligible funding cycle for the specified project.\n /// @dev Only a project's current controller can configure its funding cycles.\n /// @param _projectId The ID of the project being configured.\n /// @param _data The funding cycle configuration data.\n /// @param _metadata Arbitrary extra data to associate with this funding cycle configuration that's not used within.\n /// @param _mustStartAtOrAfter The time before which the initialized funding cycle cannot start.\n /// @return The funding cycle that the configuration will take effect during.\n function configureFor(\n uint256 _projectId,\n JBFundingCycleData calldata _data,\n uint256 _metadata,\n uint256 _mustStartAtOrAfter\n ) external override onlyController(_projectId) returns (JBFundingCycle memory) {\n // Duration must fit in a uint32.\n if (_data.duration > type(uint32).max) revert INVALID_DURATION();\n\n // Discount rate must be less than or equal to 100%.\n if (_data.discountRate > JBConstants.MAX_DISCOUNT_RATE) revert INVALID_DISCOUNT_RATE();\n\n // Weight must fit into a uint88.\n if (_data.weight > type(uint88).max) revert INVALID_WEIGHT();\n\n // If the start date is in the past, set it to be the current timestamp.\n if (_mustStartAtOrAfter < block.timestamp) _mustStartAtOrAfter = block.timestamp;\n\n // Make sure the min start date fits in a uint56, and that the start date of an upcoming cycle also starts within the max.\n if (_mustStartAtOrAfter + _data.duration > type(uint56).max) revert INVALID_TIMEFRAME();\n\n // Ballot should be a valid contract, supporting the correct interface\n if (_data.ballot != IJBFundingCycleBallot(address(0))) {\n address _ballot = address(_data.ballot);\n\n // No contract at the address ?\n if (_ballot.code.length == 0) revert INVALID_BALLOT();\n\n // Make sure the ballot supports the expected interface.\n try _data.ballot.supportsInterface(type(IJBFundingCycleBallot).interfaceId) returns (\n bool _supports\n ) {\n if (!_supports) revert INVALID_BALLOT(); // Contract exists at the address but with the wrong interface\n } catch {\n revert INVALID_BALLOT(); // No ERC165 support\n }\n }\n\n // The configuration timestamp is now.\n uint256 _configuration = block.timestamp;\n\n // Set up a reconfiguration by configuring intrinsic properties.\n _configureIntrinsicPropertiesFor(_projectId, _configuration, _data.weight, _mustStartAtOrAfter);\n\n // Efficiently stores a funding cycles provided user defined properties.\n // If all user config properties are zero, no need to store anything as the default value will have the same outcome.\n if (\n _data.ballot != IJBFundingCycleBallot(address(0)) ||\n _data.duration > 0 ||\n _data.discountRate > 0\n ) {\n // ballot in bits 0-159 bytes.\n uint256 packed = uint160(address(_data.ballot));\n\n // duration in bits 160-191 bytes.\n packed |= _data.duration << 160;\n\n // discountRate in bits 192-223 bytes.\n packed |= _data.discountRate << 192;\n\n // Set in storage.\n _packedUserPropertiesOf[_projectId][_configuration] = packed;\n }\n\n // Set the metadata if needed.\n if (_metadata > 0) _metadataOf[_projectId][_configuration] = _metadata;\n\n emit Configure(_configuration, _projectId, _data, _metadata, _mustStartAtOrAfter, msg.sender);\n\n // Return the funding cycle for the new configuration.\n return _getStructFor(_projectId, _configuration);\n }\n\n //*********************************************************************//\n // --------------------- private helper functions -------------------- //\n //*********************************************************************//\n\n /// @notice Updates the configurable funding cycle for this project if it exists, otherwise creates one.\n /// @param _projectId The ID of the project to find a configurable funding cycle for.\n /// @param _configuration The time at which the funding cycle was configured.\n /// @param _weight The weight to store in the configured funding cycle.\n /// @param _mustStartAtOrAfter The time before which the initialized funding cycle can't start.\n function _configureIntrinsicPropertiesFor(\n uint256 _projectId,\n uint256 _configuration,\n uint256 _weight,\n uint256 _mustStartAtOrAfter\n ) private {\n // If there's not yet a funding cycle for the project, initialize one.\n if (latestConfigurationOf[_projectId] == 0)\n // Use an empty funding cycle as the base.\n return\n _initFor(_projectId, _getStructFor(0, 0), _configuration, _mustStartAtOrAfter, _weight);\n\n // Get the active funding cycle's configuration.\n uint256 _currentConfiguration = _eligibleOf(_projectId);\n\n // If an eligible funding cycle does not exist, get a reference to the latest funding cycle configuration for the project.\n if (_currentConfiguration == 0)\n // Get the latest funding cycle's configuration.\n _currentConfiguration = latestConfigurationOf[_projectId];\n\n // Get a reference to the funding cycle.\n JBFundingCycle memory _baseFundingCycle = _getStructFor(_projectId, _currentConfiguration);\n\n if (!_isApproved(_projectId, _baseFundingCycle) || block.timestamp < _baseFundingCycle.start)\n // If it hasn't been approved or hasn't yet started, set the ID to be the funding cycle it's based on,\n // which carries the latest approved configuration.\n _baseFundingCycle = _getStructFor(_projectId, _baseFundingCycle.basedOn);\n\n // The configuration can't be the same as the base configuration.\n if (_baseFundingCycle.configuration == _configuration) revert NO_SAME_BLOCK_RECONFIGURATION();\n\n // The time after the ballot of the provided funding cycle has expired.\n // If the provided funding cycle has no ballot, return the current timestamp.\n uint256 _timestampAfterBallot = _baseFundingCycle.ballot == IJBFundingCycleBallot(address(0))\n ? 0\n : _configuration + _baseFundingCycle.ballot.duration();\n\n _initFor(\n _projectId,\n _baseFundingCycle,\n _configuration,\n // Can only start after the ballot.\n _timestampAfterBallot > _mustStartAtOrAfter ? _timestampAfterBallot : _mustStartAtOrAfter,\n _weight\n );\n }\n\n /// @notice Initializes a funding cycle with the specified properties.\n /// @param _projectId The ID of the project to which the funding cycle being initialized belongs.\n /// @param _baseFundingCycle The funding cycle to base the initialized one on.\n /// @param _configuration The configuration of the funding cycle being initialized.\n /// @param _mustStartAtOrAfter The time before which the initialized funding cycle cannot start.\n /// @param _weight The weight to give the newly initialized funding cycle.\n function _initFor(\n uint256 _projectId,\n JBFundingCycle memory _baseFundingCycle,\n uint256 _configuration,\n uint256 _mustStartAtOrAfter,\n uint256 _weight\n ) private {\n // If there is no base, initialize a first cycle.\n if (_baseFundingCycle.number == 0) {\n // The first number is 1.\n uint256 _number = 1;\n\n // Set fresh intrinsic properties.\n _packAndStoreIntrinsicPropertiesOf(\n _configuration,\n _projectId,\n _number,\n _weight,\n _baseFundingCycle.configuration,\n _mustStartAtOrAfter\n );\n } else {\n // Derive the correct next start time from the base.\n uint256 _start = _deriveStartFrom(_baseFundingCycle, _mustStartAtOrAfter);\n\n // A weight of 1 is treated as a weight of 0.\n // This is to allow a weight of 0 (default) to represent inheriting the discounted weight of the previous funding cycle.\n _weight = _weight > 0\n ? (_weight == 1 ? 0 : _weight)\n : _deriveWeightFrom(_baseFundingCycle, _start);\n\n // Derive the correct number.\n uint256 _number = _deriveNumberFrom(_baseFundingCycle, _start);\n\n // Update the intrinsic properties.\n _packAndStoreIntrinsicPropertiesOf(\n _configuration,\n _projectId,\n _number,\n _weight,\n _baseFundingCycle.configuration,\n _start\n );\n }\n\n // Set the project's latest funding cycle configuration.\n latestConfigurationOf[_projectId] = _configuration;\n\n emit Init(_configuration, _projectId, _baseFundingCycle.configuration);\n }\n\n /// @notice Efficiently stores a funding cycle's provided intrinsic properties.\n /// @param _configuration The configuration of the funding cycle to pack and store.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @param _number The number of the funding cycle.\n /// @param _weight The weight of the funding cycle.\n /// @param _basedOn The configuration of the base funding cycle.\n /// @param _start The start time of this funding cycle.\n function _packAndStoreIntrinsicPropertiesOf(\n uint256 _configuration,\n uint256 _projectId,\n uint256 _number,\n uint256 _weight,\n uint256 _basedOn,\n uint256 _start\n ) private {\n // weight in bits 0-87.\n uint256 packed = _weight;\n\n // basedOn in bits 88-143.\n packed |= _basedOn << 88;\n\n // start in bits 144-199.\n packed |= _start << 144;\n\n // number in bits 200-255.\n packed |= _number << 200;\n\n // Store the packed value.\n _packedIntrinsicPropertiesOf[_projectId][_configuration] = packed;\n }\n\n /// @notice The project's stored funding cycle that hasn't yet started and should be used next, if one exists.\n /// @dev A value of 0 is returned if no funding cycle was found.\n /// @dev Assumes the project has a latest configuration.\n /// @param _projectId The ID of a project to look through for a standby cycle.\n /// @return configuration The configuration of the standby funding cycle if one exists, or 0 if one doesn't exist.\n function _standbyOf(uint256 _projectId) private view returns (uint256 configuration) {\n // Get a reference to the project's latest funding cycle.\n configuration = latestConfigurationOf[_projectId];\n\n // Get the necessary properties for the latest funding cycle.\n JBFundingCycle memory _fundingCycle = _getStructFor(_projectId, configuration);\n\n // There is no upcoming funding cycle if the latest funding cycle has already started.\n if (block.timestamp >= _fundingCycle.start) return 0;\n\n // If this is the first funding cycle, it is queued.\n if (_fundingCycle.number == 1) return configuration;\n\n // Get the necessary properties for the base funding cycle.\n JBFundingCycle memory _baseFundingCycle = _getStructFor(_projectId, _fundingCycle.basedOn);\n\n // If the latest configuration doesn't start until after another base cycle, return 0.\n if (\n _baseFundingCycle.duration > 0 &&\n block.timestamp < _fundingCycle.start - _baseFundingCycle.duration\n ) return 0;\n }\n\n /// @notice The project's stored funding cycle that has started and hasn't yet expired.\n /// @dev A value of 0 is returned if no funding cycle was found.\n /// @dev Assumes the project has a latest configuration.\n /// @param _projectId The ID of the project to look through.\n /// @return configuration The configuration of an eligible funding cycle if one exists, or 0 if one doesn't exist.\n function _eligibleOf(uint256 _projectId) private view returns (uint256 configuration) {\n // Get a reference to the project's latest funding cycle.\n configuration = latestConfigurationOf[_projectId];\n\n // Get the latest funding cycle.\n JBFundingCycle memory _fundingCycle = _getStructFor(_projectId, configuration);\n\n // If the latest is expired, return an empty funding cycle.\n // A duration of 0 cannot be expired.\n if (\n _fundingCycle.duration > 0 && block.timestamp >= _fundingCycle.start + _fundingCycle.duration\n ) return 0;\n\n // Return the funding cycle's configuration if it has started.\n if (block.timestamp >= _fundingCycle.start) return _fundingCycle.configuration;\n\n // Get a reference to the cycle's base configuration.\n JBFundingCycle memory _baseFundingCycle = _getStructFor(_projectId, _fundingCycle.basedOn);\n\n // If the base cycle isn't eligible, the project has no eligible cycle.\n // A duration of 0 is always eligible.\n if (\n _baseFundingCycle.duration > 0 &&\n block.timestamp >= _baseFundingCycle.start + _baseFundingCycle.duration\n ) return 0;\n\n // Return the configuration that the latest funding cycle is based on.\n configuration = _fundingCycle.basedOn;\n }\n\n /// @notice A view of the funding cycle that would be created based on the provided one if the project doesn't make a reconfiguration.\n /// @dev Returns an empty funding cycle if there can't be a mock funding cycle based on the provided one.\n /// @dev Assumes a funding cycle with a duration of 0 will never be asked to be the base of a mock.\n /// @param _baseFundingCycle The funding cycle that the resulting funding cycle should follow.\n /// @param _allowMidCycle A flag indicating if the mocked funding cycle is allowed to already be mid cycle.\n /// @return A mock of what the next funding cycle will be.\n function _mockFundingCycleBasedOn(\n JBFundingCycle memory _baseFundingCycle,\n bool _allowMidCycle\n ) private view returns (JBFundingCycle memory) {\n // Get the distance of the current time to the start of the next possible funding cycle.\n // If the returned mock cycle must not yet have started, the start time of the mock must be in the future.\n uint256 _mustStartAtOrAfter = !_allowMidCycle\n ? block.timestamp + 1\n : block.timestamp - _baseFundingCycle.duration + 1;\n\n // Derive what the start time should be.\n uint256 _start = _deriveStartFrom(_baseFundingCycle, _mustStartAtOrAfter);\n\n // Derive what the number should be.\n uint256 _number = _deriveNumberFrom(_baseFundingCycle, _start);\n\n return\n JBFundingCycle(\n _number,\n _baseFundingCycle.configuration,\n _baseFundingCycle.basedOn,\n _start,\n _baseFundingCycle.duration,\n _deriveWeightFrom(_baseFundingCycle, _start),\n _baseFundingCycle.discountRate,\n _baseFundingCycle.ballot,\n _baseFundingCycle.metadata\n );\n }\n\n /// @notice The date that is the nearest multiple of the specified funding cycle's duration from its end.\n /// @param _baseFundingCycle The funding cycle to base the calculation on.\n /// @param _mustStartAtOrAfter A date that the derived start must be on or come after.\n /// @return start The next start time.\n function _deriveStartFrom(\n JBFundingCycle memory _baseFundingCycle,\n uint256 _mustStartAtOrAfter\n ) private pure returns (uint256 start) {\n // A subsequent cycle to one with a duration of 0 should start as soon as possible.\n if (_baseFundingCycle.duration == 0) return _mustStartAtOrAfter;\n\n // The time when the funding cycle immediately after the specified funding cycle starts.\n uint256 _nextImmediateStart = _baseFundingCycle.start + _baseFundingCycle.duration;\n\n // If the next immediate start is now or in the future, return it.\n if (_nextImmediateStart >= _mustStartAtOrAfter) return _nextImmediateStart;\n\n // The amount of seconds since the `_mustStartAtOrAfter` time which results in a start time that might satisfy the specified constraints.\n uint256 _timeFromImmediateStartMultiple = (_mustStartAtOrAfter - _nextImmediateStart) %\n _baseFundingCycle.duration;\n\n // A reference to the first possible start timestamp.\n start = _mustStartAtOrAfter - _timeFromImmediateStartMultiple;\n\n // Add increments of duration as necessary to satisfy the threshold.\n while (_mustStartAtOrAfter > start) start = start + _baseFundingCycle.duration;\n }\n\n /// @notice The accumulated weight change since the specified funding cycle.\n /// @param _baseFundingCycle The funding cycle to base the calculation on.\n /// @param _start The start time of the funding cycle to derive a number for.\n /// @return weight The derived weight, as a fixed point number with 18 decimals.\n function _deriveWeightFrom(\n JBFundingCycle memory _baseFundingCycle,\n uint256 _start\n ) private pure returns (uint256 weight) {\n // A subsequent cycle to one with a duration of 0 should have the next possible weight.\n if (_baseFundingCycle.duration == 0)\n return\n PRBMath.mulDiv(\n _baseFundingCycle.weight,\n JBConstants.MAX_DISCOUNT_RATE - _baseFundingCycle.discountRate,\n JBConstants.MAX_DISCOUNT_RATE\n );\n\n // The weight should be based off the base funding cycle's weight.\n weight = _baseFundingCycle.weight;\n\n // If the discount is 0, the weight doesn't change.\n if (_baseFundingCycle.discountRate == 0) return weight;\n\n // The difference between the start of the base funding cycle and the proposed start.\n uint256 _startDistance = _start - _baseFundingCycle.start;\n\n // Apply the base funding cycle's discount rate for each cycle that has passed.\n uint256 _discountMultiple;\n unchecked {\n _discountMultiple = _startDistance / _baseFundingCycle.duration; // Non-null duration is excluded above\n }\n\n for (uint256 _i; _i < _discountMultiple; ) {\n // The number of times to apply the discount rate.\n // Base the new weight on the specified funding cycle's weight.\n weight = PRBMath.mulDiv(\n weight,\n JBConstants.MAX_DISCOUNT_RATE - _baseFundingCycle.discountRate,\n JBConstants.MAX_DISCOUNT_RATE\n );\n\n // The calculation doesn't need to continue if the weight is 0.\n if (weight == 0) break;\n\n unchecked {\n ++_i;\n }\n }\n }\n\n /// @notice The number of the next funding cycle given the specified funding cycle.\n /// @param _baseFundingCycle The funding cycle to base the calculation on.\n /// @param _start The start time of the funding cycle to derive a number for.\n /// @return The funding cycle number.\n function _deriveNumberFrom(\n JBFundingCycle memory _baseFundingCycle,\n uint256 _start\n ) private pure returns (uint256) {\n // A subsequent cycle to one with a duration of 0 should be the next number.\n if (_baseFundingCycle.duration == 0) return _baseFundingCycle.number + 1;\n\n // The difference between the start of the base funding cycle and the proposed start.\n uint256 _startDistance = _start - _baseFundingCycle.start;\n\n // Find the number of base cycles that fit in the start distance.\n return _baseFundingCycle.number + (_startDistance / _baseFundingCycle.duration);\n }\n\n /// @notice Checks to see if the provided funding cycle is approved according to the correct ballot.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @param _fundingCycle The funding cycle to get an approval flag for.\n /// @return The approval flag.\n function _isApproved(\n uint256 _projectId,\n JBFundingCycle memory _fundingCycle\n ) private view returns (bool) {\n return\n _ballotStateOf(\n _projectId,\n _fundingCycle.configuration,\n _fundingCycle.start,\n _fundingCycle.basedOn\n ) == JBBallotState.Approved;\n }\n\n /// @notice A project's latest funding cycle configuration approval status.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @param _configuration The funding cycle configuration to get the ballot state of.\n /// @param _start The start time of the funding cycle configuration to get the ballot state of.\n /// @param _ballotFundingCycleConfiguration The configuration of the funding cycle which is configured with the ballot that should be used.\n /// @return The ballot state of the project.\n function _ballotStateOf(\n uint256 _projectId,\n uint256 _configuration,\n uint256 _start,\n uint256 _ballotFundingCycleConfiguration\n ) private view returns (JBBallotState) {\n // If there is no ballot funding cycle, implicitly approve.\n if (_ballotFundingCycleConfiguration == 0) return JBBallotState.Approved;\n\n // Get the ballot funding cycle.\n JBFundingCycle memory _ballotFundingCycle = _getStructFor(\n _projectId,\n _ballotFundingCycleConfiguration\n );\n\n // If there is no ballot, the ID is auto approved.\n if (_ballotFundingCycle.ballot == IJBFundingCycleBallot(address(0)))\n return JBBallotState.Approved;\n\n // Return the ballot's state\n return _ballotFundingCycle.ballot.stateOf(_projectId, _configuration, _start);\n }\n\n /// @notice Unpack a funding cycle's packed stored values into an easy-to-work-with funding cycle struct.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @param _configuration The funding cycle configuration to get the full struct for.\n /// @return fundingCycle A funding cycle struct.\n function _getStructFor(\n uint256 _projectId,\n uint256 _configuration\n ) private view returns (JBFundingCycle memory fundingCycle) {\n // Return an empty funding cycle if the configuration specified is 0.\n if (_configuration == 0) return fundingCycle;\n\n fundingCycle.configuration = _configuration;\n\n uint256 _packedIntrinsicProperties = _packedIntrinsicPropertiesOf[_projectId][_configuration];\n\n // weight in bits 0-87 bits.\n fundingCycle.weight = uint256(uint88(_packedIntrinsicProperties));\n // basedOn in bits 88-143 bits.\n fundingCycle.basedOn = uint256(uint56(_packedIntrinsicProperties >> 88));\n // start in bits 144-199 bits.\n fundingCycle.start = uint256(uint56(_packedIntrinsicProperties >> 144));\n // number in bits 200-255 bits.\n fundingCycle.number = uint256(uint56(_packedIntrinsicProperties >> 200));\n\n uint256 _packedUserProperties = _packedUserPropertiesOf[_projectId][_configuration];\n\n // ballot in bits 0-159 bits.\n fundingCycle.ballot = IJBFundingCycleBallot(address(uint160(_packedUserProperties)));\n // duration in bits 160-191 bits.\n fundingCycle.duration = uint256(uint32(_packedUserProperties >> 160));\n // discountRate in bits 192-223 bits.\n fundingCycle.discountRate = uint256(uint32(_packedUserProperties >> 192));\n\n fundingCycle.metadata = _metadataOf[_projectId][_configuration];\n }\n}\n" + }, + "contracts/JBController.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {ERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {SafeCast} from '@openzeppelin/contracts/utils/math/SafeCast.sol';\nimport {PRBMath} from '@paulrberg/contracts/math/PRBMath.sol';\nimport {JBOperatable} from './abstract/JBOperatable.sol';\nimport {JBBallotState} from './enums/JBBallotState.sol';\nimport {IJBController} from './interfaces/IJBController.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBFundingCycleStore} from './interfaces/IJBFundingCycleStore.sol';\nimport {IJBMigratable} from './interfaces/IJBMigratable.sol';\nimport {IJBOperatable} from './interfaces/IJBOperatable.sol';\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\nimport {IJBProjects} from './interfaces/IJBProjects.sol';\nimport {IJBSplitAllocator} from './interfaces/IJBSplitAllocator.sol';\nimport {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol';\nimport {IJBTokenStore} from './interfaces/IJBTokenStore.sol';\nimport {JBConstants} from './libraries/JBConstants.sol';\nimport {JBFundingCycleMetadataResolver} from './libraries/JBFundingCycleMetadataResolver.sol';\nimport {JBOperations} from './libraries/JBOperations.sol';\nimport {JBSplitsGroups} from './libraries/JBSplitsGroups.sol';\nimport {JBSplitAllocationData} from './structs/JBSplitAllocationData.sol';\nimport {JBFundAccessConstraints} from './structs/JBFundAccessConstraints.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\nimport {JBFundingCycleData} from './structs/JBFundingCycleData.sol';\nimport {JBFundingCycleMetadata} from './structs/JBFundingCycleMetadata.sol';\nimport {JBGroupedSplits} from './structs/JBGroupedSplits.sol';\nimport {JBProjectMetadata} from './structs/JBProjectMetadata.sol';\nimport {JBSplit} from './structs/JBSplit.sol';\n\n/// @notice Stitches together funding cycles and project tokens, making sure all activity is accounted for and correct.\ncontract JBController is JBOperatable, ERC165, IJBController, IJBMigratable {\n // A library that parses the packed funding cycle metadata into a more friendly format.\n using JBFundingCycleMetadataResolver for JBFundingCycle;\n\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error BURN_PAUSED_AND_SENDER_NOT_VALID_TERMINAL_DELEGATE();\n error CANT_MIGRATE_TO_CURRENT_CONTROLLER();\n error FUNDING_CYCLE_ALREADY_LAUNCHED();\n error INVALID_BALLOT_REDEMPTION_RATE();\n error INVALID_DISTRIBUTION_LIMIT();\n error INVALID_DISTRIBUTION_LIMIT_CURRENCY();\n error INVALID_OVERFLOW_ALLOWANCE();\n error INVALID_OVERFLOW_ALLOWANCE_CURRENCY();\n error INVALID_REDEMPTION_RATE();\n error INVALID_RESERVED_RATE();\n error MIGRATION_NOT_ALLOWED();\n error MINT_NOT_ALLOWED_AND_NOT_TERMINAL_DELEGATE();\n error NO_BURNABLE_TOKENS();\n error NOT_CURRENT_CONTROLLER();\n error ZERO_TOKENS_TO_MINT();\n\n //*********************************************************************//\n // --------------------- internal stored properties ------------------ //\n //*********************************************************************//\n\n /// @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.\n /// @custom:param _projectId The ID of the project to get the tracker of.\n mapping(uint256 => int256) internal _processedTokenTrackerOf;\n\n /// @notice Data regarding the distribution limit of a project during a configuration.\n /// @dev bits 0-231: The amount of token that a project can distribute per funding cycle.\n /// @dev bits 232-255: The currency of amount that a project can distribute.\n /// @custom:param _projectId The ID of the project to get the packed distribution limit data of.\n /// @custom:param _configuration The configuration during which the packed distribution limit data applies.\n /// @custom:param _terminal The terminal from which distributions are being limited.\n /// @custom:param _token The token for which distributions are being limited.\n mapping(uint256 => mapping(uint256 => mapping(IJBPaymentTerminal => mapping(address => uint256))))\n internal _packedDistributionLimitDataOf;\n\n /// @notice Data regarding the overflow allowance of a project during a configuration.\n /// @dev bits 0-231: The amount of overflow that a project is allowed to tap into on-demand throughout the configuration.\n /// @dev bits 232-255: The currency of the amount of overflow that a project is allowed to tap.\n /// @custom:param _projectId The ID of the project to get the packed overflow allowance data of.\n /// @custom:param _configuration The configuration during which the packed overflow allowance data applies.\n /// @custom:param _terminal The terminal managing the overflow.\n /// @custom:param _token The token for which overflow is being allowed.\n mapping(uint256 => mapping(uint256 => mapping(IJBPaymentTerminal => mapping(address => uint256))))\n internal _packedOverflowAllowanceDataOf;\n\n //*********************************************************************//\n // --------------- public immutable stored properties ---------------- //\n //*********************************************************************//\n\n /// @notice Mints ERC-721's that represent project ownership.\n IJBProjects public immutable override projects;\n\n /// @notice The contract storing all funding cycle configurations.\n IJBFundingCycleStore public immutable override fundingCycleStore;\n\n /// @notice The contract that manages token minting and burning.\n IJBTokenStore public immutable override tokenStore;\n\n /// @notice The contract that stores splits for each project.\n IJBSplitsStore public immutable override splitsStore;\n\n /// @notice The directory of terminals and controllers for projects.\n IJBDirectory public immutable override directory;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice The amount of token that a project can distribute per funding cycle, and the currency it's in terms of.\n /// @dev The number of decimals in the returned fixed point amount is the same as that of the specified terminal.\n /// @param _projectId The ID of the project to get the distribution limit of.\n /// @param _configuration The configuration during which the distribution limit applies.\n /// @param _terminal The terminal from which distributions are being limited.\n /// @param _token The token for which the distribution limit applies.\n /// @return The distribution limit, as a fixed point number with the same number of decimals as the provided terminal.\n /// @return The currency of the distribution limit.\n function distributionLimitOf(\n uint256 _projectId,\n uint256 _configuration,\n IJBPaymentTerminal _terminal,\n address _token\n ) external view override returns (uint256, uint256) {\n // Get a reference to the packed data.\n uint256 _data = _packedDistributionLimitDataOf[_projectId][_configuration][_terminal][_token];\n\n // The limit is in bits 0-231. The currency is in bits 232-255.\n return (uint256(uint232(_data)), _data >> 232);\n }\n\n /// @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.\n /// @dev The number of decimals in the returned fixed point amount is the same as that of the specified terminal.\n /// @param _projectId The ID of the project to get the overflow allowance of.\n /// @param _configuration The configuration of the during which the allowance applies.\n /// @param _terminal The terminal managing the overflow.\n /// @param _token The token for which the overflow allowance applies.\n /// @return The overflow allowance, as a fixed point number with the same number of decimals as the provided terminal.\n /// @return The currency of the overflow allowance.\n function overflowAllowanceOf(\n uint256 _projectId,\n uint256 _configuration,\n IJBPaymentTerminal _terminal,\n address _token\n ) external view override returns (uint256, uint256) {\n // Get a reference to the packed data.\n uint256 _data = _packedOverflowAllowanceDataOf[_projectId][_configuration][_terminal][_token];\n\n // The allowance is in bits 0-231. The currency is in bits 232-255.\n return (uint256(uint232(_data)), _data >> 232);\n }\n\n /// @notice Gets the amount of reserved tokens that a project has available to distribute.\n /// @param _projectId The ID of the project to get a reserved token balance of.\n /// @param _reservedRate The reserved rate to use when making the calculation.\n /// @return The current amount of reserved tokens.\n function reservedTokenBalanceOf(\n uint256 _projectId,\n uint256 _reservedRate\n ) external view override returns (uint256) {\n return\n _reservedTokenAmountFrom(\n _processedTokenTrackerOf[_projectId],\n _reservedRate,\n tokenStore.totalSupplyOf(_projectId)\n );\n }\n\n /// @notice Gets the current total amount of outstanding tokens for a project, given a reserved rate.\n /// @param _projectId The ID of the project to get total outstanding tokens of.\n /// @param _reservedRate The reserved rate to use when making the calculation.\n /// @return The current total amount of outstanding tokens for the project.\n function totalOutstandingTokensOf(\n uint256 _projectId,\n uint256 _reservedRate\n ) external view override returns (uint256) {\n // Get the total number of tokens in circulation.\n uint256 _totalSupply = tokenStore.totalSupplyOf(_projectId);\n\n // Get the number of reserved tokens the project has.\n uint256 _reservedTokenAmount = _reservedTokenAmountFrom(\n _processedTokenTrackerOf[_projectId],\n _reservedRate,\n _totalSupply\n );\n\n // Add the reserved tokens to the total supply.\n return _totalSupply + _reservedTokenAmount;\n }\n\n /// @notice A project's funding cycle for the specified configuration along with its metadata.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The funding cycle.\n /// @return metadata The funding cycle's metadata.\n function getFundingCycleOf(\n uint256 _projectId,\n uint256 _configuration\n )\n external\n view\n override\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata)\n {\n fundingCycle = fundingCycleStore.get(_projectId, _configuration);\n metadata = fundingCycle.expandMetadata();\n }\n\n /// @notice A project's latest configured funding cycle along with its metadata and the ballot state of the configuration.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The latest configured funding cycle.\n /// @return metadata The latest configured funding cycle's metadata.\n /// @return ballotState The state of the configuration.\n function latestConfiguredFundingCycleOf(\n uint256 _projectId\n )\n external\n view\n override\n returns (\n JBFundingCycle memory fundingCycle,\n JBFundingCycleMetadata memory metadata,\n JBBallotState ballotState\n )\n {\n (fundingCycle, ballotState) = fundingCycleStore.latestConfiguredOf(_projectId);\n metadata = fundingCycle.expandMetadata();\n }\n\n /// @notice A project's current funding cycle along with its metadata.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The current funding cycle.\n /// @return metadata The current funding cycle's metadata.\n function currentFundingCycleOf(\n uint256 _projectId\n )\n external\n view\n override\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata)\n {\n fundingCycle = fundingCycleStore.currentOf(_projectId);\n metadata = fundingCycle.expandMetadata();\n }\n\n /// @notice A project's queued funding cycle along with its metadata.\n /// @param _projectId The ID of the project to which the funding cycle belongs.\n /// @return fundingCycle The queued funding cycle.\n /// @return metadata The queued funding cycle's metadata.\n function queuedFundingCycleOf(\n uint256 _projectId\n )\n external\n view\n override\n returns (JBFundingCycle memory fundingCycle, JBFundingCycleMetadata memory metadata)\n {\n fundingCycle = fundingCycleStore.queuedOf(_projectId);\n metadata = fundingCycle.expandMetadata();\n }\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if the provided interface ID is supported.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(ERC165, IERC165) returns (bool) {\n return\n _interfaceId == type(IJBController).interfaceId ||\n _interfaceId == type(IJBMigratable).interfaceId ||\n _interfaceId == type(IJBOperatable).interfaceId ||\n super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // ---------------------------- constructor -------------------------- //\n //*********************************************************************//\n\n /// @param _operatorStore A contract storing operator assignments.\n /// @param _projects A contract which mints ERC-721's that represent project ownership and transfers.\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n /// @param _fundingCycleStore A contract storing all funding cycle configurations.\n /// @param _tokenStore A contract that manages token minting and burning.\n /// @param _splitsStore A contract that stores splits for each project.\n constructor(\n IJBOperatorStore _operatorStore,\n IJBProjects _projects,\n IJBDirectory _directory,\n IJBFundingCycleStore _fundingCycleStore,\n IJBTokenStore _tokenStore,\n IJBSplitsStore _splitsStore\n ) JBOperatable(_operatorStore) {\n projects = _projects;\n directory = _directory;\n fundingCycleStore = _fundingCycleStore;\n tokenStore = _tokenStore;\n splitsStore = _splitsStore;\n }\n\n //*********************************************************************//\n // --------------------- external transactions ----------------------- //\n //*********************************************************************//\n\n /// @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.\n /// @dev Each operation within this transaction can be done in sequence separately.\n /// @dev Anyone can deploy a project on an owner's behalf.\n /// @param _owner The address to set as the owner of the project. The project ERC-721 will be owned by this address.\n /// @param _projectMetadata Metadata to associate with the project within a particular domain. This can be updated any time by the owner of the project.\n /// @param _data Data that defines the project's first funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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`.\n /// @param _terminals Payment terminals to add for the project.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return projectId The ID of the project.\n function launchProjectFor(\n address _owner,\n JBProjectMetadata calldata _projectMetadata,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] calldata _groupedSplits,\n JBFundAccessConstraints[] calldata _fundAccessConstraints,\n IJBPaymentTerminal[] memory _terminals,\n string memory _memo\n ) external virtual override returns (uint256 projectId) {\n // Keep a reference to the directory.\n IJBDirectory _directory = directory;\n\n // Mint the project into the wallet of the owner.\n projectId = projects.createFor(_owner, _projectMetadata);\n\n // Set this contract as the project's controller in the directory.\n _directory.setControllerOf(projectId, address(this));\n\n // Configure the first funding cycle.\n uint256 _configuration = _configure(\n projectId,\n _data,\n _metadata,\n _mustStartAtOrAfter,\n _groupedSplits,\n _fundAccessConstraints\n );\n\n // Add the provided terminals to the list of terminals.\n if (_terminals.length > 0) _directory.setTerminalsOf(projectId, _terminals);\n\n emit LaunchProject(_configuration, projectId, _memo, msg.sender);\n }\n\n /// @notice Creates a funding cycle for an already existing project ERC-721.\n /// @dev Each operation within this transaction can be done in sequence separately.\n /// @dev Only a project owner or operator can launch its funding cycles.\n /// @param _projectId The ID of the project to launch funding cycles for.\n /// @param _data Data that defines the project's first funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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`.\n /// @param _terminals Payment terminals to add for the project.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return configuration The configuration of the funding cycle that was successfully created.\n function launchFundingCyclesFor(\n uint256 _projectId,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] calldata _groupedSplits,\n JBFundAccessConstraints[] memory _fundAccessConstraints,\n IJBPaymentTerminal[] memory _terminals,\n string memory _memo\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.RECONFIGURE)\n returns (uint256 configuration)\n {\n // If there is a previous configuration, reconfigureFundingCyclesOf should be called instead\n if (fundingCycleStore.latestConfigurationOf(_projectId) > 0)\n revert FUNDING_CYCLE_ALREADY_LAUNCHED();\n\n // Set this contract as the project's controller in the directory.\n directory.setControllerOf(_projectId, address(this));\n\n // Configure the first funding cycle.\n configuration = _configure(\n _projectId,\n _data,\n _metadata,\n _mustStartAtOrAfter,\n _groupedSplits,\n _fundAccessConstraints\n );\n\n // Add the provided terminals to the list of terminals.\n if (_terminals.length > 0) directory.setTerminalsOf(_projectId, _terminals);\n\n emit LaunchFundingCycles(configuration, _projectId, _memo, msg.sender);\n }\n\n /// @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.\n /// @dev Only a project's owner or a designated operator can configure its funding cycles.\n /// @param _projectId The ID of the project whose funding cycles are being reconfigured.\n /// @param _data Data that defines the funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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`.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return configuration The configuration of the funding cycle that was successfully reconfigured.\n function reconfigureFundingCyclesOf(\n uint256 _projectId,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] calldata _groupedSplits,\n JBFundAccessConstraints[] calldata _fundAccessConstraints,\n string calldata _memo\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.RECONFIGURE)\n returns (uint256 configuration)\n {\n // Configure the next funding cycle.\n configuration = _configure(\n _projectId,\n _data,\n _metadata,\n _mustStartAtOrAfter,\n _groupedSplits,\n _fundAccessConstraints\n );\n\n emit ReconfigureFundingCycles(configuration, _projectId, _memo, msg.sender);\n }\n\n /// @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.\n /// @dev Only a project's owner, a designated operator, one of its terminals, or the current data source can mint its tokens.\n /// @param _projectId The ID of the project to which the tokens being minted belong.\n /// @param _tokenCount The amount of tokens to mint in total, counting however many should be reserved.\n /// @param _beneficiary The account that the tokens are being minted for.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _preferClaimedTokens A flag indicating whether a project's attached token contract should be minted if they have been issued.\n /// @param _useReservedRate Whether to use the current funding cycle's reserved rate in the mint calculation.\n /// @return beneficiaryTokenCount The amount of tokens minted for the beneficiary.\n function mintTokensOf(\n uint256 _projectId,\n uint256 _tokenCount,\n address _beneficiary,\n string calldata _memo,\n bool _preferClaimedTokens,\n bool _useReservedRate\n ) external virtual override returns (uint256 beneficiaryTokenCount) {\n // There should be tokens to mint.\n if (_tokenCount == 0) revert ZERO_TOKENS_TO_MINT();\n\n // Define variables that will be needed outside scoped section below.\n // Keep a reference to the reserved rate to use\n uint256 _reservedRate;\n\n // Scoped section prevents stack too deep. `_fundingCycle` only used within scope.\n {\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Minting limited to: project owner, authorized callers, project terminal and current funding cycle data source\n _requirePermissionAllowingOverride(\n projects.ownerOf(_projectId),\n _projectId,\n JBOperations.MINT,\n directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender)) ||\n msg.sender == address(_fundingCycle.dataSource())\n );\n\n // If the message sender is not a terminal or a datasource, the current funding cycle must allow minting.\n if (\n !_fundingCycle.mintingAllowed() &&\n !directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender)) &&\n msg.sender != address(_fundingCycle.dataSource())\n ) revert MINT_NOT_ALLOWED_AND_NOT_TERMINAL_DELEGATE();\n\n // Determine the reserved rate to use.\n _reservedRate = _useReservedRate ? _fundingCycle.reservedRate() : 0;\n\n // Override the claimed token preference with the funding cycle value.\n _preferClaimedTokens = _preferClaimedTokens == true\n ? _preferClaimedTokens\n : _fundingCycle.preferClaimedTokenOverride();\n }\n\n if (_reservedRate == JBConstants.MAX_RESERVED_RATE)\n // Subtract the total weighted amount from the tracker so the full reserved token amount can be printed later.\n _processedTokenTrackerOf[_projectId] =\n _processedTokenTrackerOf[_projectId] -\n SafeCast.toInt256(_tokenCount);\n else {\n // The unreserved token count that will be minted for the beneficiary.\n beneficiaryTokenCount = PRBMath.mulDiv(\n _tokenCount,\n JBConstants.MAX_RESERVED_RATE - _reservedRate,\n JBConstants.MAX_RESERVED_RATE\n );\n\n if (_reservedRate == 0)\n // If there's no reserved rate, increment the tracker with the newly minted tokens.\n _processedTokenTrackerOf[_projectId] =\n _processedTokenTrackerOf[_projectId] +\n SafeCast.toInt256(beneficiaryTokenCount);\n\n // Mint the tokens.\n tokenStore.mintFor(_beneficiary, _projectId, beneficiaryTokenCount, _preferClaimedTokens);\n }\n\n emit MintTokens(\n _beneficiary,\n _projectId,\n _tokenCount,\n beneficiaryTokenCount,\n _memo,\n _reservedRate,\n msg.sender\n );\n }\n\n /// @notice Burns a token holder's supply.\n /// @dev Only a token's holder, a designated operator, or a project's terminal can burn it.\n /// @param _holder The account that is having its tokens burned.\n /// @param _projectId The ID of the project to which the tokens being burned belong.\n /// @param _tokenCount The number of tokens to burn.\n /// @param _memo A memo to pass along to the emitted event.\n /// @param _preferClaimedTokens A flag indicating whether a project's attached token contract should be burned first if they have been issued.\n function burnTokensOf(\n address _holder,\n uint256 _projectId,\n uint256 _tokenCount,\n string calldata _memo,\n bool _preferClaimedTokens\n )\n external\n virtual\n override\n requirePermissionAllowingOverride(\n _holder,\n _projectId,\n JBOperations.BURN,\n directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender))\n )\n {\n // There should be tokens to burn\n if (_tokenCount == 0) revert NO_BURNABLE_TOKENS();\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // If the message sender is a terminal, the current funding cycle must not be paused.\n if (\n _fundingCycle.burnPaused() &&\n !directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender))\n ) revert BURN_PAUSED_AND_SENDER_NOT_VALID_TERMINAL_DELEGATE();\n\n // Update the token tracker so that reserved tokens will still be correctly mintable.\n _processedTokenTrackerOf[_projectId] =\n _processedTokenTrackerOf[_projectId] -\n SafeCast.toInt256(_tokenCount);\n\n // Burn the tokens.\n tokenStore.burnFrom(_holder, _projectId, _tokenCount, _preferClaimedTokens);\n\n emit BurnTokens(_holder, _projectId, _tokenCount, _memo, msg.sender);\n }\n\n /// @notice Distributes all outstanding reserved tokens for a project.\n /// @param _projectId The ID of the project to which the reserved tokens belong.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return The amount of minted reserved tokens.\n function distributeReservedTokensOf(\n uint256 _projectId,\n string calldata _memo\n ) external virtual override returns (uint256) {\n return _distributeReservedTokensOf(_projectId, _memo);\n }\n\n /// @notice Allows other controllers to signal to this one that a migration is expected for the specified project.\n /// @dev This controller should not yet be the project's controller.\n /// @param _projectId The ID of the project that will be migrated to this controller.\n /// @param _from The controller being migrated from.\n function prepForMigrationOf(uint256 _projectId, address _from) external virtual override {\n // This controller must not be the project's current controller.\n if (directory.controllerOf(_projectId) == address(this))\n revert CANT_MIGRATE_TO_CURRENT_CONTROLLER();\n\n // Set the tracker as the total supply.\n _processedTokenTrackerOf[_projectId] = SafeCast.toInt256(tokenStore.totalSupplyOf(_projectId));\n\n emit PrepMigration(_projectId, _from, msg.sender);\n }\n\n /// @notice Allows a project to migrate from this controller to another.\n /// @dev Only a project's owner or a designated operator can migrate it.\n /// @param _projectId The ID of the project that will be migrated from this controller.\n /// @param _to The controller to which the project is migrating.\n function migrate(\n uint256 _projectId,\n IJBMigratable _to\n )\n external\n virtual\n override\n requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.MIGRATE_CONTROLLER)\n {\n // Keep a reference to the directory.\n IJBDirectory _directory = directory;\n\n // This controller must be the project's current controller.\n if (_directory.controllerOf(_projectId) != address(this)) revert NOT_CURRENT_CONTROLLER();\n\n // Get a reference to the project's current funding cycle.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Migration must be allowed.\n if (!_fundingCycle.controllerMigrationAllowed()) revert MIGRATION_NOT_ALLOWED();\n\n // All reserved tokens must be minted before migrating.\n if (\n _processedTokenTrackerOf[_projectId] < 0 ||\n uint256(_processedTokenTrackerOf[_projectId]) != tokenStore.totalSupplyOf(_projectId)\n ) _distributeReservedTokensOf(_projectId, '');\n\n // Make sure the new controller is prepped for the migration.\n _to.prepForMigrationOf(_projectId, address(this));\n\n // Set the new controller.\n _directory.setControllerOf(_projectId, address(_to));\n\n emit Migrate(_projectId, _to, msg.sender);\n }\n\n //*********************************************************************//\n // ------------------------ internal functions ----------------------- //\n //*********************************************************************//\n\n /// @notice Distributes all outstanding reserved tokens for a project.\n /// @param _projectId The ID of the project to which the reserved tokens belong.\n /// @param _memo A memo to pass along to the emitted event.\n /// @return tokenCount The amount of minted reserved tokens.\n function _distributeReservedTokensOf(\n uint256 _projectId,\n string memory _memo\n ) internal returns (uint256 tokenCount) {\n // Keep a reference to the token store.\n IJBTokenStore _tokenStore = tokenStore;\n\n // Get the current funding cycle to read the reserved rate from.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);\n\n // Get a reference to new total supply of tokens before minting reserved tokens.\n uint256 _totalTokens = _tokenStore.totalSupplyOf(_projectId);\n\n // Get a reference to the number of tokens that need to be minted.\n tokenCount = _reservedTokenAmountFrom(\n _processedTokenTrackerOf[_projectId],\n _fundingCycle.reservedRate(),\n _totalTokens\n );\n\n // Set the tracker to be the new total supply.\n _processedTokenTrackerOf[_projectId] = SafeCast.toInt256(_totalTokens + tokenCount);\n\n // Get a reference to the project owner.\n address _owner = projects.ownerOf(_projectId);\n\n // Distribute tokens to splits and get a reference to the leftover amount to mint after all splits have gotten their share.\n uint256 _leftoverTokenCount = tokenCount == 0\n ? 0\n : _distributeToReservedTokenSplitsOf(\n _projectId,\n _fundingCycle.configuration,\n JBSplitsGroups.RESERVED_TOKENS,\n tokenCount\n );\n\n // Mint any leftover tokens to the project owner.\n if (_leftoverTokenCount > 0)\n _tokenStore.mintFor(_owner, _projectId, _leftoverTokenCount, false);\n\n emit DistributeReservedTokens(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _owner,\n tokenCount,\n _leftoverTokenCount,\n _memo,\n msg.sender\n );\n }\n\n /// @notice Distribute tokens to the splits according to the specified funding cycle configuration.\n /// @param _projectId The ID of the project for which reserved token splits are being distributed.\n /// @param _domain The domain of the splits to distribute the reserved tokens between.\n /// @param _group The group of the splits to distribute the reserved tokens between.\n /// @param _amount The total amount of tokens to mint.\n /// @return leftoverAmount If the splits percents dont add up to 100%, the leftover amount is returned.\n function _distributeToReservedTokenSplitsOf(\n uint256 _projectId,\n uint256 _domain,\n uint256 _group,\n uint256 _amount\n ) internal returns (uint256 leftoverAmount) {\n // Keep a reference to the token store.\n IJBTokenStore _tokenStore = tokenStore;\n\n // Set the leftover amount to the initial amount.\n leftoverAmount = _amount;\n\n // Get a reference to the project's reserved token splits.\n JBSplit[] memory _splits = splitsStore.splitsOf(_projectId, _domain, _group);\n\n //Transfer between all splits.\n for (uint256 _i; _i < _splits.length; ) {\n // Get a reference to the split being iterated on.\n JBSplit memory _split = _splits[_i];\n\n // The amount to send towards the split.\n uint256 _tokenCount = PRBMath.mulDiv(\n _amount,\n _split.percent,\n JBConstants.SPLITS_TOTAL_PERCENT\n );\n\n // Mints tokens for the split if needed.\n if (_tokenCount > 0) {\n _tokenStore.mintFor(\n // If an allocator is set in the splits, set it as the beneficiary.\n // Otherwise if a projectId is set in the split, set the project's owner as the beneficiary.\n // If the split has a beneficiary send to the split's beneficiary. Otherwise send to the msg.sender.\n _split.allocator != IJBSplitAllocator(address(0))\n ? address(_split.allocator)\n : _split.projectId != 0\n ? projects.ownerOf(_split.projectId)\n : _split.beneficiary != address(0)\n ? _split.beneficiary\n : msg.sender,\n _projectId,\n _tokenCount,\n _split.preferClaimed\n );\n\n // If there's an allocator set, trigger its `allocate` function.\n if (_split.allocator != IJBSplitAllocator(address(0)))\n _split.allocator.allocate(\n JBSplitAllocationData(\n address(_tokenStore.tokenOf(_projectId)),\n _tokenCount,\n 18,\n _projectId,\n _group,\n _split\n )\n );\n\n // Subtract from the amount to be sent to the beneficiary.\n leftoverAmount = leftoverAmount - _tokenCount;\n }\n\n emit DistributeToReservedTokenSplit(\n _projectId,\n _domain,\n _group,\n _split,\n _tokenCount,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n\n /// @notice Configures a funding cycle and stores information pertinent to the configuration.\n /// @param _projectId The ID of the project whose funding cycles are being reconfigured.\n /// @param _data Data that defines the funding cycle. These properties will remain fixed for the duration of the funding cycle.\n /// @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.\n /// @param _mustStartAtOrAfter The time before which the configured funding cycle cannot start.\n /// @param _groupedSplits An array of splits to set for any number of groups.\n /// @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.\n /// @return configuration The configuration of the funding cycle that was successfully reconfigured.\n function _configure(\n uint256 _projectId,\n JBFundingCycleData calldata _data,\n JBFundingCycleMetadata calldata _metadata,\n uint256 _mustStartAtOrAfter,\n JBGroupedSplits[] memory _groupedSplits,\n JBFundAccessConstraints[] memory _fundAccessConstraints\n ) internal returns (uint256) {\n // Make sure the provided reserved rate is valid.\n if (_metadata.reservedRate > JBConstants.MAX_RESERVED_RATE) revert INVALID_RESERVED_RATE();\n\n // Make sure the provided redemption rate is valid.\n if (_metadata.redemptionRate > JBConstants.MAX_REDEMPTION_RATE)\n revert INVALID_REDEMPTION_RATE();\n\n // Make sure the provided ballot redemption rate is valid.\n if (_metadata.ballotRedemptionRate > JBConstants.MAX_REDEMPTION_RATE)\n revert INVALID_BALLOT_REDEMPTION_RATE();\n\n // Configure the funding cycle's properties.\n JBFundingCycle memory _fundingCycle = fundingCycleStore.configureFor(\n _projectId,\n _data,\n JBFundingCycleMetadataResolver.packFundingCycleMetadata(_metadata),\n _mustStartAtOrAfter\n );\n\n // Set splits for the group.\n splitsStore.set(_projectId, _fundingCycle.configuration, _groupedSplits);\n\n // Set distribution limits if there are any.\n for (uint256 _i; _i < _fundAccessConstraints.length; ) {\n JBFundAccessConstraints memory _constraints = _fundAccessConstraints[_i];\n\n // If distribution limit value is larger than 232 bits, revert.\n if (_constraints.distributionLimit > type(uint232).max) revert INVALID_DISTRIBUTION_LIMIT();\n\n // If distribution limit currency value is larger than 24 bits, revert.\n if (_constraints.distributionLimitCurrency > type(uint24).max)\n revert INVALID_DISTRIBUTION_LIMIT_CURRENCY();\n\n // If overflow allowance value is larger than 232 bits, revert.\n if (_constraints.overflowAllowance > type(uint232).max) revert INVALID_OVERFLOW_ALLOWANCE();\n\n // If overflow allowance currency value is larger than 24 bits, revert.\n if (_constraints.overflowAllowanceCurrency > type(uint24).max)\n revert INVALID_OVERFLOW_ALLOWANCE_CURRENCY();\n\n // Set the distribution limit if there is one.\n if (_constraints.distributionLimit > 0)\n _packedDistributionLimitDataOf[_projectId][_fundingCycle.configuration][\n _constraints.terminal\n ][_constraints.token] =\n _constraints.distributionLimit |\n (_constraints.distributionLimitCurrency << 232);\n\n // Set the overflow allowance if there is one.\n if (_constraints.overflowAllowance > 0)\n _packedOverflowAllowanceDataOf[_projectId][_fundingCycle.configuration][\n _constraints.terminal\n ][_constraints.token] =\n _constraints.overflowAllowance |\n (_constraints.overflowAllowanceCurrency << 232);\n\n emit SetFundAccessConstraints(\n _fundingCycle.configuration,\n _fundingCycle.number,\n _projectId,\n _constraints,\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n\n return _fundingCycle.configuration;\n }\n\n /// @notice Gets the amount of reserved tokens currently tracked for a project given a reserved rate.\n /// @param _processedTokenTracker The tracker to make the calculation with.\n /// @param _reservedRate The reserved rate to use to make the calculation.\n /// @param _totalEligibleTokens The total amount to make the calculation with.\n /// @return amount reserved token amount.\n function _reservedTokenAmountFrom(\n int256 _processedTokenTracker,\n uint256 _reservedRate,\n uint256 _totalEligibleTokens\n ) internal pure returns (uint256) {\n // Get a reference to the amount of tokens that are unprocessed.\n uint256 _unprocessedTokenBalanceOf = _processedTokenTracker >= 0\n ? _totalEligibleTokens - uint256(_processedTokenTracker)\n : _totalEligibleTokens + uint256(-_processedTokenTracker);\n\n // If there are no unprocessed tokens, return.\n if (_unprocessedTokenBalanceOf == 0) return 0;\n\n // If all tokens are reserved, return the full unprocessed amount.\n if (_reservedRate == JBConstants.MAX_RESERVED_RATE) return _unprocessedTokenBalanceOf;\n\n return\n PRBMath.mulDiv(\n _unprocessedTokenBalanceOf,\n JBConstants.MAX_RESERVED_RATE,\n JBConstants.MAX_RESERVED_RATE - _reservedRate\n ) - _unprocessedTokenBalanceOf;\n }\n}\n" + }, + "contracts/JBReconfigurationBufferBallot.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {ERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol';\nimport {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol';\nimport {JBBallotState} from './enums/JBBallotState.sol';\nimport {IJBFundingCycleBallot} from './interfaces/IJBFundingCycleBallot.sol';\nimport {JBFundingCycle} from './structs/JBFundingCycle.sol';\n\n/// @notice Manages approving funding cycle reconfigurations automatically after a buffer period.\ncontract JBReconfigurationBufferBallot is ERC165, IJBFundingCycleBallot {\n //*********************************************************************//\n // ---------------- public immutable stored properties --------------- //\n //*********************************************************************//\n\n /// @notice The number of seconds that must pass for a funding cycle reconfiguration to become either `Approved` or `Failed`.\n uint256 public immutable override duration;\n\n //*********************************************************************//\n // -------------------------- public views --------------------------- //\n //*********************************************************************//\n\n /// @notice The approval state of a particular funding cycle.\n /// @param _projectId The ID of the project to which the funding cycle being checked belongs.\n /// @param _configured The configuration of the funding cycle to check the state of.\n /// @param _start The start timestamp of the funding cycle to check the state of.\n /// @return The state of the provided ballot.\n function stateOf(\n uint256 _projectId,\n uint256 _configured,\n uint256 _start\n ) public view override returns (JBBallotState) {\n _projectId; // Prevents unused var compiler and natspec complaints.\n\n // If the provided configured timestamp is after the start timestamp, the ballot is Failed.\n if (_configured > _start) return JBBallotState.Failed;\n\n unchecked {\n // If there was sufficient time between configuration and the start of the cycle, it is approved. Otherwise, it is failed.\n return (_start - _configured < duration) ? JBBallotState.Failed : JBBallotState.Approved;\n }\n }\n\n /// @notice Indicates if this contract adheres to the specified interface.\n /// @dev See {IERC165-supportsInterface}.\n /// @param _interfaceId The ID of the interface to check for adherance to.\n /// @return A flag indicating if this contract adheres to the specified interface.\n function supportsInterface(\n bytes4 _interfaceId\n ) public view virtual override(ERC165, IERC165) returns (bool) {\n return\n _interfaceId == type(IJBFundingCycleBallot).interfaceId ||\n super.supportsInterface(_interfaceId);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _duration The number of seconds to wait until a reconfiguration can be either `Approved` or `Failed`.\n constructor(uint256 _duration) {\n duration = _duration;\n }\n}\n" + }, + "contracts/JBETHERC20ProjectPayerDeployer.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {Clones} from '@openzeppelin/contracts/proxy/Clones.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBProjectPayer} from './interfaces/IJBProjectPayer.sol';\nimport {IJBETHERC20ProjectPayerDeployer} from './interfaces/IJBETHERC20ProjectPayerDeployer.sol';\nimport {JBETHERC20ProjectPayer} from './JBETHERC20ProjectPayer.sol';\n\n/// @notice Deploys project payer contracts.\ncontract JBETHERC20ProjectPayerDeployer is IJBETHERC20ProjectPayerDeployer {\n //*********************************************************************//\n // --------------- public immutable stored properties ---------------- //\n //*********************************************************************//\n\n /// @notice The implementation contract on which Clones will be based.\n address immutable implementation;\n\n /// @notice directory instance which keeps a track of which controller is linked to which project.\n IJBDirectory immutable directory;\n\n //*********************************************************************//\n // ---------------------------- constructor -------------------------- //\n //*********************************************************************//\n\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n constructor(IJBDirectory _directory) {\n implementation = address(new JBETHERC20ProjectPayer(_directory));\n directory = _directory;\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Allows anyone to deploy a new project payer contract.\n /// @param _defaultProjectId The ID of the project whose treasury should be forwarded the project payer contract's received payments.\n /// @param _defaultBeneficiary The address that'll receive the project's tokens when the project payer receives payments.\n /// @param _defaultPreferClaimedTokens A flag indicating whether issued tokens from the project payer's received payments should be automatically claimed into the beneficiary's wallet.\n /// @param _defaultMemo The memo that'll be forwarded with the project payer's received payments.\n /// @param _defaultMetadata The metadata that'll be forwarded with the project payer's received payments.\n /// @param _defaultPreferAddToBalance A flag indicating if received payments should call the `pay` function or the `addToBalance` function of a project.\n /// @param _owner The address that will own the project payer.\n /// @return projectPayer The project payer contract.\n function deployProjectPayer(\n uint256 _defaultProjectId,\n address payable _defaultBeneficiary,\n bool _defaultPreferClaimedTokens,\n string memory _defaultMemo,\n bytes memory _defaultMetadata,\n bool _defaultPreferAddToBalance,\n address _owner\n ) external override returns (IJBProjectPayer projectPayer) {\n // Deploy the project payer.\n projectPayer = IJBProjectPayer(payable(Clones.clone(implementation)));\n\n // Initialize the project payer.\n projectPayer.initialize(\n _defaultProjectId,\n _defaultBeneficiary,\n _defaultPreferClaimedTokens,\n _defaultMemo,\n _defaultMetadata,\n _defaultPreferAddToBalance,\n _owner\n );\n\n emit DeployProjectPayer(\n projectPayer,\n _defaultProjectId,\n _defaultBeneficiary,\n _defaultPreferClaimedTokens,\n _defaultMemo,\n _defaultMetadata,\n _defaultPreferAddToBalance,\n directory,\n _owner,\n msg.sender\n );\n }\n}\n" + }, + "contracts/interfaces/IJBETHERC20ProjectPayerDeployer.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBDirectory} from './IJBDirectory.sol';\nimport {IJBProjectPayer} from './IJBProjectPayer.sol';\n\ninterface IJBETHERC20ProjectPayerDeployer {\n event DeployProjectPayer(\n IJBProjectPayer indexed projectPayer,\n uint256 defaultProjectId,\n address defaultBeneficiary,\n bool defaultPreferClaimedTokens,\n string defaultMemo,\n bytes defaultMetadata,\n bool preferAddToBalance,\n IJBDirectory directory,\n address owner,\n address caller\n );\n\n function deployProjectPayer(\n uint256 defaultProjectId,\n address payable defaultBeneficiary,\n bool defaultPreferClaimedTokens,\n string memory defaultMemo,\n bytes memory defaultMetadata,\n bool preferAddToBalance,\n address owner\n ) external returns (IJBProjectPayer projectPayer);\n}\n" + }, + "contracts/JBOperatorStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol';\nimport {JBOperatorData} from './structs/JBOperatorData.sol';\n\n/// @notice Stores operator permissions for all addresses. Addresses can give permissions to any other address to take specific indexed actions on their behalf.\ncontract JBOperatorStore is IJBOperatorStore {\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n error PERMISSION_INDEX_OUT_OF_BOUNDS();\n\n //*********************************************************************//\n // --------------------- public stored properties -------------------- //\n //*********************************************************************//\n\n /// @notice The permissions that an operator has been given to operate on a specific domain.\n /// @dev An account can give an operator permissions that only pertain to a specific domain namespace.\n /// @dev There is no domain with a value of 0 – accounts can use the 0 domain to give an operator permissions to all domains on their behalf.\n /// @dev Permissions are stored in a packed `uint256`. Each 256 bits represents the on/off state of a permission. Applications can specify the significance of each index.\n /// @custom:param _operator The address of the operator.\n /// @custom:param _account The address of the account being operated.\n /// @custom:param _domain The domain within which the permissions apply. Applications can use the domain namespace as they wish.\n mapping(address => mapping(address => mapping(uint256 => uint256))) public override permissionsOf;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice Whether or not an operator has the permission to take a certain action pertaining to the specified domain.\n /// @param _operator The operator to check.\n /// @param _account The account that has given out permissions to the operator.\n /// @param _domain The domain that the operator has been given permissions to operate.\n /// @param _permissionIndex The permission index to check for.\n /// @return A flag indicating whether the operator has the specified permission.\n function hasPermission(\n address _operator,\n address _account,\n uint256 _domain,\n uint256 _permissionIndex\n ) external view override returns (bool) {\n if (_permissionIndex > 255) revert PERMISSION_INDEX_OUT_OF_BOUNDS();\n\n return (((permissionsOf[_operator][_account][_domain] >> _permissionIndex) & 1) == 1);\n }\n\n /// @notice Whether or not an operator has the permission to take certain actions pertaining to the specified domain.\n /// @param _operator The operator to check.\n /// @param _account The account that has given out permissions to the operator.\n /// @param _domain The domain that the operator has been given permissions to operate.\n /// @param _permissionIndexes An array of permission indexes to check for.\n /// @return A flag indicating whether the operator has all specified permissions.\n function hasPermissions(\n address _operator,\n address _account,\n uint256 _domain,\n uint256[] calldata _permissionIndexes\n ) external view override returns (bool) {\n for (uint256 _i; _i < _permissionIndexes.length; ) {\n uint256 _permissionIndex = _permissionIndexes[_i];\n\n if (_permissionIndex > 255) revert PERMISSION_INDEX_OUT_OF_BOUNDS();\n\n if (((permissionsOf[_operator][_account][_domain] >> _permissionIndex) & 1) == 0)\n return false;\n\n unchecked {\n ++_i;\n }\n }\n return true;\n }\n\n //*********************************************************************//\n // ---------------------- external transactions ---------------------- //\n //*********************************************************************//\n\n /// @notice Sets permissions for an operators.\n /// @dev Only an address can set its own operators.\n /// @param _operatorData The data that specifies the params for the operator being set.\n function setOperator(JBOperatorData calldata _operatorData) external override {\n // Pack the indexes into a uint256.\n uint256 _packed = _packedPermissions(_operatorData.permissionIndexes);\n\n // Store the new value.\n permissionsOf[_operatorData.operator][msg.sender][_operatorData.domain] = _packed;\n\n emit SetOperator(\n _operatorData.operator,\n msg.sender,\n _operatorData.domain,\n _operatorData.permissionIndexes,\n _packed\n );\n }\n\n /// @notice Sets permissions for many operators.\n /// @dev Only an address can set its own operators.\n /// @param _operatorData The data that specify the params for each operator being set.\n function setOperators(JBOperatorData[] calldata _operatorData) external override {\n for (uint256 _i; _i < _operatorData.length; ) {\n // Pack the indexes into a uint256.\n uint256 _packed = _packedPermissions(_operatorData[_i].permissionIndexes);\n\n // Store the new value.\n permissionsOf[_operatorData[_i].operator][msg.sender][_operatorData[_i].domain] = _packed;\n\n emit SetOperator(\n _operatorData[_i].operator,\n msg.sender,\n _operatorData[_i].domain,\n _operatorData[_i].permissionIndexes,\n _packed\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n\n //*********************************************************************//\n // --------------------- private helper functions -------------------- //\n //*********************************************************************//\n\n /// @notice Converts an array of permission indexes to a packed `uint256`.\n /// @param _indexes The indexes of the permissions to pack.\n /// @return packed The packed value.\n function _packedPermissions(uint256[] calldata _indexes) private pure returns (uint256 packed) {\n for (uint256 _i; _i < _indexes.length; ) {\n uint256 _index = _indexes[_i];\n\n if (_index > 255) revert PERMISSION_INDEX_OUT_OF_BOUNDS();\n\n // Turn the bit at the index on.\n packed |= 1 << _index;\n\n unchecked {\n ++_i;\n }\n }\n }\n}\n" + }, + "contracts/JBFundAccessConstraintsStore.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.16;\n\nimport {ERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol';\nimport {JBControllerUtility} from './abstract/JBControllerUtility.sol';\nimport {IJBFundAccessConstraintsStore} from './interfaces/IJBFundAccessConstraintsStore.sol';\nimport {IJBDirectory} from './interfaces/IJBDirectory.sol';\nimport {IJBPaymentTerminal} from './interfaces/IJBPaymentTerminal.sol';\nimport {JBFundAccessConstraints} from './structs/JBFundAccessConstraints.sol';\n\n/// @notice Information pertaining to how much funds can be accessed by a project from each payment terminal.\ncontract JBFundAccessConstraintsStore is\n JBControllerUtility,\n ERC165,\n IJBFundAccessConstraintsStore\n{\n //*********************************************************************//\n // --------------------------- custom errors ------------------------- //\n //*********************************************************************//\n\n error INVALID_DISTRIBUTION_LIMIT();\n error INVALID_DISTRIBUTION_LIMIT_CURRENCY();\n error INVALID_OVERFLOW_ALLOWANCE();\n error INVALID_OVERFLOW_ALLOWANCE_CURRENCY();\n\n //*********************************************************************//\n // --------------------- internal stored properties ------------------ //\n //*********************************************************************//\n\n /// @notice Data regarding the distribution limit of a project during a configuration.\n /// @dev bits 0-231: The amount of token that a project can distribute per funding cycle.\n /// @dev bits 232-255: The currency of amount that a project can distribute.\n /// @custom:param _projectId The ID of the project to get the packed distribution limit data of.\n /// @custom:param _configuration The configuration during which the packed distribution limit data applies.\n /// @custom:param _terminal The terminal from which distributions are being limited.\n /// @custom:param _token The token for which distributions are being limited.\n mapping(uint256 => mapping(uint256 => mapping(IJBPaymentTerminal => mapping(address => uint256))))\n internal _packedDistributionLimitDataOf;\n\n /// @notice Data regarding the overflow allowance of a project during a configuration.\n /// @dev bits 0-231: The amount of overflow that a project is allowed to tap into on-demand throughout the configuration.\n /// @dev bits 232-255: The currency of the amount of overflow that a project is allowed to tap.\n /// @custom:param _projectId The ID of the project to get the packed overflow allowance data of.\n /// @custom:param _configuration The configuration during which the packed overflow allowance data applies.\n /// @custom:param _terminal The terminal managing the overflow.\n /// @custom:param _token The token for which overflow is being allowed.\n mapping(uint256 => mapping(uint256 => mapping(IJBPaymentTerminal => mapping(address => uint256))))\n internal _packedOverflowAllowanceDataOf;\n\n //*********************************************************************//\n // ------------------------- external views -------------------------- //\n //*********************************************************************//\n\n /// @notice The amount of token that a project can distribute per funding cycle, and the currency it's in terms of.\n /// @dev The number of decimals in the returned fixed point amount is the same as that of the specified terminal.\n /// @param _projectId The ID of the project to get the distribution limit of.\n /// @param _configuration The configuration during which the distribution limit applies.\n /// @param _terminal The terminal from which distributions are being limited.\n /// @param _token The token for which the distribution limit applies.\n /// @return The distribution limit, as a fixed point number with the same number of decimals as the provided terminal.\n /// @return The currency of the distribution limit.\n function distributionLimitOf(\n uint256 _projectId,\n uint256 _configuration,\n IJBPaymentTerminal _terminal,\n address _token\n ) external view override returns (uint256, uint256) {\n // Get a reference to the packed data.\n uint256 _data = _packedDistributionLimitDataOf[_projectId][_configuration][_terminal][_token];\n\n // The limit is in bits 0-231. The currency is in bits 232-255.\n return (uint256(uint232(_data)), _data >> 232);\n }\n\n /// @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.\n /// @dev The number of decimals in the returned fixed point amount is the same as that of the specified terminal.\n /// @param _projectId The ID of the project to get the overflow allowance of.\n /// @param _configuration The configuration of the during which the allowance applies.\n /// @param _terminal The terminal managing the overflow.\n /// @param _token The token for which the overflow allowance applies.\n /// @return The overflow allowance, as a fixed point number with the same number of decimals as the provided terminal.\n /// @return The currency of the overflow allowance.\n function overflowAllowanceOf(\n uint256 _projectId,\n uint256 _configuration,\n IJBPaymentTerminal _terminal,\n address _token\n ) external view override returns (uint256, uint256) {\n // Get a reference to the packed data.\n uint256 _data = _packedOverflowAllowanceDataOf[_projectId][_configuration][_terminal][_token];\n\n // The allowance is in bits 0-231. The currency is in bits 232-255.\n return (uint256(uint232(_data)), _data >> 232);\n }\n\n //*********************************************************************//\n // -------------------------- constructor ---------------------------- //\n //*********************************************************************//\n\n /// @param _directory A contract storing directories of terminals and controllers for each project.\n // solhint-disable-next-line no-empty-blocks\n constructor(IJBDirectory _directory) JBControllerUtility(_directory) {}\n\n //*********************************************************************//\n // --------------------- external transactions ----------------------- //\n //*********************************************************************//\n\n /// @notice Sets a project's constraints for accessing treasury funds.\n /// @dev Only a project's current controller can set its fund access constraints.\n /// @param _projectId The ID of the project whose fund access constraints are being set.\n /// @param _configuration The funding cycle configuration the constraints apply within.\n /// @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`.\n function setFor(\n uint256 _projectId,\n uint256 _configuration,\n JBFundAccessConstraints[] calldata _fundAccessConstraints\n ) external override onlyController(_projectId) {\n // Save the number of constraints.\n uint256 _numberOfFundAccessConstraints = _fundAccessConstraints.length;\n\n // Set distribution limits if there are any.\n for (uint256 _i; _i < _numberOfFundAccessConstraints; ) {\n // If distribution limit value is larger than 232 bits, revert.\n if (_fundAccessConstraints[_i].distributionLimit > type(uint232).max)\n revert INVALID_DISTRIBUTION_LIMIT();\n\n // If distribution limit currency value is larger than 24 bits, revert.\n if (_fundAccessConstraints[_i].distributionLimitCurrency > type(uint24).max)\n revert INVALID_DISTRIBUTION_LIMIT_CURRENCY();\n\n // If overflow allowance value is larger than 232 bits, revert.\n if (_fundAccessConstraints[_i].overflowAllowance > type(uint232).max)\n revert INVALID_OVERFLOW_ALLOWANCE();\n\n // If overflow allowance currency value is larger than 24 bits, revert.\n if (_fundAccessConstraints[_i].overflowAllowanceCurrency > type(uint24).max)\n revert INVALID_OVERFLOW_ALLOWANCE_CURRENCY();\n\n // Set the distribution limit if there is one.\n if (_fundAccessConstraints[_i].distributionLimit > 0)\n _packedDistributionLimitDataOf[_projectId][_configuration][\n _fundAccessConstraints[_i].terminal\n ][_fundAccessConstraints[_i].token] =\n _fundAccessConstraints[_i].distributionLimit |\n (_fundAccessConstraints[_i].distributionLimitCurrency << 232);\n\n // Set the overflow allowance if there is one.\n if (_fundAccessConstraints[_i].overflowAllowance > 0)\n _packedOverflowAllowanceDataOf[_projectId][_configuration][\n _fundAccessConstraints[_i].terminal\n ][_fundAccessConstraints[_i].token] =\n _fundAccessConstraints[_i].overflowAllowance |\n (_fundAccessConstraints[_i].overflowAllowanceCurrency << 232);\n\n emit SetFundAccessConstraints(\n _configuration,\n _projectId,\n _fundAccessConstraints[_i],\n msg.sender\n );\n\n unchecked {\n ++_i;\n }\n }\n }\n}\n" + }, + "contracts/interfaces/IJBTerminalUtility.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport {IJBDirectory} from './IJBDirectory.sol';\n\ninterface IJBPaymentTerminalUtility {\n function directory() external view returns (IJBDirectory);\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": [ + "ast" + ] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} \ No newline at end of file diff --git a/forge_tests/TestAllowance.sol b/forge_tests/TestAllowance.sol index b6f92843a..57076af98 100644 --- a/forge_tests/TestAllowance.sol +++ b/forge_tests/TestAllowance.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity >=0.8.6; -import "./helpers/TestBaseWorkflow.sol"; +import /* {*} from */ "./helpers/TestBaseWorkflow.sol"; contract TestAllowance_Local is TestBaseWorkflow { JBController controller; @@ -13,7 +13,6 @@ contract TestAllowance_Local is TestBaseWorkflow { IJBPaymentTerminal[] _terminals; JBTokenStore _tokenStore; address _projectOwner; - address _beneficiary; uint256 WEIGHT = 1000 * 10 ** 18; @@ -22,8 +21,6 @@ contract TestAllowance_Local is TestBaseWorkflow { _projectOwner = multisig(); - _beneficiary = beneficiary(); - _tokenStore = jbTokenStore(); controller = jbController(); @@ -115,7 +112,7 @@ contract TestAllowance_Local is TestBaseWorkflow { "MEMO" ); else - IJBPayoutRedemptionPaymentTerminal3_1(address(terminal)).useAllowanceOf( + JBPayoutRedemptionPaymentTerminal3_1(address(terminal)).useAllowanceOf( projectId, 5 ether, 1, // Currency @@ -143,7 +140,7 @@ contract TestAllowance_Local is TestBaseWorkflow { "Foundry payment" // Memo ); else - IJBPayoutRedemptionPaymentTerminal3_1(address(terminal)).distributePayoutsOf( + JBPayoutRedemptionPaymentTerminal3_1(address(terminal)).distributePayoutsOf( projectId, 10 ether, 1, // Currency @@ -241,7 +238,7 @@ contract TestAllowance_Local is TestBaseWorkflow { "MEMO" ); else - IJBPayoutRedemptionPaymentTerminal3_1(address(terminal)).useAllowanceOf( + JBPayoutRedemptionPaymentTerminal3_1(address(terminal)).useAllowanceOf( projectId, ALLOWANCE, CURRENCY, // Currency @@ -279,7 +276,7 @@ contract TestAllowance_Local is TestBaseWorkflow { "Foundry payment" // Memo ); else - IJBPayoutRedemptionPaymentTerminal3_1(address(terminal)).distributePayoutsOf( + JBPayoutRedemptionPaymentTerminal3_1(address(terminal)).distributePayoutsOf( projectId, TARGET, 1, // Currency diff --git a/forge_tests/TestController3_0_1.sol b/forge_tests/TestController3_0_1.sol index 54ffda689..972af5fdb 100644 --- a/forge_tests/TestController3_0_1.sol +++ b/forge_tests/TestController3_0_1.sol @@ -1,22 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.6; -import "@juicebox/JBController3_0_1.sol"; - -import "@juicebox/interfaces/IJBController.sol"; -import "@juicebox/interfaces/IJBMigratable.sol"; -import "@juicebox/interfaces/IJBOperatorStore.sol"; -import "@juicebox/interfaces/IJBPaymentTerminal.sol"; -import "@juicebox/interfaces/IJBSingleTokenPaymentTerminalStore.sol"; -import "@juicebox/interfaces/IJBProjects.sol"; - -import "@juicebox/interfaces/IJBPayoutRedemptionPaymentTerminal.sol"; - -import "@juicebox/libraries/JBTokens.sol"; -import "@juicebox/libraries/JBFundingCycleMetadataResolver.sol"; - -import "@paulrberg/contracts/math/PRBMath.sol"; -import "@paulrberg/contracts/math/PRBMathUD60x18.sol"; +import /* {*} from */ "./helpers/TestBaseWorkflow.sol"; import "forge-std/Test.sol"; @@ -82,7 +67,7 @@ contract TestController31_Fork is Test { jbFundingCycleStore = oldJbController.fundingCycleStore(); jbTokenStore = oldJbController.tokenStore(); jbSplitsStore = oldJbController.splitsStore(); - jbTerminalStore = jbEthTerminal.store(); + jbTerminalStore = IJBSingleTokenPaymentTerminalStore(jbEthTerminal.store()); // Set some mock fc data projectMetadata = JBProjectMetadata({content: "myIPFSHash", domain: 1}); diff --git a/forge_tests/TestDelegates.sol b/forge_tests/TestDelegates.sol index fdfa98dd6..da030edfa 100644 --- a/forge_tests/TestDelegates.sol +++ b/forge_tests/TestDelegates.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity >=0.8.6; -import "./helpers/TestBaseWorkflow.sol"; +import /* {*} from */ "./helpers/TestBaseWorkflow.sol"; contract TestDelegates_Local is TestBaseWorkflow { JBController controller; @@ -14,7 +14,6 @@ contract TestDelegates_Local is TestBaseWorkflow { JBTokenStore _tokenStore; address _projectOwner; - address _beneficiary; address _datasource = address(bytes20(keccak256("datasource"))); uint256 _projectId; @@ -26,8 +25,6 @@ contract TestDelegates_Local is TestBaseWorkflow { _projectOwner = multisig(); - _beneficiary = beneficiary(); - _tokenStore = jbTokenStore(); controller = jbController(); diff --git a/forge_tests/TestDistributeHeldFee.sol b/forge_tests/TestDistributeHeldFee.sol index 74cef1e98..e13da7ba6 100644 --- a/forge_tests/TestDistributeHeldFee.sol +++ b/forge_tests/TestDistributeHeldFee.sol @@ -1,10 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.6; -import "@paulrberg/contracts/math/PRBMath.sol"; -import "@paulrberg/contracts/math/PRBMathUD60x18.sol"; - -import "./helpers/TestBaseWorkflow.sol"; +import /* {*} from */ "./helpers/TestBaseWorkflow.sol"; contract TestDistributeHeldFee_Local is TestBaseWorkflow { JBController private _controller; @@ -111,7 +108,7 @@ contract TestDistributeHeldFee_Local is TestBaseWorkflow { abi.encode(feeDiscount) ); vm.prank(multisig()); - _terminal.setFeeGauge(feeGauge); + _terminal.setFeeGauge(address(feeGauge)); uint256 discountedFee = fee - PRBMath.mulDiv(fee, feeDiscount, jbLibraries().MAX_FEE()); @@ -247,7 +244,7 @@ contract TestDistributeHeldFee_Local is TestBaseWorkflow { abi.encode(feeDiscount) ); vm.prank(multisig()); - _terminal.setFeeGauge(feeGauge); + _terminal.setFeeGauge(address(feeGauge)); // -- pay -- _terminal.pay{value: payAmountInWei}( diff --git a/forge_tests/TestEIP165.sol b/forge_tests/TestEIP165.sol index 5af53fee3..c715178cc 100644 --- a/forge_tests/TestEIP165.sol +++ b/forge_tests/TestEIP165.sol @@ -1,10 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.6; -import "./helpers/TestBaseWorkflow.sol"; -import "@juicebox/JBReconfigurationBufferBallot.sol"; -import "@juicebox/JBETHERC20SplitsPayer.sol"; -import "@juicebox/JBETHERC20SplitsPayerDeployer.sol"; +import /* {*} from */ "./helpers/TestBaseWorkflow.sol"; contract TestEIP165_Local is TestBaseWorkflow { bytes4 constant notSupportedInterface = 0xffffffff; diff --git a/forge_tests/TestERC20Terminal.sol b/forge_tests/TestERC20Terminal.sol index d4d3f2958..f88588486 100644 --- a/forge_tests/TestERC20Terminal.sol +++ b/forge_tests/TestERC20Terminal.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.6; -import "./helpers/TestBaseWorkflow.sol"; +import /* {*} from */ "./helpers/TestBaseWorkflow.sol"; import {MockMaliciousAllocator, GasGussler} from "./mock/MockMaliciousAllocator.sol"; -import "./mock/MockMaliciousTerminal.sol"; +import {MockMaliciousTerminal} from "./mock/MockMaliciousTerminal.sol"; contract TestERC20Terminal_Local is TestBaseWorkflow { event PayoutReverted(uint256 indexed projectId, JBSplit split, uint256 amount, bytes reason, address caller); diff --git a/forge_tests/TestLaunchProject.sol b/forge_tests/TestLaunchProject.sol index e079db2aa..fadcc490b 100644 --- a/forge_tests/TestLaunchProject.sol +++ b/forge_tests/TestLaunchProject.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.6; -import "./helpers/TestBaseWorkflow.sol"; +import /* {*} from */ "./helpers/TestBaseWorkflow.sol"; contract TestLaunchProject_Local is TestBaseWorkflow { JBProjectMetadata _projectMetadata; diff --git a/forge_tests/TestMigrationOperator.sol b/forge_tests/TestMigrationOperator.sol index 7b9916656..bac65ffe8 100644 --- a/forge_tests/TestMigrationOperator.sol +++ b/forge_tests/TestMigrationOperator.sol @@ -1,27 +1,9 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.6; -import "@juicebox/JBController3_0_1.sol"; -import "@juicebox/JBMigrationOperator.sol"; -import "@juicebox/JBReconfigurationBufferBallot.sol"; - -import "@juicebox/interfaces/IJBController.sol"; -import "@juicebox/interfaces/IJBMigratable.sol"; -import "@juicebox/interfaces/IJBOperatorStore.sol"; -import "@juicebox/interfaces/IJBPaymentTerminal.sol"; -import "@juicebox/interfaces/IJBSingleTokenPaymentTerminalStore.sol"; -import "@juicebox/interfaces/IJBProjects.sol"; -import "@juicebox/interfaces/IJBPayoutRedemptionPaymentTerminal.sol"; - -import "@juicebox/libraries/JBTokens.sol"; -import "@juicebox/libraries/JBFundingCycleMetadataResolver.sol"; - -import "@paulrberg/contracts/math/PRBMath.sol"; -import "@paulrberg/contracts/math/PRBMathUD60x18.sol"; - import "forge-std/Test.sol"; -import "./helpers/TestBaseWorkflow.sol"; +import /* {*} from */ "./helpers/TestBaseWorkflow.sol"; /** * @title Migration operator test @@ -99,7 +81,7 @@ contract TestMigrationOperator_Local is TestBaseWorkflow { jbDirectory(), jbSplitsStore(), jbPrices(), - jbTerminalStore3_1, + address(jbTerminalStore3_1), Ownable(address(jbETHPaymentTerminal())).owner() ); @@ -185,7 +167,7 @@ contract TestMigrationOperator_Local is TestBaseWorkflow { jbDirectory(), jbSplitsStore(), jbPrices(), - jbTerminalStore3_1, + address(jbTerminalStore3_1), Ownable(address(jbETHPaymentTerminal())).owner() ); @@ -352,7 +334,7 @@ contract TestMigrationOperator_Fork is Test { jbFundingCycleStore = oldJbController.fundingCycleStore(); jbTokenStore = oldJbController.tokenStore(); jbSplitsStore = oldJbController.splitsStore(); - jbTerminalStore = jbEthTerminal.store(); + jbTerminalStore = IJBSingleTokenPaymentTerminalStore(jbEthTerminal.store()); // Set some mock fc data _initMetadata(); diff --git a/forge_tests/TestMultipleTerminals.sol b/forge_tests/TestMultipleTerminals.sol index 3f087da87..28ef7f59f 100644 --- a/forge_tests/TestMultipleTerminals.sol +++ b/forge_tests/TestMultipleTerminals.sol @@ -1,10 +1,9 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.6; -import "@paulrberg/contracts/math/PRBMath.sol"; -import "./helpers/TestBaseWorkflow.sol"; -import "./mock/MockPriceFeed.sol"; -import "@paulrberg/contracts/math/PRBMath.sol"; +import /* {*} from */ "./helpers/TestBaseWorkflow.sol"; + +import {MockPriceFeed} from "./mock/MockPriceFeed.sol"; contract TestMultipleTerminals_Local is TestBaseWorkflow { JBController controller; @@ -96,7 +95,7 @@ contract TestMultipleTerminals_Local is TestBaseWorkflow { jbDirectory(), jbSplitsStore(), jbPrices(), - jbPaymentTerminalStore(), + address(jbPaymentTerminalStore()), multisig() ); }else{ @@ -110,7 +109,7 @@ contract TestMultipleTerminals_Local is TestBaseWorkflow { jbDirectory(), jbSplitsStore(), jbPrices(), - jbPaymentTerminalStore(), + address(jbPaymentTerminalStore()), multisig() ))); } diff --git a/forge_tests/TestPayBurnRedeemFlow.sol b/forge_tests/TestPayBurnRedeemFlow.sol index 42e90691e..58559622c 100644 --- a/forge_tests/TestPayBurnRedeemFlow.sol +++ b/forge_tests/TestPayBurnRedeemFlow.sol @@ -1,10 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.6; -import "@paulrberg/contracts/math/PRBMath.sol"; -import "@paulrberg/contracts/math/PRBMathUD60x18.sol"; - -import "./helpers/TestBaseWorkflow.sol"; +import /* {*} from */ "./helpers/TestBaseWorkflow.sol"; /** * This system test file verifies the following flow: diff --git a/forge_tests/TestPlanetable.sol b/forge_tests/TestPlanetable.sol.bak similarity index 99% rename from forge_tests/TestPlanetable.sol rename to forge_tests/TestPlanetable.sol.bak index ac51b2228..442cfa9cd 100644 --- a/forge_tests/TestPlanetable.sol +++ b/forge_tests/TestPlanetable.sol.bak @@ -1,3 +1,8 @@ +// +// Planetable migration achieved - this is now deprecated +// + + // SPDX-License-Identifier: MIT pragma solidity ^0.8.6; diff --git a/forge_tests/TestReconfigure.sol b/forge_tests/TestReconfigure.sol index 088d44e0a..f89d2272b 100644 --- a/forge_tests/TestReconfigure.sol +++ b/forge_tests/TestReconfigure.sol @@ -1,9 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.6; -import "./helpers/TestBaseWorkflow.sol"; - -import "@juicebox/JBReconfigurationBufferBallot.sol"; +import /* {*} from */ "./helpers/TestBaseWorkflow.sol"; uint256 constant WEIGHT = 1000 * 10 ** 18; diff --git a/forge_tests/TestRedeeem.sol b/forge_tests/TestRedeeem.sol index 1c9aee96f..62024cb02 100644 --- a/forge_tests/TestRedeeem.sol +++ b/forge_tests/TestRedeeem.sol @@ -1,10 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.6; -import "@paulrberg/contracts/math/PRBMath.sol"; -import "@paulrberg/contracts/math/PRBMathUD60x18.sol"; - -import "./helpers/TestBaseWorkflow.sol"; +import /* {*} from */ "./helpers/TestBaseWorkflow.sol"; /** * This system test file verifies the following flow: @@ -13,6 +10,7 @@ import "./helpers/TestBaseWorkflow.sol"; contract TestRedeem_Local is TestBaseWorkflow { JBController private _controller; JBETHPaymentTerminal private _terminal; + JBETHPaymentTerminal3_1_1 private _terminal3_1_1; JBTokenStore private _tokenStore; JBProjectMetadata private _projectMetadata; @@ -32,6 +30,18 @@ contract TestRedeem_Local is TestBaseWorkflow { _controller = jbController(); _terminal = jbETHPaymentTerminal(); + + _terminal3_1_1 = new JBETHPaymentTerminal3_1_1( + _accessJBLib.ETH(), + _jbOperatorStore, + _jbProjects, + _jbDirectory, + _jbSplitsStore, + _jbPrices, + address(_jbPaymentTerminalStore3_1), + _multisig + ); + _tokenStore = jbTokenStore(); _projectMetadata = JBProjectMetadata({content: "myIPFSHash", domain: 1}); @@ -51,7 +61,7 @@ contract TestRedeem_Local is TestBaseWorkflow { }), reservedRate: 0, redemptionRate: 5000, - ballotRedemptionRate: 0, + ballotRedemptionRate: 5000, pausePay: false, pauseDistributions: false, pauseRedeem: false, @@ -69,6 +79,7 @@ contract TestRedeem_Local is TestBaseWorkflow { }); _terminals.push(_terminal); + _terminals.push(_terminal3_1_1); _fundAccessConstraints.push( JBFundAccessConstraints({ @@ -81,8 +92,32 @@ contract TestRedeem_Local is TestBaseWorkflow { }) ); + _fundAccessConstraints.push( + JBFundAccessConstraints({ + terminal: _terminal3_1_1, + token: jbLibraries().ETHToken(), + distributionLimit: 0, // only overflow + overflowAllowance: 5 ether, + distributionLimitCurrency: 1, // Currency = ETH + overflowAllowanceCurrency: 1 + }) + ); + _projectOwner = multisig(); + // Launch a protocol project first + _controller.launchProjectFor( + _projectOwner, + _projectMetadata, + _data, + _metadata, + block.timestamp, + _groupedSplits, + _fundAccessConstraints, + _terminals, + "" + ); + _projectId = _controller.launchProjectFor( _projectOwner, _projectMetadata, @@ -156,4 +191,96 @@ contract TestRedeem_Local is TestBaseWorkflow { // verify: ETH balance in terminal should be up to date assertEq(jbPaymentTerminalStore().balanceOf(_terminal, _projectId), _terminalBalanceInWei - _reclaimAmtInWei); } + + function testRedeemTerminal3_1_1(uint256 _tokenAmountToRedeem) external { + bool payPreferClaimed = true; //false + uint96 payAmountInWei = 10 ether; + + // issue an ERC-20 token for project + vm.prank(_projectOwner); + _tokenStore.issueFor(_projectId, "TestName", "TestSymbol"); + + address _userWallet = address(1234); + + // pay terminal + _terminal3_1_1.pay{value: payAmountInWei}( + _projectId, + payAmountInWei, + address(0), + _userWallet, + /* _minReturnedTokens */ + 0, + /* _preferClaimedTokens */ + payPreferClaimed, + /* _memo */ + "Take my money!", + /* _delegateMetadata */ + new bytes(0) + ); + + // verify: beneficiary should have a balance of JBTokens + uint256 _userTokenBalance = PRBMathUD60x18.mul(payAmountInWei, _weight); + assertEq(_tokenStore.balanceOf(_userWallet, _projectId), _userTokenBalance); + + // verify: ETH balance in terminal should be up to date + uint256 _terminalBalanceInWei = payAmountInWei; + assertEq(jbPaymentTerminalStore().balanceOf(_terminal3_1_1, _projectId), _terminalBalanceInWei); + + // Fuzz 1 to full balance redemption + _tokenAmountToRedeem = bound(_tokenAmountToRedeem, 1, _userTokenBalance); + + // Test: redeem + vm.prank(_userWallet); + uint256 _reclaimAmtInWei = _terminal3_1_1.redeemTokensOf( + /* _holder */ + _userWallet, + /* _projectId */ + _projectId, + /* _tokenCount */ + _tokenAmountToRedeem, + /* token (unused) */ + address(0), + /* _minReturnedWei */ + 0, + /* _beneficiary */ + payable(_userWallet), + /* _memo */ + "Refund me now!", + /* _delegateMetadata */ + new bytes(0) + ); + + // Check: correct amount returned, 50% redemption rate + uint256 _grossRedeemed = PRBMath.mulDiv( + _tokenAmountToRedeem, + 5000 + + PRBMath.mulDiv( + _tokenAmountToRedeem, + JBConstants.MAX_REDEMPTION_RATE - 5000, + _userTokenBalance + ), + JBConstants.MAX_REDEMPTION_RATE + ); + + // Compute the fee taken + uint256 _fee = _grossRedeemed - PRBMath.mulDiv(_grossRedeemed, 1_000_000_000, 25000000 + 1_000_000_000); // 2.5% fee + + // Compute the net amount received, still in $project + uint256 _netReceived = _grossRedeemed - _fee; + + // Convert in actual ETH, based on the weight + uint256 _convertedInEth = PRBMath.mulDiv(_netReceived, 1e18, _weight); + + // Verify: correct amount returned (2 wei precision) + assertApproxEqAbs(_reclaimAmtInWei, _convertedInEth, 2, "incorrect amount returned"); + + // Verify: beneficiary received correct amount of ETH + assertEq(payable(_userWallet).balance, _reclaimAmtInWei); + + // verify: beneficiary has correct amount of token + assertEq(_tokenStore.balanceOf(_userWallet, _projectId), _userTokenBalance - _tokenAmountToRedeem, "incorrect beneficiary balance"); + + // verify: ETH balance in terminal should be up to date (with 1 wei precision) + assertApproxEqAbs(jbPaymentTerminalStore().balanceOf(_terminal3_1_1, _projectId), _terminalBalanceInWei - _reclaimAmtInWei - (_reclaimAmtInWei * 25 / 1000), 1); + } } diff --git a/forge_tests/TestTerminal3_1.sol b/forge_tests/TestTerminal3_1.sol index ff8cc5982..f73fd7faa 100644 --- a/forge_tests/TestTerminal3_1.sol +++ b/forge_tests/TestTerminal3_1.sol @@ -1,26 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.6; -import "@juicebox/JBController3_1.sol"; -import "@juicebox/JBFundAccessConstraintsStore.sol"; - -import "@juicebox/interfaces/IJBController.sol"; -import "@juicebox/interfaces/IJBMigratable.sol"; -import "@juicebox/interfaces/IJBOperatorStore.sol"; -import "@juicebox/interfaces/IJBPaymentTerminal.sol"; -import "@juicebox/interfaces/IJBSingleTokenPaymentTerminalStore.sol"; -import "@juicebox/interfaces/IJBPrices.sol"; -import "@juicebox/interfaces/IJBProjects.sol"; -import "@juicebox/interfaces/IJBPayoutRedemptionPaymentTerminal.sol"; - -import "@juicebox/libraries/JBTokens.sol"; -import "@juicebox/libraries/JBFundingCycleMetadataResolver.sol"; - -import "@juicebox/JBETHPaymentTerminal3_1.sol"; -import "@juicebox/JBSingleTokenPaymentTerminalStore3_1.sol"; - -import "@paulrberg/contracts/math/PRBMath.sol"; -import "@paulrberg/contracts/math/PRBMathUD60x18.sol"; +import /* {*} from */ "./helpers/TestBaseWorkflow.sol"; import "forge-std/Test.sol"; @@ -94,7 +75,7 @@ contract TestTerminal31_Fork is Test { jbFundingCycleStore = oldJbController.fundingCycleStore(); jbTokenStore = oldJbController.tokenStore(); jbSplitsStore = oldJbController.splitsStore(); - jbTerminalStore = jbEthTerminal.store(); + jbTerminalStore = IJBSingleTokenPaymentTerminalStore(jbEthTerminal.store()); jbPrices = jbEthTerminal.prices(); jbTerminalStore3_1 = new JBSingleTokenPaymentTerminalStore3_1( @@ -110,7 +91,7 @@ contract TestTerminal31_Fork is Test { jbDirectory, jbSplitsStore, jbPrices, - jbTerminalStore3_1, + address(jbTerminalStore3_1), Ownable(address(jbEthTerminal)).owner() ); diff --git a/forge_tests/TestTokenFlow.sol b/forge_tests/TestTokenFlow.sol index 6fd4ad3c4..2fef7c26a 100644 --- a/forge_tests/TestTokenFlow.sol +++ b/forge_tests/TestTokenFlow.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.6; -import "./helpers/TestBaseWorkflow.sol"; +import /* {*} from */ "./helpers/TestBaseWorkflow.sol"; /// @notice This file tests JBToken related flows contract TestTokenFlow_Local is TestBaseWorkflow { diff --git a/forge_tests/helpers/AccessJBLib.sol b/forge_tests/helpers/AccessJBLib.sol index 707d16ee7..f9f8abacb 100644 --- a/forge_tests/helpers/AccessJBLib.sol +++ b/forge_tests/helpers/AccessJBLib.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.6; -import "@juicebox/libraries/JBCurrencies.sol"; -import "@juicebox/libraries/JBConstants.sol"; -import "@juicebox/libraries/JBTokens.sol"; +import {JBCurrencies} from "@juicebox/libraries/JBCurrencies.sol"; +import {JBConstants} from "@juicebox/libraries/JBConstants.sol"; +import {JBTokens} from "@juicebox/libraries/JBTokens.sol"; contract AccessJBLib { function ETH() external pure returns (uint256) { diff --git a/forge_tests/helpers/TestBaseWorkflow.sol b/forge_tests/helpers/TestBaseWorkflow.sol index 6917106da..571064439 100644 --- a/forge_tests/helpers/TestBaseWorkflow.sol +++ b/forge_tests/helpers/TestBaseWorkflow.sol @@ -3,94 +3,153 @@ pragma solidity ^0.8.6; import "forge-std/Test.sol"; -import "@juicebox/JBController.sol"; -import "@juicebox/JBController3_1.sol"; -import "@juicebox/JBDirectory.sol"; -import "@juicebox/JBETHPaymentTerminal.sol"; -import "@juicebox/JBETHPaymentTerminal3_1.sol"; -import "@juicebox/JBERC20PaymentTerminal.sol"; -import "@juicebox/JBERC20PaymentTerminal3_1.sol"; -import "@juicebox/JBSingleTokenPaymentTerminalStore.sol"; -import "@juicebox/JBSingleTokenPaymentTerminalStore3_1.sol"; -import "@juicebox/JBFundAccessConstraintsStore.sol"; -import "@juicebox/JBFundingCycleStore.sol"; -import "@juicebox/JBOperatorStore.sol"; -import "@juicebox/JBPrices.sol"; -import "@juicebox/JBProjects.sol"; -import "@juicebox/JBSplitsStore.sol"; -import "@juicebox/JBToken.sol"; -import "@juicebox/JBTokenStore.sol"; - -import "@juicebox/structs/JBDidPayData.sol"; -import "@juicebox/structs/JBDidRedeemData.sol"; -import "@juicebox/structs/JBFee.sol"; -import "@juicebox/structs/JBFundAccessConstraints.sol"; -import "@juicebox/structs/JBFundingCycle.sol"; -import "@juicebox/structs/JBFundingCycleData.sol"; -import "@juicebox/structs/JBFundingCycleMetadata.sol"; -import "@juicebox/structs/JBGroupedSplits.sol"; -import "@juicebox/structs/JBOperatorData.sol"; -import "@juicebox/structs/JBPayParamsData.sol"; -import "@juicebox/structs/JBProjectMetadata.sol"; -import "@juicebox/structs/JBRedeemParamsData.sol"; -import "@juicebox/structs/JBSplit.sol"; - -import "@juicebox/interfaces/IJBPaymentTerminal.sol"; -import "@juicebox/interfaces/IJBToken.sol"; +import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; +import {IERC721Metadata} from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; +import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; +import {ERC165, IERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol"; + +import {JBController} from "@juicebox/JBController.sol"; +import {JBController3_1} from "@juicebox/JBController3_1.sol"; +import {JBDirectory} from "@juicebox/JBDirectory.sol"; +import {JBETHPaymentTerminal} from "@juicebox/JBETHPaymentTerminal.sol"; +import {JBETHPaymentTerminal3_1} from "@juicebox/JBETHPaymentTerminal3_1.sol"; +import {JBERC20PaymentTerminal} from "@juicebox/JBERC20PaymentTerminal.sol"; +import {JBERC20PaymentTerminal3_1} from "@juicebox/JBERC20PaymentTerminal3_1.sol"; +import {JBSingleTokenPaymentTerminalStore} from "@juicebox/JBSingleTokenPaymentTerminalStore.sol"; +import {JBSingleTokenPaymentTerminalStore3_1} from "@juicebox/JBSingleTokenPaymentTerminalStore3_1.sol"; +import {JBFundAccessConstraintsStore} from "@juicebox/JBFundAccessConstraintsStore.sol"; +import {JBFundingCycleStore} from "@juicebox/JBFundingCycleStore.sol"; +import {JBOperatorStore} from "@juicebox/JBOperatorStore.sol"; +import {JBPrices} from "@juicebox/JBPrices.sol"; +import {JBProjects} from "@juicebox/JBProjects.sol"; +import {JBSplitsStore} from "@juicebox/JBSplitsStore.sol"; +import {JBToken} from "@juicebox/JBToken.sol"; +import {JBTokenStore} from "@juicebox/JBTokenStore.sol"; +import {JBMigrationOperator} from "@juicebox/JBMigrationOperator.sol"; +import {JBReconfigurationBufferBallot} from "@juicebox/JBReconfigurationBufferBallot.sol"; +import {JBETHERC20SplitsPayerDeployer} from "@juicebox/JBETHERC20SplitsPayerDeployer.sol"; +import {JBETHERC20SplitsPayer} from "@juicebox/JBETHERC20SplitsPayer.sol"; +import {JBETHPaymentTerminal3_1_1} from "@juicebox/JBETHPaymentTerminal3_1_1.sol"; + +import {JBPayoutRedemptionPaymentTerminal3_1} from "@juicebox/abstract/JBPayoutRedemptionPaymentTerminal3_1.sol"; +import {JBSingleTokenPaymentTerminal} from "@juicebox/abstract/JBSingleTokenPaymentTerminal.sol"; + + +import {JBDidPayData} from "@juicebox/structs/JBDidPayData.sol"; +import {JBDidRedeemData} from "@juicebox/structs/JBDidRedeemData.sol"; +import {JBFee} from "@juicebox/structs/JBFee.sol"; +import {JBFundAccessConstraints} from "@juicebox/structs/JBFundAccessConstraints.sol"; +import {JBFundingCycle} from "@juicebox/structs/JBFundingCycle.sol"; +import {JBFundingCycleData} from "@juicebox/structs/JBFundingCycleData.sol"; +import {JBFundingCycleMetadata} from "@juicebox/structs/JBFundingCycleMetadata.sol"; +import {JBGroupedSplits} from "@juicebox/structs/JBGroupedSplits.sol"; +import {JBOperatorData} from "@juicebox/structs/JBOperatorData.sol"; +import {JBPayParamsData} from "@juicebox/structs/JBPayParamsData.sol"; +import {JBProjectMetadata} from "@juicebox/structs/JBProjectMetadata.sol"; +import {JBRedeemParamsData} from "@juicebox/structs/JBRedeemParamsData.sol"; +import {JBSplit} from "@juicebox/structs/JBSplit.sol"; +import {JBProjectMetadata} from "@juicebox/structs/JBProjectMetadata.sol"; +import {JBGlobalFundingCycleMetadata} from "@juicebox/structs/JBGlobalFundingCycleMetadata.sol"; +import {JBPayDelegateAllocation} from "@juicebox/structs/JBPayDelegateAllocation.sol"; +import {JBTokenAmount} from "@juicebox/structs/JBTokenAmount.sol"; +import {JBSplitAllocationData} from "@juicebox/structs/JBSplitAllocationData.sol"; + +import {IJBPaymentTerminal} from "@juicebox/interfaces/IJBPaymentTerminal.sol"; +import {IJBToken} from "@juicebox/interfaces/IJBToken.sol"; +import {JBController3_0_1} from "@juicebox/JBController3_0_1.sol"; +import {IJBController} from "@juicebox/interfaces/IJBController.sol"; +import {IJBMigratable} from "@juicebox/interfaces/IJBMigratable.sol"; +import {IJBOperatorStore} from "@juicebox/interfaces/IJBOperatorStore.sol"; +import {IJBSingleTokenPaymentTerminalStore} from "@juicebox/interfaces/IJBSingleTokenPaymentTerminalStore.sol"; +import {IJBProjects} from "@juicebox/interfaces/IJBProjects.sol"; +import {IJBFundingCycleBallot} from "@juicebox/interfaces/IJBFundingCycleBallot.sol"; +import {IJBPayoutRedemptionPaymentTerminal} from "@juicebox/interfaces/IJBPayoutRedemptionPaymentTerminal.sol"; +import {IJBDirectory} from "@juicebox/interfaces/IJBDirectory.sol"; +import {IJBFundingCycleStore} from "@juicebox/interfaces/IJBFundingCycleStore.sol"; +import {IJBSplitsStore} from "@juicebox/interfaces/IJBSplitsStore.sol"; +import {IJBTokenStore} from "@juicebox/interfaces/IJBTokenStore.sol"; +import {IJBSplitAllocator} from "@juicebox/interfaces/IJBSplitAllocator.sol"; +import {IJBPayDelegate} from "@juicebox/interfaces/IJBPayDelegate.sol"; +import {IJBFundingCycleDataSource} from "@juicebox/interfaces/IJBFundingCycleDataSource.sol"; +import {IJBFeeGauge} from "@juicebox/interfaces/IJBFeeGauge.sol"; +import {IJBPayoutRedemptionPaymentTerminal3_1} from "@juicebox/interfaces/IJBPayoutRedemptionPaymentTerminal3_1.sol"; +import {IJBFeeHoldingTerminal} from "@juicebox/interfaces/IJBFeeHoldingTerminal.sol"; +import {IJBProjectPayer} from "@juicebox/interfaces/IJBProjectPayer.sol"; +import {IJBOperatable} from "@juicebox/interfaces/IJBOperatable.sol"; +import {IJBAllowanceTerminal} from "@juicebox/interfaces/IJBAllowanceTerminal.sol"; +import {IJBPayoutTerminal} from "@juicebox/interfaces/IJBPayoutTerminal.sol"; +import {IJBRedemptionTerminal} from "@juicebox/interfaces/IJBRedemptionTerminal.sol"; +import {IJBPayoutTerminal3_1} from "@juicebox/interfaces/IJBPayoutTerminal3_1.sol"; +import {IJBAllowanceTerminal3_1} from "@juicebox/interfaces/IJBAllowanceTerminal3_1.sol"; +import {IJBSingleTokenPaymentTerminal} from "@juicebox/interfaces/IJBSingleTokenPaymentTerminal.sol"; +import {IJBController3_1} from "@juicebox/interfaces/IJBController3_1.sol"; +import {IJBSingleTokenPaymentTerminalStore} from "@juicebox/interfaces/IJBSingleTokenPaymentTerminalStore.sol"; +import {IJBFundingCycleBallot} from "@juicebox/interfaces/IJBFundingCycleBallot.sol"; +import {IJBPrices} from "@juicebox/interfaces/IJBPrices.sol"; +import {IJBPriceFeed} from "@juicebox/interfaces/IJBPriceFeed.sol"; +import {IJBSplitsPayer} from "@juicebox/interfaces/IJBSplitsPayer.sol"; + +import {JBTokens} from "@juicebox/libraries/JBTokens.sol"; +import {JBFundingCycleMetadataResolver} from "@juicebox/libraries/JBFundingCycleMetadataResolver.sol"; +import {JBConstants} from "@juicebox/libraries/JBConstants.sol"; +import {JBSplitsGroups} from "@juicebox/libraries/JBSplitsGroups.sol"; +import {JBOperations} from "@juicebox/libraries/JBOperations.sol"; import "./AccessJBLib.sol"; import "@paulrberg/contracts/math/PRBMath.sol"; +import "@paulrberg/contracts/math/PRBMathUD60x18.sol"; // Base contract for Juicebox system tests. // // Provides common functionality, such as deploying contracts on test setup. contract TestBaseWorkflow is Test { //*********************************************************************// - // --------------------- private stored properties ------------------- // + // --------------------- internal stored properties ------------------- // //*********************************************************************// // Multisig address used for testing. - address private _multisig = address(123); + address internal _multisig = address(123); - address private _beneficiary = address(69420); + address internal _beneficiary = address(69420); // JBOperatorStore - JBOperatorStore private _jbOperatorStore; + JBOperatorStore internal _jbOperatorStore; // JBProjects - JBProjects private _jbProjects; + JBProjects internal _jbProjects; // JBPrices - JBPrices private _jbPrices; + JBPrices internal _jbPrices; // JBDirectory - JBDirectory private _jbDirectory; + JBDirectory internal _jbDirectory; // JBFundingCycleStore - JBFundingCycleStore private _jbFundingCycleStore; + JBFundingCycleStore internal _jbFundingCycleStore; // JBToken - JBToken private _jbToken; + JBToken internal _jbToken; // JBTokenStore - JBTokenStore private _jbTokenStore; + JBTokenStore internal _jbTokenStore; // JBSplitsStore - JBSplitsStore private _jbSplitsStore; + JBSplitsStore internal _jbSplitsStore; // JBController(s) - JBController private _jbController; - JBController3_1 private _jbController3_1; + JBController internal _jbController; + JBController3_1 internal _jbController3_1; - JBFundAccessConstraintsStore private _jbFundAccessConstraintsStore; + JBFundAccessConstraintsStore internal _jbFundAccessConstraintsStore; // JBETHPaymentTerminalStore - JBSingleTokenPaymentTerminalStore private _jbPaymentTerminalStore; - JBSingleTokenPaymentTerminalStore3_1 private _jbPaymentTerminalStore3_1; + JBSingleTokenPaymentTerminalStore internal _jbPaymentTerminalStore; + JBSingleTokenPaymentTerminalStore3_1 internal _jbPaymentTerminalStore3_1; // JBETHPaymentTerminal - JBETHPaymentTerminal private _jbETHPaymentTerminal; - JBETHPaymentTerminal3_1 private _jbETHPaymentTerminal3_1; + JBETHPaymentTerminal internal _jbETHPaymentTerminal; + JBETHPaymentTerminal3_1 internal _jbETHPaymentTerminal3_1; // JBERC20PaymentTerminal - JBERC20PaymentTerminal private _jbERC20PaymentTerminal; - JBERC20PaymentTerminal3_1 private _jbERC20PaymentTerminal3_1; + JBERC20PaymentTerminal internal _jbERC20PaymentTerminal; + JBERC20PaymentTerminal3_1 internal _jbERC20PaymentTerminal3_1; // AccessJBLib - AccessJBLib private _accessJBLib; + AccessJBLib internal _accessJBLib; //*********************************************************************// // ------------------------- internal views -------------------------- // @@ -100,10 +159,6 @@ contract TestBaseWorkflow is Test { return _multisig; } - function beneficiary() internal view returns (address) { - return _beneficiary; - } - function jbOperatorStore() internal view returns (JBOperatorStore) { return _jbOperatorStore; } @@ -283,7 +338,7 @@ contract TestBaseWorkflow is Test { _jbDirectory, _jbSplitsStore, _jbPrices, - _jbPaymentTerminalStore, + address(_jbPaymentTerminalStore), _multisig ); vm.label(address(_jbETHPaymentTerminal), "JBETHPaymentTerminal"); @@ -296,7 +351,7 @@ contract TestBaseWorkflow is Test { _jbDirectory, _jbSplitsStore, _jbPrices, - _jbPaymentTerminalStore3_1, + address(_jbPaymentTerminalStore3_1), _multisig ); vm.label(address(_jbETHPaymentTerminal3_1), "JBETHPaymentTerminal3_1"); @@ -318,7 +373,7 @@ contract TestBaseWorkflow is Test { _jbDirectory, _jbSplitsStore, _jbPrices, - _jbPaymentTerminalStore, + address(_jbPaymentTerminalStore), _multisig ); vm.label(address(_jbERC20PaymentTerminal), "JBERC20PaymentTerminal"); @@ -334,7 +389,7 @@ contract TestBaseWorkflow is Test { _jbDirectory, _jbSplitsStore, _jbPrices, - _jbPaymentTerminalStore3_1, + address(_jbPaymentTerminalStore3_1), _multisig ); diff --git a/forge_tests/mock/MockMaliciousAllocator.sol b/forge_tests/mock/MockMaliciousAllocator.sol index 0d90da05e..4a3151cf7 100644 --- a/forge_tests/mock/MockMaliciousAllocator.sol +++ b/forge_tests/mock/MockMaliciousAllocator.sol @@ -1,10 +1,9 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.16; -import '../../contracts/structs/JBSplitAllocationData.sol'; -import '../../contracts/interfaces/IJBPayDelegate.sol'; -import '../../contracts/interfaces/IJBSplitAllocator.sol'; -import '@openzeppelin/contracts/utils/introspection/ERC165.sol'; +import /* {*} from */ "../helpers/TestBaseWorkflow.sol"; + +import {ERC165, IERC165} from '@openzeppelin/contracts/utils/introspection/ERC165.sol'; contract MockMaliciousAllocator is ERC165, IJBSplitAllocator { error NopeNotGonnaDoIt(); diff --git a/forge_tests/mock/MockMaliciousTerminal.sol b/forge_tests/mock/MockMaliciousTerminal.sol index 77cead64a..14024da38 100644 --- a/forge_tests/mock/MockMaliciousTerminal.sol +++ b/forge_tests/mock/MockMaliciousTerminal.sol @@ -1,9 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.16; -import '../../contracts/JBERC20PaymentTerminal3_1.sol'; - - +import /* {*} from */ "../helpers/TestBaseWorkflow.sol"; contract MockMaliciousTerminal is JBERC20PaymentTerminal3_1 { error NopeNotGonnaDoIt(); @@ -50,7 +48,7 @@ contract MockMaliciousTerminal is JBERC20PaymentTerminal3_1 { _directory, _splitsStore, _prices, - _store, + address(_store), _owner ) // solhint-disable-next-line no-empty-blocks diff --git a/forge_tests/mock/MockPriceFeed.sol b/forge_tests/mock/MockPriceFeed.sol index 792c67fb6..600eec8de 100644 --- a/forge_tests/mock/MockPriceFeed.sol +++ b/forge_tests/mock/MockPriceFeed.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.16; -import "@juicebox/interfaces/IJBPriceFeed.sol"; +import /* {*} from */ "../helpers/TestBaseWorkflow.sol"; contract MockPriceFeed is IJBPriceFeed { uint256 public fakePrice; diff --git a/hardhat.config.js b/hardhat.config.js index 3c2e05246..712df2b84 100644 --- a/hardhat.config.js +++ b/hardhat.config.js @@ -11,10 +11,11 @@ require('solidity-coverage'); dotenv.config(); -const defaultNetwork = 'localhost'; +const defaultNetwork = 'hardhat'; function mnemonic() { try { + // 0xc64533F8d8dEbC301cb4791e6ED941Cb38473DE6 return fs.readFileSync('./mnemonic.txt').toString().trim(); } catch (e) { if (defaultNetwork !== 'localhost') { @@ -42,6 +43,12 @@ module.exports = { mnemonic: mnemonic(), }, }, + sepolia: { + url: 'https://sepolia.infura.io/v3/' + infuraId, + accounts: { + mnemonic: mnemonic(), + }, + }, mainnet: { url: 'https://mainnet.infura.io/v3/' + infuraId, accounts: { @@ -66,13 +73,13 @@ module.exports = { optimizer: { enabled: true, // https://docs.soliditylang.org/en/v0.8.10/internals/optimizer.html#:~:text=Optimizer%20Parameter%20Runs,-The%20number%20of&text=A%20%E2%80%9Cruns%E2%80%9D%20parameter%20of%20%E2%80%9C,is%202**32%2D1%20. - runs: 10000, + runs: 200, }, }, }, mocha: { - bail: true, - timeout: 12000, + // bail: true, + timeout: 100000000, }, gasReporter: { currency: 'USD', diff --git a/lib/ds-test/LICENSE b/lib/ds-test/LICENSE deleted file mode 100644 index 94a9ed024..000000000 --- a/lib/ds-test/LICENSE +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/lib/ds-test/Makefile b/lib/ds-test/Makefile deleted file mode 100644 index 661dac486..000000000 --- a/lib/ds-test/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -all:; dapp build - -test: - -dapp --use solc:0.4.23 build - -dapp --use solc:0.4.26 build - -dapp --use solc:0.5.17 build - -dapp --use solc:0.6.12 build - -dapp --use solc:0.7.5 build - -demo: - DAPP_SRC=demo dapp --use solc:0.7.5 build - -hevm dapp-test --verbose 3 - -.PHONY: test demo diff --git a/lib/ds-test/default.nix b/lib/ds-test/default.nix deleted file mode 100644 index cf65419ab..000000000 --- a/lib/ds-test/default.nix +++ /dev/null @@ -1,4 +0,0 @@ -{ solidityPackage, dappsys }: solidityPackage { - name = "ds-test"; - src = ./src; -} diff --git a/lib/ds-test/demo/demo.sol b/lib/ds-test/demo/demo.sol deleted file mode 100644 index 9367f7d32..000000000 --- a/lib/ds-test/demo/demo.sol +++ /dev/null @@ -1,243 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.4.23; - -import '../src/test.sol'; - -contract DemoTest is DSTest { - function test_this() public pure { - require(true); - } - - function test_logs() public { - emit log('-- log(string)'); - emit log('a string'); - - emit log('-- log_named_uint(string, uint)'); - log_named_uint('uint', 512); - - emit log('-- log_named_int(string, int)'); - log_named_int('int', -512); - - emit log('-- log_named_address(string, address)'); - log_named_address('address', address(this)); - - emit log('-- log_named_bytes32(string, bytes32)'); - log_named_bytes32('bytes32', 'a string'); - - emit log('-- log_named_bytes(string, bytes)'); - log_named_bytes('bytes', hex'cafefe'); - - emit log('-- log_named_string(string, string)'); - log_named_string('string', 'a string'); - - emit log('-- log_named_decimal_uint(string, uint, uint)'); - log_named_decimal_uint('decimal uint', 1.0e18, 18); - - emit log('-- log_named_decimal_int(string, int, uint)'); - log_named_decimal_int('decimal int', -1.0e18, 18); - } - - event log_old_named_uint(bytes32, uint256); - - function test_old_logs() public { - log_old_named_uint('key', 500); - log_named_bytes32('bkey', 'val'); - } - - function test_trace() public view { - this.echo('string 1', 'string 2'); - } - - function test_multiline() public { - emit log( - 'a multiline\\n' - 'string' - ); - emit log( - 'a multiline ' - 'string' - ); - log_bytes('a string'); - log_bytes( - 'a multiline\n' - 'string' - ); - log_bytes( - 'a multiline\\n' - 'string' - ); - emit log(unicode'Ώ'); - logs(hex'0000'); - log_named_bytes('0x0000', hex'0000'); - logs(hex'ff'); - } - - function echo(string memory s1, string memory s2) - public - pure - returns (string memory, string memory) - { - return (s1, s2); - } - - function prove_this(uint256 x) public { - log_named_uint('sym x', x); - assertGt(x + 1, 0); - } - - function test_logn() public { - assembly { - log0(0x01, 0x02) - log1(0x01, 0x02, 0x03) - log2(0x01, 0x02, 0x03, 0x04) - log3(0x01, 0x02, 0x03, 0x04, 0x05) - } - } - - event MyEvent(uint256, uint256 indexed, uint256, uint256 indexed); - - function test_events() public { - emit MyEvent(1, 2, 3, 4); - } - - function test_asserts() public { - string memory err = 'this test has failed!'; - emit log('## assertTrue(bool)\n'); - assertTrue(false); - emit log('\n'); - assertTrue(false, err); - - emit log('\n## assertEq(address,address)\n'); - assertEq(address(this), msg.sender); - emit log('\n'); - assertEq(address(this), msg.sender, err); - - emit log('\n## assertEq32(bytes32,bytes32)\n'); - assertEq32('bytes 1', 'bytes 2'); - emit log('\n'); - assertEq32('bytes 1', 'bytes 2', err); - - emit log('\n## assertEq(bytes32,bytes32)\n'); - assertEq32('bytes 1', 'bytes 2'); - emit log('\n'); - assertEq32('bytes 1', 'bytes 2', err); - - emit log('\n## assertEq(uint,uint)\n'); - assertEq(uint256(0), 1); - emit log('\n'); - assertEq(uint256(0), 1, err); - - emit log('\n## assertEq(int,int)\n'); - assertEq(-1, -2); - emit log('\n'); - assertEq(-1, -2, err); - - emit log('\n## assertEqDecimal(int,int,uint)\n'); - assertEqDecimal(-1.0e18, -1.1e18, 18); - emit log('\n'); - assertEqDecimal(-1.0e18, -1.1e18, 18, err); - - emit log('\n## assertEqDecimal(uint,uint,uint)\n'); - assertEqDecimal(uint256(1.0e18), 1.1e18, 18); - emit log('\n'); - assertEqDecimal(uint256(1.0e18), 1.1e18, 18, err); - - emit log('\n## assertGt(uint,uint)\n'); - assertGt(uint256(0), 0); - emit log('\n'); - assertGt(uint256(0), 0, err); - - emit log('\n## assertGt(int,int)\n'); - assertGt(-1, -1); - emit log('\n'); - assertGt(-1, -1, err); - - emit log('\n## assertGtDecimal(int,int,uint)\n'); - assertGtDecimal(-2.0e18, -1.1e18, 18); - emit log('\n'); - assertGtDecimal(-2.0e18, -1.1e18, 18, err); - - emit log('\n## assertGtDecimal(uint,uint,uint)\n'); - assertGtDecimal(uint256(1.0e18), 1.1e18, 18); - emit log('\n'); - assertGtDecimal(uint256(1.0e18), 1.1e18, 18, err); - - emit log('\n## assertGe(uint,uint)\n'); - assertGe(uint256(0), 1); - emit log('\n'); - assertGe(uint256(0), 1, err); - - emit log('\n## assertGe(int,int)\n'); - assertGe(-1, 0); - emit log('\n'); - assertGe(-1, 0, err); - - emit log('\n## assertGeDecimal(int,int,uint)\n'); - assertGeDecimal(-2.0e18, -1.1e18, 18); - emit log('\n'); - assertGeDecimal(-2.0e18, -1.1e18, 18, err); - - emit log('\n## assertGeDecimal(uint,uint,uint)\n'); - assertGeDecimal(uint256(1.0e18), 1.1e18, 18); - emit log('\n'); - assertGeDecimal(uint256(1.0e18), 1.1e18, 18, err); - - emit log('\n## assertLt(uint,uint)\n'); - assertLt(uint256(0), 0); - emit log('\n'); - assertLt(uint256(0), 0, err); - - emit log('\n## assertLt(int,int)\n'); - assertLt(-1, -1); - emit log('\n'); - assertLt(-1, -1, err); - - emit log('\n## assertLtDecimal(int,int,uint)\n'); - assertLtDecimal(-1.0e18, -1.1e18, 18); - emit log('\n'); - assertLtDecimal(-1.0e18, -1.1e18, 18, err); - - emit log('\n## assertLtDecimal(uint,uint,uint)\n'); - assertLtDecimal(uint256(2.0e18), 1.1e18, 18); - emit log('\n'); - assertLtDecimal(uint256(2.0e18), 1.1e18, 18, err); - - emit log('\n## assertLe(uint,uint)\n'); - assertLe(uint256(1), 0); - emit log('\n'); - assertLe(uint256(1), 0, err); - - emit log('\n## assertLe(int,int)\n'); - assertLe(0, -1); - emit log('\n'); - assertLe(0, -1, err); - - emit log('\n## assertLeDecimal(int,int,uint)\n'); - assertLeDecimal(-1.0e18, -1.1e18, 18); - emit log('\n'); - assertLeDecimal(-1.0e18, -1.1e18, 18, err); - - emit log('\n## assertLeDecimal(uint,uint,uint)\n'); - assertLeDecimal(uint256(2.0e18), 1.1e18, 18); - emit log('\n'); - assertLeDecimal(uint256(2.0e18), 1.1e18, 18, err); - - emit log('\n## assertEq(string,string)\n'); - string memory s1 = 'string 1'; - string memory s2 = 'string 2'; - assertEq(s1, s2); - emit log('\n'); - assertEq(s1, s2, err); - - emit log('\n## assertEq0(bytes,bytes)\n'); - assertEq0(hex'abcdef01', hex'abcdef02'); - log('\n'); - assertEq0(hex'abcdef01', hex'abcdef02', err); - } -} - -contract DemoTestWithSetUp { - function setUp() public {} - - function test_pass() public pure {} -} diff --git a/lib/ds-test/src/test.sol b/lib/ds-test/src/test.sol deleted file mode 100644 index 166183cb5..000000000 --- a/lib/ds-test/src/test.sol +++ /dev/null @@ -1,629 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -pragma solidity >=0.4.23; - -contract DSTest { - event log(string); - event logs(bytes); - - event log_address(address); - event log_bytes32(bytes32); - event log_int(int256); - event log_uint(uint256); - event log_bytes(bytes); - event log_string(string); - - event log_named_address(string key, address val); - event log_named_bytes32(string key, bytes32 val); - event log_named_decimal_int(string key, int256 val, uint256 decimals); - event log_named_decimal_uint(string key, uint256 val, uint256 decimals); - event log_named_int(string key, int256 val); - event log_named_uint(string key, uint256 val); - event log_named_bytes(string key, bytes val); - event log_named_string(string key, string val); - - bool public IS_TEST = true; - bool public failed; - - address constant HEVM_ADDRESS = address(bytes20(uint160(uint256(keccak256('hevm cheat code'))))); - - modifier mayRevert() { - _; - } - modifier testopts(string memory) { - _; - } - - function fail() internal { - failed = true; - } - - modifier logs_gas() { - uint256 startGas = gasleft(); - _; - uint256 endGas = gasleft(); - emit log_named_uint('gas', startGas - endGas); - } - - function assertTrue(bool condition) internal { - if (!condition) { - emit log('Error: Assertion Failed'); - fail(); - } - } - - function assertTrue(bool condition, string memory err) internal { - if (!condition) { - emit log_named_string('Error', err); - assertTrue(condition); - } - } - - function assertEq(address a, address b) internal { - if (a != b) { - emit log('Error: a == b not satisfied [address]'); - emit log_named_address(' Expected', b); - emit log_named_address(' Actual', a); - fail(); - } - } - - function assertEq( - address a, - address b, - string memory err - ) internal { - if (a != b) { - emit log_named_string('Error', err); - assertEq(a, b); - } - } - - function assertEq(bytes32 a, bytes32 b) internal { - if (a != b) { - emit log('Error: a == b not satisfied [bytes32]'); - emit log_named_bytes32(' Expected', b); - emit log_named_bytes32(' Actual', a); - fail(); - } - } - - function assertEq( - bytes32 a, - bytes32 b, - string memory err - ) internal { - if (a != b) { - emit log_named_string('Error', err); - assertEq(a, b); - } - } - - function assertEq32(bytes32 a, bytes32 b) internal { - assertEq(a, b); - } - - function assertEq32( - bytes32 a, - bytes32 b, - string memory err - ) internal { - assertEq(a, b, err); - } - - function assertEq(int256 a, int256 b) internal { - if (a != b) { - emit log('Error: a == b not satisfied [int]'); - emit log_named_int(' Expected', b); - emit log_named_int(' Actual', a); - fail(); - } - } - - function assertEq( - int256 a, - int256 b, - string memory err - ) internal { - if (a != b) { - emit log_named_string('Error', err); - assertEq(a, b); - } - } - - function assertEq(uint256 a, uint256 b) internal { - if (a != b) { - emit log('Error: a == b not satisfied [uint]'); - emit log_named_uint(' Expected', b); - emit log_named_uint(' Actual', a); - fail(); - } - } - - function assertEq( - uint256 a, - uint256 b, - string memory err - ) internal { - if (a != b) { - emit log_named_string('Error', err); - assertEq(a, b); - } - } - - function assertEqDecimal( - int256 a, - int256 b, - uint256 decimals - ) internal { - if (a != b) { - emit log('Error: a == b not satisfied [decimal int]'); - emit log_named_decimal_int(' Expected', b, decimals); - emit log_named_decimal_int(' Actual', a, decimals); - fail(); - } - } - - function assertEqDecimal( - int256 a, - int256 b, - uint256 decimals, - string memory err - ) internal { - if (a != b) { - emit log_named_string('Error', err); - assertEqDecimal(a, b, decimals); - } - } - - function assertEqDecimal( - uint256 a, - uint256 b, - uint256 decimals - ) internal { - if (a != b) { - emit log('Error: a == b not satisfied [decimal uint]'); - emit log_named_decimal_uint(' Expected', b, decimals); - emit log_named_decimal_uint(' Actual', a, decimals); - fail(); - } - } - - function assertEqDecimal( - uint256 a, - uint256 b, - uint256 decimals, - string memory err - ) internal { - if (a != b) { - emit log_named_string('Error', err); - assertEqDecimal(a, b, decimals); - } - } - - function assertGt(uint256 a, uint256 b) internal { - if (a <= b) { - emit log('Error: a > b not satisfied [uint]'); - emit log_named_uint(' Value a', a); - emit log_named_uint(' Value b', b); - fail(); - } - } - - function assertGt( - uint256 a, - uint256 b, - string memory err - ) internal { - if (a <= b) { - emit log_named_string('Error', err); - assertGt(a, b); - } - } - - function assertGt(int256 a, int256 b) internal { - if (a <= b) { - emit log('Error: a > b not satisfied [int]'); - emit log_named_int(' Value a', a); - emit log_named_int(' Value b', b); - fail(); - } - } - - function assertGt( - int256 a, - int256 b, - string memory err - ) internal { - if (a <= b) { - emit log_named_string('Error', err); - assertGt(a, b); - } - } - - function assertGtDecimal( - int256 a, - int256 b, - uint256 decimals - ) internal { - if (a <= b) { - emit log('Error: a > b not satisfied [decimal int]'); - emit log_named_decimal_int(' Value a', a, decimals); - emit log_named_decimal_int(' Value b', b, decimals); - fail(); - } - } - - function assertGtDecimal( - int256 a, - int256 b, - uint256 decimals, - string memory err - ) internal { - if (a <= b) { - emit log_named_string('Error', err); - assertGtDecimal(a, b, decimals); - } - } - - function assertGtDecimal( - uint256 a, - uint256 b, - uint256 decimals - ) internal { - if (a <= b) { - emit log('Error: a > b not satisfied [decimal uint]'); - emit log_named_decimal_uint(' Value a', a, decimals); - emit log_named_decimal_uint(' Value b', b, decimals); - fail(); - } - } - - function assertGtDecimal( - uint256 a, - uint256 b, - uint256 decimals, - string memory err - ) internal { - if (a <= b) { - emit log_named_string('Error', err); - assertGtDecimal(a, b, decimals); - } - } - - function assertGe(uint256 a, uint256 b) internal { - if (a < b) { - emit log('Error: a >= b not satisfied [uint]'); - emit log_named_uint(' Value a', a); - emit log_named_uint(' Value b', b); - fail(); - } - } - - function assertGe( - uint256 a, - uint256 b, - string memory err - ) internal { - if (a < b) { - emit log_named_string('Error', err); - assertGe(a, b); - } - } - - function assertGe(int256 a, int256 b) internal { - if (a < b) { - emit log('Error: a >= b not satisfied [int]'); - emit log_named_int(' Value a', a); - emit log_named_int(' Value b', b); - fail(); - } - } - - function assertGe( - int256 a, - int256 b, - string memory err - ) internal { - if (a < b) { - emit log_named_string('Error', err); - assertGe(a, b); - } - } - - function assertGeDecimal( - int256 a, - int256 b, - uint256 decimals - ) internal { - if (a < b) { - emit log('Error: a >= b not satisfied [decimal int]'); - emit log_named_decimal_int(' Value a', a, decimals); - emit log_named_decimal_int(' Value b', b, decimals); - fail(); - } - } - - function assertGeDecimal( - int256 a, - int256 b, - uint256 decimals, - string memory err - ) internal { - if (a < b) { - emit log_named_string('Error', err); - assertGeDecimal(a, b, decimals); - } - } - - function assertGeDecimal( - uint256 a, - uint256 b, - uint256 decimals - ) internal { - if (a < b) { - emit log('Error: a >= b not satisfied [decimal uint]'); - emit log_named_decimal_uint(' Value a', a, decimals); - emit log_named_decimal_uint(' Value b', b, decimals); - fail(); - } - } - - function assertGeDecimal( - uint256 a, - uint256 b, - uint256 decimals, - string memory err - ) internal { - if (a < b) { - emit log_named_string('Error', err); - assertGeDecimal(a, b, decimals); - } - } - - function assertLt(uint256 a, uint256 b) internal { - if (a >= b) { - emit log('Error: a < b not satisfied [uint]'); - emit log_named_uint(' Value a', a); - emit log_named_uint(' Value b', b); - fail(); - } - } - - function assertLt( - uint256 a, - uint256 b, - string memory err - ) internal { - if (a >= b) { - emit log_named_string('Error', err); - assertLt(a, b); - } - } - - function assertLt(int256 a, int256 b) internal { - if (a >= b) { - emit log('Error: a < b not satisfied [int]'); - emit log_named_int(' Value a', a); - emit log_named_int(' Value b', b); - fail(); - } - } - - function assertLt( - int256 a, - int256 b, - string memory err - ) internal { - if (a >= b) { - emit log_named_string('Error', err); - assertLt(a, b); - } - } - - function assertLtDecimal( - int256 a, - int256 b, - uint256 decimals - ) internal { - if (a >= b) { - emit log('Error: a < b not satisfied [decimal int]'); - emit log_named_decimal_int(' Value a', a, decimals); - emit log_named_decimal_int(' Value b', b, decimals); - fail(); - } - } - - function assertLtDecimal( - int256 a, - int256 b, - uint256 decimals, - string memory err - ) internal { - if (a >= b) { - emit log_named_string('Error', err); - assertLtDecimal(a, b, decimals); - } - } - - function assertLtDecimal( - uint256 a, - uint256 b, - uint256 decimals - ) internal { - if (a >= b) { - emit log('Error: a < b not satisfied [decimal uint]'); - emit log_named_decimal_uint(' Value a', a, decimals); - emit log_named_decimal_uint(' Value b', b, decimals); - fail(); - } - } - - function assertLtDecimal( - uint256 a, - uint256 b, - uint256 decimals, - string memory err - ) internal { - if (a >= b) { - emit log_named_string('Error', err); - assertLtDecimal(a, b, decimals); - } - } - - function assertLe(uint256 a, uint256 b) internal { - if (a > b) { - emit log('Error: a <= b not satisfied [uint]'); - emit log_named_uint(' Value a', a); - emit log_named_uint(' Value b', b); - fail(); - } - } - - function assertLe( - uint256 a, - uint256 b, - string memory err - ) internal { - if (a > b) { - emit log_named_string('Error', err); - assertLe(a, b); - } - } - - function assertLe(int256 a, int256 b) internal { - if (a > b) { - emit log('Error: a <= b not satisfied [int]'); - emit log_named_int(' Value a', a); - emit log_named_int(' Value b', b); - fail(); - } - } - - function assertLe( - int256 a, - int256 b, - string memory err - ) internal { - if (a > b) { - emit log_named_string('Error', err); - assertLe(a, b); - } - } - - function assertLeDecimal( - int256 a, - int256 b, - uint256 decimals - ) internal { - if (a > b) { - emit log('Error: a <= b not satisfied [decimal int]'); - emit log_named_decimal_int(' Value a', a, decimals); - emit log_named_decimal_int(' Value b', b, decimals); - fail(); - } - } - - function assertLeDecimal( - int256 a, - int256 b, - uint256 decimals, - string memory err - ) internal { - if (a > b) { - emit log_named_string('Error', err); - assertLeDecimal(a, b, decimals); - } - } - - function assertLeDecimal( - uint256 a, - uint256 b, - uint256 decimals - ) internal { - if (a > b) { - emit log('Error: a <= b not satisfied [decimal uint]'); - emit log_named_decimal_uint(' Value a', a, decimals); - emit log_named_decimal_uint(' Value b', b, decimals); - fail(); - } - } - - function assertLeDecimal( - uint256 a, - uint256 b, - uint256 decimals, - string memory err - ) internal { - if (a > b) { - emit log_named_string('Error', err); - assertGeDecimal(a, b, decimals); - } - } - - function assertEq(string memory a, string memory b) internal { - if (keccak256(abi.encodePacked(a)) != keccak256(abi.encodePacked(b))) { - emit log('Error: a == b not satisfied [string]'); - emit log_named_string(' Value a', a); - emit log_named_string(' Value b', b); - fail(); - } - } - - function assertEq( - string memory a, - string memory b, - string memory err - ) internal { - if (keccak256(abi.encodePacked(a)) != keccak256(abi.encodePacked(b))) { - emit log_named_string('Error', err); - assertEq(a, b); - } - } - - function checkEq0(bytes memory a, bytes memory b) internal pure returns (bool ok) { - ok = true; - if (a.length == b.length) { - for (uint256 i = 0; i < a.length; i++) { - if (a[i] != b[i]) { - ok = false; - } - } - } else { - ok = false; - } - } - - function assertEq0(bytes memory a, bytes memory b) internal { - if (!checkEq0(a, b)) { - emit log('Error: a == b not satisfied [bytes]'); - emit log_named_bytes(' Expected', a); - emit log_named_bytes(' Actual', b); - fail(); - } - } - - function assertEq0( - bytes memory a, - bytes memory b, - string memory err - ) internal { - if (!checkEq0(a, b)) { - emit log_named_string('Error', err); - assertEq0(a, b); - } - } -} diff --git a/package.json b/package.json index f30656ad9..588c584b6 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "type": "git", "url": "https://github.com/jbx-protocol/juice-contracts-v3" }, - "version": "3.1.2", + "version": "4.0.0", "license": "MIT", "dependencies": { "@chainlink/contracts": "^0.1.6", @@ -38,7 +38,7 @@ "scripts": { "chain": "hardhat node", "account": "hardhat account", - "test": "mocha './test/**/*.test.js' -r esm --bail && FOUNDRY_PROFILE=fork foundry test", + "test": "mocha './test/**/*.test.js' -r esm --bail --timeout 20000 && FOUNDRY_PROFILE=fork foundry test", "coverage": "node --require esm ./node_modules/.bin/hardhat coverage --network hardhat", "clean": "rimraf ./cache && rimraf ./artifacts", "compile": "yarn clean && hardhat compile", diff --git a/test/jb_controller_3_1/burn_tokens_of.test.js b/test/jb_controller_3_1/burn_tokens_of.test.js new file mode 100644 index 000000000..9f3bd0b4b --- /dev/null +++ b/test/jb_controller_3_1/burn_tokens_of.test.js @@ -0,0 +1,305 @@ +import { expect } from 'chai'; +import { ethers } from 'hardhat'; +import { deployMockContract } from '@ethereum-waffle/mock-contract'; +import { impersonateAccount, packFundingCycleMetadata } from '../helpers/utils'; +import errors from '../helpers/errors.json'; + +import jbDirectory from '../../artifacts/contracts/JBDirectory.sol/JBDirectory.json'; +import jbFundingCycleStore from '../../artifacts/contracts/JBFundingCycleStore.sol/JBFundingCycleStore.json'; +import jbOperatoreStore from '../../artifacts/contracts/JBOperatorStore.sol/JBOperatorStore.json'; +import jbFundAccessConstraintsStore from '../../artifacts/contracts/JBFundAccessConstraintsStore.sol/JBFundAccessConstraintsStore.json'; +import jbProjects from '../../artifacts/contracts/JBProjects.sol/JBProjects.json'; +import jbSplitsStore from '../../artifacts/contracts/JBSplitsStore.sol/JBSplitsStore.json'; +import jbTerminal from '../../artifacts/contracts/JBETHPaymentTerminal3_1.sol/JBETHPaymentTerminal3_1.json'; +import jbToken from '../../artifacts/contracts/JBToken.sol/JBToken.json'; +import jbTokenStore from '../../artifacts/contracts/JBTokenStore.sol/JBTokenStore.json'; + +describe('JBController3_1::burnTokenOf(...)', function () { + const PROJECT_ID = 1; + const MEMO = 'Test Memo'; + const TOTAL_SUPPLY = 100000; + const RESERVED_RATE = 5000; + const EFFECTIVE_SUPPLY = (TOTAL_SUPPLY * (10000 - RESERVED_RATE)) / 10000; + const AMOUNT_TO_BURN = 20000; + const PREFERED_CLAIMED_TOKEN = true; + let BURN_INDEX; + + before(async function () { + let jbOperationsFactory = await ethers.getContractFactory('JBOperations'); + let jbOperations = await jbOperationsFactory.deploy(); + + BURN_INDEX = await jbOperations.BURN(); + }); + + async function setup() { + let [deployer, projectOwner, holder, ...addrs] = await ethers.getSigners(); + + const blockNum = await ethers.provider.getBlockNumber(); + const block = await ethers.provider.getBlock(blockNum); + const timestamp = block.timestamp; + + let [ + mockJbDirectory, + mockJbFundingCycleStore, + mockJbOperatorStore, + mockJbProjects, + mockJbSplitsStore, + mockJbToken, + mockJbTokenStore, + mockJbFundAccessConstraintsStore, + ] = await Promise.all([ + deployMockContract(deployer, jbDirectory.abi), + deployMockContract(deployer, jbFundingCycleStore.abi), + deployMockContract(deployer, jbOperatoreStore.abi), + deployMockContract(deployer, jbProjects.abi), + deployMockContract(deployer, jbSplitsStore.abi), + deployMockContract(deployer, jbToken.abi), + deployMockContract(deployer, jbTokenStore.abi), + deployMockContract(deployer, jbTokenStore.abi), + deployMockContract(deployer, jbFundAccessConstraintsStore.abi), + ]); + + let jbControllerFactory = await ethers.getContractFactory( + 'contracts/JBController3_1.sol:JBController3_1', + ); + let jbController = await jbControllerFactory.deploy( + mockJbOperatorStore.address, + mockJbProjects.address, + mockJbDirectory.address, + mockJbFundingCycleStore.address, + mockJbTokenStore.address, + mockJbSplitsStore.address, + mockJbFundAccessConstraintsStore.address + ); + + await Promise.all([ + mockJbProjects.mock.ownerOf.withArgs(PROJECT_ID).returns(projectOwner.address), + + mockJbDirectory.mock.isTerminalOf.withArgs(PROJECT_ID, holder.address).returns(false), + + mockJbDirectory.mock.isTerminalOf.withArgs(PROJECT_ID, projectOwner.address).returns(false), + + mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: 0, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ + pauseBurn: 0, + allowMinting: 1, + reservedRate: RESERVED_RATE, + }), + }), + + // only non-reserved are minted, minting total supply in holder account + mockJbTokenStore.mock.mintFor + .withArgs(holder.address, PROJECT_ID, EFFECTIVE_SUPPLY, PREFERED_CLAIMED_TOKEN) + .returns(), + + mockJbTokenStore.mock.burnFrom + .withArgs(holder.address, PROJECT_ID, AMOUNT_TO_BURN, PREFERED_CLAIMED_TOKEN) + .returns(), + + mockJbTokenStore.mock.totalSupplyOf.withArgs(PROJECT_ID).returns(EFFECTIVE_SUPPLY), + ]); + + await jbController + .connect(projectOwner) + .mintTokensOf( + PROJECT_ID, + TOTAL_SUPPLY, + holder.address, + MEMO, + PREFERED_CLAIMED_TOKEN, + true /*use fc reserved rate*/, + ); + + return { + projectOwner, + holder, + addrs, + jbController, + mockJbOperatorStore, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbTokenStore, + mockJbToken, + timestamp, + }; + } + + it(`Should burn if caller is token owner and update reserved token balance of the project`, async function () { + const { holder, jbController, mockJbTokenStore } = await setup(); + let initReservedTokenBalance = await jbController.reservedTokenBalanceOf( + PROJECT_ID + ); + + await expect( + jbController + .connect(holder) + .burnTokensOf(holder.address, PROJECT_ID, AMOUNT_TO_BURN, MEMO, PREFERED_CLAIMED_TOKEN), + ) + .to.emit(jbController, 'BurnTokens') + .withArgs(holder.address, PROJECT_ID, AMOUNT_TO_BURN, MEMO, holder.address); + + // New total supply = previous total supply minus amount burned + await mockJbTokenStore.mock.totalSupplyOf + .withArgs(PROJECT_ID) + .returns(EFFECTIVE_SUPPLY - AMOUNT_TO_BURN); + + let newReservedTokenBalance = await jbController.reservedTokenBalanceOf( + PROJECT_ID + ); + expect(newReservedTokenBalance).to.equal(initReservedTokenBalance); + }); + + it(`Should burn token if caller is not project owner but is authorized`, async function () { + const { holder, addrs, jbController, mockJbOperatorStore, mockJbDirectory } = await setup(); + let caller = addrs[0]; + + await mockJbOperatorStore.mock.hasPermission + .withArgs(caller.address, holder.address, PROJECT_ID, BURN_INDEX) + .returns(true); + + await mockJbDirectory.mock.isTerminalOf.withArgs(PROJECT_ID, caller.address).returns(false); + + await expect( + jbController + .connect(caller) + .burnTokensOf(holder.address, PROJECT_ID, AMOUNT_TO_BURN, MEMO, PREFERED_CLAIMED_TOKEN), + ) + .to.emit(jbController, 'BurnTokens') + .withArgs(holder.address, PROJECT_ID, AMOUNT_TO_BURN, MEMO, caller.address); + }); + + it(`Can't burn token if caller is not authorized`, async function () { + const { holder, addrs, jbController, mockJbOperatorStore, mockJbDirectory } = await setup(); + let caller = addrs[0]; + + await mockJbOperatorStore.mock.hasPermission + .withArgs(caller.address, holder.address, PROJECT_ID, BURN_INDEX) + .returns(false); + + await mockJbOperatorStore.mock.hasPermission + .withArgs(caller.address, holder.address, 0, BURN_INDEX) + .returns(false); + + await mockJbDirectory.mock.isTerminalOf.withArgs(PROJECT_ID, caller.address).returns(false); + + await expect( + jbController + .connect(caller) + .burnTokensOf(holder.address, PROJECT_ID, AMOUNT_TO_BURN, MEMO, PREFERED_CLAIMED_TOKEN), + ).to.be.revertedWith(errors.UNAUTHORIZED); + }); + + it(`Should burn token if caller is a terminal of the corresponding project`, async function () { + const { projectOwner, holder, jbController, mockJbOperatorStore, mockJbDirectory } = + await setup(); + const terminal = await deployMockContract(projectOwner, jbTerminal.abi); + const terminalSigner = await impersonateAccount(terminal.address); + + await mockJbOperatorStore.mock.hasPermission + .withArgs(terminalSigner.address, projectOwner.address, PROJECT_ID, BURN_INDEX) + .returns(false); + + await mockJbOperatorStore.mock.hasPermission + .withArgs(terminalSigner.address, projectOwner.address, 0, BURN_INDEX) + .returns(false); + + await mockJbDirectory.mock.isTerminalOf + .withArgs(PROJECT_ID, terminalSigner.address) + .returns(true); + + await expect( + jbController + .connect(terminalSigner) + .burnTokensOf(holder.address, PROJECT_ID, AMOUNT_TO_BURN, MEMO, PREFERED_CLAIMED_TOKEN), + ) + .to.emit(jbController, 'BurnTokens') + .withArgs(holder.address, PROJECT_ID, AMOUNT_TO_BURN, MEMO, terminalSigner.address); + }); + + it(`Can't burn 0 token`, async function () { + const { holder, jbController } = await setup(); + + await expect( + jbController + .connect(holder) + .burnTokensOf(holder.address, PROJECT_ID, /*_tokenCount=*/ 0, MEMO, PREFERED_CLAIMED_TOKEN), + ).to.be.revertedWith(errors.NO_BURNABLE_TOKENS); + }); + + it(`Can't burn token if funding cycle is paused and caller is not a terminal delegate`, async function () { + const { holder, jbController, mockJbFundingCycleStore, timestamp } = await setup(); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: 0, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ pauseBurn: 1, reservedRate: RESERVED_RATE }), + }); + + await expect( + jbController + .connect(holder) + .burnTokensOf(holder.address, PROJECT_ID, AMOUNT_TO_BURN, MEMO, PREFERED_CLAIMED_TOKEN), + ).to.be.revertedWith(errors.BURN_PAUSED_AND_SENDER_NOT_VALID_TERMINAL_DELEGATE); + }); + + it(`Should burn token if funding cycle is paused and caller is a terminal delegate`, async function () { + const { + projectOwner, + holder, + jbController, + mockJbFundingCycleStore, + mockJbOperatorStore, + mockJbDirectory, + timestamp, + } = await setup(); + + const terminal = await deployMockContract(projectOwner, jbTerminal.abi); + const terminalSigner = await impersonateAccount(terminal.address); + + await mockJbOperatorStore.mock.hasPermission + .withArgs(terminalSigner.address, projectOwner.address, PROJECT_ID, BURN_INDEX) + .returns(false); + + await mockJbOperatorStore.mock.hasPermission + .withArgs(terminalSigner.address, projectOwner.address, 0, BURN_INDEX) + .returns(false); + + await mockJbDirectory.mock.isTerminalOf + .withArgs(PROJECT_ID, terminalSigner.address) + .returns(true); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: 0, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ pauseBurn: 1, reservedRate: RESERVED_RATE }), + }); + + await expect( + jbController + .connect(terminalSigner) + .burnTokensOf(holder.address, PROJECT_ID, AMOUNT_TO_BURN, MEMO, PREFERED_CLAIMED_TOKEN), + ) + .to.emit(jbController, 'BurnTokens') + .withArgs(holder.address, PROJECT_ID, AMOUNT_TO_BURN, MEMO, terminalSigner.address); + }); +}); diff --git a/test/jb_controller/distribute_reserved_token_of_v3_1.test.js b/test/jb_controller_3_1/distribute_reserved_token_of.test.js similarity index 100% rename from test/jb_controller/distribute_reserved_token_of_v3_1.test.js rename to test/jb_controller_3_1/distribute_reserved_token_of.test.js diff --git a/test/jb_controller_3_1/launch_funding_cycle_for.test.js b/test/jb_controller_3_1/launch_funding_cycle_for.test.js new file mode 100644 index 000000000..e0c94582f --- /dev/null +++ b/test/jb_controller_3_1/launch_funding_cycle_for.test.js @@ -0,0 +1,486 @@ +import { expect } from 'chai'; +import { ethers } from 'hardhat'; +import { deployMockContract } from '@ethereum-waffle/mock-contract'; +import { makeSplits, packFundingCycleMetadata } from '../helpers/utils'; +import errors from '../helpers/errors.json'; + +import JbController from '../../artifacts/contracts/JBController3_1.sol/JBController3_1.json'; +import jbDirectory from '../../artifacts/contracts/JBDirectory.sol/JBDirectory.json'; +import jbFundingCycleStore from '../../artifacts/contracts/JBFundingCycleStore.sol/JBFundingCycleStore.json'; +import jbOperatoreStore from '../../artifacts/contracts/JBOperatorStore.sol/JBOperatorStore.json'; +import jbFundAccessConstraintsStore from '../../artifacts/contracts/JBFundAccessConstraintsStore.sol/JBFundAccessConstraintsStore.json'; +import jbProjects from '../../artifacts/contracts/JBProjects.sol/JBProjects.json'; +import jbSplitsStore from '../../artifacts/contracts/JBSplitsStore.sol/JBSplitsStore.json'; +import jbTerminal from '../../artifacts/contracts/JBETHPaymentTerminal3_1.sol/JBETHPaymentTerminal3_1.json'; +import jbTokenStore from '../../artifacts/contracts/JBTokenStore.sol/JBTokenStore.json'; + +describe('JBController3_1::launchFundingCyclesFor(...)', function () { + const EXISTING_PROJECT = 1; + const LAUNCHED_PROJECT = 2; + const NONEXISTANT_PROJECT = 3; + const METADATA_CID = ''; + const METADATA_DOMAIN = 1234; + const MEMO = 'Test Memo'; + const PROJECT_START = '1'; + let RECONFIGURE_INDEX; + let MIGRATE_CONTROLLER_INDEX; + + before(async function () { + let jbOperationsFactory = await ethers.getContractFactory('JBOperations'); + let jbOperations = await jbOperationsFactory.deploy(); + + RECONFIGURE_INDEX = await jbOperations.RECONFIGURE(); + MIGRATE_CONTROLLER_INDEX = await jbOperations.MIGRATE_CONTROLLER(); + }); + + async function setup() { + let [deployer, projectOwner, nonOwner, ...addrs] = await ethers.getSigners(); + + const blockNum = await ethers.provider.getBlockNumber(); + const block = await ethers.provider.getBlock(blockNum); + const timestamp = block.timestamp; + const fundingCycleData = makeFundingCycleDataStruct(); + const fundingCycleMetadata = makeFundingCycleMetadata(); + const splits = makeSplits(); + + let [ + mockJbController, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbOperatorStore, + mockJbProjects, + mockJbSplitsStore, + mockJbTerminal1, + mockJbTerminal2, + mockJbTokenStore, + mockJbFundAccessConstraintsStore, + ] = await Promise.all([ + deployMockContract(deployer, JbController.abi), + deployMockContract(deployer, jbDirectory.abi), + deployMockContract(deployer, jbFundingCycleStore.abi), + deployMockContract(deployer, jbOperatoreStore.abi), + deployMockContract(deployer, jbProjects.abi), + deployMockContract(deployer, jbSplitsStore.abi), + deployMockContract(deployer, jbTerminal.abi), + deployMockContract(deployer, jbTerminal.abi), + deployMockContract(deployer, jbTokenStore.abi), + deployMockContract(deployer, jbFundAccessConstraintsStore.abi), + ]); + + let jbControllerFactory = await ethers.getContractFactory( + 'contracts/JBController3_1.sol:JBController3_1', + ); + let jbController = await jbControllerFactory.deploy( + mockJbOperatorStore.address, + mockJbProjects.address, + mockJbDirectory.address, + mockJbFundingCycleStore.address, + mockJbTokenStore.address, + mockJbSplitsStore.address, + mockJbFundAccessConstraintsStore.address + ); + + await mockJbProjects.mock.createFor + .withArgs(projectOwner.address, [METADATA_CID, METADATA_DOMAIN]) + .returns(EXISTING_PROJECT); + + await mockJbProjects.mock.ownerOf.withArgs(EXISTING_PROJECT).returns(projectOwner.address); + + await mockJbProjects.mock.ownerOf.withArgs(LAUNCHED_PROJECT).returns(projectOwner.address); + + await mockJbProjects.mock.ownerOf.withArgs(NONEXISTANT_PROJECT).reverts(); + + await mockJbDirectory.mock.setControllerOf + .withArgs(EXISTING_PROJECT, jbController.address) + .returns(); + + await mockJbDirectory.mock.setTerminalsOf + .withArgs(EXISTING_PROJECT, [mockJbTerminal1.address, mockJbTerminal2.address]) + .returns(); + + await mockJbFundingCycleStore.mock.configureFor + .withArgs(EXISTING_PROJECT, fundingCycleData, fundingCycleMetadata.packed, PROJECT_START) + .returns( + Object.assign( + { + number: EXISTING_PROJECT, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + metadata: fundingCycleMetadata.packed, + }, + fundingCycleData, + ), + ); + + await mockJbFundingCycleStore.mock.latestConfigurationOf.withArgs(EXISTING_PROJECT).returns(0); + + await mockJbFundingCycleStore.mock.latestConfigurationOf.withArgs(LAUNCHED_PROJECT).returns(1); + + const groupedSplits = [{ group: 1, splits }]; + + await mockJbSplitsStore.mock.set + .withArgs(EXISTING_PROJECT, /*configuration=*/ timestamp, groupedSplits) + .returns(); + + return { + deployer, + projectOwner, + nonOwner, + addrs, + jbController, + mockJbDirectory, + mockJbTokenStore, + mockJbController, + mockJbProjects, + mockJbOperatorStore, + mockJbFundingCycleStore, + mockJbFundAccessConstraintsStore, + mockJbTerminal1, + mockJbTerminal2, + timestamp, + fundingCycleData, + fundingCycleMetadata, + splits, + }; + } + + function makeFundingCycleMetadata({ + reservedRate = 0, + redemptionRate = 10000, + ballotRedemptionRate = 10000, + pausePay = false, + pauseDistributions = false, + pauseRedeem = false, + pauseBurn = false, + pauseTransfers = false, + allowMinting = false, + allowChangeToken = false, + allowTerminalMigration = false, + allowControllerMigration = false, + allowSetTerminals = false, + allowSetControllers = false, + holdFees = false, + preferClaimedTokenOverride = false, + useTotalOverflowForRedemptions = false, + useDataSourceForPay = false, + useDataSourceForRedeem = false, + dataSource = ethers.constants.AddressZero, + metadata = 0, + } = {}) { + const unpackedMetadata = { + global: { + allowSetTerminals, + allowSetControllers, + pauseTransfers, + }, + reservedRate, + redemptionRate, + ballotRedemptionRate, + pausePay, + pauseDistributions, + pauseRedeem, + pauseBurn, + allowMinting, + allowChangeToken, + allowTerminalMigration, + allowControllerMigration, + holdFees, + preferClaimedTokenOverride, + useTotalOverflowForRedemptions, + useDataSourceForPay, + useDataSourceForRedeem, + dataSource, + metadata, + }; + return { unpacked: unpackedMetadata, packed: packFundingCycleMetadata(unpackedMetadata) }; + } + + function makeFundingCycleDataStruct({ + duration = 0, + weight = ethers.BigNumber.from('1' + '0'.repeat(18)), + discountRate = 900000000, + ballot = ethers.constants.AddressZero, + } = {}) { + return { duration, weight, discountRate, ballot }; + } + + function makeFundingAccessConstraints({ + terminals, + token = ethers.Wallet.createRandom().address, + distributionLimit = 200, + distributionLimitCurrency = 1, + overflowAllowance = 100, + overflowAllowanceCurrency = 2, + } = {}) { + let constraints = []; + for (let terminal of terminals) { + constraints.push({ + terminal, + token, + distributionLimit, + distributionLimitCurrency, + overflowAllowance, + overflowAllowanceCurrency, + }); + } + return constraints; + } + + it(`Should launch a funding cycle for an existing project and emit events`, async function () { + const { + jbController, + projectOwner, + timestamp, + fundingCycleData, + fundingCycleMetadata, + splits, + mockJbTerminal1, + mockJbTerminal2, + mockJbFundAccessConstraintsStore + } = await setup(); + const groupedSplits = [{ group: 1, splits }]; + const terminals = [mockJbTerminal1.address, mockJbTerminal2.address]; + const token = ethers.Wallet.createRandom().address; + const fundAccessConstraints = makeFundingAccessConstraints({ terminals, token }); + + await mockJbFundAccessConstraintsStore.mock.setFor + .withArgs(EXISTING_PROJECT, timestamp, fundAccessConstraints) + .returns(); + + expect( + await jbController + .connect(projectOwner) + .callStatic.launchFundingCyclesFor( + EXISTING_PROJECT, + fundingCycleData, + fundingCycleMetadata.unpacked, + PROJECT_START, + groupedSplits, + fundAccessConstraints, + terminals, + MEMO, + ), + ).to.equal(timestamp); + + let tx = jbController + .connect(projectOwner) + .launchFundingCyclesFor( + EXISTING_PROJECT, + fundingCycleData, + fundingCycleMetadata.unpacked, + PROJECT_START, + groupedSplits, + fundAccessConstraints, + terminals, + MEMO, + ); + + await expect(tx) + .to.emit(jbController, 'LaunchFundingCycles') + .withArgs( + /*fundingCycleData.configuration=*/ timestamp, + EXISTING_PROJECT, + MEMO, + projectOwner.address, + ); + }); + + it(`Should launch a funding cycle without payment terminals and funding cycle constraints`, async function () { + const { + jbController, + projectOwner, + timestamp, + fundingCycleData, + fundingCycleMetadata, + splits, + mockJbFundAccessConstraintsStore + } = await setup(); + const groupedSplits = [{ group: 1, splits }]; + const fundAccessConstraints = []; + + await mockJbFundAccessConstraintsStore.mock.setFor + .withArgs(EXISTING_PROJECT, timestamp, fundAccessConstraints) + .returns(); + + expect( + await jbController + .connect(projectOwner) + .callStatic.launchFundingCyclesFor( + EXISTING_PROJECT, + fundingCycleData, + fundingCycleMetadata.unpacked, + PROJECT_START, + groupedSplits, + fundAccessConstraints, + [], + MEMO, + ), + ).to.equal(timestamp); + }); + + it(`Can't launch a project with a reserved rate superior to 10000`, async function () { + const { + jbController, + projectOwner, + fundingCycleData, + splits, + mockJbTerminal1, + mockJbTerminal2, + } = await setup(); + const groupedSplits = [{ group: 1, splits }]; + const terminals = [mockJbTerminal1.address, mockJbTerminal2.address]; + const fundAccessConstraints = makeFundingAccessConstraints({ terminals }); + const fundingCycleMetadata = makeFundingCycleMetadata({ reservedRate: 10001 }); + + let tx = jbController + .connect(projectOwner) + .launchFundingCyclesFor( + EXISTING_PROJECT, + fundingCycleData, + fundingCycleMetadata.unpacked, + PROJECT_START, + groupedSplits, + fundAccessConstraints, + terminals, + MEMO, + ); + + await expect(tx).to.be.revertedWith(errors.INVALID_RESERVED_RATE); + }); + + it(`Can't launch a project with a redemption rate superior to 10000`, async function () { + const { + jbController, + projectOwner, + fundingCycleData, + fundingCycleMetadata, + splits, + mockJbTerminal1, + mockJbTerminal2, + } = await setup(); + const groupedSplits = [{ group: 1, splits }]; + const terminals = [mockJbTerminal1.address, mockJbTerminal2.address]; + const fundAccessConstraints = makeFundingAccessConstraints({ terminals }); + + fundingCycleMetadata.unpacked.redemptionRate = 10001; //not possible in packed metadata (shl of a negative value) + + let tx = jbController + .connect(projectOwner) + .launchFundingCyclesFor( + EXISTING_PROJECT, + fundingCycleData, + fundingCycleMetadata.unpacked, + PROJECT_START, + groupedSplits, + fundAccessConstraints, + terminals, + MEMO, + ); + + await expect(tx).to.be.revertedWith(errors.INVALID_REDEMPTION_RATE); + }); + + it(`Can't launch a project with a ballot redemption rate superior to 10000`, async function () { + const { + jbController, + projectOwner, + fundingCycleData, + fundingCycleMetadata, + splits, + mockJbTerminal1, + mockJbTerminal2, + } = await setup(); + + const groupedSplits = [{ group: 1, splits }]; + const terminals = [mockJbTerminal1.address, mockJbTerminal2.address]; + const fundAccessConstraints = makeFundingAccessConstraints({ terminals }); + + fundingCycleMetadata.unpacked.ballotRedemptionRate = 10001; //not possible in packed metadata (shl of a negative value) + + let tx = jbController + .connect(projectOwner) + .launchFundingCyclesFor( + EXISTING_PROJECT, + fundingCycleData, + fundingCycleMetadata.unpacked, + PROJECT_START, + groupedSplits, + fundAccessConstraints, + terminals, + MEMO, + ); + + await expect(tx).to.be.revertedWith(errors.INVALID_BALLOT_REDEMPTION_RATE); + }); + + it(`Can't be called for a project by a non-owner`, async function () { + const { + jbController, + projectOwner, + nonOwner, + fundingCycleData, + fundingCycleMetadata, + splits, + mockJbTerminal1, + mockJbTerminal2, + mockJbOperatorStore, + } = await setup(); + const groupedSplits = [{ group: 1, splits }]; + const terminals = [mockJbTerminal1.address, mockJbTerminal2.address]; + const fundAccessConstraints = makeFundingAccessConstraints({ terminals }); + + await mockJbOperatorStore.mock.hasPermission + .withArgs(nonOwner.address, projectOwner.address, EXISTING_PROJECT, RECONFIGURE_INDEX) + .returns(false); + + await mockJbOperatorStore.mock.hasPermission + .withArgs(nonOwner.address, projectOwner.address, 0, RECONFIGURE_INDEX) + .returns(false); + + let tx = jbController + .connect(nonOwner) + .callStatic.launchFundingCyclesFor( + EXISTING_PROJECT, + fundingCycleData, + fundingCycleMetadata.unpacked, + PROJECT_START, + groupedSplits, + fundAccessConstraints, + terminals, + MEMO, + ); + + await expect(tx).to.be.revertedWith(errors.UNAUTHORIZED); + }); + + it(`Can't launch for a project with an existing funding cycle`, async function () { + const { + jbController, + projectOwner, + fundingCycleData, + fundingCycleMetadata, + splits, + mockJbTerminal1, + mockJbTerminal2, + } = await setup(); + const groupedSplits = [{ group: 1, splits }]; + const terminals = [mockJbTerminal1.address, mockJbTerminal2.address]; + const fundAccessConstraints = makeFundingAccessConstraints({ terminals }); + + let tx = jbController + .connect(projectOwner) + .callStatic.launchFundingCyclesFor( + LAUNCHED_PROJECT, + fundingCycleData, + fundingCycleMetadata.unpacked, + PROJECT_START, + groupedSplits, + fundAccessConstraints, + terminals, + MEMO, + ); + + await expect(tx).to.be.revertedWith(errors.FUNDING_CYCLE_ALREADY_LAUNCHED); + }); +}); diff --git a/test/jb_controller_3_1/launch_project_for.test.js b/test/jb_controller_3_1/launch_project_for.test.js new file mode 100644 index 000000000..c891e1930 --- /dev/null +++ b/test/jb_controller_3_1/launch_project_for.test.js @@ -0,0 +1,392 @@ +import { expect } from 'chai'; +import { ethers } from 'hardhat'; +import { deployMockContract } from '@ethereum-waffle/mock-contract'; +import { makeSplits, packFundingCycleMetadata } from '../helpers/utils'; +import errors from '../helpers/errors.json'; + +import JbController from '../../artifacts/contracts/JBController3_1.sol/JBController3_1.json'; +import jbDirectory from '../../artifacts/contracts/JBDirectory.sol/JBDirectory.json'; +import jbFundingCycleStore from '../../artifacts/contracts/JBFundingCycleStore.sol/JBFundingCycleStore.json'; +import jbOperatoreStore from '../../artifacts/contracts/JBOperatorStore.sol/JBOperatorStore.json'; +import jbFundAccessConstraintsStore from '../../artifacts/contracts/JBFundAccessConstraintsStore.sol/JBFundAccessConstraintsStore.json'; +import jbProjects from '../../artifacts/contracts/JBProjects.sol/JBProjects.json'; +import jbSplitsStore from '../../artifacts/contracts/JBSplitsStore.sol/JBSplitsStore.json'; +import jbTerminal from '../../artifacts/contracts/JBETHPaymentTerminal3_1.sol/JBETHPaymentTerminal3_1.json'; +import jbTokenStore from '../../artifacts/contracts/JBTokenStore.sol/JBTokenStore.json'; + +describe('JBController3_1::launchProjectFor(...)', function () { + const PROJECT_ID = 1; + const METADATA_CID = ''; + const METADATA_DOMAIN = 1234; + const PROJECT_START = '1'; + const MEMO = 'Test Memo'; + + async function setup() { + let [deployer, projectOwner, caller, ...addrs] = await ethers.getSigners(); + + const blockNum = await ethers.provider.getBlockNumber(); + const block = await ethers.provider.getBlock(blockNum); + const timestamp = block.timestamp; + const fundingCycleData = makeFundingCycleDataStruct(); + const fundingCycleMetadata = makeFundingCycleMetadata(); + const splits = makeSplits(); + + let [ + mockJbController, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbOperatorStore, + mockJbProjects, + mockJbSplitsStore, + mockJbTerminal1, + mockJbTerminal2, + mockJbTokenStore, + mockJbFundAccessConstraintsStore, + ] = await Promise.all([ + deployMockContract(deployer, JbController.abi), + deployMockContract(deployer, jbDirectory.abi), + deployMockContract(deployer, jbFundingCycleStore.abi), + deployMockContract(deployer, jbOperatoreStore.abi), + deployMockContract(deployer, jbProjects.abi), + deployMockContract(deployer, jbSplitsStore.abi), + deployMockContract(deployer, jbTerminal.abi), + deployMockContract(deployer, jbTerminal.abi), + deployMockContract(deployer, jbTokenStore.abi), + deployMockContract(deployer, jbFundAccessConstraintsStore.abi), + ]); + + let jbControllerFactory = await ethers.getContractFactory( + 'contracts/JBController3_1.sol:JBController3_1', + ); + let jbController = await jbControllerFactory.deploy( + mockJbOperatorStore.address, + mockJbProjects.address, + mockJbDirectory.address, + mockJbFundingCycleStore.address, + mockJbTokenStore.address, + mockJbSplitsStore.address, + mockJbFundAccessConstraintsStore.address + ); + + await mockJbProjects.mock.createFor + .withArgs(projectOwner.address, [METADATA_CID, METADATA_DOMAIN]) + .returns(PROJECT_ID); + + await mockJbDirectory.mock.setControllerOf.withArgs(PROJECT_ID, jbController.address).returns(); + + await mockJbDirectory.mock.setTerminalsOf + .withArgs(PROJECT_ID, [mockJbTerminal1.address, mockJbTerminal2.address]) + .returns(); + + await mockJbFundingCycleStore.mock.configureFor + .withArgs(PROJECT_ID, fundingCycleData, fundingCycleMetadata.packed, PROJECT_START) + .returns( + Object.assign( + { + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + metadata: fundingCycleMetadata.packed, + }, + fundingCycleData, + ), + ); + + const groupedSplits = [{ group: 1, splits }]; + + await mockJbSplitsStore.mock.set + .withArgs(PROJECT_ID, /*configuration=*/ timestamp, groupedSplits) + .returns(); + + const token = ethers.Wallet.createRandom().address; + + return { + deployer, + projectOwner, + caller, + addrs, + jbController, + mockJbDirectory, + mockJbTokenStore, + mockJbController, + mockJbOperatorStore, + mockJbFundingCycleStore, + mockJbFundAccessConstraintsStore, + mockJbTerminal1, + mockJbTerminal2, + timestamp, + token, + fundingCycleData, + fundingCycleMetadata, + splits, + }; + } + + function makeFundingCycleMetadata({ + reservedRate = 0, + redemptionRate = 10000, + ballotRedemptionRate = 10000, + pausePay = false, + pauseDistributions = false, + pauseRedeem = false, + pauseBurn = false, + pauseTransfers = false, + allowMinting = false, + allowChangeToken = false, + allowTerminalMigration = false, + allowControllerMigration = false, + allowSetTerminals = false, + allowSetControllers = false, + holdFees = false, + preferClaimedTokenOverride = false, + useTotalOverflowForRedemptions = false, + useDataSourceForPay = false, + useDataSourceForRedeem = false, + dataSource = ethers.constants.AddressZero, + metadata = 0, + } = {}) { + const unpackedMetadata = { + global: { + allowSetTerminals, + allowSetControllers, + pauseTransfers, + }, + reservedRate, + redemptionRate, + ballotRedemptionRate, + pausePay, + pauseDistributions, + pauseRedeem, + pauseBurn, + allowMinting, + allowChangeToken, + allowTerminalMigration, + allowControllerMigration, + holdFees, + preferClaimedTokenOverride, + useTotalOverflowForRedemptions, + useDataSourceForPay, + useDataSourceForRedeem, + dataSource, + metadata, + }; + return { unpacked: unpackedMetadata, packed: packFundingCycleMetadata(unpackedMetadata) }; + } + + function makeFundingCycleDataStruct({ + duration = 0, + weight = ethers.BigNumber.from('1' + '0'.repeat(18)), + discountRate = 900000000, + ballot = ethers.constants.AddressZero, + } = {}) { + return { duration, weight, discountRate, ballot }; + } + + function makeFundingAccessConstraints({ + terminals, + token = ethers.Wallet.createRandom().address, + distributionLimit = 200, + distributionLimitCurrency = 1, + overflowAllowance = 100, + overflowAllowanceCurrency = 2, + } = {}) { + let constraints = []; + for (let terminal of terminals) { + constraints.push({ + terminal, + token, + distributionLimit, + distributionLimitCurrency, + overflowAllowance, + overflowAllowanceCurrency, + }); + } + return constraints; + } + + it(`Should launch a project and emit events`, async function () { + const { + jbController, + projectOwner, + timestamp, + token, + fundingCycleData, + fundingCycleMetadata, + splits, + mockJbTerminal1, + mockJbTerminal2, + mockJbFundAccessConstraintsStore + } = await setup(); + const groupedSplits = [{ group: 1, splits }]; + const terminals = [mockJbTerminal1.address, mockJbTerminal2.address]; + const fundAccessConstraints = makeFundingAccessConstraints({ terminals, token }); + + await mockJbFundAccessConstraintsStore.mock.setFor + .withArgs(PROJECT_ID, timestamp, fundAccessConstraints) + .returns(); + + expect( + await jbController + .connect(projectOwner) + .callStatic.launchProjectFor( + projectOwner.address, + [METADATA_CID, METADATA_DOMAIN], + fundingCycleData, + fundingCycleMetadata.unpacked, + PROJECT_START, + groupedSplits, + fundAccessConstraints, + terminals, + MEMO, + ), + ).to.equal(PROJECT_ID); + + let tx = jbController + .connect(projectOwner) + .launchProjectFor( + projectOwner.address, + [METADATA_CID, METADATA_DOMAIN], + fundingCycleData, + fundingCycleMetadata.unpacked, + PROJECT_START, + groupedSplits, + fundAccessConstraints, + terminals, + MEMO, + ); + await expect(tx) + .to.emit(jbController, 'LaunchProject') + .withArgs( + /*fundingCycleData.configuration=*/ timestamp, + PROJECT_ID, + MEMO, + projectOwner.address, + ); + }); + + it(`Should launch a project without payment terminals and funding cycle constraints`, async function () { + const { jbController, projectOwner, timestamp, fundingCycleData, fundingCycleMetadata, splits, mockJbFundAccessConstraintsStore } = + await setup(); + const groupedSplits = [{ group: 1, splits }]; + const fundAccessConstraints = []; + + await mockJbFundAccessConstraintsStore.mock.setFor + .withArgs(PROJECT_ID, timestamp, fundAccessConstraints) + .returns(); + + expect( + await jbController + .connect(projectOwner) + .callStatic.launchProjectFor( + projectOwner.address, + [METADATA_CID, METADATA_DOMAIN], + fundingCycleData, + fundingCycleMetadata.unpacked, + PROJECT_START, + groupedSplits, + fundAccessConstraints, + [], + MEMO, + ), + ).to.equal(PROJECT_ID); + }); + + it(`Can't launch a project with a reserved rate superior to 10000`, async function () { + const { + jbController, + projectOwner, + fundingCycleData, + splits, + mockJbTerminal1, + mockJbTerminal2, + } = await setup(); + const groupedSplits = [{ group: 1, splits }]; + const terminals = [mockJbTerminal1.address, mockJbTerminal2.address]; + const fundAccessConstraints = makeFundingAccessConstraints({ terminals }); + const fundingCycleMetadata = makeFundingCycleMetadata({ reservedRate: 10001 }); + + let tx = jbController + .connect(projectOwner) + .launchProjectFor( + projectOwner.address, + [METADATA_CID, METADATA_DOMAIN], + fundingCycleData, + fundingCycleMetadata.unpacked, + PROJECT_START, + groupedSplits, + fundAccessConstraints, + terminals, + MEMO, + ); + + await expect(tx).to.be.revertedWith('INVALID_RESERVED_RATE()'); + }); + + it(`Can't launch a project with a redemption rate superior to 10000`, async function () { + const { + jbController, + projectOwner, + fundingCycleData, + fundingCycleMetadata, + splits, + mockJbTerminal1, + mockJbTerminal2, + } = await setup(); + const groupedSplits = [{ group: 1, splits }]; + const terminals = [mockJbTerminal1.address, mockJbTerminal2.address]; + const fundAccessConstraints = makeFundingAccessConstraints({ terminals }); + + fundingCycleMetadata.unpacked.redemptionRate = 10001; //not possible in packed metadata (shl of a negative value) + + let tx = jbController + .connect(projectOwner) + .launchProjectFor( + projectOwner.address, + [METADATA_CID, METADATA_DOMAIN], + fundingCycleData, + fundingCycleMetadata.unpacked, + PROJECT_START, + groupedSplits, + fundAccessConstraints, + terminals, + MEMO, + ); + + await expect(tx).to.be.revertedWith(errors.INVALID_REDEMPTION_RATE); + }); + + it(`Can't launch a project with a ballot redemption rate superior to 10000`, async function () { + const { + jbController, + projectOwner, + fundingCycleData, + fundingCycleMetadata, + splits, + mockJbTerminal1, + mockJbTerminal2, + } = await setup(); + + const groupedSplits = [{ group: 1, splits }]; + const terminals = [mockJbTerminal1.address, mockJbTerminal2.address]; + const fundAccessConstraints = makeFundingAccessConstraints({ terminals }); + + fundingCycleMetadata.unpacked.ballotRedemptionRate = 10001; //not possible in packed metadata (shl of a negative value) + + let tx = jbController + .connect(projectOwner) + .launchProjectFor( + projectOwner.address, + [METADATA_CID, METADATA_DOMAIN], + fundingCycleData, + fundingCycleMetadata.unpacked, + PROJECT_START, + groupedSplits, + fundAccessConstraints, + terminals, + MEMO, + ); + + await expect(tx).to.be.revertedWith(errors.INVALID_BALLOT_REDEMPTION_RATE); + }); +}); diff --git a/test/jb_controller_3_1/migrate.test.js b/test/jb_controller_3_1/migrate.test.js new file mode 100644 index 000000000..3d3e2e141 --- /dev/null +++ b/test/jb_controller_3_1/migrate.test.js @@ -0,0 +1,195 @@ +import { expect } from 'chai'; +import { ethers } from 'hardhat'; +import { deployMockContract } from '@ethereum-waffle/mock-contract'; +import { packFundingCycleMetadata } from '../helpers/utils'; +import errors from '../helpers/errors.json'; + +import JbController from '../../artifacts/contracts/JBController.sol/JBController.json'; +import jbDirectory from '../../artifacts/contracts/JBDirectory.sol/JBDirectory.json'; +import jbFundingCycleStore from '../../artifacts/contracts/JBFundingCycleStore.sol/JBFundingCycleStore.json'; +import jbOperatoreStore from '../../artifacts/contracts/JBOperatorStore.sol/JBOperatorStore.json'; +import jbFundAccessConstraintsStore from '../../artifacts/contracts/JBFundAccessConstraintsStore.sol/JBFundAccessConstraintsStore.json'; +import jbProjects from '../../artifacts/contracts/JBProjects.sol/JBProjects.json'; +import jbSplitsStore from '../../artifacts/contracts/JBSplitsStore.sol/JBSplitsStore.json'; +import jbTokenStore from '../../artifacts/contracts/JBTokenStore.sol/JBTokenStore.json'; + +describe('JBController3_1::migrate(...)', function () { + const PROJECT_ID = 1; + const TOTAL_SUPPLY = 20000; + let MIGRATE_CONTROLLER_INDEX; + + before(async function () { + let jbOperationsFactory = await ethers.getContractFactory('JBOperations'); + let jbOperations = await jbOperationsFactory.deploy(); + + MIGRATE_CONTROLLER_INDEX = await jbOperations.MIGRATE_CONTROLLER(); + }); + + async function setup() { + let [deployer, projectOwner, caller, ...addrs] = await ethers.getSigners(); + + const blockNum = await ethers.provider.getBlockNumber(); + const block = await ethers.provider.getBlock(blockNum); + const timestamp = block.timestamp; + + let [ + mockJbController, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbOperatorStore, + mockJbProjects, + mockJbSplitsStore, + mockJbTokenStore, + mockJbFundAccessConstraintsStore, + ] = await Promise.all([ + deployMockContract(deployer, JbController.abi), + deployMockContract(deployer, jbDirectory.abi), + deployMockContract(deployer, jbFundingCycleStore.abi), + deployMockContract(deployer, jbOperatoreStore.abi), + deployMockContract(deployer, jbProjects.abi), + deployMockContract(deployer, jbSplitsStore.abi), + deployMockContract(deployer, jbTokenStore.abi), + deployMockContract(deployer, jbFundAccessConstraintsStore.abi), + ]); + + let jbControllerFactory = await ethers.getContractFactory( + 'contracts/JBController3_1.sol:JBController3_1', + ); + let jbController = await jbControllerFactory.deploy( + mockJbOperatorStore.address, + mockJbProjects.address, + mockJbDirectory.address, + mockJbFundingCycleStore.address, + mockJbTokenStore.address, + mockJbSplitsStore.address, + mockJbFundAccessConstraintsStore.address + ); + + await mockJbProjects.mock.ownerOf.withArgs(PROJECT_ID).returns(projectOwner.address); + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(jbController.address); + + await mockJbDirectory.mock.setControllerOf + .withArgs(PROJECT_ID, mockJbController.address) + .returns(); + + await mockJbTokenStore.mock.totalSupplyOf.withArgs(PROJECT_ID).returns(TOTAL_SUPPLY); + + await mockJbController.mock.prepForMigrationOf + .withArgs(PROJECT_ID, jbController.address) + .returns(); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + // mock JBFundingCycle obj + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: 0, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ allowControllerMigration: 1 }), + }); + + return { + deployer, + projectOwner, + caller, + addrs, + jbController, + mockJbDirectory, + mockJbTokenStore, + mockJbController, + mockJbOperatorStore, + mockJbFundingCycleStore, + timestamp, + }; + } + + it(`Should mint all reserved token and migrate controller if caller is project's current controller`, async function () { + const { jbController, projectOwner, mockJbController, timestamp } = await setup(); + + let tx = jbController.connect(projectOwner).migrate(PROJECT_ID, mockJbController.address); + }); + + it(`Should mint all reserved token and migrate controller if caller is authorized`, async function () { + const { jbController, projectOwner, caller, mockJbController, mockJbOperatorStore, timestamp } = + await setup(); + + await mockJbOperatorStore.mock.hasPermission + .withArgs(caller.address, projectOwner.address, PROJECT_ID, MIGRATE_CONTROLLER_INDEX) + .returns(true); + + let tx = jbController.connect(caller).migrate(PROJECT_ID, mockJbController.address); + + await expect(tx) + .to.emit(jbController, 'Migrate') + .withArgs(PROJECT_ID, mockJbController.address, caller.address); + }); + + it(`Should migrate controller without minting if there is no reserved token`, async function () { + const { jbController, projectOwner, mockJbController, mockJbTokenStore } = await setup(); + + await mockJbTokenStore.mock.totalSupplyOf.withArgs(PROJECT_ID).returns(0); + + let tx = jbController.connect(projectOwner).migrate(PROJECT_ID, mockJbController.address); + + await expect(tx) + .to.emit(jbController, 'Migrate') + .withArgs(PROJECT_ID, mockJbController.address, projectOwner.address); + }); + + it(`Can't migrate controller if caller is not the owner nor is authorized`, async function () { + const { jbController, projectOwner, caller, mockJbController, mockJbOperatorStore, timestamp } = + await setup(); + + await mockJbOperatorStore.mock.hasPermission + .withArgs(caller.address, projectOwner.address, PROJECT_ID, MIGRATE_CONTROLLER_INDEX) + .returns(false); + + await mockJbOperatorStore.mock.hasPermission + .withArgs(caller.address, projectOwner.address, 0, MIGRATE_CONTROLLER_INDEX) + .returns(false); + + await expect( + jbController.connect(caller).migrate(PROJECT_ID, mockJbController.address), + ).to.be.revertedWith('UNAUTHORIZED()'); + }); + + it(`Can't migrate if migration is not initiated via the current controller`, async function () { + const { deployer, jbController, projectOwner, mockJbDirectory, mockJbController } = + await setup(); + + let mockCurrentController = await deployMockContract(deployer, JbController.abi); + + await mockJbDirectory.mock.controllerOf + .withArgs(PROJECT_ID) + .returns(mockCurrentController.address); + + await expect( + jbController.connect(projectOwner).migrate(PROJECT_ID, mockJbController.address), + ).to.be.revertedWith(errors.NOT_CURRENT_CONTROLLER); + }); + + it(`Can't migrate if migration is not allowed in funding cycle`, async function () { + const { jbController, projectOwner, mockJbFundingCycleStore, mockJbController, timestamp } = + await setup(); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: 0, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ allowControllerMigration: 0 }), + }); + + await expect( + jbController.connect(projectOwner).migrate(PROJECT_ID, mockJbController.address), + ).to.be.revertedWith(errors.MIGRATION_NOT_ALLOWED); + }); +}); diff --git a/test/jb_controller_3_1/mint_tokens_of.test.js b/test/jb_controller_3_1/mint_tokens_of.test.js new file mode 100644 index 000000000..d6c69093f --- /dev/null +++ b/test/jb_controller_3_1/mint_tokens_of.test.js @@ -0,0 +1,670 @@ +import { expect } from 'chai'; +import { ethers } from 'hardhat'; +import { deployMockContract } from '@ethereum-waffle/mock-contract'; +import { impersonateAccount, packFundingCycleMetadata } from '../helpers/utils'; +import errors from '../helpers/errors.json'; + +import jbDirectory from '../../artifacts/contracts/JBDirectory.sol/JBDirectory.json'; +import jbFundingCycleStore from '../../artifacts/contracts/JBFundingCycleStore.sol/JBFundingCycleStore.json'; +import jbOperatoreStore from '../../artifacts/contracts/JBOperatorStore.sol/JBOperatorStore.json'; +import jbProjects from '../../artifacts/contracts/JBProjects.sol/JBProjects.json'; +import jbFundAccessConstraintsStore from '../../artifacts/contracts/JBFundAccessConstraintsStore.sol/JBFundAccessConstraintsStore.json'; +import jbSplitsStore from '../../artifacts/contracts/JBSplitsStore.sol/JBSplitsStore.json'; +import jbTerminal from '../../artifacts/contracts/abstract/JBPayoutRedemptionPaymentTerminal3_1.sol/JBPayoutRedemptionPaymentTerminal3_1.json'; +import jbToken from '../../artifacts/contracts/JBToken.sol/JBToken.json'; +import jbTokenStore from '../../artifacts/contracts/JBTokenStore.sol/JBTokenStore.json'; + +describe('JBController3_1::mintTokensOf(...)', function () { + const PROJECT_ID = 1; + const MEMO = 'Test Memo'; + const AMOUNT_TO_MINT = 20000; + const RESERVED_RATE = 5000; // 50% + const AMOUNT_TO_RECEIVE = AMOUNT_TO_MINT - (AMOUNT_TO_MINT * RESERVED_RATE) / 10000; + + let MINT_INDEX; + + before(async function () { + let jbOperationsFactory = await ethers.getContractFactory('JBOperations'); + let jbOperations = await jbOperationsFactory.deploy(); + + MINT_INDEX = await jbOperations.MINT(); + }); + + async function setup() { + let [deployer, projectOwner, beneficiary, mockDatasource, ...addrs] = await ethers.getSigners(); + + const blockNum = await ethers.provider.getBlockNumber(); + const block = await ethers.provider.getBlock(blockNum); + const timestamp = block.timestamp; + + let [ + mockJbDirectory, + mockJbFundingCycleStore, + mockJbOperatorStore, + mockJbProjects, + mockJbSplitsStore, + mockJbToken, + mockJbTokenStore, + mockJbFundAccessConstraintsStore, + ] = await Promise.all([ + deployMockContract(deployer, jbDirectory.abi), + deployMockContract(deployer, jbFundingCycleStore.abi), + deployMockContract(deployer, jbOperatoreStore.abi), + deployMockContract(deployer, jbProjects.abi), + deployMockContract(deployer, jbSplitsStore.abi), + deployMockContract(deployer, jbToken.abi), + deployMockContract(deployer, jbTokenStore.abi), + deployMockContract(deployer, jbFundAccessConstraintsStore.abi), + ]); + + let jbControllerFactory = await ethers.getContractFactory( + 'contracts/JBController3_1.sol:JBController3_1', + ); + let jbController = await jbControllerFactory.deploy( + mockJbOperatorStore.address, + mockJbProjects.address, + mockJbDirectory.address, + mockJbFundingCycleStore.address, + mockJbTokenStore.address, + mockJbSplitsStore.address, + mockJbFundAccessConstraintsStore.address + ); + + await mockJbProjects.mock.ownerOf.withArgs(PROJECT_ID).returns(projectOwner.address); + + await mockJbDirectory.mock.isTerminalOf + .withArgs(PROJECT_ID, projectOwner.address) + .returns(false); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + // mock JBFundingCycle obj + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: 0, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ + allowMinting: 1, + reservedRate: RESERVED_RATE, + }), + }); + + await mockJbTokenStore.mock.mintFor + .withArgs(beneficiary.address, PROJECT_ID, AMOUNT_TO_RECEIVE, /*_preferClaimedTokens=*/ true) + .returns(); + + await mockJbTokenStore.mock.totalSupplyOf.withArgs(PROJECT_ID).returns(AMOUNT_TO_RECEIVE); + + return { + projectOwner, + beneficiary, + mockDatasource, + addrs, + jbController, + mockJbOperatorStore, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbTokenStore, + mockJbToken, + timestamp, + }; + } + + it(`Should mint token if caller is project owner and funding cycle not paused`, async function () { + const { projectOwner, beneficiary, jbController } = await setup(); + + await expect( + jbController + .connect(projectOwner) + .mintTokensOf( + PROJECT_ID, + AMOUNT_TO_MINT, + beneficiary.address, + MEMO, + /*_preferClaimedTokens=*/ true, + /* _useReservedRate=*/ true, + ), + ) + .to.emit(jbController, 'MintTokens') + .withArgs( + beneficiary.address, + PROJECT_ID, + AMOUNT_TO_MINT, + AMOUNT_TO_RECEIVE, + MEMO, + RESERVED_RATE, + projectOwner.address, + ); + + let newReservedTokenBalance = await jbController.reservedTokenBalanceOf( + PROJECT_ID, + ); + expect(newReservedTokenBalance).to.equal(AMOUNT_TO_MINT - AMOUNT_TO_RECEIVE); + }); + + it(`Should mint claimed token if funding cycle forces it`, async function () { + const { projectOwner, beneficiary, jbController, mockJbFundingCycleStore, mockJbTokenStore } = + await setup(); + + const blockNum = await ethers.provider.getBlockNumber(); + const block = await ethers.provider.getBlock(blockNum); + const timestamp = block.timestamp; + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: 0, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ + preferClaimedTokenOverride: 1, + allowMinting: 1, + reservedRate: RESERVED_RATE, + }), + }); + + // _preferClaimedTokens will be forced as true + await mockJbTokenStore.mock.mintFor + .withArgs(beneficiary.address, PROJECT_ID, AMOUNT_TO_RECEIVE, /*_preferClaimedTokens=*/ true) + .returns(); + + await expect( + jbController + .connect(projectOwner) + .mintTokensOf( + PROJECT_ID, + AMOUNT_TO_MINT, + beneficiary.address, + MEMO, + /*_preferClaimedTokens=*/ false, + /* _useReservedRate=*/ true, + ), + ) + .to.emit(jbController, 'MintTokens') + .withArgs( + beneficiary.address, + PROJECT_ID, + AMOUNT_TO_MINT, + AMOUNT_TO_RECEIVE, + MEMO, + RESERVED_RATE, + projectOwner.address, + ); + + let newReservedTokenBalance = await jbController.reservedTokenBalanceOf( + PROJECT_ID, + ); + expect(newReservedTokenBalance).to.equal(AMOUNT_TO_MINT - AMOUNT_TO_RECEIVE); + }); + + it(`Should mint token if caller is not project owner but is authorized`, async function () { + const { projectOwner, beneficiary, addrs, jbController, mockJbOperatorStore, mockJbDirectory } = + await setup(); + let caller = addrs[0]; + + await mockJbOperatorStore.mock.hasPermission + .withArgs(caller.address, projectOwner.address, PROJECT_ID, MINT_INDEX) + .returns(true); + + await mockJbDirectory.mock.isTerminalOf.withArgs(PROJECT_ID, caller.address).returns(false); + + await expect( + jbController + .connect(caller) + .mintTokensOf( + PROJECT_ID, + AMOUNT_TO_MINT, + beneficiary.address, + MEMO, + /*_preferClaimedTokens=*/ true, + /* _useReservedRate=*/ true, + ), + ) + .to.emit(jbController, 'MintTokens') + .withArgs( + beneficiary.address, + PROJECT_ID, + AMOUNT_TO_MINT, + AMOUNT_TO_RECEIVE, + MEMO, + RESERVED_RATE, + caller.address, + ); + + let newReservedTokenBalance = await jbController.reservedTokenBalanceOf( + PROJECT_ID, + ); + expect(newReservedTokenBalance).to.equal(AMOUNT_TO_MINT - AMOUNT_TO_RECEIVE); + }); + + it(`Should mint token if caller is a terminal of the corresponding project`, async function () { + const { projectOwner, beneficiary, jbController, mockJbOperatorStore, mockJbDirectory } = + await setup(); + const terminal = await deployMockContract(projectOwner, jbTerminal.abi); + const terminalSigner = await impersonateAccount(terminal.address); + + await mockJbOperatorStore.mock.hasPermission + .withArgs(terminalSigner.address, projectOwner.address, PROJECT_ID, MINT_INDEX) + .returns(false); + + await mockJbOperatorStore.mock.hasPermission + .withArgs(terminalSigner.address, projectOwner.address, 0, MINT_INDEX) + .returns(false); + + await mockJbDirectory.mock.isTerminalOf + .withArgs(PROJECT_ID, terminalSigner.address) + .returns(true); + + await expect( + jbController + .connect(terminalSigner) + .mintTokensOf( + PROJECT_ID, + AMOUNT_TO_MINT, + beneficiary.address, + MEMO, + /*_preferClaimedTokens=*/ true, + /* _useReservedRate=*/ true, + ), + ) + .to.emit(jbController, 'MintTokens') + .withArgs( + beneficiary.address, + PROJECT_ID, + AMOUNT_TO_MINT, + AMOUNT_TO_RECEIVE, + MEMO, + RESERVED_RATE, + terminalSigner.address, + ); + + let newReservedTokenBalance = await jbController.reservedTokenBalanceOf( + PROJECT_ID, + ); + expect(newReservedTokenBalance).to.equal(AMOUNT_TO_MINT - AMOUNT_TO_RECEIVE); + }); + + it(`Should mint token if caller is the current funding cycle's datasource of the corresponding project`, async function () { + const { + projectOwner, + beneficiary, + mockDatasource, + jbController, + mockJbFundingCycleStore, + mockJbOperatorStore, + mockJbDirectory, + timestamp, + } = await setup(); + const terminal = await deployMockContract(projectOwner, jbTerminal.abi); + const terminalSigner = await impersonateAccount(terminal.address); + + await mockJbOperatorStore.mock.hasPermission + .withArgs(terminalSigner.address, projectOwner.address, PROJECT_ID, MINT_INDEX) + .returns(false); + + await mockJbOperatorStore.mock.hasPermission + .withArgs(terminalSigner.address, projectOwner.address, 0, MINT_INDEX) + .returns(false); + + await mockJbDirectory.mock.isTerminalOf + .withArgs(PROJECT_ID, mockDatasource.address) + .returns(false); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + // mock JBFundingCycle obj + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: 0, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ + allowMinting: 1, + reservedRate: RESERVED_RATE, + dataSource: mockDatasource.address, + }), + }); + + await expect( + jbController + .connect(mockDatasource) + .mintTokensOf( + PROJECT_ID, + AMOUNT_TO_MINT, + beneficiary.address, + MEMO, + /*_preferClaimedTokens=*/ true, + /* _useReservedRate=*/ true, + ), + ) + .to.emit(jbController, 'MintTokens') + .withArgs( + beneficiary.address, + PROJECT_ID, + AMOUNT_TO_MINT, + AMOUNT_TO_RECEIVE, + MEMO, + RESERVED_RATE, + mockDatasource.address, + ); + + let newReservedTokenBalance = await jbController.reservedTokenBalanceOf( + PROJECT_ID, + ); + expect(newReservedTokenBalance).to.equal(AMOUNT_TO_MINT - AMOUNT_TO_RECEIVE); + }); + + it(`Can't mint token if caller is not authorized`, async function () { + const { projectOwner, beneficiary, addrs, jbController, mockJbOperatorStore, mockJbDirectory } = + await setup(); + let caller = addrs[0]; + + await mockJbOperatorStore.mock.hasPermission + .withArgs(caller.address, projectOwner.address, PROJECT_ID, MINT_INDEX) + .returns(false); + + await mockJbOperatorStore.mock.hasPermission + .withArgs(caller.address, projectOwner.address, 0, MINT_INDEX) + .returns(false); + + await mockJbDirectory.mock.isTerminalOf.withArgs(PROJECT_ID, caller.address).returns(false); + + await expect( + jbController + .connect(caller) + .mintTokensOf( + PROJECT_ID, + AMOUNT_TO_MINT, + beneficiary.address, + MEMO, + /*_preferClaimedTokens=*/ true, + /* _useReservedRate=*/ true, + ), + ).to.be.revertedWith(errors.UNAUTHORIZED); + }); + + it(`Can't mint 0 token`, async function () { + const { projectOwner, beneficiary, jbController } = await setup(); + + await expect( + jbController + .connect(projectOwner) + .mintTokensOf( + PROJECT_ID, + 0, + beneficiary.address, + MEMO, + /*_preferClaimedTokens=*/ true, + /* _useReservedRate=*/ true, + ), + ).to.be.revertedWith(errors.ZERO_TOKENS_TO_MINT); + }); + + it(`Can't mint token if funding cycle is paused and caller is not a terminal delegate or a datasource`, async function () { + const { projectOwner, beneficiary, jbController, mockJbFundingCycleStore, timestamp } = + await setup(); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + // mock JBFundingCycle obj + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: 0, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ allowMinting: 0, reservedRate: RESERVED_RATE }), + }); + + await expect( + jbController + .connect(projectOwner) + .mintTokensOf( + PROJECT_ID, + AMOUNT_TO_MINT, + beneficiary.address, + MEMO, + /*_preferClaimedTokens=*/ true, + /* _useReservedRate=*/ true, + ), + ).to.be.revertedWith(errors.MINT_NOT_ALLOWED_AND_NOT_TERMINAL_DELEGATE); + }); + + it(`Should mint token if funding cycle is paused and caller is a terminal delegate`, async function () { + const { + projectOwner, + beneficiary, + jbController, + mockJbFundingCycleStore, + mockJbOperatorStore, + mockJbDirectory, + timestamp, + } = await setup(); + const terminal = await deployMockContract(projectOwner, jbTerminal.abi); + const terminalSigner = await impersonateAccount(terminal.address); + + await mockJbOperatorStore.mock.hasPermission + .withArgs(terminalSigner.address, projectOwner.address, PROJECT_ID, MINT_INDEX) + .returns(false); + + await mockJbOperatorStore.mock.hasPermission + .withArgs(terminalSigner.address, projectOwner.address, 0, MINT_INDEX) + .returns(false); + + await mockJbDirectory.mock.isTerminalOf + .withArgs(PROJECT_ID, terminalSigner.address) + .returns(true); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + // mock JBFundingCycle obj + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: 0, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ allowMinting: 0, reservedRate: RESERVED_RATE }), + }); + + await expect( + jbController + .connect(terminalSigner) + .mintTokensOf( + PROJECT_ID, + AMOUNT_TO_MINT, + beneficiary.address, + MEMO, + /*_preferClaimedTokens=*/ true, + /* _useReservedRate=*/ true, + ), + ) + .to.emit(jbController, 'MintTokens') + .withArgs( + beneficiary.address, + PROJECT_ID, + AMOUNT_TO_MINT, + AMOUNT_TO_RECEIVE, + MEMO, + RESERVED_RATE, + terminalSigner.address, + ); + + let newReservedTokenBalance = await jbController.reservedTokenBalanceOf( + PROJECT_ID, + ); + expect(newReservedTokenBalance).to.equal(AMOUNT_TO_MINT - AMOUNT_TO_RECEIVE); + }); + + it(`Should add the minted amount to the reserved tokens if reserved rate is 100%`, async function () { + const { + projectOwner, + beneficiary, + jbController, + mockJbFundingCycleStore, + mockJbTokenStore, + timestamp, + } = await setup(); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + // mock JBFundingCycle obj + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: 0, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ reservedRate: 10000, allowMinting: 1 }), + }); + + await mockJbTokenStore.mock.totalSupplyOf.withArgs(PROJECT_ID).returns(0); + + let previousReservedTokenBalance = await jbController.reservedTokenBalanceOf( + PROJECT_ID, + ); + + await expect( + jbController + .connect(projectOwner) + .mintTokensOf( + PROJECT_ID, + AMOUNT_TO_MINT, + beneficiary.address, + MEMO, + /*_preferClaimedTokens=*/ true, + /* _useReservedRate=*/ true, + ), + ) + .to.emit(jbController, 'MintTokens') + .withArgs( + beneficiary.address, + PROJECT_ID, + AMOUNT_TO_MINT, + 0, + MEMO, + 10000, + projectOwner.address, + ); + + let newReservedTokenBalance = await jbController.reservedTokenBalanceOf(PROJECT_ID); + + expect(newReservedTokenBalance).to.equal(previousReservedTokenBalance.add(AMOUNT_TO_MINT)); + }); + + it('Should not use a reserved rate even if one is specified if the `_useReservedRate` arg is false', async function () { + const { projectOwner, beneficiary, jbController, mockJbTokenStore } = await setup(); + + await mockJbTokenStore.mock.mintFor + .withArgs(beneficiary.address, PROJECT_ID, AMOUNT_TO_MINT, /*_preferClaimedTokens=*/ true) + .returns(); + + await mockJbTokenStore.mock.totalSupplyOf.withArgs(PROJECT_ID).returns(0); + + let previousReservedTokenBalance = await jbController.reservedTokenBalanceOf( + PROJECT_ID, + ); + + await expect( + jbController + .connect(projectOwner) + .mintTokensOf( + PROJECT_ID, + AMOUNT_TO_MINT, + beneficiary.address, + MEMO, + /*_preferClaimedTokens=*/ true, + /* _useReservedRate=*/ false, + ), + ) + .to.emit(jbController, 'MintTokens') + .withArgs( + beneficiary.address, + PROJECT_ID, + AMOUNT_TO_MINT, + AMOUNT_TO_MINT, + MEMO, + 0, + projectOwner.address, + ); + + await mockJbTokenStore.mock.totalSupplyOf.withArgs(PROJECT_ID).returns(AMOUNT_TO_MINT); + + let newReservedTokenBalance = await jbController.reservedTokenBalanceOf( + PROJECT_ID, + ); + + expect(newReservedTokenBalance).to.equal(previousReservedTokenBalance); + }); + + it(`Should not change the reserved tokens amount if reserved rate is 0%`, async function () { + const { + projectOwner, + beneficiary, + jbController, + mockJbFundingCycleStore, + mockJbTokenStore, + timestamp, + } = await setup(); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: 0, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ reservedRate: 0, allowMinting: 1 }), + }); + + await mockJbTokenStore.mock.totalSupplyOf.withArgs(PROJECT_ID).returns(AMOUNT_TO_MINT); // to mint == to receive <=> reserve rate = 0 + + await mockJbTokenStore.mock.mintFor + .withArgs(beneficiary.address, PROJECT_ID, AMOUNT_TO_MINT, true) + .returns(); // to mint == to receive (reserve rate = 0) + + let previousReservedTokenBalance = await jbController.reservedTokenBalanceOf( + PROJECT_ID, + ); + + await expect( + jbController + .connect(projectOwner) + .mintTokensOf( + PROJECT_ID, + AMOUNT_TO_MINT, + beneficiary.address, + MEMO, + /*_preferClaimedTokens=*/ true, + /* _useReservedRate=*/ true, + ), + ) + .to.emit(jbController, 'MintTokens') + .withArgs( + beneficiary.address, + PROJECT_ID, + AMOUNT_TO_MINT, + AMOUNT_TO_MINT, + MEMO, + 0, + projectOwner.address, + ); + + let newReservedTokenBalance = await jbController.reservedTokenBalanceOf(PROJECT_ID); + + expect(newReservedTokenBalance).to.equal(previousReservedTokenBalance); + }); +}); diff --git a/test/jb_controller_3_1/prep_for_migration.test.js b/test/jb_controller_3_1/prep_for_migration.test.js new file mode 100644 index 000000000..024db7ada --- /dev/null +++ b/test/jb_controller_3_1/prep_for_migration.test.js @@ -0,0 +1,92 @@ +import { expect } from 'chai'; +import { ethers } from 'hardhat'; +import { deployMockContract } from '@ethereum-waffle/mock-contract'; +import { impersonateAccount } from '../helpers/utils'; +import errors from '../helpers/errors.json'; + +import JbController from '../../artifacts/contracts/JBController3_1.sol/JBController3_1.json'; +import jbDirectory from '../../artifacts/contracts/JBDirectory.sol/JBDirectory.json'; +import jbFundingCycleStore from '../../artifacts/contracts/JBFundingCycleStore.sol/JBFundingCycleStore.json'; +import jbOperatoreStore from '../../artifacts/contracts/JBOperatorStore.sol/JBOperatorStore.json'; +import jbFundAccessConstraintsStore from '../../artifacts/contracts/JBFundAccessConstraintsStore.sol/JBFundAccessConstraintsStore.json'; +import jbProjects from '../../artifacts/contracts/JBProjects.sol/JBProjects.json'; +import jbSplitsStore from '../../artifacts/contracts/JBSplitsStore.sol/JBSplitsStore.json'; +import jbTokenStore from '../../artifacts/contracts/JBTokenStore.sol/JBTokenStore.json'; + +describe('JBController3_1::prepForMigrationOf(...)', function () { + const PROJECT_ID = 1; + const TOTAL_SUPPLY = 20000; + + async function setup() { + let [deployer, projectOwner, ...addrs] = await ethers.getSigners(); + + let [ + mockJbController, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbOperatorStore, + mockJbProjects, + mockJbSplitsStore, + mockJbTokenStore, + mockJbFundAccessConstraintsStore, + ] = await Promise.all([ + deployMockContract(deployer, JbController.abi), + deployMockContract(deployer, jbDirectory.abi), + deployMockContract(deployer, jbFundingCycleStore.abi), + deployMockContract(deployer, jbOperatoreStore.abi), + deployMockContract(deployer, jbProjects.abi), + deployMockContract(deployer, jbSplitsStore.abi), + deployMockContract(deployer, jbTokenStore.abi), + deployMockContract(deployer, jbFundAccessConstraintsStore.abi), + ]); + + let jbControllerFactory = await ethers.getContractFactory( + 'contracts/JBController3_1.sol:JBController3_1', + ); + let jbController = await jbControllerFactory.deploy( + mockJbOperatorStore.address, + mockJbProjects.address, + mockJbDirectory.address, + mockJbFundingCycleStore.address, + mockJbTokenStore.address, + mockJbSplitsStore.address, + mockJbFundAccessConstraintsStore.address + ); + + await mockJbProjects.mock.ownerOf.withArgs(PROJECT_ID).returns(projectOwner.address); + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + + await mockJbTokenStore.mock.totalSupplyOf.withArgs(PROJECT_ID).returns(TOTAL_SUPPLY); + + return { + projectOwner, + addrs, + jbController, + mockJbDirectory, + mockJbTokenStore, + mockJbController, + }; + } + + it(`Should set the processed token tracker as the total supply if caller is not project's current controller`, async function () { + const { jbController } = await setup(); + let controllerSigner = await impersonateAccount(jbController.address); + + const tx = jbController + .connect(controllerSigner) + .prepForMigrationOf(PROJECT_ID, ethers.constants.AddressZero); + + await expect(tx).to.be.not.reverted; + + // reserved token balance should be at 0 if processed token = total supply + expect(await jbController.reservedTokenBalanceOf(PROJECT_ID)).to.equal(0); + }); + + it(`Can't prep for migration if the caller is the current controller`, async function () { + const { jbController, mockJbController, mockJbDirectory } = await setup(); + let controllerSigner = await impersonateAccount(mockJbController.address); + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(jbController.address); + }); +}); diff --git a/test/jb_controller_3_1/reconfigure_funding_cycles_of.test.js b/test/jb_controller_3_1/reconfigure_funding_cycles_of.test.js new file mode 100644 index 000000000..389d8bfef --- /dev/null +++ b/test/jb_controller_3_1/reconfigure_funding_cycles_of.test.js @@ -0,0 +1,621 @@ +import { expect } from 'chai'; +import { ethers } from 'hardhat'; +import { deployMockContract } from '@ethereum-waffle/mock-contract'; +import { makeSplits, packFundingCycleMetadata } from '../helpers/utils'; +import errors from '../helpers/errors.json'; + +import JbController from '../../artifacts/contracts/JBController3_1.sol/JBController3_1.json'; +import jbDirectory from '../../artifacts/contracts/JBDirectory.sol/JBDirectory.json'; +import jbFundingCycleStore from '../../artifacts/contracts/JBFundingCycleStore.sol/JBFundingCycleStore.json'; +import jbOperatoreStore from '../../artifacts/contracts/JBOperatorStore.sol/JBOperatorStore.json'; +import jbFundAccessConstraintsStore from '../../artifacts/contracts/JBFundAccessConstraintsStore.sol/JBFundAccessConstraintsStore.json'; +import jbProjects from '../../artifacts/contracts/JBProjects.sol/JBProjects.json'; +import jbSplitsStore from '../../artifacts/contracts/JBSplitsStore.sol/JBSplitsStore.json'; +import jbTerminal from '../../artifacts/contracts/JBETHPaymentTerminal3_1.sol/JBETHPaymentTerminal3_1.json'; +import jbTokenStore from '../../artifacts/contracts/JBTokenStore.sol/JBTokenStore.json'; + +describe('JBController3_1::reconfigureFundingCycleOf(...)', function () { + const PROJECT_ID = 1; + const PROJECT_START = '1'; + const MEMO = 'Test Memo'; + + let RECONFIGURE_INDEX; + + before(async function () { + let jbOperationsFactory = await ethers.getContractFactory('JBOperations'); + let jbOperations = await jbOperationsFactory.deploy(); + + RECONFIGURE_INDEX = await jbOperations.RECONFIGURE(); + }); + + async function setup() { + let [deployer, projectOwner, caller, ...addrs] = await ethers.getSigners(); + + const blockNum = await ethers.provider.getBlockNumber(); + const block = await ethers.provider.getBlock(blockNum); + const timestamp = block.timestamp; + + let [ + mockJbController, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbOperatorStore, + mockJbProjects, + mockJbSplitsStore, + mockJbTerminal1, + mockJbTerminal2, + mockJbTokenStore, + mockJbFundAccessConstraintsStore, + ] = await Promise.all([ + deployMockContract(deployer, JbController.abi), + deployMockContract(deployer, jbDirectory.abi), + deployMockContract(deployer, jbFundingCycleStore.abi), + deployMockContract(deployer, jbOperatoreStore.abi), + deployMockContract(deployer, jbProjects.abi), + deployMockContract(deployer, jbSplitsStore.abi), + deployMockContract(deployer, jbTerminal.abi), + deployMockContract(deployer, jbTerminal.abi), + deployMockContract(deployer, jbTokenStore.abi), + deployMockContract(deployer, jbFundAccessConstraintsStore.abi), + ]); + + let jbControllerFactory = await ethers.getContractFactory( + 'contracts/JBController3_1.sol:JBController3_1', + ); + let jbController = await jbControllerFactory.deploy( + mockJbOperatorStore.address, + mockJbProjects.address, + mockJbDirectory.address, + mockJbFundingCycleStore.address, + mockJbTokenStore.address, + mockJbSplitsStore.address, + mockJbFundAccessConstraintsStore.address + ); + + const fundingCycleData = makeFundingCycleDataStruct(); + const fundingCycleMetadata = makeFundingCycleMetadata(); + const splits = makeSplits(); + + await mockJbProjects.mock.ownerOf.withArgs(PROJECT_ID).returns(projectOwner.address); + + await mockJbFundingCycleStore.mock.configureFor + .withArgs(PROJECT_ID, fundingCycleData, fundingCycleMetadata.packed, PROJECT_START) + .returns( + Object.assign( + { + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + metadata: fundingCycleMetadata.packed, + }, + fundingCycleData, + ), + ); + + const groupedSplits = [{ group: 1, splits }]; + + await mockJbSplitsStore.mock.set + .withArgs(PROJECT_ID, /*configuration=*/ timestamp, groupedSplits) + .returns(); + + return { + deployer, + projectOwner, + caller, + addrs, + jbController, + mockJbDirectory, + mockJbTokenStore, + mockJbController, + mockJbOperatorStore, + mockJbFundAccessConstraintsStore, + mockJbFundingCycleStore, + mockJbTerminal1, + mockJbTerminal2, + mockJbSplitsStore, + timestamp, + fundingCycleData, + fundingCycleMetadata, + splits, + }; + } + + function makeFundingCycleMetadata({ + reservedRate = 0, + redemptionRate = 10000, + ballotRedemptionRate = 10000, + pausePay = false, + pauseDistributions = false, + pauseRedeem = false, + pauseBurn = false, + pauseTransfers = false, + allowMinting = false, + allowChangeToken = false, + allowTerminalMigration = false, + allowControllerMigration = false, + allowSetTerminals = false, + allowSetControllers = false, + holdFees = false, + preferClaimedTokenOverride = false, + useTotalOverflowForRedemptions = false, + useDataSourceForPay = false, + useDataSourceForRedeem = false, + dataSource = ethers.constants.AddressZero, + metadata = 0, + } = {}) { + const unpackedMetadata = { + global: { + allowSetTerminals, + allowSetControllers, + pauseTransfers, + }, + reservedRate, + redemptionRate, + ballotRedemptionRate, + pausePay, + pauseDistributions, + pauseRedeem, + pauseBurn, + allowMinting, + allowChangeToken, + allowTerminalMigration, + allowControllerMigration, + holdFees, + preferClaimedTokenOverride, + useTotalOverflowForRedemptions, + useDataSourceForPay, + useDataSourceForRedeem, + dataSource, + metadata, + }; + return { unpacked: unpackedMetadata, packed: packFundingCycleMetadata(unpackedMetadata) }; + } + function makeFundingCycleDataStruct({ + duration = 0, + weight = ethers.BigNumber.from('1' + '0'.repeat(18)), + discountRate = 900000000, + ballot = ethers.constants.AddressZero, + } = {}) { + return { duration, weight, discountRate, ballot }; + } + + function makeFundingAccessConstraints({ + terminals, + token = ethers.Wallet.createRandom().address, + distributionLimit = 200, + distributionLimitCurrency = 1, + overflowAllowance = 100, + overflowAllowanceCurrency = 2, + } = {}) { + let constraints = []; + for (let terminal of terminals) { + constraints.push({ + terminal, + token, + distributionLimit, + distributionLimitCurrency, + overflowAllowance, + overflowAllowanceCurrency, + }); + } + return constraints; + } + + it(`Should reconfigure funding cycle and emit events if caller is project owner`, async function () { + const { + jbController, + projectOwner, + timestamp, + fundingCycleData, + fundingCycleMetadata, + splits, + mockJbTerminal1, + mockJbTerminal2, + mockJbFundAccessConstraintsStore + } = await setup(); + + const groupedSplits = [{ group: 1, splits }]; + const terminals = [mockJbTerminal1.address, mockJbTerminal2.address]; + const fundAccessConstraints = makeFundingAccessConstraints({ terminals }); + + await mockJbFundAccessConstraintsStore.mock.setFor + .withArgs(PROJECT_ID, timestamp, fundAccessConstraints) + .returns(); + + expect( + await jbController + .connect(projectOwner) + .callStatic.reconfigureFundingCyclesOf( + PROJECT_ID, + fundingCycleData, + fundingCycleMetadata.unpacked, + PROJECT_START, + groupedSplits, + fundAccessConstraints, + MEMO, + ), + ).to.equal(timestamp); + + let tx = jbController + .connect(projectOwner) + .reconfigureFundingCyclesOf( + PROJECT_ID, + fundingCycleData, + fundingCycleMetadata.unpacked, + PROJECT_START, + groupedSplits, + fundAccessConstraints, + MEMO, + ); + + await expect(tx) + .to.emit(jbController, 'ReconfigureFundingCycles') + .withArgs( + /*fundingCycleData.configuration=*/ timestamp, + PROJECT_ID, + MEMO, + projectOwner.address, + ); + }); + + it(`Should reconfigure funding cycle with metadata using truthy bools`, async function () { + const { + jbController, + projectOwner, + timestamp, + fundingCycleData, + splits, + mockJbTerminal1, + mockJbTerminal2, + mockJbFundingCycleStore, + mockJbFundAccessConstraintsStore + } = await setup(); + + const groupedSplits = [{ group: 1, splits }]; + const terminals = [mockJbTerminal1.address, mockJbTerminal2.address]; + const fundAccessConstraints = makeFundingAccessConstraints({ terminals }); + + await mockJbFundAccessConstraintsStore.mock.setFor + .withArgs(PROJECT_ID, timestamp, fundAccessConstraints) + .returns(); + + const truthyMetadata = makeFundingCycleMetadata({ + pausePay: true, + pauseDistributions: true, + pauseRedeem: true, + pauseBurn: true, + allowMinting: true, + allowChangeToken: true, + allowTerminalMigration: true, + allowControllerMigration: true, + holdFees: true, + useTotalOverflowForRedemptions: true, + useDataSourceForPay: true, + useDataSourceForRedeem: true, + }); + await mockJbFundingCycleStore.mock.configureFor + .withArgs(PROJECT_ID, fundingCycleData, truthyMetadata.packed, PROJECT_START) + .returns( + Object.assign( + { + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + metadata: truthyMetadata.packed, + }, + fundingCycleData, + ), + ); + expect( + await jbController + .connect(projectOwner) + .callStatic.reconfigureFundingCyclesOf( + PROJECT_ID, + fundingCycleData, + truthyMetadata.unpacked, + PROJECT_START, + groupedSplits, + fundAccessConstraints, + MEMO, + ), + ).to.equal(timestamp); + }); + + it(`Should reconfigure funding cycle and emit events if caller is not project owner but is authorized`, async function () { + const { + jbController, + projectOwner, + addrs, + timestamp, + fundingCycleData, + fundingCycleMetadata, + splits, + mockJbOperatorStore, + mockJbTerminal1, + mockJbTerminal2, + mockJbFundAccessConstraintsStore + } = await setup(); + const caller = addrs[0]; + + await mockJbOperatorStore.mock.hasPermission + .withArgs(caller.address, projectOwner.address, PROJECT_ID, RECONFIGURE_INDEX) + .returns(true); + + const groupedSplits = [{ group: 1, splits }]; + const terminals = [mockJbTerminal1.address, mockJbTerminal2.address]; + const fundAccessConstraints = makeFundingAccessConstraints({ terminals }); + + await mockJbFundAccessConstraintsStore.mock.setFor + .withArgs(PROJECT_ID, timestamp, fundAccessConstraints) + .returns(); + + expect( + await jbController + .connect(caller) + .callStatic.reconfigureFundingCyclesOf( + PROJECT_ID, + fundingCycleData, + fundingCycleMetadata.unpacked, + PROJECT_START, + groupedSplits, + fundAccessConstraints, + MEMO, + ), + ).to.equal(timestamp); + + let tx = jbController + .connect(caller) + .reconfigureFundingCyclesOf( + PROJECT_ID, + fundingCycleData, + fundingCycleMetadata.unpacked, + PROJECT_START, + groupedSplits, + fundAccessConstraints, + MEMO, + ); + }); + + it(`Can't reconfigure funding cycle if caller is not authorized`, async function () { + const { + jbController, + projectOwner, + addrs, + fundingCycleData, + fundingCycleMetadata, + splits, + mockJbOperatorStore, + mockJbTerminal1, + mockJbTerminal2, + } = await setup(); + + const caller = addrs[0]; + await mockJbOperatorStore.mock.hasPermission + .withArgs(caller.address, projectOwner.address, PROJECT_ID, RECONFIGURE_INDEX) + .returns(false); + + await mockJbOperatorStore.mock.hasPermission + .withArgs(caller.address, projectOwner.address, 0, RECONFIGURE_INDEX) + .returns(false); + + const groupedSplits = [{ group: 1, splits }]; + const terminals = [mockJbTerminal1.address, mockJbTerminal2.address]; + const fundAccessConstraints = makeFundingAccessConstraints({ terminals }); + + let tx = jbController + .connect(caller) + .reconfigureFundingCyclesOf( + PROJECT_ID, + fundingCycleData, + fundingCycleMetadata.unpacked, + PROJECT_START, + groupedSplits, + fundAccessConstraints, + MEMO, + ); + + await expect(tx).to.be.revertedWith(errors.UNAUTHORIZED); + }); + + it(`Should reconfigure funding cycle without grouped splits`, async function () { + const { + jbController, + projectOwner, + timestamp, + fundingCycleData, + fundingCycleMetadata, + mockJbTerminal1, + mockJbTerminal2, + mockJbSplitsStore, + mockJbFundAccessConstraintsStore + } = await setup(); + + const terminals = [mockJbTerminal1.address, mockJbTerminal2.address]; + const fundAccessConstraints = makeFundingAccessConstraints({ terminals }); + + await mockJbFundAccessConstraintsStore.mock.setFor + .withArgs(PROJECT_ID, timestamp, fundAccessConstraints) + .returns(); + + const groupedSplits = []; + + await mockJbSplitsStore.mock.set + .withArgs(PROJECT_ID, /*configuration=*/ timestamp, groupedSplits) + .returns(); + + expect( + await jbController + .connect(projectOwner) + .callStatic.reconfigureFundingCyclesOf( + PROJECT_ID, + fundingCycleData, + fundingCycleMetadata.unpacked, + PROJECT_START, + groupedSplits, + fundAccessConstraints, + MEMO, + ), + ).to.equal(timestamp); + + let tx = jbController + .connect(projectOwner) + .reconfigureFundingCyclesOf( + PROJECT_ID, + fundingCycleData, + fundingCycleMetadata.unpacked, + PROJECT_START, + [], + fundAccessConstraints, + MEMO, + ); + }); + + it(`Should reconfigure funding cycle with empty grouped split and without defined funding cycle constraints`, async function () { + const { + jbController, + projectOwner, + timestamp, + fundingCycleData, + fundingCycleMetadata, + mockJbTerminal1, + mockJbTerminal2, + mockJbSplitsStore, + mockJbFundAccessConstraintsStore + } = await setup(); + + const groupedSplits = [{ group: 1, splits: [] }]; + const terminals = [mockJbTerminal1.address, mockJbTerminal2.address]; + const fundAccessConstraints = makeFundingAccessConstraints({ + terminals, + distributionLimit: 0, + overflowAllowance: 0, + currency: 0, + }); + + await mockJbFundAccessConstraintsStore.mock.setFor + .withArgs(PROJECT_ID, timestamp, fundAccessConstraints) + .returns(); + + await mockJbSplitsStore.mock.set + .withArgs(PROJECT_ID, /*configuration=*/ timestamp, groupedSplits) + .returns(); + + expect( + await jbController + .connect(projectOwner) + .callStatic.reconfigureFundingCyclesOf( + PROJECT_ID, + fundingCycleData, + fundingCycleMetadata.unpacked, + PROJECT_START, + groupedSplits, + fundAccessConstraints, + MEMO, + ), + ).to.equal(timestamp); + + let tx = jbController + .connect(projectOwner) + .reconfigureFundingCyclesOf( + PROJECT_ID, + fundingCycleData, + fundingCycleMetadata.unpacked, + PROJECT_START, + groupedSplits, + fundAccessConstraints, + MEMO, + ); + }); + + it(`Can't set a reserved rate superior to 10000`, async function () { + const { + jbController, + projectOwner, + fundingCycleData, + splits, + mockJbTerminal1, + mockJbTerminal2, + } = await setup(); + const groupedSplits = [{ group: 1, splits }]; + const terminals = [mockJbTerminal1.address, mockJbTerminal2.address]; + const fundAccessConstraints = makeFundingAccessConstraints({ terminals }); + const fundingCycleMetadata = makeFundingCycleMetadata({ reservedRate: 10001 }); + + let tx = jbController + .connect(projectOwner) + .reconfigureFundingCyclesOf( + PROJECT_ID, + fundingCycleData, + fundingCycleMetadata.unpacked, + PROJECT_START, + groupedSplits, + fundAccessConstraints, + MEMO, + ); + + await expect(tx).to.be.revertedWith('INVALID_RESERVED_RATE()'); + }); + + it(`Can't set a redemption rate superior to 10000`, async function () { + const { + jbController, + projectOwner, + fundingCycleData, + fundingCycleMetadata, + splits, + mockJbTerminal1, + mockJbTerminal2, + } = await setup(); + const groupedSplits = [{ group: 1, splits }]; + const terminals = [mockJbTerminal1.address, mockJbTerminal2.address]; + const fundAccessConstraints = makeFundingAccessConstraints({ terminals }); + fundingCycleMetadata.unpacked.redemptionRate = 10001; //not possible in packed metadata (shl of a negative value) + + let tx = jbController + .connect(projectOwner) + .reconfigureFundingCyclesOf( + PROJECT_ID, + fundingCycleData, + fundingCycleMetadata.unpacked, + PROJECT_START, + groupedSplits, + fundAccessConstraints, + MEMO, + ); + + await expect(tx).to.be.revertedWith(errors.INVALID_REDEMPTION_RATE); + }); + + it(`Can't set a ballot redemption rate superior to 10000`, async function () { + const { + jbController, + projectOwner, + fundingCycleData, + fundingCycleMetadata, + splits, + mockJbTerminal1, + mockJbTerminal2, + } = await setup(); + const groupedSplits = [{ group: 1, splits }]; + const terminals = [mockJbTerminal1.address, mockJbTerminal2.address]; + const fundAccessConstraints = makeFundingAccessConstraints({ terminals }); + + fundingCycleMetadata.unpacked.ballotRedemptionRate = 10001; //not possible in packed metadata (shl of a negative value) + + let tx = jbController + .connect(projectOwner) + .reconfigureFundingCyclesOf( + PROJECT_ID, + fundingCycleData, + fundingCycleMetadata.unpacked, + PROJECT_START, + groupedSplits, + fundAccessConstraints, + MEMO, + ); + + await expect(tx).to.be.revertedWith(errors.INVALID_BALLOT_REDEMPTION_RATE); + }); +}); diff --git a/test/jb_controller_3_1/total_oustanding_tokens_of.test.js b/test/jb_controller_3_1/total_oustanding_tokens_of.test.js new file mode 100644 index 000000000..cc99d4e34 --- /dev/null +++ b/test/jb_controller_3_1/total_oustanding_tokens_of.test.js @@ -0,0 +1,204 @@ +import { expect } from 'chai'; +import { ethers } from 'hardhat'; +import { deployMockContract } from '@ethereum-waffle/mock-contract'; +import { packFundingCycleMetadata, makeSplits } from '../helpers/utils'; + +import jbDirectory from '../../artifacts/contracts/JBDirectory.sol/JBDirectory.json'; +import jbFundingCycleStore from '../../artifacts/contracts/JBFundingCycleStore.sol/JBFundingCycleStore.json'; +import jbOperatoreStore from '../../artifacts/contracts/JBOperatorStore.sol/JBOperatorStore.json'; +import jbProjects from '../../artifacts/contracts/JBProjects.sol/JBProjects.json'; +import jbFundAccessConstraintsStore from '../../artifacts/contracts/JBFundAccessConstraintsStore.sol/JBFundAccessConstraintsStore.json'; +import jbSplitsStore from '../../artifacts/contracts/JBSplitsStore.sol/JBSplitsStore.json'; +import jbToken from '../../artifacts/contracts/JBToken.sol/JBToken.json'; +import jbTokenStore from '../../artifacts/contracts/JBTokenStore.sol/JBTokenStore.json'; + +describe('JBController3_1::totalOutstandingTokensOf(...)', function () { + const PROJECT_ID = 1; + const MEMO = 'Test Memo'; + const RESERVED_AMOUNT = 20000; + const ALREADY_MINTED_TOKEN = 1000; + const PREFERED_CLAIMED_TOKEN = true; + const RESERVED_RATE = 10000; + + let MINT_INDEX; + let RESERVED_SPLITS_GROUP; + + before(async function () { + let jbOperationsFactory = await ethers.getContractFactory('JBOperations'); + let jbOperations = await jbOperationsFactory.deploy(); + MINT_INDEX = await jbOperations.MINT(); + + let jbSplitsGroupsFactory = await ethers.getContractFactory('JBSplitsGroups'); + let jbSplitsGroups = await jbSplitsGroupsFactory.deploy(); + RESERVED_SPLITS_GROUP = await jbSplitsGroups.RESERVED_TOKENS(); + }); + + async function setup() { + let [deployer, projectOwner, ...addrs] = await ethers.getSigners(); + + const blockNum = await ethers.provider.getBlockNumber(); + const block = await ethers.provider.getBlock(blockNum); + const timestamp = block.timestamp; + + let [ + mockJbDirectory, + mockJbFundingCycleStore, + mockJbOperatorStore, + mockJbProjects, + mockSplitsStore, + mockJbToken, + mockJbTokenStore, + mockJbFundAccessConstraintsStore, + ] = await Promise.all([ + deployMockContract(deployer, jbDirectory.abi), + deployMockContract(deployer, jbFundingCycleStore.abi), + deployMockContract(deployer, jbOperatoreStore.abi), + deployMockContract(deployer, jbProjects.abi), + deployMockContract(deployer, jbSplitsStore.abi), + deployMockContract(deployer, jbToken.abi), + deployMockContract(deployer, jbTokenStore.abi), + deployMockContract(deployer, jbFundAccessConstraintsStore.abi), + ]); + + let jbControllerFactory = await ethers.getContractFactory( + 'contracts/JBController3_1.sol:JBController3_1', + ); + let jbController = await jbControllerFactory.deploy( + mockJbOperatorStore.address, + mockJbProjects.address, + mockJbDirectory.address, + mockJbFundingCycleStore.address, + mockJbTokenStore.address, + mockSplitsStore.address, + mockJbFundAccessConstraintsStore.address + ); + + await mockJbProjects.mock.ownerOf.withArgs(PROJECT_ID).returns(projectOwner.address); + await mockJbDirectory.mock.isTerminalOf + .withArgs(PROJECT_ID, projectOwner.address) + .returns(false); + await mockJbTokenStore.mock.totalSupplyOf.withArgs(PROJECT_ID).returns(ALREADY_MINTED_TOKEN); + + return { + projectOwner, + addrs, + jbController, + mockJbOperatorStore, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbTokenStore, + mockJbToken, + mockSplitsStore, + mockJbProjects, + timestamp, + }; + } + + it(`Should return the total amount of outstanding token, when the reserve rate is maximum`, async function () { + const { jbController, timestamp, projectOwner, mockJbFundingCycleStore, mockJbTokenStore } = + await setup(); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: 0, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ reservedRate: RESERVED_RATE, allowMinting: true }), + }), + await mockJbTokenStore.mock.mintFor + .withArgs(ethers.constants.AddressZero, PROJECT_ID, RESERVED_AMOUNT, true) + .returns(); + + await jbController + .connect(projectOwner) + .mintTokensOf( + PROJECT_ID, + RESERVED_AMOUNT, + ethers.constants.AddressZero, + MEMO, + PREFERED_CLAIMED_TOKEN, + /*useReservedRate*/ true, + ); + + expect(await jbController.totalOutstandingTokensOf(PROJECT_ID)).to.equal( + RESERVED_AMOUNT + ALREADY_MINTED_TOKEN, + ); + }); + + it(`Should return the total amount of outstanding token, when the reserve rate is less than the maximum`, async function () { + const { jbController, projectOwner, timestamp, mockJbFundingCycleStore, mockJbTokenStore } = + await setup(); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: 0, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ reservedRate: 5000, allowMinting: true }), + }); + + // 50% reserved rate + await mockJbTokenStore.mock.mintFor + .withArgs(ethers.constants.AddressZero, PROJECT_ID, RESERVED_AMOUNT / 2, true) + .returns(); + + await jbController + .connect(projectOwner) + .mintTokensOf( + PROJECT_ID, + RESERVED_AMOUNT, + ethers.constants.AddressZero, + MEMO, + PREFERED_CLAIMED_TOKEN, + /*useReservedRate*/ true, + ); + + expect(await jbController.totalOutstandingTokensOf(PROJECT_ID)).to.equal( + ALREADY_MINTED_TOKEN + (RESERVED_AMOUNT / 2), + ); + }); + + it(`Should return the total amount of outstanding token equals to the total supply, when the reserve rate is 0`, async function () { + const { jbController, projectOwner, timestamp, mockJbFundingCycleStore, mockJbTokenStore } = + await setup(); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: 0, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ reservedRate: 0, allowMinting: 1 }), + }); + + await mockJbTokenStore.mock.mintFor + .withArgs(ethers.constants.AddressZero, PROJECT_ID, ALREADY_MINTED_TOKEN, true) + .returns(); + + await jbController + .connect(projectOwner) + .mintTokensOf( + PROJECT_ID, + ALREADY_MINTED_TOKEN, + ethers.constants.AddressZero, + MEMO, + PREFERED_CLAIMED_TOKEN, + /*useReservedRate*/ true, + ); + + expect(await jbController.totalOutstandingTokensOf(PROJECT_ID)).to.equal( + ALREADY_MINTED_TOKEN, + ); + }); +}); diff --git a/test/jb_payment_terminal_3_1/add_to_balance_of.test.js b/test/jb_payment_terminal_3_1/add_to_balance_of.test.js index 4cdac442f..ab74bfdcb 100644 --- a/test/jb_payment_terminal_3_1/add_to_balance_of.test.js +++ b/test/jb_payment_terminal_3_1/add_to_balance_of.test.js @@ -7,8 +7,8 @@ import { smock } from '@defi-wonderland/smock'; import errors from '../helpers/errors.json'; import jbDirectory from '../../artifacts/contracts/JBDirectory.sol/JBDirectory.json'; -import JBEthPaymentTerminal from '../../artifacts/contracts/JBETHPaymentTerminal.sol/JBETHPaymentTerminal.json'; -import jbPaymentTerminalStore from '../../artifacts/contracts/JBSingleTokenPaymentTerminalStore.sol/JBSingleTokenPaymentTerminalStore.json'; +import JBEthPaymentTerminal from '../../artifacts/contracts/JBETHPaymentTerminal3_1.sol/JBETHPaymentTerminal3_1.json'; +import jbPaymentTerminalStore from '../../artifacts/contracts/JBSingleTokenPaymentTerminalStore3_1.sol/JBSingleTokenPaymentTerminalStore3_1.json'; import jbOperatoreStore from '../../artifacts/contracts/JBOperatorStore.sol/JBOperatorStore.json'; import jbProjects from '../../artifacts/contracts/JBProjects.sol/JBProjects.json'; import jbSplitsStore from '../../artifacts/contracts/JBSplitsStore.sol/JBSplitsStore.json'; @@ -243,15 +243,15 @@ describe('JBPayoutRedemptionPaymentTerminal3_1::addToBalanceOf(...)', function ( expect( await jbEthPaymentTerminal .connect(caller) - ['addToBalanceOf(uint256,uint256,address,bool,string,bytes)']( - PROJECT_ID, - AMOUNT, - ETH_ADDRESS, - true, - MEMO, - METADATA, - { value: AMOUNT }, - ), + ['addToBalanceOf(uint256,uint256,address,bool,string,bytes)']( + PROJECT_ID, + AMOUNT, + ETH_ADDRESS, + true, + MEMO, + METADATA, + { value: AMOUNT }, + ), ) .to.emit(jbEthPaymentTerminal, 'AddToBalance') .withArgs(PROJECT_ID, AMOUNT, feeNetAmount, MEMO, METADATA, caller.address) @@ -313,15 +313,15 @@ describe('JBPayoutRedemptionPaymentTerminal3_1::addToBalanceOf(...)', function ( expect( await jbEthPaymentTerminal .connect(caller) - ['addToBalanceOf(uint256,uint256,address,bool,string,bytes)']( - PROJECT_ID, - AMOUNT, - ETH_ADDRESS, - false, - MEMO, - METADATA, - { value: AMOUNT }, - ), + ['addToBalanceOf(uint256,uint256,address,bool,string,bytes)']( + PROJECT_ID, + AMOUNT, + ETH_ADDRESS, + false, + MEMO, + METADATA, + { value: AMOUNT }, + ), ) .to.emit(jbEthPaymentTerminal, 'AddToBalance') .withArgs(PROJECT_ID, AMOUNT, 0 /*refunded fee*/, MEMO, METADATA, caller.address) @@ -341,14 +341,14 @@ describe('JBPayoutRedemptionPaymentTerminal3_1::addToBalanceOf(...)', function ( await jbEthPaymentTerminal .connect(caller) - ['addToBalanceOf(uint256,uint256,address,string,bytes)']( - PROJECT_ID, - AMOUNT + 1, - ETH_ADDRESS, - MEMO, - METADATA, - { value: AMOUNT }, - ); + ['addToBalanceOf(uint256,uint256,address,string,bytes)']( + PROJECT_ID, + AMOUNT + 1, + ETH_ADDRESS, + MEMO, + METADATA, + { value: AMOUNT }, + ); }); it('Should work with non-eth terminal if no value is sent', async function () { @@ -448,15 +448,15 @@ describe('JBPayoutRedemptionPaymentTerminal3_1::addToBalanceOf(...)', function ( await expect( await jbEthPaymentTerminal .connect(caller) - ['addToBalanceOf(uint256,uint256,address,bool,string,bytes)']( - PROJECT_ID, - 1, - ETH_ADDRESS, - true, - MEMO, - METADATA, - { value: 1 }, - ), + ['addToBalanceOf(uint256,uint256,address,bool,string,bytes)']( + PROJECT_ID, + 1, + ETH_ADDRESS, + true, + MEMO, + METADATA, + { value: 1 }, + ), ) .to.emit(jbEthPaymentTerminal, 'AddToBalance') .withArgs(PROJECT_ID, 1, 1, MEMO, METADATA, caller.address) @@ -548,17 +548,17 @@ describe('JBPayoutRedemptionPaymentTerminal3_1::addToBalanceOf(...)', function ( expect( await jbEthPaymentTerminal .connect(caller) - ['addToBalanceOf(uint256,uint256,address,bool,string,bytes)']( - PROJECT_ID, - AMOUNT.sub('10'), - ETH_ADDRESS, - true, - MEMO, - METADATA, - { - value: AMOUNT.sub('10'), - }, - ), + ['addToBalanceOf(uint256,uint256,address,bool,string,bytes)']( + PROJECT_ID, + AMOUNT.sub('10'), + ETH_ADDRESS, + true, + MEMO, + METADATA, + { + value: AMOUNT.sub('10'), + }, + ), ) .to.emit(jbEthPaymentTerminal, 'AddToBalance') .withArgs( @@ -670,17 +670,17 @@ describe('JBPayoutRedemptionPaymentTerminal3_1::addToBalanceOf(...)', function ( expect( await jbEthPaymentTerminal .connect(caller) - ['addToBalanceOf(uint256,uint256,address,bool,string,bytes)']( - PROJECT_ID, - amountToAdd, - ETH_ADDRESS, - true, - MEMO, - METADATA, - { - value: amountToAdd, - }, - ), + ['addToBalanceOf(uint256,uint256,address,bool,string,bytes)']( + PROJECT_ID, + amountToAdd, + ETH_ADDRESS, + true, + MEMO, + METADATA, + { + value: amountToAdd, + }, + ), ) .to.emit(jbEthPaymentTerminal, 'AddToBalance') .withArgs(PROJECT_ID, amountToAdd, feeNetAmount, MEMO, METADATA, caller.address) @@ -752,17 +752,17 @@ describe('JBPayoutRedemptionPaymentTerminal3_1::addToBalanceOf(...)', function ( expect( await jbEthPaymentTerminal .connect(caller) - ['addToBalanceOf(uint256,uint256,address,bool,string,bytes)']( - PROJECT_ID, - AMOUNT.mul(2), - ETH_ADDRESS, - true, - MEMO, - METADATA, - { - value: AMOUNT.mul(2), - }, - ), + ['addToBalanceOf(uint256,uint256,address,bool,string,bytes)']( + PROJECT_ID, + AMOUNT.mul(2), + ETH_ADDRESS, + true, + MEMO, + METADATA, + { + value: AMOUNT.mul(2), + }, + ), ) .to.emit(jbEthPaymentTerminal, 'AddToBalance') .withArgs(PROJECT_ID, AMOUNT.mul(2), netHeldFee, MEMO, METADATA, caller.address) @@ -803,14 +803,14 @@ describe('JBPayoutRedemptionPaymentTerminal3_1::addToBalanceOf(...)', function ( await expect( jbEthPaymentTerminal .connect(caller) - ['addToBalanceOf(uint256,uint256,address,string,bytes)']( - otherProjectId, - AMOUNT, - ETH_ADDRESS, - MEMO, - METADATA, - { value: 0 }, - ), + ['addToBalanceOf(uint256,uint256,address,string,bytes)']( + otherProjectId, + AMOUNT, + ETH_ADDRESS, + MEMO, + METADATA, + { value: 0 }, + ), ).to.be.revertedWith(errors.PROJECT_TERMINAL_MISMATCH); }); }); diff --git a/test/jb_payment_terminal_3_1/current_eth_overflow_of.test.js b/test/jb_payment_terminal_3_1/current_eth_overflow_of.test.js index 66fa8a20f..388093463 100644 --- a/test/jb_payment_terminal_3_1/current_eth_overflow_of.test.js +++ b/test/jb_payment_terminal_3_1/current_eth_overflow_of.test.js @@ -3,7 +3,7 @@ import { ethers } from 'hardhat'; import { deployMockContract } from '@ethereum-waffle/mock-contract'; import jbDirectory from '../../artifacts/contracts/JBDirectory.sol/JBDirectory.json'; -import jbPaymentTerminalStore from '../../artifacts/contracts/JBSingleTokenPaymentTerminalStore.sol/JBSingleTokenPaymentTerminalStore.json'; +import jbPaymentTerminalStore from '../../artifacts/contracts/JBSingleTokenPaymentTerminalStore3_1.sol/JBSingleTokenPaymentTerminalStore3_1.json'; import jbOperatoreStore from '../../artifacts/contracts/JBOperatorStore.sol/JBOperatorStore.json'; import jbPrices from '../../artifacts/contracts/interfaces/IJBPrices.sol/IJBPrices.json'; import jbProjects from '../../artifacts/contracts/JBProjects.sol/JBProjects.json'; diff --git a/test/jb_payment_terminal_3_1/distribute_payouts_of.test.js b/test/jb_payment_terminal_3_1/distribute_payouts_of.test.js index c57ea0c50..d508b3040 100644 --- a/test/jb_payment_terminal_3_1/distribute_payouts_of.test.js +++ b/test/jb_payment_terminal_3_1/distribute_payouts_of.test.js @@ -156,8 +156,8 @@ describe('JBPayoutRedemptionPaymentTerminal3_1::distributePayoutsOf(...)', funct // JBDAO await mockJbDirectory.mock.isTerminalOf - .withArgs(1, jbEthPaymentTerminal.address) - .returns(true); + .withArgs(1, jbEthPaymentTerminal.address) + .returns(true); await mockJbDirectory.mock.isTerminalOf .withArgs(OTHER_PROJECT_ID, jbEthPaymentTerminal.address) @@ -182,11 +182,11 @@ describe('JBPayoutRedemptionPaymentTerminal3_1::distributePayoutsOf(...)', funct // Mock the JBAllocator supports interface check await mockJbAllocator.mock.supportsInterface.withArgs("0x01ffc9a7") - .returns(true); + .returns(true); await mockJbAllocator.mock.supportsInterface.withArgs("0x9d740bfa") - .returns(true); + .returns(true); await mockJbAllocator.mock.supportsInterface.withArgs("0xffffffff") - .returns(false); + .returns(false); await setBalance(jbEthPaymentTerminal.address, AMOUNT_DISTRIBUTED); @@ -324,8 +324,8 @@ describe('JBPayoutRedemptionPaymentTerminal3_1::distributePayoutsOf(...)', funct [ /*token*/ '0x000000000000000000000000000000000000eeee', /*amount paid*/ Math.floor( - (AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT, - ), + (AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT, + ), /*decimal*/ 18, CURRENCY, ], @@ -335,7 +335,7 @@ describe('JBPayoutRedemptionPaymentTerminal3_1::distributePayoutsOf(...)', funct '', ethers.utils.hexZeroPad(ethers.utils.hexlify(PROJECT_ID), 32), ) - .returns(fundingCycle, /*count*/ 0, /* delegateAllocation */ [], ''); + .returns(fundingCycle, /*count*/ 0, /* delegateAllocation */[], ''); }), ); @@ -443,8 +443,8 @@ describe('JBPayoutRedemptionPaymentTerminal3_1::distributePayoutsOf(...)', funct [ /*token*/ '0x000000000000000000000000000000000000eeee', /*amount paid*/ Math.floor( - (AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT, - ), + (AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT, + ), /*decimal*/ 18, CURRENCY, ], @@ -454,7 +454,7 @@ describe('JBPayoutRedemptionPaymentTerminal3_1::distributePayoutsOf(...)', funct '', ethers.utils.hexZeroPad(ethers.utils.hexlify(PROJECT_ID), 32), ) - .returns(fundingCycle, 0, /* delegateAllocation */ [], ''); + .returns(fundingCycle, 0, /* delegateAllocation */[], ''); }), ); @@ -489,6 +489,9 @@ describe('JBPayoutRedemptionPaymentTerminal3_1::distributePayoutsOf(...)', funct /*payoutAmount*/ Math.floor( (AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT, ), + /*netAmount*/ Math.floor( + (AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT, + ), caller.address, ) .and.to.emit(jbEthPaymentTerminal, 'Pay'); @@ -1253,7 +1256,7 @@ describe('JBPayoutRedemptionPaymentTerminal3_1::distributePayoutsOf(...)', funct '', ethers.utils.hexZeroPad(ethers.utils.hexlify(PROJECT_ID), 32), ) - .returns(fundingCycle, 0, /* delegateAllocation */ [], ''); + .returns(fundingCycle, 0, /* delegateAllocation */[], ''); await Promise.all( splits.map(async (split) => { @@ -1263,8 +1266,8 @@ describe('JBPayoutRedemptionPaymentTerminal3_1::distributePayoutsOf(...)', funct [ /*token*/ '0x000000000000000000000000000000000000eeee', /*amount paid*/ Math.floor( - (AMOUNT_MINUS_FEES * split.percent) / SPLITS_TOTAL_PERCENT, - ), + (AMOUNT_MINUS_FEES * split.percent) / SPLITS_TOTAL_PERCENT, + ), /*decimal*/ 18, CURRENCY, ], @@ -1274,7 +1277,7 @@ describe('JBPayoutRedemptionPaymentTerminal3_1::distributePayoutsOf(...)', funct '', '0x', ) - .returns(fundingCycle, 0, /* delegateAllocation */ [], ''); + .returns(fundingCycle, 0, /* delegateAllocation */[], ''); }), ); @@ -1306,7 +1309,8 @@ describe('JBPayoutRedemptionPaymentTerminal3_1::distributePayoutsOf(...)', funct split.lockedUntil, split.allocator, ], - /*payoutAmount*/ Math.floor((AMOUNT_MINUS_FEES * split.percent) / SPLITS_TOTAL_PERCENT), + /*payoutAmount*/ Math.floor((AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT), + /*netAmount*/ Math.floor((AMOUNT_MINUS_FEES * split.percent) / SPLITS_TOTAL_PERCENT), caller.address, ) .and.to.emit(jbEthPaymentTerminal, 'Pay') @@ -2587,8 +2591,8 @@ describe('JBPayoutRedemptionPaymentTerminal3_1::distributePayoutsOf(...)', funct [ /*token*/ '0x000000000000000000000000000000000000eeee', /*amount paid*/ Math.floor( - (AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT, - ), + (AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT, + ), /*decimal*/ 18, CURRENCY, ], @@ -2598,7 +2602,7 @@ describe('JBPayoutRedemptionPaymentTerminal3_1::distributePayoutsOf(...)', funct '', ethers.utils.hexZeroPad(ethers.utils.hexlify(PROJECT_ID), 32), ) - .returns(fundingCycle, 0, /* delegateAllocation */ [], ''); + .returns(fundingCycle, 0, /* delegateAllocation */[], ''); }), ); @@ -2739,6 +2743,9 @@ describe('JBPayoutRedemptionPaymentTerminal3_1::distributePayoutsOf(...)', funct /*payoutAmount*/ Math.floor( (AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT, ), + /*netAmount*/ Math.floor( + (AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT, + ), caller.address, ) .and.to.emit(jbEthPaymentTerminal, 'AddToBalance') @@ -2843,7 +2850,7 @@ describe('JBPayoutRedemptionPaymentTerminal3_1::distributePayoutsOf(...)', funct /*_distributedAmount*/ AMOUNT_DISTRIBUTED, /*_feeAmount*/ 0, /*_leftoverDistributionAmount*/ AMOUNT_DISTRIBUTED - - ((AMOUNT_DISTRIBUTED * PERCENT) / SPLITS_TOTAL_PERCENT) * splits.length, + ((AMOUNT_DISTRIBUTED * PERCENT) / SPLITS_TOTAL_PERCENT) * splits.length, METADATA, caller.address, ); @@ -2903,7 +2910,7 @@ describe('JBPayoutRedemptionPaymentTerminal3_1::distributePayoutsOf(...)', funct // '', // ethers.utils.hexZeroPad(ethers.utils.hexlify(PROJECT_ID), 32), // ) - .returns(fundingCycle, /*count*/ 0, /* delegateAllocation */ [], ''); + .returns(fundingCycle, /*count*/ 0, /* delegateAllocation */[], ''); }), ); @@ -2923,7 +2930,7 @@ describe('JBPayoutRedemptionPaymentTerminal3_1::distributePayoutsOf(...)', funct '', ethers.utils.hexZeroPad(ethers.utils.hexlify(PROJECT_ID), 32), ) - .returns(fundingCycle, /*count*/ 0, /* delegateAllocation */ [], ''); + .returns(fundingCycle, /*count*/ 0, /* delegateAllocation */[], ''); let tx = await jbEthPaymentTerminal .connect(caller) diff --git a/test/jb_payment_terminal_3_1/migrate.test.js b/test/jb_payment_terminal_3_1/migrate.test.js index ddacfb038..3f2ba9170 100644 --- a/test/jb_payment_terminal_3_1/migrate.test.js +++ b/test/jb_payment_terminal_3_1/migrate.test.js @@ -5,9 +5,9 @@ import { setBalance } from '../helpers/utils'; import errors from '../helpers/errors.json'; import jbDirectory from '../../artifacts/contracts/JBDirectory.sol/JBDirectory.json'; -import JBEthPaymentTerminal from '../../artifacts/contracts/JBETHPaymentTerminal.sol/JBETHPaymentTerminal.json'; -import jbErc20PaymentTerminal from '../../artifacts/contracts/JBERC20PaymentTerminal.sol/JBERC20PaymentTerminal.json'; -import jbPaymentTerminalStore from '../../artifacts/contracts/JBSingleTokenPaymentTerminalStore.sol/JBSingleTokenPaymentTerminalStore.json'; +import JBEthPaymentTerminal from '../../artifacts/contracts/JBETHPaymentTerminal3_1.sol/JBETHPaymentTerminal3_1.json'; +import jbErc20PaymentTerminal from '../../artifacts/contracts/JBERC20PaymentTerminal3_1.sol/JBERC20PaymentTerminal3_1.json'; +import jbPaymentTerminalStore from '../../artifacts/contracts/JBSingleTokenPaymentTerminalStore3_1.sol/JBSingleTokenPaymentTerminalStore3_1.json'; import jbOperatoreStore from '../../artifacts/contracts/JBOperatorStore.sol/JBOperatorStore.json'; import jbProjects from '../../artifacts/contracts/JBProjects.sol/JBProjects.json'; import jbSplitsStore from '../../artifacts/contracts/JBSplitsStore.sol/JBSplitsStore.json'; @@ -125,10 +125,10 @@ describe('JBPayoutRedemptionPaymentTerminal3_1::migrate(...)', function () { .returns(true); // addToBalanceOf _amount is 0 if ETH terminal - await mockJbEthPaymentTerminal.mock.addToBalanceOf + await mockJbEthPaymentTerminal.mock["addToBalanceOf(uint256,uint256,address,string,bytes)"] .withArgs(PROJECT_ID, CURRENT_TERMINAL_BALANCE, TOKEN_ETH, '', '0x') .returns(); - await mockJBERC20PaymentTerminal.mock.addToBalanceOf + await mockJBERC20PaymentTerminal.mock["addToBalanceOf(uint256,uint256,address,string,bytes)"] .withArgs(PROJECT_ID, CURRENT_TERMINAL_BALANCE, NON_ETH_TOKEN, '', '0x') .returns(); diff --git a/test/jb_payment_terminal_3_1/pay.test.js b/test/jb_payment_terminal_3_1/pay.test.js index 40c25722b..d26fa8cc6 100644 --- a/test/jb_payment_terminal_3_1/pay.test.js +++ b/test/jb_payment_terminal_3_1/pay.test.js @@ -8,8 +8,8 @@ import errors from '../helpers/errors.json'; import ierc20 from '../../artifacts/@openzeppelin/contracts/token/ERC20/ERC20.sol/ERC20.json'; import jbDirectory from '../../artifacts/contracts/JBDirectory.sol/JBDirectory.json'; -import jbController from '../../artifacts/contracts/interfaces/IJBController.sol/IJBController.json'; -import jbPaymentTerminalStore from '../../artifacts/contracts/JBSingleTokenPaymentTerminalStore.sol/JBSingleTokenPaymentTerminalStore.json'; +import jbController from '../../artifacts/contracts/interfaces/IJBController3_1.sol/IJBController3_1.json'; +import jbPaymentTerminalStore from '../../artifacts/contracts/JBSingleTokenPaymentTerminalStore3_1.sol/JBSingleTokenPaymentTerminalStore3_1.json'; import jbOperatoreStore from '../../artifacts/contracts/JBOperatorStore.sol/JBOperatorStore.json'; import jbProjects from '../../artifacts/contracts/JBProjects.sol/JBProjects.json'; import jbSplitsStore from '../../artifacts/contracts/JBSplitsStore.sol/JBSplitsStore.json'; diff --git a/test/jb_payment_terminal_3_1/redeem_tokens_of.test.js b/test/jb_payment_terminal_3_1/redeem_tokens_of.test.js index cad29cd97..7d7f60a00 100644 --- a/test/jb_payment_terminal_3_1/redeem_tokens_of.test.js +++ b/test/jb_payment_terminal_3_1/redeem_tokens_of.test.js @@ -5,9 +5,9 @@ import { deployMockContract } from '@ethereum-waffle/mock-contract'; import { setBalance } from '../helpers/utils'; import errors from '../helpers/errors.json'; -import jbController from '../../artifacts/contracts/interfaces/IJBController.sol/IJBController.json'; +import jbController from '../../artifacts/contracts/interfaces/IJBController3_1.sol/IJBController3_1.json'; import jbDirectory from '../../artifacts/contracts/interfaces/IJBDirectory.sol/IJBDirectory.json'; -import jbPaymentTerminalStore from '../../artifacts/contracts/JBSingleTokenPaymentTerminalStore.sol/JBSingleTokenPaymentTerminalStore.json'; +import jbPaymentTerminalStore from '../../artifacts/contracts/JBSingleTokenPaymentTerminalStore3_1.sol/JBSingleTokenPaymentTerminalStore3_1.json'; import jbOperatoreStore from '../../artifacts/contracts/interfaces/IJBOperatorStore.sol/IJBOperatorStore.json'; import jbProjects from '../../artifacts/contracts/interfaces/IJBProjects.sol/IJBProjects.json'; import jbSplitsStore from '../../artifacts/contracts/interfaces/IJBSplitsStore.sol/IJBSplitsStore.json'; @@ -146,7 +146,7 @@ describe('JBPayoutRedemptionPaymentTerminal3_1::redeemTokensOf(...)', function ( .returns( fundingCycle, /* reclaimAmount */ RECLAIM_AMOUNT, - /* delegateAllocation */ [], + /* delegateAllocation */[], ADJUSTED_MEMO, ); @@ -207,7 +207,7 @@ describe('JBPayoutRedemptionPaymentTerminal3_1::redeemTokensOf(...)', function ( .returns( fundingCycle, /* reclaimAmount */ RECLAIM_AMOUNT, - /* delegateAllocation */ [], + /* delegateAllocation */[], ADJUSTED_MEMO, ); @@ -278,7 +278,7 @@ describe('JBPayoutRedemptionPaymentTerminal3_1::redeemTokensOf(...)', function ( .returns( fundingCycle, /* reclaimAmount */ redeemedAmount, - /* delegateAllocations */ [ + /* delegateAllocations */[ { delegate: mockJbRedemptionDelegate.address, amount: delegateAmount }, ], ADJUSTED_MEMO, @@ -412,7 +412,7 @@ describe('JBPayoutRedemptionPaymentTerminal3_1::redeemTokensOf(...)', function ( .returns( fundingCycle, /* reclaimAmount */ redeemedAmount, - /* delegate */ [ + /* delegate */[ { delegate: mockJbRedemptionDelegate.address, amount: delegate1Amount }, { delegate: mockJbRedemptionDelegate2.address, amount: delegate2Amount }, ], @@ -569,7 +569,7 @@ describe('JBPayoutRedemptionPaymentTerminal3_1::redeemTokensOf(...)', function ( // Keep it simple and let 1 token exchange for 1 wei await mockJBPaymentTerminalStore.mock.recordRedemptionFor .withArgs(holder.address, PROJECT_ID, /* tokenCount */ AMOUNT, MEMO, METADATA) - .returns(fundingCycle, /* reclaimAmount */ 0, /* delegateAllocation */ [], ADJUSTED_MEMO); // Set reclaimAmount to 0 + .returns(fundingCycle, /* reclaimAmount */ 0, /* delegateAllocation */[], ADJUSTED_MEMO); // Set reclaimAmount to 0 await setBalance(jbEthPaymentTerminal.address, AMOUNT); @@ -672,7 +672,7 @@ describe('JBPayoutRedemptionPaymentTerminal3_1::redeemTokensOf(...)', function ( // Keep it simple and let 1 token exchange for 1 wei await mockJBPaymentTerminalStore.mock.recordRedemptionFor .withArgs(holder.address, PROJECT_ID, /* tokenCount */ AMOUNT, MEMO, METADATA) - .returns(fundingCycle, /* reclaimAmount */ 0, /* delegateAllocation */ [], ADJUSTED_MEMO); // Set reclaimAmount to 0 + .returns(fundingCycle, /* reclaimAmount */ 0, /* delegateAllocation */[], ADJUSTED_MEMO); // Set reclaimAmount to 0 await expect( jbEthPaymentTerminal diff --git a/test/jb_payment_terminal_3_1/set_fee.test.js b/test/jb_payment_terminal_3_1/set_fee.test.js index a50cf6dd0..e4da43f8b 100644 --- a/test/jb_payment_terminal_3_1/set_fee.test.js +++ b/test/jb_payment_terminal_3_1/set_fee.test.js @@ -5,7 +5,7 @@ import errors from '../helpers/errors.json'; import { deployMockContract } from '@ethereum-waffle/mock-contract'; import jbDirectory from '../../artifacts/contracts/interfaces/IJBDirectory.sol/IJBDirectory.json'; -import jbPaymentTerminalStore from '../../artifacts/contracts/JBSingleTokenPaymentTerminalStore.sol/JBSingleTokenPaymentTerminalStore.json'; +import jbPaymentTerminalStore from '../../artifacts/contracts/JBSingleTokenPaymentTerminalStore3_1.sol/JBSingleTokenPaymentTerminalStore3_1.json'; import jbOperatoreStore from '../../artifacts/contracts/interfaces/IJBOperatorStore.sol/IJBOperatorStore.json'; import jbProjects from '../../artifacts/contracts/interfaces/IJBProjects.sol/IJBProjects.json'; import jbSplitsStore from '../../artifacts/contracts/interfaces/IJBSplitsStore.sol/IJBSplitsStore.json'; diff --git a/test/jb_payment_terminal_3_1/set_fee_gauge.test.js b/test/jb_payment_terminal_3_1/set_fee_gauge.test.js index 1936dbce8..3aedc8a8f 100644 --- a/test/jb_payment_terminal_3_1/set_fee_gauge.test.js +++ b/test/jb_payment_terminal_3_1/set_fee_gauge.test.js @@ -4,7 +4,7 @@ import { ethers } from 'hardhat'; import { deployMockContract } from '@ethereum-waffle/mock-contract'; import jbDirectory from '../../artifacts/contracts/interfaces/IJBDirectory.sol/IJBDirectory.json'; -import jbPaymentTerminalStore from '../../artifacts/contracts/JBSingleTokenPaymentTerminalStore.sol/JBSingleTokenPaymentTerminalStore.json'; +import jbPaymentTerminalStore from '../../artifacts/contracts/JBSingleTokenPaymentTerminalStore3_1.sol/JBSingleTokenPaymentTerminalStore3_1.json'; import jbFeeGauge from '../../artifacts/contracts/interfaces/IJBFeeGauge.sol/IJBFeeGauge.json'; import jbOperatoreStore from '../../artifacts/contracts/interfaces/IJBOperatorStore.sol/IJBOperatorStore.json'; import jbProjects from '../../artifacts/contracts/interfaces/IJBProjects.sol/IJBProjects.json'; diff --git a/test/jb_payment_terminal_3_1/set_feeless_terminal.test.js b/test/jb_payment_terminal_3_1/set_feeless_terminal.test.js index 7a8ece9f4..3e5635c3e 100644 --- a/test/jb_payment_terminal_3_1/set_feeless_terminal.test.js +++ b/test/jb_payment_terminal_3_1/set_feeless_terminal.test.js @@ -4,8 +4,8 @@ import { ethers } from 'hardhat'; import { deployMockContract } from '@ethereum-waffle/mock-contract'; import jbDirectory from '../../artifacts/contracts/interfaces/IJBDirectory.sol/IJBDirectory.json'; -import JBEthPaymentTerminal from '../../artifacts/contracts/JBETHPaymentTerminal.sol/JBETHPaymentTerminal.json'; -import jbPaymentTerminalStore from '../../artifacts/contracts/JBSingleTokenPaymentTerminalStore.sol/JBSingleTokenPaymentTerminalStore.json'; +import JBEthPaymentTerminal from '../../artifacts/contracts/JBETHPaymentTerminal3_1.sol/JBETHPaymentTerminal3_1.json'; +import jbPaymentTerminalStore from '../../artifacts/contracts/JBSingleTokenPaymentTerminalStore3_1.sol/JBSingleTokenPaymentTerminalStore3_1.json'; import jbOperatoreStore from '../../artifacts/contracts/interfaces/IJBOperatorStore.sol/IJBOperatorStore.json'; import jbProjects from '../../artifacts/contracts/interfaces/IJBProjects.sol/IJBProjects.json'; import jbSplitsStore from '../../artifacts/contracts/interfaces/IJBSplitsStore.sol/IJBSplitsStore.json'; diff --git a/test/jb_payment_terminal_3_1/use_allowance_of.test.js b/test/jb_payment_terminal_3_1/use_allowance_of.test.js index fb70e3d33..9a6ff41e9 100644 --- a/test/jb_payment_terminal_3_1/use_allowance_of.test.js +++ b/test/jb_payment_terminal_3_1/use_allowance_of.test.js @@ -6,7 +6,7 @@ import errors from '../helpers/errors.json'; import { packFundingCycleMetadata, setBalance } from '../helpers/utils.js'; import jbDirectory from '../../artifacts/contracts/interfaces/IJBDirectory.sol/IJBDirectory.json'; -import jbPaymentTerminalStore from '../../artifacts/contracts/JBSingleTokenPaymentTerminalStore.sol/JBSingleTokenPaymentTerminalStore.json'; +import jbPaymentTerminalStore from '../../artifacts/contracts/JBSingleTokenPaymentTerminalStore3_1.sol/JBSingleTokenPaymentTerminalStore3_1.json'; import jbFeeGauge from '../../artifacts/contracts/interfaces/IJBFeeGauge.sol/IJBFeeGauge.json'; import jbOperatoreStore from '../../artifacts/contracts/interfaces/IJBOperatorStore.sol/IJBOperatorStore.json'; import jbProjects from '../../artifacts/contracts/interfaces/IJBProjects.sol/IJBProjects.json'; @@ -212,6 +212,7 @@ describe('JBPayoutRedemptionPaymentTerminal3_1::useAllowanceOf(...)', function ( /* _distributedAmount */ AMOUNT, /* _netDistributedAmount */ AMOUNT, MEMO, + METADATA, /* msg.sender */ projectOwner.address, ); @@ -272,6 +273,7 @@ describe('JBPayoutRedemptionPaymentTerminal3_1::useAllowanceOf(...)', function ( /* _distributedAmount */ AMOUNT, /* _netDistributedAmount */ AMOUNT, MEMO, + METADATA, /* msg.sender */ projectOwner.address, ); @@ -349,7 +351,7 @@ describe('JBPayoutRedemptionPaymentTerminal3_1::useAllowanceOf(...)', function ( /* memo */ '', ethers.utils.hexZeroPad(ethers.utils.hexlify(PROJECT_ID), 32), ) - .returns(fundingCycle, 0, /* delegateAllocation */ [], ''); + .returns(fundingCycle, 0, /* delegateAllocation */[], ''); await mockJbDirectory.mock.primaryTerminalOf .withArgs(1, ETH_ADDRESS) @@ -442,7 +444,7 @@ describe('JBPayoutRedemptionPaymentTerminal3_1::useAllowanceOf(...)', function ( /* memo */ '', ethers.utils.hexZeroPad(ethers.utils.hexlify(PROJECT_ID), 32), ) - .returns(fundingCycle, 0, /* delegateAllocation */ [], ''); + .returns(fundingCycle, 0, /* delegateAllocation */[], ''); await mockJbDirectory.mock.primaryTerminalOf .withArgs(1, ETH_ADDRESS) @@ -531,7 +533,7 @@ describe('JBPayoutRedemptionPaymentTerminal3_1::useAllowanceOf(...)', function ( /* memo */ '', ethers.utils.hexZeroPad(ethers.utils.hexlify(PROJECT_ID), 32), ) - .returns(fundingCycle, 0, /* delegateAllocation */ [], ''); + .returns(fundingCycle, 0, /* delegateAllocation */[], ''); await mockJbDirectory.mock.primaryTerminalOf .withArgs(1, ETH_ADDRESS) @@ -620,7 +622,7 @@ describe('JBPayoutRedemptionPaymentTerminal3_1::useAllowanceOf(...)', function ( /* memo */ '', ethers.utils.hexZeroPad(ethers.utils.hexlify(PROJECT_ID), 32), ) - .returns(fundingCycle, 0, /* delegateAllocation */ [], ''); + .returns(fundingCycle, 0, /* delegateAllocation */[], ''); await mockJbDirectory.mock.primaryTerminalOf .withArgs(1, ETH_ADDRESS) @@ -717,7 +719,7 @@ describe('JBPayoutRedemptionPaymentTerminal3_1::useAllowanceOf(...)', function ( /* memo */ '', ethers.utils.hexZeroPad(ethers.utils.hexlify(PROJECT_ID), 32), ) - .returns(newFundingCycle, 0, /* delegateAllocation */ [], ''); + .returns(newFundingCycle, 0, /* delegateAllocation */[], ''); await mockJbDirectory.mock.primaryTerminalOf .withArgs(1, ETH_ADDRESS) @@ -826,7 +828,7 @@ describe('JBPayoutRedemptionPaymentTerminal3_1::useAllowanceOf(...)', function ( /* memo */ '', ethers.utils.hexZeroPad(ethers.utils.hexlify(PROJECT_ID), 32), ) - .returns(newFundingCycle, 0, /* delegateAllocation */ [], ''); + .returns(newFundingCycle, 0, /* delegateAllocation */[], ''); await mockJbDirectory.mock.primaryTerminalOf .withArgs(1, ETH_ADDRESS) @@ -939,7 +941,7 @@ describe('JBPayoutRedemptionPaymentTerminal3_1::useAllowanceOf(...)', function ( /* memo */ '', ethers.utils.hexZeroPad(ethers.utils.hexlify(PROJECT_ID), 32), ) - .returns(newFundingCycle, 0, /* delegateAllocation */ [], ''); + .returns(newFundingCycle, 0, /* delegateAllocation */[], ''); await mockJbDirectory.mock.primaryTerminalOf .withArgs(1, ETH_ADDRESS) diff --git a/test/jb_payment_terminal_3_1/view.test.js b/test/jb_payment_terminal_3_1/view.test.js index 73533727c..a958feaaa 100644 --- a/test/jb_payment_terminal_3_1/view.test.js +++ b/test/jb_payment_terminal_3_1/view.test.js @@ -6,8 +6,8 @@ import { makeSplits, packFundingCycleMetadata, setBalance } from '../helpers/uti import errors from '../helpers/errors.json'; import jbDirectory from '../../artifacts/contracts/JBDirectory.sol/JBDirectory.json'; -import JBEthPaymentTerminal from '../../artifacts/contracts/JBETHPaymentTerminal.sol/JBETHPaymentTerminal.json'; -import jbPaymentTerminalStore from '../../artifacts/contracts/JBSingleTokenPaymentTerminalStore.sol/JBSingleTokenPaymentTerminalStore.json'; +import JBEthPaymentTerminal from '../../artifacts/contracts/JBETHPaymentTerminal3_1.sol/JBETHPaymentTerminal3_1.json'; +import jbPaymentTerminalStore from '../../artifacts/contracts/JBSingleTokenPaymentTerminalStore3_1.sol/JBSingleTokenPaymentTerminalStore3_1.json'; import jbOperatoreStore from '../../artifacts/contracts/JBOperatorStore.sol/JBOperatorStore.json'; import jbProjects from '../../artifacts/contracts/JBProjects.sol/JBProjects.json'; import jbSplitsStore from '../../artifacts/contracts/JBSplitsStore.sol/JBSplitsStore.json'; diff --git a/test/jb_payment_terminal_3_1_1/add_to_balance_of.test.js b/test/jb_payment_terminal_3_1_1/add_to_balance_of.test.js new file mode 100644 index 000000000..a3c5c1698 --- /dev/null +++ b/test/jb_payment_terminal_3_1_1/add_to_balance_of.test.js @@ -0,0 +1,816 @@ +import { expect } from 'chai'; +import { ethers } from 'hardhat'; +import { deployMockContract } from '@ethereum-waffle/mock-contract'; +import { makeSplits, packFundingCycleMetadata, setBalance } from '../helpers/utils.js'; +import { smock } from '@defi-wonderland/smock'; + +import errors from '../helpers/errors.json'; + +import jbDirectory from '../../artifacts/contracts/JBDirectory.sol/JBDirectory.json'; +import JBEthPaymentTerminal from '../../artifacts/contracts/JBETHPaymentTerminal3_1_1.sol/JBETHPaymentTerminal3_1_1.json'; +import jbPaymentTerminalStore from '../../artifacts/contracts/JBSingleTokenPaymentTerminalStore3_1_1.sol/JBSingleTokenPaymentTerminalStore3_1_1.json'; +import jbOperatoreStore from '../../artifacts/contracts/JBOperatorStore.sol/JBOperatorStore.json'; +import jbProjects from '../../artifacts/contracts/JBProjects.sol/JBProjects.json'; +import jbSplitsStore from '../../artifacts/contracts/JBSplitsStore.sol/JBSplitsStore.json'; +import jbPrices from '../../artifacts/contracts/JBPrices.sol/JBPrices.json'; +import ierc20 from '../../artifacts/@openzeppelin/contracts/token/ERC20/ERC20.sol/ERC20.json'; + +describe('JBPayoutRedemptionPaymentTerminal3_1_1::addToBalanceOf(...)', function () { + const PROTOCOL_PROJECT_ID = 1; + const PROJECT_ID = 2; + const AMOUNT = ethers.utils.parseEther('10'); + const MIN_TOKEN_REQUESTED = 0; + const MEMO = 'Memo Test'; + const METADATA = '0x69'; + const ETH_ADDRESS = '0x000000000000000000000000000000000000EEEe'; + + let CURRENCY_ETH; + let ETH_PAYOUT_INDEX; + let MAX_FEE; + let MAX_FEE_DISCOUNT; + + before(async function () { + let jbSplitsGroupsFactory = await ethers.getContractFactory('JBSplitsGroups'); + let jbSplitsGroups = await jbSplitsGroupsFactory.deploy(); + + ETH_PAYOUT_INDEX = await jbSplitsGroups.ETH_PAYOUT(); + + const jbCurrenciesFactory = await ethers.getContractFactory('JBCurrencies'); + const jbCurrencies = await jbCurrenciesFactory.deploy(); + CURRENCY_ETH = await jbCurrencies.ETH(); + + const jbConstantsFactory = await ethers.getContractFactory('JBConstants'); + const jbConstants = await jbConstantsFactory.deploy(); + MAX_FEE = await jbConstants.MAX_FEE(); + MAX_FEE_DISCOUNT = await jbConstants.MAX_FEE_DISCOUNT(); + }); + + async function setup() { + let [deployer, projectOwner, terminalOwner, caller, beneficiaryOne, beneficiaryTwo, ...addrs] = + await ethers.getSigners(); + + const blockNum = await ethers.provider.getBlockNumber(); + const block = await ethers.provider.getBlock(blockNum); + const timestamp = block.timestamp; + + const SPLITS_GROUP = 1; + + let [ + mockJbDirectory, + mockJbEthPaymentTerminal, + mockJBPaymentTerminalStore, + mockJbOperatorStore, + mockJbProjects, + mockJbSplitsStore, + mockJbPrices, + ] = await Promise.all([ + deployMockContract(deployer, jbDirectory.abi), + deployMockContract(deployer, JBEthPaymentTerminal.abi), + deployMockContract(deployer, jbPaymentTerminalStore.abi), + deployMockContract(deployer, jbOperatoreStore.abi), + deployMockContract(deployer, jbProjects.abi), + deployMockContract(deployer, jbSplitsStore.abi), + deployMockContract(deployer, jbPrices.abi), + ]); + + let mockToken = await smock.fake(ierc20.abi); + + let jbTerminalFactory = await ethers.getContractFactory( + 'contracts/JBETHPaymentTerminal3_1_1.sol:JBETHPaymentTerminal3_1_1', + deployer, + ); + let jbErc20TerminalFactory = await ethers.getContractFactory( + 'contracts/JBERC20PaymentTerminal3_1_1.sol:JBERC20PaymentTerminal3_1_1', + deployer, + ); + const NON_ETH_TOKEN = mockToken.address; + + let jbEthPaymentTerminal = await jbTerminalFactory + .connect(deployer) + .deploy( + /*base weight currency*/ CURRENCY_ETH, + mockJbOperatorStore.address, + mockJbProjects.address, + mockJbDirectory.address, + mockJbSplitsStore.address, + mockJbPrices.address, + mockJBPaymentTerminalStore.address, + terminalOwner.address, + ); + + const DECIMALS = 1; + + mockToken.decimals.returns(DECIMALS); + + let JBERC20PaymentTerminal = await jbErc20TerminalFactory + .connect(deployer) + .deploy( + NON_ETH_TOKEN, + CURRENCY_ETH, + CURRENCY_ETH, + SPLITS_GROUP, + mockJbOperatorStore.address, + mockJbProjects.address, + mockJbDirectory.address, + mockJbSplitsStore.address, + mockJbPrices.address, + mockJBPaymentTerminalStore.address, + terminalOwner.address, + ); + + let fundingCycle = { + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: 0, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ holdFees: 1 }), + }; + + await mockJbDirectory.mock.isTerminalOf + .withArgs(PROJECT_ID, jbEthPaymentTerminal.address) + .returns(true); + + await mockJbDirectory.mock.isTerminalOf + .withArgs(PROJECT_ID, JBERC20PaymentTerminal.address) + .returns(true); + + await mockJbDirectory.mock.primaryTerminalOf + .withArgs(PROTOCOL_PROJECT_ID, ETH_ADDRESS) + .returns(jbEthPaymentTerminal.address); + + await mockJbDirectory.mock.primaryTerminalOf + .withArgs(PROTOCOL_PROJECT_ID, NON_ETH_TOKEN) + .returns(JBERC20PaymentTerminal.address); + + await mockJBPaymentTerminalStore.mock.recordDistributionFor + .withArgs(PROJECT_ID, AMOUNT, CURRENCY_ETH) + .returns( + { + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: 0, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ holdFees: 1 }), + }, + AMOUNT, + ); + + await mockJbProjects.mock.ownerOf.withArgs(PROJECT_ID).returns(projectOwner.address); + + await mockJBPaymentTerminalStore.mock.recordAddedBalanceFor + .withArgs(PROJECT_ID, AMOUNT) + .returns(); + + await ethers.provider.send('hardhat_setBalance', [ + jbEthPaymentTerminal.address, + '0x100000000000000000000', + ]); + + return { + deployer, + projectOwner, + terminalOwner, + caller, + beneficiaryOne, + beneficiaryTwo, + addrs, + jbEthPaymentTerminal, + JBERC20PaymentTerminal, + mockJbDirectory, + mockJbEthPaymentTerminal, + mockJBPaymentTerminalStore, + mockToken, + mockJbOperatorStore, + mockJbSplitsStore, + timestamp, + fundingCycle, + }; + } + + it('Should add to the project balance, refund any held fee if _shouldRefundHeldFees is true, and remove them if the transferred amount is enough, and emit event', async function () { + const { + caller, + beneficiaryOne, + beneficiaryTwo, + jbEthPaymentTerminal, + timestamp, + mockJbSplitsStore, + mockJBPaymentTerminalStore, + } = await setup(); + const splits = makeSplits({ + count: 2, + beneficiary: [beneficiaryOne.address, beneficiaryTwo.address], + }); + + await mockJbSplitsStore.mock.splitsOf + .withArgs(PROJECT_ID, timestamp, ETH_PAYOUT_INDEX) + .returns(splits); + + await jbEthPaymentTerminal + .connect(caller) + .distributePayoutsOf( + PROJECT_ID, + AMOUNT, + ETH_PAYOUT_INDEX, + ethers.constants.AddressZero, + MIN_TOKEN_REQUESTED, + METADATA, + ); + + let heldFee = await jbEthPaymentTerminal.heldFeesOf(PROJECT_ID); + + let discountedFee = ethers.BigNumber.from(heldFee[0].fee).sub( + ethers.BigNumber.from(heldFee[0].fee) + .mul(ethers.BigNumber.from(heldFee[0].feeDiscount)) + .div(MAX_FEE_DISCOUNT), + ); + + let feeNetAmount = ethers.BigNumber.from(heldFee[0].amount).sub( + ethers.BigNumber.from(heldFee[0].amount).mul(MAX_FEE).div(discountedFee.add(MAX_FEE)), + ); + await mockJBPaymentTerminalStore.mock.recordAddedBalanceFor + .withArgs(PROJECT_ID, AMOUNT.add(feeNetAmount)) + .returns(); + + expect( + await jbEthPaymentTerminal + .connect(caller) + ['addToBalanceOf(uint256,uint256,address,bool,string,bytes)']( + PROJECT_ID, + AMOUNT, + ETH_ADDRESS, + true, + MEMO, + METADATA, + { value: AMOUNT }, + ), + ) + .to.emit(jbEthPaymentTerminal, 'AddToBalance') + .withArgs(PROJECT_ID, AMOUNT, feeNetAmount, MEMO, METADATA, caller.address) + .and.to.emit(jbEthPaymentTerminal, 'RefundHeldFees') + // add to balance: AMOUNT -> refund feeNetAmount (given AMOUNT > feeNetAmount) and left over is 0 + .withArgs(PROJECT_ID, AMOUNT, feeNetAmount, 0 /*leftOver*/, caller.address); + + expect(await jbEthPaymentTerminal.heldFeesOf(PROJECT_ID)).to.eql([]); + }); + + it('Should add to the project balance and not refund held fee if _shouldRefundHeldFees is false, and emit event', async function () { + const { + caller, + terminalOwner, + beneficiaryOne, + beneficiaryTwo, + jbEthPaymentTerminal, + timestamp, + mockJbSplitsStore, + mockJBPaymentTerminalStore, + } = await setup(); + const splits = makeSplits({ + count: 2, + beneficiary: [beneficiaryOne.address, beneficiaryTwo.address], + }); + + await mockJbSplitsStore.mock.splitsOf + .withArgs(PROJECT_ID, timestamp, ETH_PAYOUT_INDEX) + .returns(splits); + + await jbEthPaymentTerminal + .connect(caller) + .distributePayoutsOf( + PROJECT_ID, + AMOUNT, + ETH_PAYOUT_INDEX, + ethers.constants.AddressZero, + MIN_TOKEN_REQUESTED, + METADATA, + ); + + let heldFee = await jbEthPaymentTerminal.heldFeesOf(PROJECT_ID); + + await jbEthPaymentTerminal.connect(terminalOwner).setFeelessAddress(caller.address, true); + + let discountedFee = ethers.BigNumber.from(heldFee[0].fee).sub( + ethers.BigNumber.from(heldFee[0].fee) + .mul(ethers.BigNumber.from(heldFee[0].feeDiscount)) + .div(MAX_FEE_DISCOUNT), + ); + + let feeNetAmount = ethers.BigNumber.from(heldFee[0].amount).sub( + ethers.BigNumber.from(heldFee[0].amount).mul(MAX_FEE).div(discountedFee.add(MAX_FEE)), + ); + await mockJBPaymentTerminalStore.mock.recordAddedBalanceFor + .withArgs(PROJECT_ID, AMOUNT.add(feeNetAmount)) + .returns(); + + expect( + await jbEthPaymentTerminal + .connect(caller) + ['addToBalanceOf(uint256,uint256,address,bool,string,bytes)']( + PROJECT_ID, + AMOUNT, + ETH_ADDRESS, + false, + MEMO, + METADATA, + { value: AMOUNT }, + ), + ) + .to.emit(jbEthPaymentTerminal, 'AddToBalance') + .withArgs(PROJECT_ID, AMOUNT, 0 /*refunded fee*/, MEMO, METADATA, caller.address) + .and.to.not.emit(jbEthPaymentTerminal, 'RefundHeldFees'); + + let heldFeeAfter = await jbEthPaymentTerminal.heldFeesOf(PROJECT_ID); + + expect(heldFeeAfter[0]).to.eql(heldFee[0]); + }); + + it('Should work with eth terminal with non msg.value amount sent', async function () { + const { caller, jbEthPaymentTerminal, mockJBPaymentTerminalStore, fundingCycle } = + await setup(); + await mockJBPaymentTerminalStore.mock.recordAddedBalanceFor + .withArgs(PROJECT_ID, AMOUNT) + .returns(); + + await jbEthPaymentTerminal + .connect(caller) + ['addToBalanceOf(uint256,uint256,address,string,bytes)']( + PROJECT_ID, + AMOUNT + 1, + ETH_ADDRESS, + MEMO, + METADATA, + { value: AMOUNT }, + ); + }); + + it('Should work with non-eth terminal if no value is sent', async function () { + const { caller, JBERC20PaymentTerminal, mockToken, mockJBPaymentTerminalStore } = await setup(); + await mockJBPaymentTerminalStore.mock.recordAddedBalanceFor + .withArgs(PROJECT_ID, AMOUNT) + .returns(); + + // first call to balanceOF -> empty + mockToken.balanceOf.returnsAtCall(0, 0); + + // Pulling the tokens + mockToken.transferFrom + .whenCalledWith(caller.address, JBERC20PaymentTerminal.address, AMOUNT) + .returns(true); + + // Second call to balanceOf, with the token now in balance + mockToken.balanceOf.returnsAtCall(1, AMOUNT); + + await JBERC20PaymentTerminal.connect(caller)[ + 'addToBalanceOf(uint256,uint256,address,string,bytes)' + ](PROJECT_ID, AMOUNT, mockToken.address, MEMO, METADATA, { + value: 0, + }); + }); + + it('Should work with non-eth terminal supporting fee on transfer token', async function () { + const { caller, JBERC20PaymentTerminal, mockToken, mockJBPaymentTerminalStore } = await setup(); + + // The net amount received by the terminal (AMOUNT - fee on transfer) + const NET_AMOUNT = AMOUNT.sub(100); + + await mockJBPaymentTerminalStore.mock.recordAddedBalanceFor + .withArgs(PROJECT_ID, NET_AMOUNT) + .returns(); + + // first call to balanceOF -> empty + mockToken.balanceOf.returnsAtCall(0, 0); + + // Pulling the tokens + mockToken.transferFrom + .whenCalledWith(caller.address, JBERC20PaymentTerminal.address, AMOUNT) + .returns(true); + + // Second call to balanceOf, with the net token balance + mockToken.balanceOf.returnsAtCall(1, NET_AMOUNT); + + await expect( + await JBERC20PaymentTerminal.connect(caller)[ + 'addToBalanceOf(uint256,uint256,address,string,bytes)' + ](PROJECT_ID, AMOUNT, mockToken.address, MEMO, METADATA, { + value: 0, + }), + ) + .to.emit(JBERC20PaymentTerminal, 'AddToBalance') + .withArgs(PROJECT_ID, NET_AMOUNT, 0, MEMO, METADATA, caller.address); + }); + + it('Should add to the project balance, partially refund a held fee and substract the amount from the held fee amount and emit event', async function () { + const { + caller, + beneficiaryOne, + beneficiaryTwo, + jbEthPaymentTerminal, + timestamp, + mockJbSplitsStore, + mockJBPaymentTerminalStore, + fundingCycle, + } = await setup(); + const splits = makeSplits({ + count: 2, + beneficiary: [beneficiaryOne.address, beneficiaryTwo.address], + }); + + await mockJbSplitsStore.mock.splitsOf + .withArgs(PROJECT_ID, timestamp, ETH_PAYOUT_INDEX) + .returns(splits); + + await jbEthPaymentTerminal + .connect(caller) + .distributePayoutsOf( + PROJECT_ID, + AMOUNT, + ETH_PAYOUT_INDEX, + ethers.constants.AddressZero, + MIN_TOKEN_REQUESTED, + METADATA, + ); + + // Add 1 and refund 1 + await mockJBPaymentTerminalStore.mock.recordAddedBalanceFor + .withArgs(PROJECT_ID, 1 + 1) + .returns(); + + let heldFeeBefore = await jbEthPaymentTerminal.heldFeesOf(PROJECT_ID); + + await expect( + await jbEthPaymentTerminal + .connect(caller) + ['addToBalanceOf(uint256,uint256,address,bool,string,bytes)']( + PROJECT_ID, + 1, + ETH_ADDRESS, + true, + MEMO, + METADATA, + { value: 1 }, + ), + ) + .to.emit(jbEthPaymentTerminal, 'AddToBalance') + .withArgs(PROJECT_ID, 1, 1, MEMO, METADATA, caller.address) + .and.to.emit(jbEthPaymentTerminal, 'RefundHeldFees') + // add to balance: 1 -> refund 1 and left over is 0 + .withArgs(PROJECT_ID, 1 /*amount*/, 1 /*refund*/, 0 /*leftOver*/, caller.address); + + let heldFeeAfter = await jbEthPaymentTerminal.heldFeesOf(PROJECT_ID); + + expect(heldFeeAfter[0].amount).to.equal(heldFeeBefore[0].amount.sub(1)); + }); + + it('Should add to the project balance, refund multiple held fee by substracting the amount from the held fee amount when possible and emit event', async function () { + const { + caller, + beneficiaryOne, + beneficiaryTwo, + jbEthPaymentTerminal, + timestamp, + mockJbSplitsStore, + mockJBPaymentTerminalStore, + fundingCycle, + } = await setup(); + const splits = makeSplits({ + count: 2, + beneficiary: [beneficiaryOne.address, beneficiaryTwo.address], + }); + + await mockJbSplitsStore.mock.splitsOf + .withArgs(PROJECT_ID, timestamp, ETH_PAYOUT_INDEX) + .returns(splits); + + await mockJBPaymentTerminalStore.mock.recordDistributionFor + .withArgs(PROJECT_ID, AMOUNT.div(2), CURRENCY_ETH) + .returns( + { + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: 0, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ holdFees: 1 }), + }, + AMOUNT.div(2), + ); + + await jbEthPaymentTerminal + .connect(caller) + .distributePayoutsOf( + PROJECT_ID, + AMOUNT.div(2), + ETH_PAYOUT_INDEX, + ethers.constants.AddressZero, + MIN_TOKEN_REQUESTED, + METADATA, + ); + + await jbEthPaymentTerminal + .connect(caller) + .distributePayoutsOf( + PROJECT_ID, + AMOUNT.div(2), + ETH_PAYOUT_INDEX, + ethers.constants.AddressZero, + MIN_TOKEN_REQUESTED, + METADATA, + ); + + let heldFee = await jbEthPaymentTerminal.heldFeesOf(PROJECT_ID); + + // Both held fees are identical: + let discountedFee = ethers.BigNumber.from(heldFee[0].fee).sub( + ethers.BigNumber.from(heldFee[0].fee) + .mul(ethers.BigNumber.from(heldFee[0].feeDiscount)) + .div(MAX_FEE_DISCOUNT), + ); + + let feeNetAmount = ethers.BigNumber.from(heldFee[0].amount).sub( + ethers.BigNumber.from(heldFee[0].amount).mul(MAX_FEE).div(discountedFee.add(MAX_FEE)), + ); + + await mockJBPaymentTerminalStore.mock.recordAddedBalanceFor + .withArgs(PROJECT_ID, AMOUNT.sub('10').add(feeNetAmount.mul(2))) + .returns(); + + expect( + await jbEthPaymentTerminal + .connect(caller) + ['addToBalanceOf(uint256,uint256,address,bool,string,bytes)']( + PROJECT_ID, + AMOUNT.sub('10'), + ETH_ADDRESS, + true, + MEMO, + METADATA, + { + value: AMOUNT.sub('10'), + }, + ), + ) + .to.emit(jbEthPaymentTerminal, 'AddToBalance') + .withArgs( + PROJECT_ID, + AMOUNT.sub('10'), + feeNetAmount.add(feeNetAmount), + MEMO, + METADATA, + caller.address, + ) + .and.to.emit(jbEthPaymentTerminal, 'RefundHeldFees') + // add to balance: AMOUNT.sub('10') -> refund feeNetAmount.mul(2) and left over is 0 + .withArgs( + PROJECT_ID, + AMOUNT.sub('10') /*amount*/, + feeNetAmount.mul(2) /*refund*/, + 0 /*leftOver*/, + caller.address, + ); + + let heldFeeAfter = await jbEthPaymentTerminal.heldFeesOf(PROJECT_ID); + // Only 10 left + expect(heldFeeAfter[0].amount).to.equal(10); + }); + + it('Should add to the project balance, refund one out of multiple held fees bigger than the amount, keep the held fee difference and emit event', async function () { + const { + caller, + beneficiaryOne, + beneficiaryTwo, + jbEthPaymentTerminal, + timestamp, + mockJbSplitsStore, + mockJBPaymentTerminalStore, + fundingCycle, + } = await setup(); + const splits = makeSplits({ + count: 2, + beneficiary: [beneficiaryOne.address, beneficiaryTwo.address], + }); + + await mockJbSplitsStore.mock.splitsOf + .withArgs(PROJECT_ID, timestamp, ETH_PAYOUT_INDEX) + .returns(splits); + + await mockJBPaymentTerminalStore.mock.recordDistributionFor + .withArgs(PROJECT_ID, AMOUNT.div(2), CURRENCY_ETH) + .returns( + { + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: 0, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ holdFees: 1 }), + }, + AMOUNT, + ); + + await jbEthPaymentTerminal + .connect(caller) + .distributePayoutsOf( + PROJECT_ID, + AMOUNT, + ETH_PAYOUT_INDEX, + ethers.constants.AddressZero, + MIN_TOKEN_REQUESTED, + METADATA, + ); + + await jbEthPaymentTerminal + .connect(caller) + .distributePayoutsOf( + PROJECT_ID, + AMOUNT, + ETH_PAYOUT_INDEX, + ethers.constants.AddressZero, + MIN_TOKEN_REQUESTED, + METADATA, + ); + + let heldFee = await jbEthPaymentTerminal.heldFeesOf(PROJECT_ID); + + // Both held fees are identical: + let discountedFee = ethers.BigNumber.from(heldFee[0].fee).sub( + ethers.BigNumber.from(heldFee[0].fee) + .mul(ethers.BigNumber.from(heldFee[0].feeDiscount)) + .div(MAX_FEE_DISCOUNT), + ); + + // Adding amount/4 to balance while there are 2 fee held on 'amount' + const amountToAdd = AMOUNT.div(2); + + // fee from one distribute + let feeFromOneAmount = ethers.BigNumber.from(heldFee[0].amount).sub( + ethers.BigNumber.from(heldFee[0].amount).mul(MAX_FEE).div(discountedFee.add(MAX_FEE)), + ); + + // fee which can be used based on amountToAdd + let feeNetAmount = feeFromOneAmount.div(2); + + await mockJBPaymentTerminalStore.mock.recordAddedBalanceFor + .withArgs(PROJECT_ID, amountToAdd.add(feeNetAmount)) + .returns(); + + expect( + await jbEthPaymentTerminal + .connect(caller) + ['addToBalanceOf(uint256,uint256,address,bool,string,bytes)']( + PROJECT_ID, + amountToAdd, + ETH_ADDRESS, + true, + MEMO, + METADATA, + { + value: amountToAdd, + }, + ), + ) + .to.emit(jbEthPaymentTerminal, 'AddToBalance') + .withArgs(PROJECT_ID, amountToAdd, feeNetAmount, MEMO, METADATA, caller.address) + .and.to.emit(jbEthPaymentTerminal, 'RefundHeldFees') + // add to balance: amountToAdd -> refund feeNetAmount * 0.75 and left over is 0 + .withArgs( + PROJECT_ID, + amountToAdd /*amount*/, + feeNetAmount /*refund*/, + 0 /*leftOver*/, + caller.address, + ); + + let heldFeeAfter = await jbEthPaymentTerminal.heldFeesOf(PROJECT_ID); + + // Only 25% of the initial held fee left + expect(heldFeeAfter[0].amount).to.equal(AMOUNT.div(2)); + }); + + it('Should add to the project balance, refund all the held fees if the amount to add to balance if bigger and emit event', async function () { + const { + caller, + beneficiaryOne, + beneficiaryTwo, + jbEthPaymentTerminal, + timestamp, + mockJbSplitsStore, + mockJBPaymentTerminalStore, + fundingCycle, + } = await setup(); + const splits = makeSplits({ + count: 2, + beneficiary: [beneficiaryOne.address, beneficiaryTwo.address], + }); + + await mockJbSplitsStore.mock.splitsOf + .withArgs(PROJECT_ID, timestamp, ETH_PAYOUT_INDEX) + .returns(splits); + + await jbEthPaymentTerminal + .connect(caller) + .distributePayoutsOf( + PROJECT_ID, + AMOUNT, + ETH_PAYOUT_INDEX, + ethers.constants.AddressZero, + MIN_TOKEN_REQUESTED, + METADATA, + ); + + // Only one held fee + let heldFeeBefore = await jbEthPaymentTerminal.heldFeesOf(PROJECT_ID); + + let discountedFee = ethers.BigNumber.from(heldFeeBefore[0].fee).sub( + ethers.BigNumber.from(heldFeeBefore[0].fee) + .mul(ethers.BigNumber.from(heldFeeBefore[0].feeDiscount)) + .div(MAX_FEE_DISCOUNT), + ); + + let netHeldFee = ethers.BigNumber.from(heldFeeBefore[0].amount).sub( + ethers.BigNumber.from(heldFeeBefore[0].amount).mul(MAX_FEE).div(discountedFee.add(MAX_FEE)), + ); + + // both total amount and refund fee are added + await mockJBPaymentTerminalStore.mock.recordAddedBalanceFor + .withArgs(PROJECT_ID, AMOUNT.mul(2).add(netHeldFee)) + .returns(); + + expect( + await jbEthPaymentTerminal + .connect(caller) + ['addToBalanceOf(uint256,uint256,address,bool,string,bytes)']( + PROJECT_ID, + AMOUNT.mul(2), + ETH_ADDRESS, + true, + MEMO, + METADATA, + { + value: AMOUNT.mul(2), + }, + ), + ) + .to.emit(jbEthPaymentTerminal, 'AddToBalance') + .withArgs(PROJECT_ID, AMOUNT.mul(2), netHeldFee, MEMO, METADATA, caller.address) + .and.to.emit(jbEthPaymentTerminal, 'RefundHeldFees') + // add to balance: AMOUNT*2 -> refund the whole net fee and the left over is the amount for which a fee wasn't refunded + .withArgs( + PROJECT_ID, + AMOUNT.mul(2) /*amount*/, + netHeldFee /*refund*/, + AMOUNT /*leftOver*/, + caller.address, + ); + + let heldFeeAfter = await jbEthPaymentTerminal.heldFeesOf(PROJECT_ID); + expect(heldFeeAfter).to.eql([]); + }); + + it("Can't add with value if terminal token isn't ETH", async function () { + const { caller, JBERC20PaymentTerminal, mockToken } = await setup(); + + await expect( + JBERC20PaymentTerminal.connect(caller)[ + 'addToBalanceOf(uint256,uint256,address,string,bytes)' + ](PROJECT_ID, AMOUNT, mockToken.address, MEMO, METADATA, { + value: 10, + }), + ).to.be.revertedWith(errors.NO_MSG_VALUE_ALLOWED); + }); + + it("Can't add to balance if terminal doesn't belong to project", async function () { + const { caller, jbEthPaymentTerminal, mockJbDirectory } = await setup(); + + const otherProjectId = 18; + await mockJbDirectory.mock.isTerminalOf + .withArgs(otherProjectId, jbEthPaymentTerminal.address) + .returns(false); + + await expect( + jbEthPaymentTerminal + .connect(caller) + ['addToBalanceOf(uint256,uint256,address,string,bytes)']( + otherProjectId, + AMOUNT, + ETH_ADDRESS, + MEMO, + METADATA, + { value: 0 }, + ), + ).to.be.revertedWith(errors.PROJECT_TERMINAL_MISMATCH); + }); +}); diff --git a/test/jb_payment_terminal_3_1_1/current_eth_overflow_of.test.js b/test/jb_payment_terminal_3_1_1/current_eth_overflow_of.test.js new file mode 100644 index 000000000..47e903ffb --- /dev/null +++ b/test/jb_payment_terminal_3_1_1/current_eth_overflow_of.test.js @@ -0,0 +1,129 @@ +import { expect } from 'chai'; +import { ethers } from 'hardhat'; +import { deployMockContract } from '@ethereum-waffle/mock-contract'; + +import jbDirectory from '../../artifacts/contracts/JBDirectory.sol/JBDirectory.json'; +import jbPaymentTerminalStore from '../../artifacts/contracts/JBSingleTokenPaymentTerminalStore3_1_1.sol/JBSingleTokenPaymentTerminalStore3_1_1.json'; +import jbOperatoreStore from '../../artifacts/contracts/JBOperatorStore.sol/JBOperatorStore.json'; +import jbPrices from '../../artifacts/contracts/interfaces/IJBPrices.sol/IJBPrices.json'; +import jbProjects from '../../artifacts/contracts/JBProjects.sol/JBProjects.json'; +import jbSplitsStore from '../../artifacts/contracts/JBSplitsStore.sol/JBSplitsStore.json'; +import jbToken from '../../artifacts/contracts/JBToken.sol/JBToken.json'; + +describe('JBPayoutRedemptionPaymentTerminal3_1_1::currentEthOverflowOf(...)', function () { + const PROJECT_ID = 2; + const AMOUNT = ethers.utils.parseEther('10'); + const PRICE = ethers.BigNumber.from('100'); + let CURRENCY_ETH; + let CURRENCY_USD; + + before(async function () { + const jbCurrenciesFactory = await ethers.getContractFactory('JBCurrencies'); + const jbCurrencies = await jbCurrenciesFactory.deploy(); + CURRENCY_ETH = await jbCurrencies.ETH(); + CURRENCY_USD = await jbCurrencies.USD(); + }); + + async function setup() { + let [deployer, terminalOwner, caller] = await ethers.getSigners(); + + const SPLITS_GROUP = 1; + + let [ + mockJbDirectory, + mockJBPaymentTerminalStore, + mockJbOperatorStore, + mockJbProjects, + mockJbSplitsStore, + mockJbPrices, + mockJbToken, + ] = await Promise.all([ + deployMockContract(deployer, jbDirectory.abi), + deployMockContract(deployer, jbPaymentTerminalStore.abi), + deployMockContract(deployer, jbOperatoreStore.abi), + deployMockContract(deployer, jbProjects.abi), + deployMockContract(deployer, jbSplitsStore.abi), + deployMockContract(deployer, jbPrices.abi), + deployMockContract(deployer, jbToken.abi), + ]); + + let jbTerminalFactory = await ethers.getContractFactory( + 'contracts/JBETHPaymentTerminal3_1_1.sol:JBETHPaymentTerminal3_1_1', + deployer, + ); + let jbErc20TerminalFactory = await ethers.getContractFactory( + 'contracts/JBERC20PaymentTerminal3_1_1.sol:JBERC20PaymentTerminal3_1_1', + deployer, + ); + + // ETH terminal + let jbEthPaymentTerminal = await jbTerminalFactory + .connect(deployer) + .deploy( + /*base weight currency*/ CURRENCY_ETH, + mockJbOperatorStore.address, + mockJbProjects.address, + mockJbDirectory.address, + mockJbSplitsStore.address, + mockJbPrices.address, + mockJBPaymentTerminalStore.address, + terminalOwner.address, + ); + + // Non-eth 16 decimals terminal + const NON_ETH_TOKEN = mockJbToken.address; + const DECIMALS = 16; + await mockJbToken.mock.decimals.returns(DECIMALS); + + let JBERC20PaymentTerminal = await jbErc20TerminalFactory + .connect(deployer) + .deploy( + NON_ETH_TOKEN, + CURRENCY_USD, + CURRENCY_USD, + SPLITS_GROUP, + mockJbOperatorStore.address, + mockJbProjects.address, + mockJbDirectory.address, + mockJbSplitsStore.address, + mockJbPrices.address, + mockJBPaymentTerminalStore.address, + terminalOwner.address, + ); + + await mockJBPaymentTerminalStore.mock.currentOverflowOf + .withArgs(jbEthPaymentTerminal.address, PROJECT_ID) + .returns(AMOUNT); + await mockJBPaymentTerminalStore.mock.currentOverflowOf + .withArgs(JBERC20PaymentTerminal.address, PROJECT_ID) + .returns(AMOUNT); + + await mockJBPaymentTerminalStore.mock.prices.returns(mockJbPrices.address); + + return { + caller, + jbEthPaymentTerminal, + JBERC20PaymentTerminal, + mockJbDirectory, + mockJbPrices, + mockJBPaymentTerminalStore, + }; + } + + it('Should return the current terminal overflow in eth if the terminal uses eth as currency', async function () { + const { jbEthPaymentTerminal } = await setup(); + expect(await jbEthPaymentTerminal.currentEthOverflowOf(PROJECT_ID)).to.equal(AMOUNT); + }); + + it('Should return the current terminal overflow quoted in eth if the terminal uses another currency than eth', async function () { + const { mockJbPrices, JBERC20PaymentTerminal } = await setup(); + + await mockJbPrices.mock.priceFor + .withArgs(CURRENCY_USD, CURRENCY_ETH, 16) // 16-decimal + .returns(100); + + expect(await JBERC20PaymentTerminal.currentEthOverflowOf(PROJECT_ID)).to.equal( + AMOUNT.mul(ethers.utils.parseEther('1')).div(PRICE), + ); + }); +}); diff --git a/test/jb_payment_terminal_3_1_1/distribute_payouts_of.test.js b/test/jb_payment_terminal_3_1_1/distribute_payouts_of.test.js new file mode 100644 index 000000000..da7e16dfa --- /dev/null +++ b/test/jb_payment_terminal_3_1_1/distribute_payouts_of.test.js @@ -0,0 +1,3256 @@ +import { expect } from 'chai'; +import { ethers } from 'hardhat'; +import { deployMockContract } from '@ethereum-waffle/mock-contract'; +import { makeSplits, packFundingCycleMetadata, setBalance } from '../helpers/utils.js'; +import errors from '../helpers/errors.json'; + +import jbAllocator from '../../artifacts/contracts/interfaces/IJBSplitAllocator.sol/IJBSplitAllocator.json'; +import jbDirectory from '../../artifacts/contracts/JBDirectory.sol/JBDirectory.json'; +import JBETHPaymentTerminal from '../../artifacts/contracts/JBETHPaymentTerminal3_1_1.sol/JBETHPaymentTerminal3_1_1.json'; +import jbPaymentTerminalStore from '../../artifacts/contracts/JBSingleTokenPaymentTerminalStore3_1_1.sol/JBSingleTokenPaymentTerminalStore3_1_1.json'; +import jbFeeGauge from '../../artifacts/contracts/interfaces/IJBFeeGauge3_1.sol/IJBFeeGauge3_1.json'; +import jbOperatoreStore from '../../artifacts/contracts/JBOperatorStore.sol/JBOperatorStore.json'; +import jbProjects from '../../artifacts/contracts/JBProjects.sol/JBProjects.json'; +import jbSplitsStore from '../../artifacts/contracts/JBSplitsStore.sol/JBSplitsStore.json'; +import jbPrices from '../../artifacts/contracts/JBPrices.sol/JBPrices.json'; +import IERC20Metadata from '../../artifacts/@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol/IERC20Metadata.json'; + +describe('JBPayoutRedemptionPaymentTerminal3_1_1::distributePayoutsOf(...)', function () { + const PLATFORM_PROJECT_ID = 1; + const PROJECT_ID = 2; + const OTHER_PROJECT_ID = 3; + + const AMOUNT_TO_DISTRIBUTE = 1100000000000; + const AMOUNT_DISTRIBUTED = 1000000000000; + + const DEFAULT_FEE = 25000000; // 2.5% + const FEE_DISCOUNT = 500000000; // 50% + + const CURRENCY = 1; + const MIN_TOKEN_REQUESTED = 180; + const METADATA = '0x69'; + + let ETH_ADDRESS; + let ETH_PAYOUT_INDEX; + let SPLITS_TOTAL_PERCENT; + let MAX_FEE; + let MAX_FEE_DISCOUNT; + let AMOUNT_MINUS_FEES; + + let fundingCycle; + + before(async function () { + let jbTokenFactory = await ethers.getContractFactory('JBTokens'); + let jbToken = await jbTokenFactory.deploy(); + + let jbSplitsGroupsFactory = await ethers.getContractFactory('JBSplitsGroups'); + let jbSplitsGroups = await jbSplitsGroupsFactory.deploy(); + + let jbConstantsFactory = await ethers.getContractFactory('JBConstants'); + let jbConstants = await jbConstantsFactory.deploy(); + + ETH_PAYOUT_INDEX = await jbSplitsGroups.ETH_PAYOUT(); + + ETH_ADDRESS = await jbToken.ETH(); + SPLITS_TOTAL_PERCENT = await jbConstants.SPLITS_TOTAL_PERCENT(); + MAX_FEE_DISCOUNT = await jbConstants.MAX_FEE_DISCOUNT(); + MAX_FEE = (await jbConstants.MAX_FEE()).toNumber(); + + let FEE = + AMOUNT_DISTRIBUTED - Math.floor((AMOUNT_DISTRIBUTED * MAX_FEE) / (DEFAULT_FEE + MAX_FEE)); + AMOUNT_MINUS_FEES = AMOUNT_DISTRIBUTED - FEE; + }); + + async function setup() { + let [deployer, projectOwner, terminalOwner, caller, beneficiaryOne, beneficiaryTwo, ...addrs] = + await ethers.getSigners(); + + const blockNum = await ethers.provider.getBlockNumber(); + const block = await ethers.provider.getBlock(blockNum); + const timestamp = block.timestamp; + + fundingCycle = { + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: 0, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata(), + }; + + let [ + fakeToken, + mockJbAllocator, + mockJbDirectory, + mockJbEthPaymentTerminal, + mockJBPaymentTerminalStore, + mockJbFeeGauge, + mockJbOperatorStore, + mockJbProjects, + mockJbSplitsStore, + mockJbPrices, + ] = await Promise.all([ + deployMockContract(deployer, IERC20Metadata.abi), + deployMockContract(deployer, jbAllocator.abi), + deployMockContract(deployer, jbDirectory.abi), + deployMockContract(deployer, JBETHPaymentTerminal.abi), + deployMockContract(deployer, jbPaymentTerminalStore.abi), + deployMockContract(deployer, jbFeeGauge.abi), + deployMockContract(deployer, jbOperatoreStore.abi), + deployMockContract(deployer, jbProjects.abi), + deployMockContract(deployer, jbSplitsStore.abi), + deployMockContract(deployer, jbPrices.abi), + ]); + + const jbCurrenciesFactory = await ethers.getContractFactory('JBCurrencies'); + const jbCurrencies = await jbCurrenciesFactory.deploy(); + const CURRENCY_ETH = await jbCurrencies.ETH(); + const CURRENCY_USD = await jbCurrencies.USD(); + + let jbEthTerminalFactory = await ethers.getContractFactory( + 'contracts/JBETHPaymentTerminal3_1_1.sol:JBETHPaymentTerminal3_1_1', + deployer, + ); + let jbErc20TerminalFactory = await ethers.getContractFactory( + 'contracts/JBERC20PaymentTerminal3_1_1.sol:JBERC20PaymentTerminal3_1_1', + deployer, + ); + + let jbEthPaymentTerminal = await jbEthTerminalFactory + .connect(deployer) + .deploy( + CURRENCY_ETH, + mockJbOperatorStore.address, + mockJbProjects.address, + mockJbDirectory.address, + mockJbSplitsStore.address, + mockJbPrices.address, + mockJBPaymentTerminalStore.address, + terminalOwner.address, + ); + + await fakeToken.mock.decimals.returns(18); + + let jbErc20PaymentTerminal = await jbErc20TerminalFactory + .connect(deployer) + .deploy( + fakeToken.address, + CURRENCY_USD, + CURRENCY_USD, + 1, + mockJbOperatorStore.address, + mockJbProjects.address, + mockJbDirectory.address, + mockJbSplitsStore.address, + mockJbPrices.address, + mockJBPaymentTerminalStore.address, + terminalOwner.address, + ); + + await mockJbEthPaymentTerminal.mock.decimals.returns(18); + + await mockJbProjects.mock.ownerOf.withArgs(PROJECT_ID).returns(projectOwner.address); + + // JBDAO + await mockJbDirectory.mock.isTerminalOf + .withArgs(1, jbEthPaymentTerminal.address) + .returns(true); + + await mockJbDirectory.mock.isTerminalOf + .withArgs(OTHER_PROJECT_ID, jbEthPaymentTerminal.address) + .returns(true); + + // Used with hardcoded one to get JBDao terminal + await mockJbDirectory.mock.primaryTerminalOf + .withArgs(1, ETH_ADDRESS) + .returns(jbEthPaymentTerminal.address); + + // ETH distribution + await mockJBPaymentTerminalStore.mock.recordDistributionFor + .withArgs(PROJECT_ID, AMOUNT_TO_DISTRIBUTE, CURRENCY) + .returns(fundingCycle, AMOUNT_DISTRIBUTED); + + // ERC20 distribution + await mockJBPaymentTerminalStore.mock.recordDistributionFor + .withArgs(PROJECT_ID, AMOUNT_TO_DISTRIBUTE, CURRENCY) + .returns(fundingCycle, AMOUNT_DISTRIBUTED); + + await mockJBPaymentTerminalStore.mock.recordAddedBalanceFor.returns(); + + // Mock the JBAllocator supports interface check + await mockJbAllocator.mock.supportsInterface.withArgs("0x01ffc9a7") + .returns(true); + await mockJbAllocator.mock.supportsInterface.withArgs("0x9d740bfa") + .returns(true); + await mockJbAllocator.mock.supportsInterface.withArgs("0xffffffff") + .returns(false); + + await setBalance(jbEthPaymentTerminal.address, AMOUNT_DISTRIBUTED); + + return { + deployer, + projectOwner, + terminalOwner, + caller, + beneficiaryOne, + beneficiaryTwo, + addrs, + jbEthPaymentTerminal, + jbErc20PaymentTerminal, + mockJbAllocator, + mockJbDirectory, + mockJbEthPaymentTerminal, + mockJBPaymentTerminalStore, + mockJbFeeGauge, + mockJbProjects, + mockJbSplitsStore, + timestamp, + CURRENCY_USD, + fakeToken, + }; + } + + it('Should distribute payout without fee when fee is set to 0 and emit event', async function () { + const { + projectOwner, + terminalOwner, + caller, + beneficiaryOne, + beneficiaryTwo, + jbEthPaymentTerminal, + timestamp, + mockJbSplitsStore, + } = await setup(); + const splits = makeSplits({ + count: 2, + beneficiary: [beneficiaryOne.address, beneficiaryTwo.address], + }); + + await jbEthPaymentTerminal.connect(terminalOwner).setFee(0); + + await mockJbSplitsStore.mock.splitsOf + .withArgs(PROJECT_ID, timestamp, ETH_PAYOUT_INDEX) + .returns(splits); + + let tx = await jbEthPaymentTerminal + .connect(caller) + .distributePayoutsOf( + PROJECT_ID, + AMOUNT_TO_DISTRIBUTE, + ETH_PAYOUT_INDEX, + ethers.constants.AddressZero, + MIN_TOKEN_REQUESTED, + METADATA, + ); + + await Promise.all( + splits.map(async (split) => { + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'DistributeToPayoutSplit') + .withArgs( + PROJECT_ID, + /*_fundingCycle.configuration*/ timestamp, + ETH_PAYOUT_INDEX, + [ + split.preferClaimed, + split.preferAddToBalance, + split.percent, + split.projectId, + split.beneficiary, + split.lockedUntil, + split.allocator, + ], + /*payoutAmount*/ Math.floor( + (AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT, + ), + /*netPayout*/ Math.floor((AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT), + caller.address, + ); + }), + ); + + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'DistributePayouts') + .withArgs( + timestamp, + /*_fundingCycle.number*/ 1, + PROJECT_ID, + projectOwner.address, + /*amount*/ AMOUNT_TO_DISTRIBUTE, + /*distributedAmount*/ AMOUNT_DISTRIBUTED, + /*_feeAmount*/ 0, + /*_leftoverDistributionAmount*/ 0, + METADATA, + caller.address, + ); + }); + + it('Should distribute payout and emit event, without fee if the beneficiary is another project within the same terminal', async function () { + const { + projectOwner, + caller, + beneficiaryOne, + beneficiaryTwo, + jbEthPaymentTerminal, + timestamp, + mockJbDirectory, + mockJBPaymentTerminalStore, + mockJbSplitsStore, + } = await setup(); + const splits = makeSplits({ + count: 2, + projectId: OTHER_PROJECT_ID, + beneficiary: [beneficiaryOne.address, beneficiaryTwo.address], + }); + + await mockJbDirectory.mock.primaryTerminalOf + .withArgs(OTHER_PROJECT_ID, ETH_ADDRESS) + .returns(jbEthPaymentTerminal.address); + + await mockJbSplitsStore.mock.splitsOf + .withArgs(PROJECT_ID, timestamp, ETH_PAYOUT_INDEX) + .returns(splits); + + await mockJBPaymentTerminalStore.mock.recordAddedBalanceFor.returns(); + + await Promise.all( + splits.map(async (split) => { + await mockJBPaymentTerminalStore.mock.recordPaymentFrom + .withArgs( + jbEthPaymentTerminal.address, + [ + /*token*/ '0x000000000000000000000000000000000000eeee', + /*amount paid*/ Math.floor( + (AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT, + ), + /*decimal*/ 18, + CURRENCY, + ], + split.projectId, + CURRENCY, + split.beneficiary, + '', + ethers.utils.hexZeroPad(ethers.utils.hexlify(PROJECT_ID), 32), + ) + .returns(fundingCycle, /*count*/ 0, /* delegateAllocation */[], ''); + }), + ); + + let tx = await jbEthPaymentTerminal + .connect(caller) + .distributePayoutsOf( + PROJECT_ID, + AMOUNT_TO_DISTRIBUTE, + ETH_PAYOUT_INDEX, + ethers.constants.AddressZero, + MIN_TOKEN_REQUESTED, + METADATA, + ); + + await Promise.all( + splits.map(async (split) => { + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'DistributeToPayoutSplit') + .withArgs( + PROJECT_ID, + /*_fundingCycle.configuration*/ timestamp, + ETH_PAYOUT_INDEX, + [ + split.preferClaimed, + split.preferAddToBalance, + split.percent, + split.projectId, + split.beneficiary, + split.lockedUntil, + split.allocator, + ], + /*payoutAmount*/ Math.floor( + (AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT, + ), + Math.floor((AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT), + caller.address, + ) + .and.to.emit(jbEthPaymentTerminal, 'Pay') + .withArgs( + timestamp, + 1, + split.projectId, + jbEthPaymentTerminal.address, + split.beneficiary, + Math.floor((AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT), + 0, + '', + ethers.utils.hexZeroPad(ethers.utils.hexlify(PROJECT_ID), 32), + jbEthPaymentTerminal.address, + ); + }), + ); + + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'DistributePayouts') + .withArgs( + /*_fundingCycle.configuration*/ timestamp, + /*_fundingCycle.number*/ 1, + PROJECT_ID, + projectOwner.address, + /*_amount*/ AMOUNT_TO_DISTRIBUTE, + /*_distributedAmount*/ AMOUNT_DISTRIBUTED, + /*_feeAmount*/ 0, + /*_leftoverDistributionAmount*/ 0, + METADATA, + caller.address, + ); + }); + + it("Should distribute payout and emit event, without fee if the platform project has not terminal for this terminal's token", async function () { + const { + projectOwner, + caller, + beneficiaryOne, + beneficiaryTwo, + jbEthPaymentTerminal, + timestamp, + mockJbDirectory, + mockJBPaymentTerminalStore, + mockJbSplitsStore, + } = await setup(); + const splits = makeSplits({ + count: 2, + projectId: OTHER_PROJECT_ID, + beneficiary: [beneficiaryOne.address, beneficiaryTwo.address], + }); + + await mockJbDirectory.mock.primaryTerminalOf + .withArgs(OTHER_PROJECT_ID, ETH_ADDRESS) + .returns(jbEthPaymentTerminal.address); + + await mockJbDirectory.mock.primaryTerminalOf + .withArgs(1, ETH_ADDRESS) + .returns(ethers.constants.AddressZero); + + await mockJbSplitsStore.mock.splitsOf + .withArgs(PROJECT_ID, timestamp, ETH_PAYOUT_INDEX) + .returns(splits); + + await Promise.all( + splits.map(async (split) => { + await mockJBPaymentTerminalStore.mock.recordPaymentFrom + .withArgs( + jbEthPaymentTerminal.address, + [ + /*token*/ '0x000000000000000000000000000000000000eeee', + /*amount paid*/ Math.floor( + (AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT, + ), + /*decimal*/ 18, + CURRENCY, + ], + split.projectId, + CURRENCY, + split.beneficiary, + '', + ethers.utils.hexZeroPad(ethers.utils.hexlify(PROJECT_ID), 32), + ) + .returns(fundingCycle, 0, /* delegateAllocation */[], ''); + }), + ); + + let tx = await jbEthPaymentTerminal + .connect(caller) + .distributePayoutsOf( + PROJECT_ID, + AMOUNT_TO_DISTRIBUTE, + ETH_PAYOUT_INDEX, + ethers.constants.AddressZero, + MIN_TOKEN_REQUESTED, + METADATA, + ); + + await Promise.all( + splits.map(async (split) => { + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'DistributeToPayoutSplit') + .withArgs( + PROJECT_ID, + /*_fundingCycle.configuration*/ timestamp, + ETH_PAYOUT_INDEX, + [ + split.preferClaimed, + split.preferAddToBalance, + split.percent, + split.projectId, + split.beneficiary, + split.lockedUntil, + split.allocator, + ], + /*payoutAmount*/ Math.floor( + (AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT, + ), + /*netAmount*/ Math.floor( + (AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT, + ), + caller.address, + ) + .and.to.emit(jbEthPaymentTerminal, 'Pay'); + // .withArgs( + // timestamp, + // 1, + // split.projectId, + // jbEthPaymentTerminal.address, + // split.beneficiary, + // Math.floor((AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT), + // 0, + // '', + // ethers.utils.hexZeroPad(ethers.utils.hexlify(PROJECT_ID), 32), + // caller.address, + // ); + }), + ); + + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'DistributePayouts') + .withArgs( + /*_fundingCycle.configuration*/ timestamp, + /*_fundingCycle.number*/ 1, + PROJECT_ID, + projectOwner.address, + /*_amount*/ AMOUNT_TO_DISTRIBUTE, + /*_distributedAmount*/ AMOUNT_DISTRIBUTED, + /*_feeAmount*/ 0, + /*_leftoverDistributionAmount*/ 0, + METADATA, + caller.address, + ); + }); + + it('Should distribute payout minus fee, hold the fee in the contract and emit event', async function () { + const { + projectOwner, + caller, + beneficiaryOne, + beneficiaryTwo, + jbEthPaymentTerminal, + timestamp, + mockJBPaymentTerminalStore, + mockJbSplitsStore, + } = await setup(); + const splits = makeSplits({ + count: 2, + beneficiary: [beneficiaryOne.address, beneficiaryTwo.address], + }); + + await mockJBPaymentTerminalStore.mock.recordDistributionFor + .withArgs(PROJECT_ID, AMOUNT_TO_DISTRIBUTE, CURRENCY) + .returns( + { + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: 0, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ holdFees: 1 }), + }, + AMOUNT_DISTRIBUTED, + ); + + await mockJbSplitsStore.mock.splitsOf + .withArgs(PROJECT_ID, timestamp, ETH_PAYOUT_INDEX) + .returns(splits); + + let tx = await jbEthPaymentTerminal + .connect(caller) + .distributePayoutsOf( + PROJECT_ID, + AMOUNT_TO_DISTRIBUTE, + ETH_PAYOUT_INDEX, + ethers.constants.AddressZero, + MIN_TOKEN_REQUESTED, + METADATA, + ); + + await Promise.all( + splits.map(async (split) => { + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'DistributeToPayoutSplit') + .withArgs( + PROJECT_ID, + /*_fundingCycle.configuration*/ timestamp, + ETH_PAYOUT_INDEX, + [ + split.preferClaimed, + split.preferAddToBalance, + split.percent, + split.projectId, + split.beneficiary, + split.lockedUntil, + split.allocator, + ], + /* Amount */ Math.floor((AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT), + /* NetAmount */ Math.floor((AMOUNT_MINUS_FEES * split.percent) / SPLITS_TOTAL_PERCENT), + caller.address, + ); + }), + ); + + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'DistributePayouts') + .withArgs( + /*_fundingCycle.configuration*/ timestamp, + 1, + PROJECT_ID, + projectOwner.address, + /*_amount*/ AMOUNT_TO_DISTRIBUTE, + /*_distributedAmount*/ AMOUNT_DISTRIBUTED, + /*_feeAmount*/ AMOUNT_DISTRIBUTED - AMOUNT_MINUS_FEES, + /*_leftoverDistributionAmount*/ 0, + METADATA, + caller.address, + ); + + expect(await jbEthPaymentTerminal.heldFeesOf(PROJECT_ID)).to.eql([ + [ + ethers.BigNumber.from(AMOUNT_DISTRIBUTED), + DEFAULT_FEE, + /*discount*/ 0, + projectOwner.address, + ], + ]); + }); + + it('Should distribute payout minus fee and pay the fee via Juicebox DAO terminal, if using another terminal', async function () { + const { + projectOwner, + caller, + beneficiaryOne, + beneficiaryTwo, + jbEthPaymentTerminal, + timestamp, + mockJbEthPaymentTerminal, + mockJBPaymentTerminalStore, + mockJbDirectory, + mockJbSplitsStore, + } = await setup(); + const splits = makeSplits({ + count: 2, + beneficiary: [beneficiaryOne.address, beneficiaryTwo.address], + }); + + await mockJbSplitsStore.mock.splitsOf + .withArgs(PROJECT_ID, timestamp, ETH_PAYOUT_INDEX) + .returns(splits); + + await mockJbDirectory.mock.primaryTerminalOf + .withArgs(1, ETH_ADDRESS) + .returns(mockJbEthPaymentTerminal.address); + + await mockJbEthPaymentTerminal.mock.pay + .withArgs( + 1, //JBX Dao + AMOUNT_DISTRIBUTED - AMOUNT_MINUS_FEES, + ETH_ADDRESS, + projectOwner.address, + 0, + /*preferedClaimedToken*/ false, + '', + ethers.utils.hexZeroPad(ethers.utils.hexlify(PROJECT_ID), 32), + ) + .returns(0); + + let tx = await jbEthPaymentTerminal + .connect(caller) + .distributePayoutsOf( + PROJECT_ID, + AMOUNT_TO_DISTRIBUTE, + ETH_PAYOUT_INDEX, + ethers.constants.AddressZero, + MIN_TOKEN_REQUESTED, + METADATA, + ); + + await Promise.all( + splits.map(async (split) => { + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'DistributeToPayoutSplit') + .withArgs( + PROJECT_ID, + /*_fundingCycle.configuration*/ timestamp, + ETH_PAYOUT_INDEX, + [ + split.preferClaimed, + split.preferAddToBalance, + split.percent, + split.projectId, + split.beneficiary, + split.lockedUntil, + split.allocator, + ], + /* Amount */ Math.floor((AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT), + /* NetAmount */ Math.floor((AMOUNT_MINUS_FEES * split.percent) / SPLITS_TOTAL_PERCENT), + caller.address, + ); + }), + ); + + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'DistributePayouts') + .withArgs( + /*_fundingCycle.configuration*/ timestamp, + /*_fundingCycle.number*/ 1, + PROJECT_ID, + projectOwner.address, + /*_amount*/ AMOUNT_TO_DISTRIBUTE, + /*_distributedAmount*/ AMOUNT_DISTRIBUTED, + /*_feeAmount*/ AMOUNT_DISTRIBUTED - AMOUNT_MINUS_FEES, + /*_leftoverDistributionAmount*/ 0, + METADATA, + caller.address, + ); + }); + + it('Should distribute payout without fee if distributing to a project in another terminal not subject to fees, using add to balance', async function () { + const { + projectOwner, + terminalOwner, + caller, + jbEthPaymentTerminal, + timestamp, + mockJbDirectory, + mockJbEthPaymentTerminal, + mockJbSplitsStore, + } = await setup(); + const splits = makeSplits({ count: 2, projectId: OTHER_PROJECT_ID, preferAddToBalance: true }); + + await mockJbDirectory.mock.primaryTerminalOf + .withArgs(OTHER_PROJECT_ID, ETH_ADDRESS) + .returns(mockJbEthPaymentTerminal.address); + + await mockJbSplitsStore.mock.splitsOf + .withArgs(PROJECT_ID, timestamp, ETH_PAYOUT_INDEX) + .returns(splits); + + await Promise.all( + splits.map(async (split) => { + // Since this function name is overloaded we need to specify the entire signature + await mockJbEthPaymentTerminal.mock["addToBalanceOf(uint256,uint256,address,string,bytes)"] + .withArgs( + split.projectId, + /*payoutAmount*/ Math.floor( + (AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT, + ), + ETH_ADDRESS, + '', + ethers.utils.hexZeroPad(ethers.utils.hexlify(PROJECT_ID), 32), + ) + .returns(); + }), + ); + + await jbEthPaymentTerminal + .connect(terminalOwner) + .setFeelessAddress(mockJbEthPaymentTerminal.address, true); + + let tx = await jbEthPaymentTerminal + .connect(caller) + .distributePayoutsOf( + PROJECT_ID, + AMOUNT_TO_DISTRIBUTE, + ETH_PAYOUT_INDEX, + ethers.constants.AddressZero, + MIN_TOKEN_REQUESTED, + METADATA, + ); + + await Promise.all( + splits.map(async (split) => { + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'DistributeToPayoutSplit') + .withArgs( + PROJECT_ID, + /*_fundingCycle.configuration*/ timestamp, + ETH_PAYOUT_INDEX, + [ + split.preferClaimed, + split.preferAddToBalance, + split.percent, + split.projectId, + split.beneficiary, + split.lockedUntil, + split.allocator, + ], + // Amount and NetAmount are the same since there is no fee being paid + /*Amount*/ Math.floor( + (AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT, + ), + /*NetAmount*/ Math.floor( + (AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT, + ), + caller.address, + ); + }), + ); + + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'DistributePayouts') + .withArgs( + /*_fundingCycle.configuration*/ timestamp, + /*_fundingCycle.number*/ 1, + PROJECT_ID, + projectOwner.address, + /*_amount*/ AMOUNT_TO_DISTRIBUTE, + /*_distributedAmount*/ AMOUNT_DISTRIBUTED, + /*_feeAmount*/ 0, + /*_leftoverDistributionAmount*/ 0, + METADATA, + caller.address, + ); + }); + + it('Should distribute payout without fee if distributing to a project in another terminal not subject to fees, using pay, with a beneficiary', async function () { + const { + projectOwner, + terminalOwner, + caller, + jbEthPaymentTerminal, + timestamp, + mockJbDirectory, + mockJbEthPaymentTerminal, + mockJbSplitsStore, + } = await setup(); + const beneficiaryOne = ethers.Wallet.createRandom(); + const beneficiaryTwo = ethers.Wallet.createRandom(); + + const splits = makeSplits({ + count: 2, + projectId: OTHER_PROJECT_ID, + preferAddToBalance: false, + beneficiary: [beneficiaryOne.address, beneficiaryTwo.address], + }); + + await mockJbDirectory.mock.primaryTerminalOf + .withArgs(OTHER_PROJECT_ID, ETH_ADDRESS) + .returns(mockJbEthPaymentTerminal.address); + + await mockJbSplitsStore.mock.splitsOf + .withArgs(PROJECT_ID, timestamp, ETH_PAYOUT_INDEX) + .returns(splits); + + await Promise.all( + splits.map(async (split) => { + await mockJbEthPaymentTerminal.mock.pay + .withArgs( + split.projectId, + /*payoutAmount*/ Math.floor( + (AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT, + ), + ETH_ADDRESS, + split.beneficiary, + 0, + split.preferClaimed, + '', + ethers.utils.hexZeroPad(ethers.utils.hexlify(PROJECT_ID), 32), + ) + .returns(0); + }), + ); + + await jbEthPaymentTerminal + .connect(terminalOwner) + .setFeelessAddress(mockJbEthPaymentTerminal.address, true); + + let tx = await jbEthPaymentTerminal + .connect(caller) + .distributePayoutsOf( + PROJECT_ID, + AMOUNT_TO_DISTRIBUTE, + ETH_PAYOUT_INDEX, + ethers.constants.AddressZero, + MIN_TOKEN_REQUESTED, + METADATA, + ); + + await Promise.all( + splits.map(async (split) => { + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'DistributeToPayoutSplit') + .withArgs( + PROJECT_ID, + /*_fundingCycle.configuration*/ timestamp, + ETH_PAYOUT_INDEX, + [ + split.preferClaimed, + split.preferAddToBalance, + split.percent, + split.projectId, + split.beneficiary, + split.lockedUntil, + split.allocator, + ], + /*Amount*/ Math.floor( + (AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT, + ), + /*NetAmount*/ Math.floor( + (AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT, + ), + caller.address, + ); + }), + ); + + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'DistributePayouts') + .withArgs( + /*_fundingCycle.configuration*/ timestamp, + /*_fundingCycle.number*/ 1, + PROJECT_ID, + projectOwner.address, + /*_amount*/ AMOUNT_TO_DISTRIBUTE, + /*_distributedAmount*/ AMOUNT_DISTRIBUTED, + /*_feeAmount*/ 0, + /*_leftoverDistributionAmount*/ 0, + METADATA, + caller.address, + ); + }); + + it('Should distribute payout without fee if distributing to a project in another terminal not subject to fees, using pay, with caller as default beneficiary', async function () { + const { + projectOwner, + terminalOwner, + caller, + jbEthPaymentTerminal, + timestamp, + mockJbDirectory, + mockJbEthPaymentTerminal, + mockJbSplitsStore, + } = await setup(); + + const splits = makeSplits({ count: 2, projectId: OTHER_PROJECT_ID, preferAddToBalance: false }); + + await mockJbDirectory.mock.primaryTerminalOf + .withArgs(OTHER_PROJECT_ID, ETH_ADDRESS) + .returns(mockJbEthPaymentTerminal.address); + + await mockJbSplitsStore.mock.splitsOf + .withArgs(PROJECT_ID, timestamp, ETH_PAYOUT_INDEX) + .returns(splits); + + await Promise.all( + splits.map(async (split) => { + await mockJbEthPaymentTerminal.mock.pay + .withArgs( + split.projectId, + /*payoutAmount*/ Math.floor( + (AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT, + ), + ETH_ADDRESS, + caller.address, + 0, + split.preferClaimed, + '', + ethers.utils.hexZeroPad(ethers.utils.hexlify(PROJECT_ID), 32), + ) + .returns(0); + }), + ); + + await jbEthPaymentTerminal + .connect(terminalOwner) + .setFeelessAddress(mockJbEthPaymentTerminal.address, true); + + let tx = await jbEthPaymentTerminal + .connect(caller) + .distributePayoutsOf( + PROJECT_ID, + AMOUNT_TO_DISTRIBUTE, + ETH_PAYOUT_INDEX, + ethers.constants.AddressZero, + MIN_TOKEN_REQUESTED, + METADATA, + ); + + await Promise.all( + splits.map(async (split) => { + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'DistributeToPayoutSplit') + .withArgs( + PROJECT_ID, + /*_fundingCycle.configuration*/ timestamp, + ETH_PAYOUT_INDEX, + [ + split.preferClaimed, + split.preferAddToBalance, + split.percent, + split.projectId, + split.beneficiary, + split.lockedUntil, + split.allocator, + ], + /*Amount*/ Math.floor( + (AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT, + ), + /*NetAmount*/ Math.floor( + (AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT, + ), + caller.address, + ); + }), + ); + + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'DistributePayouts') + .withArgs( + /*_fundingCycle.configuration*/ timestamp, + /*_fundingCycle.number*/ 1, + PROJECT_ID, + projectOwner.address, + /*_amount*/ AMOUNT_TO_DISTRIBUTE, + /*_distributedAmount*/ AMOUNT_DISTRIBUTED, + /*_feeAmount*/ 0, + /*_leftoverDistributionAmount*/ 0, + METADATA, + caller.address, + ); + }); + + it('Should distribute to projects in same terminal using pay if prefered', async function () { + const { + projectOwner, + caller, + beneficiaryOne, + beneficiaryTwo, + jbEthPaymentTerminal, + timestamp, + mockJbEthPaymentTerminal, + mockJbDirectory, + mockJbSplitsStore, + } = await setup(); + const splits = makeSplits({ + count: 2, + beneficiary: [beneficiaryOne.address, beneficiaryTwo.address], + preferAddToBalance: false, + }); + + await mockJbSplitsStore.mock.splitsOf + .withArgs(PROJECT_ID, timestamp, ETH_PAYOUT_INDEX) + .returns(splits); + + await mockJbDirectory.mock.primaryTerminalOf + .withArgs(1, ETH_ADDRESS) + .returns(mockJbEthPaymentTerminal.address); + + // Fee + await mockJbEthPaymentTerminal.mock.pay + .withArgs( + 1, //JBX Dao + AMOUNT_DISTRIBUTED - AMOUNT_MINUS_FEES, + ETH_ADDRESS, + projectOwner.address, + 0, + /*preferedClaimedToken*/ false, + '', + ethers.utils.hexZeroPad(ethers.utils.hexlify(PROJECT_ID), 32), + ) + .returns(0); + + let tx = await jbEthPaymentTerminal + .connect(caller) + .distributePayoutsOf( + PROJECT_ID, + AMOUNT_TO_DISTRIBUTE, + ETH_PAYOUT_INDEX, + ethers.constants.AddressZero, + MIN_TOKEN_REQUESTED, + METADATA, + ); + + await Promise.all( + splits.map(async (split) => { + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'DistributeToPayoutSplit') + .withArgs( + PROJECT_ID, + /*_fundingCycle.configuration*/ timestamp, + ETH_PAYOUT_INDEX, + [ + split.preferClaimed, + split.preferAddToBalance, + split.percent, + split.projectId, + split.beneficiary, + split.lockedUntil, + split.allocator, + ], + /*Amount*/ Math.floor( + (AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT, + ), + /*NetAmount*/ Math.floor((AMOUNT_MINUS_FEES * split.percent) / SPLITS_TOTAL_PERCENT), + caller.address, + ); + }), + ); + + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'DistributePayouts') + .withArgs( + /*_fundingCycle.configuration*/ timestamp, + /*_fundingCycle.number*/ 1, + PROJECT_ID, + projectOwner.address, + /*_amount*/ AMOUNT_TO_DISTRIBUTE, + /*_distributedAmount*/ AMOUNT_DISTRIBUTED, + /*_feeAmount*/ AMOUNT_DISTRIBUTED - AMOUNT_MINUS_FEES, + /*_leftoverDistributionAmount*/ 0, + METADATA, + caller.address, + ); + }); + + it('Should distribute to projects in same terminal using addToBalance if prefered', async function () { + const { + projectOwner, + caller, + beneficiaryOne, + beneficiaryTwo, + jbEthPaymentTerminal, + timestamp, + mockJbEthPaymentTerminal, + mockJbDirectory, + mockJbSplitsStore, + } = await setup(); + const splits = makeSplits({ + count: 2, + beneficiary: [beneficiaryOne.address, beneficiaryTwo.address], + preferAddToBalance: true, + }); + + await mockJbSplitsStore.mock.splitsOf + .withArgs(PROJECT_ID, timestamp, ETH_PAYOUT_INDEX) + .returns(splits); + + await mockJbDirectory.mock.primaryTerminalOf + .withArgs(1, ETH_ADDRESS) + .returns(mockJbEthPaymentTerminal.address); + + // Fee + await mockJbEthPaymentTerminal.mock.pay + .withArgs( + 1, //JBX Dao + AMOUNT_DISTRIBUTED - AMOUNT_MINUS_FEES, + ETH_ADDRESS, + projectOwner.address, + 0, + /*preferedClaimedToken*/ false, + '', + ethers.utils.hexZeroPad(ethers.utils.hexlify(PROJECT_ID), 32), + ) + .returns(0); + + await mockJbEthPaymentTerminal.mock["addToBalanceOf(uint256,uint256,address,string,bytes)"] + .withArgs( + 1, //JBX Dao + AMOUNT_DISTRIBUTED - AMOUNT_MINUS_FEES, + ETH_ADDRESS, + '', + '0x', + ) + .returns(); + + let tx = await jbEthPaymentTerminal + .connect(caller) + .distributePayoutsOf( + PROJECT_ID, + AMOUNT_TO_DISTRIBUTE, + ETH_PAYOUT_INDEX, + ethers.constants.AddressZero, + MIN_TOKEN_REQUESTED, + METADATA, + ); + + await Promise.all( + splits.map(async (split) => { + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'DistributeToPayoutSplit') + .withArgs( + PROJECT_ID, + /*_fundingCycle.configuration*/ timestamp, + ETH_PAYOUT_INDEX, + [ + split.preferClaimed, + split.preferAddToBalance, + split.percent, + split.projectId, + split.beneficiary, + split.lockedUntil, + split.allocator, + ], + /*Amount*/ Math.floor( + (AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT, + ), + /*NetAmount*/ Math.floor((AMOUNT_MINUS_FEES * split.percent) / SPLITS_TOTAL_PERCENT), + ///*payoutAmount*/ Math.floor((AMOUNT_MINUS_FEES * split.percent) / SPLITS_TOTAL_PERCENT), + caller.address, + ); + }), + ); + + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'DistributePayouts') + .withArgs( + /*_fundingCycle.configuration*/ timestamp, + /*_fundingCycle.number*/ 1, + PROJECT_ID, + projectOwner.address, + /*_amount*/ AMOUNT_TO_DISTRIBUTE, + /*_distributedAmount*/ AMOUNT_DISTRIBUTED, + /*_feeAmount*/ AMOUNT_DISTRIBUTED - AMOUNT_MINUS_FEES, + /*_leftoverDistributionAmount*/ 0, + METADATA, + caller.address, + ); + }); + + it('Should distribute payout minus fee and pay the fee via the same terminal, if using Juicebox DAO terminal', async function () { + const { + projectOwner, + caller, + beneficiaryOne, + beneficiaryTwo, + jbEthPaymentTerminal, + timestamp, + mockJBPaymentTerminalStore, + mockJbDirectory, + mockJbSplitsStore, + } = await setup(); + const AMOUNT_MINUS_FEES = Math.floor((AMOUNT_DISTRIBUTED * MAX_FEE) / (DEFAULT_FEE + MAX_FEE)); + const splits = makeSplits({ + count: 2, + beneficiary: [beneficiaryOne.address, beneficiaryTwo.address], + }); + + await mockJbSplitsStore.mock.splitsOf + .withArgs(PROJECT_ID, timestamp, ETH_PAYOUT_INDEX) + .returns(splits); + + await mockJbDirectory.mock.primaryTerminalOf + .withArgs(1, ETH_ADDRESS) + .returns(jbEthPaymentTerminal.address); + + await mockJBPaymentTerminalStore.mock.recordPaymentFrom + .withArgs( + jbEthPaymentTerminal.address, + [ + /*token*/ '0x000000000000000000000000000000000000eeee', + /*amount paid*/ AMOUNT_DISTRIBUTED - AMOUNT_MINUS_FEES, + /*decimal*/ 18, + CURRENCY, + ], + PLATFORM_PROJECT_ID, + /*CURRENCY*/ CURRENCY, + projectOwner.address, + '', + ethers.utils.hexZeroPad(ethers.utils.hexlify(PROJECT_ID), 32), + ) + .returns(fundingCycle, 0, /* delegateAllocation */[], ''); + + await Promise.all( + splits.map(async (split) => { + await mockJBPaymentTerminalStore.mock.recordPaymentFrom + .withArgs( + jbEthPaymentTerminal.address, + [ + /*token*/ '0x000000000000000000000000000000000000eeee', + /*amount paid*/ Math.floor( + (AMOUNT_MINUS_FEES * split.percent) / SPLITS_TOTAL_PERCENT, + ), + /*decimal*/ 18, + CURRENCY, + ], + split.projectId, + CURRENCY, + split.beneficiary, + '', + '0x', + ) + .returns(fundingCycle, 0, /* delegateAllocation */[], ''); + }), + ); + + let tx = await jbEthPaymentTerminal + .connect(caller) + .distributePayoutsOf( + PROJECT_ID, + AMOUNT_TO_DISTRIBUTE, + ETH_PAYOUT_INDEX, + ethers.constants.AddressZero, + MIN_TOKEN_REQUESTED, + METADATA, + ); + + await Promise.all( + splits.map(async (split) => { + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'DistributeToPayoutSplit') + // .withArgs( + // PROJECT_ID, + // /*_fundingCycle.configuration*/ timestamp, + // ETH_PAYOUT_INDEX, + // [ + // split.preferClaimed, + // split.preferAddToBalance, + // split.percent, + // split.projectId, + // split.beneficiary, + // split.lockedUntil, + // split.allocator, + // ], + // /*payoutAmount*/ Math.floor((AMOUNT_MINUS_FEES * split.percent) / SPLITS_TOTAL_PERCENT), + // caller.address, + // ) + .and.to.emit(jbEthPaymentTerminal, 'Pay') + .withArgs( + timestamp, + 1, + /*projectId*/ 1, + jbEthPaymentTerminal.address, + projectOwner.address, + Math.floor(AMOUNT_DISTRIBUTED - AMOUNT_MINUS_FEES), + 0, + '', + ethers.utils.hexZeroPad(ethers.utils.hexlify(PROJECT_ID), 32), + jbEthPaymentTerminal.address, + ); + }), + ); + + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'DistributePayouts') + .withArgs( + /*_fundingCycle.configuration*/ timestamp, + /*_fundingCycle.number*/ 1, + PROJECT_ID, + projectOwner.address, + /*_amount*/ AMOUNT_TO_DISTRIBUTE, + /*_distributedAmount*/ AMOUNT_DISTRIBUTED, + /*_feeAmount*/ AMOUNT_DISTRIBUTED - AMOUNT_MINUS_FEES, + /*_leftoverDistributionAmount*/ 0, + METADATA, + caller.address, + ); + }); + + it('Should distribute payout minus discounted fee if a fee gauge is set', async function () { + const { + projectOwner, + terminalOwner, + caller, + beneficiaryOne, + beneficiaryTwo, + jbEthPaymentTerminal, + timestamp, + mockJbDirectory, + mockJbEthPaymentTerminal, + mockJbFeeGauge, + mockJbSplitsStore, + } = await setup(); + + const DISCOUNTED_FEE = + DEFAULT_FEE - Math.floor((DEFAULT_FEE * FEE_DISCOUNT) / MAX_FEE_DISCOUNT); + const AMOUNT_MINUS_FEES = Math.floor( + (AMOUNT_DISTRIBUTED * MAX_FEE) / (MAX_FEE + DISCOUNTED_FEE), + ); + const FEE_AMOUNT = AMOUNT_DISTRIBUTED - AMOUNT_MINUS_FEES; + + const splits = makeSplits({ + count: 2, + beneficiary: [beneficiaryOne.address, beneficiaryTwo.address], + }); + + await jbEthPaymentTerminal.connect(terminalOwner).setFeeGauge(mockJbFeeGauge.address); + + await mockJbFeeGauge.mock.currentDiscountFor.withArgs(PROJECT_ID, 0).returns(FEE_DISCOUNT); + + await mockJbSplitsStore.mock.splitsOf + .withArgs(PROJECT_ID, timestamp, ETH_PAYOUT_INDEX) + .returns(splits); + + await mockJbDirectory.mock.primaryTerminalOf + .withArgs(1, ETH_ADDRESS) + .returns(mockJbEthPaymentTerminal.address); + + await mockJbEthPaymentTerminal.mock.pay + .withArgs( + 1, //JBX Dao + FEE_AMOUNT, + ETH_ADDRESS, + projectOwner.address, + 0, + false, + '', + ethers.utils.hexZeroPad(ethers.utils.hexlify(PROJECT_ID), 32), + ) + .returns(0); + + await Promise.all( + splits.map(async (split) => { + await mockJbEthPaymentTerminal.mock.pay + .withArgs( + split.projectId, //JBX Dao + /*payoutAmount*/ Math.floor((AMOUNT_MINUS_FEES * split.percent) / SPLITS_TOTAL_PERCENT), + ETH_ADDRESS, + split.beneficiary, + 0, + split.preferClaimed, + '', + '0x', + ) + .returns(0); + }), + ); + + let tx = await jbEthPaymentTerminal + .connect(caller) + .distributePayoutsOf( + PROJECT_ID, + AMOUNT_TO_DISTRIBUTE, + ETH_PAYOUT_INDEX, + ethers.constants.AddressZero, + MIN_TOKEN_REQUESTED, + METADATA, + ); + + await Promise.all( + splits.map(async (split) => { + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'DistributeToPayoutSplit') + .withArgs( + PROJECT_ID, + /*_fundingCycle.configuration*/ timestamp, + ETH_PAYOUT_INDEX, + [ + split.preferClaimed, + split.preferAddToBalance, + split.percent, + split.projectId, + split.beneficiary, + split.lockedUntil, + split.allocator, + ], + /*Amount*/ Math.floor( + (AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT, + ), + /*NetAmount*/ Math.floor((AMOUNT_MINUS_FEES * split.percent) / SPLITS_TOTAL_PERCENT), + caller.address, + ); + }), + ); + + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'DistributePayouts') + .withArgs( + /*_fundingCycle.configuration*/ timestamp, + /*_fundingCycle.number*/ 1, + PROJECT_ID, + projectOwner.address, + /*_amount*/ AMOUNT_TO_DISTRIBUTE, + /*_distributedAmount*/ AMOUNT_DISTRIBUTED, + /*_feeAmount*/ FEE_AMOUNT, + /*_leftoverDistributionAmount*/ 0, + METADATA, + caller.address, + ); + }); + + it('Should distribute payout minus non-discounted fee if the fee gauge is faulty', async function () { + const { + projectOwner, + terminalOwner, + caller, + beneficiaryOne, + beneficiaryTwo, + jbEthPaymentTerminal, + timestamp, + mockJbDirectory, + mockJbEthPaymentTerminal, + mockJbFeeGauge, + mockJbSplitsStore, + } = await setup(); + + const AMOUNT_MINUS_FEES = Math.floor((AMOUNT_DISTRIBUTED * MAX_FEE) / (MAX_FEE + DEFAULT_FEE)); + + const splits = makeSplits({ + count: 2, + beneficiary: [beneficiaryOne.address, beneficiaryTwo.address], + }); + + await jbEthPaymentTerminal.connect(terminalOwner).setFeeGauge(mockJbFeeGauge.address); + + await mockJbFeeGauge.mock.currentDiscountFor.withArgs(PROJECT_ID, 0).reverts(); + + await mockJbSplitsStore.mock.splitsOf + .withArgs(PROJECT_ID, timestamp, ETH_PAYOUT_INDEX) + .returns(splits); + + await mockJbDirectory.mock.primaryTerminalOf + .withArgs(1, ETH_ADDRESS) + .returns(mockJbEthPaymentTerminal.address); + + await mockJbEthPaymentTerminal.mock.pay + .withArgs( + 1, //JBX Dao + AMOUNT_DISTRIBUTED - AMOUNT_MINUS_FEES, // 0 if fee is in ETH (as the amount is then in msg.value) + ETH_ADDRESS, + projectOwner.address, + 0, + false, + '', + ethers.utils.hexZeroPad(ethers.utils.hexlify(PROJECT_ID), 32), + ) + .returns(0); + + await Promise.all( + splits.map(async (split) => { + await mockJbEthPaymentTerminal.mock.pay + .withArgs( + 1, //JBX Dao + /*payoutAmount*/ Math.floor((AMOUNT_MINUS_FEES * split.percent) / SPLITS_TOTAL_PERCENT), + ETH_ADDRESS, + split.beneficiary, + 0, + split.preferClaimed, + '', + '0x', + ) + .returns(0); + }), + ); + + let tx = await jbEthPaymentTerminal + .connect(caller) + .distributePayoutsOf( + PROJECT_ID, + AMOUNT_TO_DISTRIBUTE, + ETH_PAYOUT_INDEX, + ethers.constants.AddressZero, + MIN_TOKEN_REQUESTED, + METADATA, + ); + + await Promise.all( + splits.map(async (split) => { + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'DistributeToPayoutSplit') + .withArgs( + PROJECT_ID, + /*_fundingCycle.configuration*/ timestamp, + ETH_PAYOUT_INDEX, + [ + split.preferClaimed, + split.preferAddToBalance, + split.percent, + split.projectId, + split.beneficiary, + split.lockedUntil, + split.allocator, + ], + /*Amount*/ Math.floor( + (AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT, + ), + /*NetAmount*/ Math.floor((AMOUNT_MINUS_FEES * split.percent) / SPLITS_TOTAL_PERCENT), + caller.address, + ); + }), + ); + + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'DistributePayouts') + .withArgs( + /*_fundingCycle.configuration*/ timestamp, + /*_fundingCycle.number*/ 1, + PROJECT_ID, + projectOwner.address, + /*_amount*/ AMOUNT_TO_DISTRIBUTE, + /*_distributedAmount*/ AMOUNT_DISTRIBUTED, + /*_feeAmount*/ AMOUNT_DISTRIBUTED - AMOUNT_MINUS_FEES, + /*_leftoverDistributionAmount*/ 0, + METADATA, + caller.address, + ); + }); + + it('Should distribute payout minus non-discounted fee if the discount is above 100%', async function () { + const { + projectOwner, + terminalOwner, + caller, + beneficiaryOne, + beneficiaryTwo, + jbEthPaymentTerminal, + timestamp, + mockJbDirectory, + mockJbEthPaymentTerminal, + mockJbFeeGauge, + mockJbSplitsStore, + } = await setup(); + + const AMOUNT_MINUS_FEES = Math.floor((AMOUNT_DISTRIBUTED * MAX_FEE) / (MAX_FEE + DEFAULT_FEE)); + + const splits = makeSplits({ + count: 2, + beneficiary: [beneficiaryOne.address, beneficiaryTwo.address], + }); + + await jbEthPaymentTerminal.connect(terminalOwner).setFeeGauge(mockJbFeeGauge.address); + + await mockJbFeeGauge.mock.currentDiscountFor.withArgs(PROJECT_ID, 0).returns(MAX_FEE_DISCOUNT + 1); + + await mockJbSplitsStore.mock.splitsOf + .withArgs(PROJECT_ID, timestamp, ETH_PAYOUT_INDEX) + .returns(splits); + + await mockJbDirectory.mock.primaryTerminalOf + .withArgs(1, ETH_ADDRESS) + .returns(mockJbEthPaymentTerminal.address); + + await mockJbEthPaymentTerminal.mock.pay + .withArgs( + 1, //JBX Dao + AMOUNT_DISTRIBUTED - AMOUNT_MINUS_FEES, // 0 if fee is in ETH (as the amount is then in msg.value) + ETH_ADDRESS, + projectOwner.address, + 0, + false, + '', + ethers.utils.hexZeroPad(ethers.utils.hexlify(PROJECT_ID), 32), + ) + .returns(0); + + await Promise.all( + splits.map(async (split) => { + await mockJbEthPaymentTerminal.mock.pay + .withArgs( + 1, //JBX Dao + /*payoutAmount*/ Math.floor((AMOUNT_MINUS_FEES * split.percent) / SPLITS_TOTAL_PERCENT), + ETH_ADDRESS, + split.beneficiary, + 0, + split.preferClaimed, + '', + '0x', + ) + .returns(0); + }), + ); + + let tx = await jbEthPaymentTerminal + .connect(caller) + .distributePayoutsOf( + PROJECT_ID, + AMOUNT_TO_DISTRIBUTE, + ETH_PAYOUT_INDEX, + ethers.constants.AddressZero, + MIN_TOKEN_REQUESTED, + METADATA, + ); + + await Promise.all( + splits.map(async (split) => { + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'DistributeToPayoutSplit') + .withArgs( + PROJECT_ID, + /*_fundingCycle.configuration*/ timestamp, + ETH_PAYOUT_INDEX, + [ + split.preferClaimed, + split.preferAddToBalance, + split.percent, + split.projectId, + split.beneficiary, + split.lockedUntil, + split.allocator, + ], + /*Amount*/ Math.floor( + (AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT, + ), + /*NetAmount*/ Math.floor((AMOUNT_MINUS_FEES * split.percent) / SPLITS_TOTAL_PERCENT), + caller.address, + ); + }), + ); + + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'DistributePayouts') + .withArgs( + /*_fundingCycle.configuration*/ timestamp, + /*_fundingCycle.number*/ 1, + PROJECT_ID, + projectOwner.address, + /*_amount*/ AMOUNT_TO_DISTRIBUTE, + /*_distributedAmount*/ AMOUNT_DISTRIBUTED, + /*_feeAmount*/ AMOUNT_DISTRIBUTED - AMOUNT_MINUS_FEES, + /*_leftoverDistributionAmount*/ 0, + METADATA, + caller.address, + ); + }); + + it('Should distribute payout and use the allocator if set in splits', async function () { + const { + projectOwner, + terminalOwner, + caller, + jbEthPaymentTerminal, + timestamp, + mockJbAllocator, + mockJbSplitsStore, + } = await setup(); + const splits = makeSplits({ count: 2, allocator: mockJbAllocator.address }); + + await jbEthPaymentTerminal.connect(terminalOwner).setFee(0); + + await mockJbSplitsStore.mock.splitsOf + .withArgs(PROJECT_ID, timestamp, ETH_PAYOUT_INDEX) + .returns(splits); + + await Promise.all( + splits.map(async (split) => { + await mockJbAllocator.mock.allocate + .withArgs({ + // JBSplitAllocationData + token: ETH_ADDRESS, + amount: Math.floor((AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT), + decimals: 18, + projectId: PROJECT_ID, + group: ETH_PAYOUT_INDEX, + split, + }) + .returns(); + }), + ); + + let tx = await jbEthPaymentTerminal + .connect(caller) + .distributePayoutsOf( + PROJECT_ID, + AMOUNT_TO_DISTRIBUTE, + ETH_PAYOUT_INDEX, + ethers.constants.AddressZero, + MIN_TOKEN_REQUESTED, + METADATA, + ); + + await Promise.all( + splits.map(async (split) => { + // NetAmount and Amount are the same since the fee was set to 0 + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'DistributeToPayoutSplit') + .withArgs( + PROJECT_ID, + /*_fundingCycle.configuration*/ timestamp, + ETH_PAYOUT_INDEX, + [ + split.preferClaimed, + split.preferAddToBalance, + split.percent, + split.projectId, + split.beneficiary, + split.lockedUntil, + split.allocator, + ], + /*Amount*/ Math.floor( + (AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT, + ), + /*NetAmount*/ Math.floor((AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT), + caller.address, + ); + }), + ); + + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'DistributePayouts') + .withArgs( + /*_fundingCycle.configuration*/ timestamp, + /*_fundingCycle.number*/ 1, + PROJECT_ID, + projectOwner.address, + /*_amount*/ AMOUNT_TO_DISTRIBUTE, + /*_distributedAmount*/ AMOUNT_DISTRIBUTED, + /*_feeAmount*/ 0, + /*_leftoverDistributionAmount*/ 0, + METADATA, + caller.address, + ); + }); + + it('Should distribute payout and use the allocator if set in splits, using a fee discount', async function () { + const { + projectOwner, + terminalOwner, + caller, + jbEthPaymentTerminal, + timestamp, + mockJbAllocator, + mockJbFeeGauge, + mockJBPaymentTerminalStore, + mockJbSplitsStore, + } = await setup(); + + const DISCOUNTED_FEE = + DEFAULT_FEE - Math.floor((DEFAULT_FEE * FEE_DISCOUNT) / MAX_FEE_DISCOUNT); + + const FEE_AMOUNT = + AMOUNT_DISTRIBUTED - Math.floor((AMOUNT_DISTRIBUTED * MAX_FEE) / (DISCOUNTED_FEE + MAX_FEE)); + + const AMOUNT_MINUS_FEES = AMOUNT_DISTRIBUTED - FEE_AMOUNT; + + const splits = makeSplits({ count: 1, allocator: mockJbAllocator.address }); + + fundingCycle = { + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: 0, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ holdFees: true }), + }; + + await mockJBPaymentTerminalStore.mock.recordDistributionFor + .withArgs(PROJECT_ID, AMOUNT_TO_DISTRIBUTE, CURRENCY) + .returns(fundingCycle, AMOUNT_DISTRIBUTED); + + await jbEthPaymentTerminal.connect(terminalOwner).setFeeGauge(mockJbFeeGauge.address); + + await mockJbFeeGauge.mock.currentDiscountFor.withArgs(PROJECT_ID, 0).returns(FEE_DISCOUNT); + + await mockJbSplitsStore.mock.splitsOf + .withArgs(PROJECT_ID, timestamp, ETH_PAYOUT_INDEX) + .returns(splits); + + await Promise.all( + splits.map(async (split) => { + await mockJbAllocator.mock.allocate + .withArgs({ + // JBSplitAllocationData + token: ETH_ADDRESS, + amount: AMOUNT_MINUS_FEES, // One split + decimals: 18, + projectId: PROJECT_ID, + group: ETH_PAYOUT_INDEX, + split, + }) + .returns(); + }), + ); + + let tx = await jbEthPaymentTerminal + .connect(caller) + .distributePayoutsOf( + PROJECT_ID, + AMOUNT_TO_DISTRIBUTE, + ETH_PAYOUT_INDEX, + ethers.constants.AddressZero, + MIN_TOKEN_REQUESTED, + METADATA, + ); + + await Promise.all( + splits.map(async (split) => { + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'DistributeToPayoutSplit') + .withArgs( + PROJECT_ID, + /*_fundingCycle.configuration*/ timestamp, + ETH_PAYOUT_INDEX, + [ + split.preferClaimed, + split.preferAddToBalance, + split.percent, + split.projectId, + split.beneficiary, + split.lockedUntil, + split.allocator, + ], + /*Amount*/ Math.floor( + (AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT, + ), + /*NetAmount*/ Math.floor((AMOUNT_MINUS_FEES * split.percent) / SPLITS_TOTAL_PERCENT), + caller.address, + ); + }), + ); + + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'DistributePayouts') + .withArgs( + /*_fundingCycle.configuration*/ timestamp, + /*_fundingCycle.number*/ 1, + PROJECT_ID, + projectOwner.address, + /*_amount*/ AMOUNT_TO_DISTRIBUTE, + /*_distributedAmount*/ AMOUNT_DISTRIBUTED, + /*_feeAmount*/ FEE_AMOUNT, + /*_leftoverDistributionAmount*/ 0, + METADATA, + caller.address, + ); + }); + + it('Should distribute payout and use the allocator if set in splits without fee if the allocator is feeless', async function () { + const { + projectOwner, + terminalOwner, + caller, + jbEthPaymentTerminal, + timestamp, + mockJbAllocator, + mockJbFeeGauge, + mockJBPaymentTerminalStore, + mockJbSplitsStore, + } = await setup(); + + const splits = makeSplits({ count: 1, allocator: mockJbAllocator.address }); + + fundingCycle = { + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: 0, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ holdFees: true }), + }; + + await mockJBPaymentTerminalStore.mock.recordDistributionFor + .withArgs(PROJECT_ID, AMOUNT_TO_DISTRIBUTE, CURRENCY) + .returns(fundingCycle, AMOUNT_DISTRIBUTED); + + await jbEthPaymentTerminal + .connect(terminalOwner) + .setFeelessAddress(mockJbAllocator.address, true); + + //await mockJbFeeGauge.mock.currentDiscountFor.withArgs(PROJECT_ID).returns(FEE_DISCOUNT); + + await mockJbSplitsStore.mock.splitsOf + .withArgs(PROJECT_ID, timestamp, ETH_PAYOUT_INDEX) + .returns(splits); + + await Promise.all( + splits.map(async (split) => { + await mockJbAllocator.mock.allocate + .withArgs({ + // JBSplitAllocationData + token: ETH_ADDRESS, + amount: AMOUNT_DISTRIBUTED, // One split + decimals: 18, + projectId: PROJECT_ID, + group: ETH_PAYOUT_INDEX, + split, + }) + .returns(); + }), + ); + + let tx = await jbEthPaymentTerminal + .connect(caller) + .distributePayoutsOf( + PROJECT_ID, + AMOUNT_TO_DISTRIBUTE, + ETH_PAYOUT_INDEX, + ethers.constants.AddressZero, + MIN_TOKEN_REQUESTED, + METADATA, + ); + + await Promise.all( + splits.map(async (split) => { + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'DistributeToPayoutSplit') + .withArgs( + PROJECT_ID, + /*_fundingCycle.configuration*/ timestamp, + ETH_PAYOUT_INDEX, + [ + split.preferClaimed, + split.preferAddToBalance, + split.percent, + split.projectId, + split.beneficiary, + split.lockedUntil, + split.allocator, + ], + AMOUNT_DISTRIBUTED, + AMOUNT_DISTRIBUTED, + caller.address, + ); + }), + ); + + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'DistributePayouts') + .withArgs( + /*_fundingCycle.configuration*/ timestamp, + /*_fundingCycle.number*/ 1, + PROJECT_ID, + projectOwner.address, + /*_amount*/ AMOUNT_TO_DISTRIBUTE, + /*_distributedAmount*/ AMOUNT_DISTRIBUTED, + /*_feeAmount*/ 0, + /*_leftoverDistributionAmount*/ 0, + METADATA, + caller.address, + ); + }); + + it('Should distribute payout and use the allocator if set in splits, using a non-eth token', async function () { + const { + projectOwner, + terminalOwner, + caller, + jbErc20PaymentTerminal, + timestamp, + mockJbAllocator, + mockJbSplitsStore, + fakeToken, + } = await setup(); + const splits = makeSplits({ count: 2, allocator: mockJbAllocator.address }); + + await jbErc20PaymentTerminal.connect(terminalOwner).setFee(0); + + await mockJbSplitsStore.mock.splitsOf + .withArgs(PROJECT_ID, timestamp, ETH_PAYOUT_INDEX) + .returns(splits); + + await Promise.all( + splits.map(async (split) => { + await fakeToken.mock.allowance + .withArgs(jbErc20PaymentTerminal.address, mockJbAllocator.address) + .returns(0); + + await fakeToken.mock.approve + .withArgs( + mockJbAllocator.address, + Math.floor((AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT), + ) + .returns(true); + + await mockJbAllocator.mock.allocate + .withArgs({ + // JBSplitAllocationData + token: fakeToken.address, + amount: Math.floor((AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT), + decimals: 18, + projectId: PROJECT_ID, + group: ETH_PAYOUT_INDEX, + split, + }) + .returns(); + }), + ); + + let tx = await jbErc20PaymentTerminal + .connect(caller) + .distributePayoutsOf( + PROJECT_ID, + AMOUNT_TO_DISTRIBUTE, + ETH_PAYOUT_INDEX, + ethers.constants.AddressZero, + MIN_TOKEN_REQUESTED, + METADATA, + ); + + await Promise.all( + splits.map(async (split) => { + await expect(tx) + .to.emit(jbErc20PaymentTerminal, 'DistributeToPayoutSplit') + .withArgs( + PROJECT_ID, + /*_fundingCycle.configuration*/ timestamp, + ETH_PAYOUT_INDEX, + [ + split.preferClaimed, + split.preferAddToBalance, + split.percent, + split.projectId, + split.beneficiary, + split.lockedUntil, + split.allocator, + ], + /*Amount*/ Math.floor( + (AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT, + ), + /*NetAmount*/ Math.floor((AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT), + caller.address, + ); + }), + ); + + await expect(tx) + .to.emit(jbErc20PaymentTerminal, 'DistributePayouts') + .withArgs( + /*_fundingCycle.configuration*/ timestamp, + /*_fundingCycle.number*/ 1, + PROJECT_ID, + projectOwner.address, + /*_amount*/ AMOUNT_TO_DISTRIBUTE, + /*_distributedAmount*/ AMOUNT_DISTRIBUTED, + /*_feeAmount*/ 0, + /*_leftoverDistributionAmount*/ 0, + METADATA, + caller.address, + ); + }); + + it('Should distribute payout to the caller if no beneficiary, allocator or project id is set in split', async function () { + const { + projectOwner, + terminalOwner, + caller, + jbEthPaymentTerminal, + timestamp, + mockJbSplitsStore, + } = await setup(); + const splits = makeSplits({ + count: 2, + }); + + await jbEthPaymentTerminal.connect(terminalOwner).setFee(0); + + await mockJbSplitsStore.mock.splitsOf + .withArgs(PROJECT_ID, timestamp, ETH_PAYOUT_INDEX) + .returns(splits); + + let tx = await jbEthPaymentTerminal + .connect(caller) + .distributePayoutsOf( + PROJECT_ID, + AMOUNT_TO_DISTRIBUTE, + ETH_PAYOUT_INDEX, + ethers.constants.AddressZero, + MIN_TOKEN_REQUESTED, + METADATA, + ); + + await Promise.all( + splits.map(async (split) => { + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'DistributeToPayoutSplit') + .withArgs( + PROJECT_ID, + /*_fundingCycle.configuration*/ timestamp, + ETH_PAYOUT_INDEX, + [ + split.preferClaimed, + split.preferAddToBalance, + split.percent, + split.projectId, + split.beneficiary, + split.lockedUntil, + split.allocator, + ], + /*Amount*/ Math.floor( + (AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT, + ), + /*NetAmount*/ Math.floor( + (AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT, + ), + caller.address, + ); + }), + ); + + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'DistributePayouts') + .withArgs( + timestamp, + /*_fundingCycle.number*/ 1, + PROJECT_ID, + projectOwner.address, + /*amount*/ AMOUNT_TO_DISTRIBUTE, + /*distributedAmount*/ AMOUNT_DISTRIBUTED, + /*_feeAmount*/ 0, + /*_leftoverDistributionAmount*/ 0, + METADATA, + caller.address, + ); + + await expect(tx).to.changeEtherBalance(caller, AMOUNT_DISTRIBUTED); + }); + + it('Should distribute payout and use the terminal of the project if project id and beneficiary are set in splits', async function () { + const { + projectOwner, + terminalOwner, + caller, + jbEthPaymentTerminal, + timestamp, + mockJbDirectory, + mockJbEthPaymentTerminal, + mockJbSplitsStore, + beneficiaryOne, + } = await setup(); + const splits = makeSplits({ + count: 2, + projectId: OTHER_PROJECT_ID, + beneficiary: [beneficiaryOne.address, beneficiaryOne.address], + }); + + await jbEthPaymentTerminal.connect(terminalOwner).setFee(0); + + await mockJbDirectory.mock.primaryTerminalOf + .withArgs(OTHER_PROJECT_ID, ETH_ADDRESS) + .returns(mockJbEthPaymentTerminal.address); + + await mockJbSplitsStore.mock.splitsOf + .withArgs(PROJECT_ID, timestamp, ETH_PAYOUT_INDEX) + .returns(splits); + + await Promise.all( + splits.map(async (split) => { + await mockJbEthPaymentTerminal.mock.pay + .withArgs( + split.projectId, + /*payoutAmount*/ Math.floor( + (AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT, + ), + ETH_ADDRESS, + split.beneficiary, + /*minReturnedToken*/ 0, + split.preferClaimed, + '', + ethers.utils.hexZeroPad(ethers.utils.hexlify(PROJECT_ID), 32), + ) + .returns(0); + }), + ); + + let tx = await jbEthPaymentTerminal + .connect(caller) + .distributePayoutsOf( + PROJECT_ID, + AMOUNT_TO_DISTRIBUTE, + ETH_PAYOUT_INDEX, + ethers.constants.AddressZero, + MIN_TOKEN_REQUESTED, + METADATA, + ); + + await Promise.all( + splits.map(async (split) => { + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'DistributeToPayoutSplit') + .withArgs( + PROJECT_ID, + /*_fundingCycle.configuration*/ timestamp, + ETH_PAYOUT_INDEX, + [ + split.preferClaimed, + split.preferAddToBalance, + split.percent, + split.projectId, + split.beneficiary, + split.lockedUntil, + split.allocator, + ], + /*Amount*/ Math.floor( + (AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT, + ), + /*NetAmount*/ Math.floor( + (AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT, + ), + caller.address, + ); + }), + ); + + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'DistributePayouts') + .withArgs( + /*_fundingCycle.configuration*/ timestamp, + /*_fundingCycle.number*/ 1, + PROJECT_ID, + projectOwner.address, + /*_amount*/ AMOUNT_TO_DISTRIBUTE, + /*_distributedAmount*/ AMOUNT_DISTRIBUTED, + /*_feeAmount*/ 0, + /*_leftoverDistributionAmount*/ 0, + METADATA, + caller.address, + ); + }); + + it('Should distribute payout using a fee discount and use the terminal of the project if project id is set in splits', async function () { + const { + projectOwner, + terminalOwner, + caller, + jbEthPaymentTerminal, + timestamp, + mockJbDirectory, + mockJbEthPaymentTerminal, + mockJbFeeGauge, + mockJbSplitsStore, + mockJBPaymentTerminalStore, + } = await setup(); + const DISCOUNTED_FEE = + DEFAULT_FEE - Math.floor((DEFAULT_FEE * FEE_DISCOUNT) / MAX_FEE_DISCOUNT); + + const FEE_AMOUNT = + AMOUNT_DISTRIBUTED - Math.floor((AMOUNT_DISTRIBUTED * MAX_FEE) / (DISCOUNTED_FEE + MAX_FEE)); + + const AMOUNT_MINUS_FEES = AMOUNT_DISTRIBUTED - FEE_AMOUNT; + + await jbEthPaymentTerminal.connect(terminalOwner).setFeeGauge(mockJbFeeGauge.address); + + await mockJbFeeGauge.mock.currentDiscountFor.withArgs(PROJECT_ID, 0).returns(FEE_DISCOUNT); + + const splits = makeSplits({ count: 1, projectId: OTHER_PROJECT_ID, preferAddToBalance: true }); + + await mockJbDirectory.mock.primaryTerminalOf + .withArgs(OTHER_PROJECT_ID, ETH_ADDRESS) + .returns(mockJbEthPaymentTerminal.address); + + await mockJbSplitsStore.mock.splitsOf + .withArgs(PROJECT_ID, timestamp, ETH_PAYOUT_INDEX) + .returns(splits); + + fundingCycle = { + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: 0, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ holdFees: true }), + }; + + await mockJBPaymentTerminalStore.mock.recordDistributionFor + .withArgs(PROJECT_ID, AMOUNT_TO_DISTRIBUTE, CURRENCY) + .returns(fundingCycle, AMOUNT_DISTRIBUTED); + + await Promise.all( + splits.map(async (split) => { + await mockJbEthPaymentTerminal.mock["addToBalanceOf(uint256,uint256,address,string,bytes)"] + .withArgs( + split.projectId, + AMOUNT_MINUS_FEES, + ETH_ADDRESS, + '', + ethers.utils.hexZeroPad(ethers.utils.hexlify(PROJECT_ID), 32), + ) + .returns(); + }), + ); + + let tx = await jbEthPaymentTerminal + .connect(caller) + .distributePayoutsOf( + PROJECT_ID, + AMOUNT_TO_DISTRIBUTE, + ETH_PAYOUT_INDEX, + ethers.constants.AddressZero, + MIN_TOKEN_REQUESTED, + METADATA, + ); + + await Promise.all( + splits.map(async (split) => { + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'DistributeToPayoutSplit') + .withArgs( + PROJECT_ID, + /*_fundingCycle.configuration*/ timestamp, + ETH_PAYOUT_INDEX, + [ + split.preferClaimed, + split.preferAddToBalance, + split.percent, + split.projectId, + split.beneficiary, + split.lockedUntil, + split.allocator, + ], + /*Amount*/ Math.floor( + (AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT, + ), + /*NetAmount*/ Math.floor((AMOUNT_MINUS_FEES * split.percent) / SPLITS_TOTAL_PERCENT), + caller.address, + ); + }), + ); + + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'DistributePayouts') + .withArgs( + /*_fundingCycle.configuration*/ timestamp, + /*_fundingCycle.number*/ 1, + PROJECT_ID, + projectOwner.address, + /*_amount*/ AMOUNT_TO_DISTRIBUTE, + /*_distributedAmount*/ AMOUNT_DISTRIBUTED, + /*_feeAmount*/ FEE_AMOUNT, + /*_leftoverDistributionAmount*/ 0, + METADATA, + caller.address, + ); + }); + + it('Should distribute payout and use the terminal of the project if project id is set in splits, for non-eth token', async function () { + const { + projectOwner, + caller, + jbErc20PaymentTerminal, + timestamp, + mockJbDirectory, + mockJbEthPaymentTerminal, + mockJBPaymentTerminalStore, + mockJbSplitsStore, + fakeToken, + CURRENCY_USD, + } = await setup(); + + const FEE_AMOUNT = + AMOUNT_DISTRIBUTED - Math.floor((AMOUNT_DISTRIBUTED * MAX_FEE) / (DEFAULT_FEE + MAX_FEE)); + + const AMOUNT_MINUS_FEES = AMOUNT_DISTRIBUTED - FEE_AMOUNT; + + const splits = makeSplits({ count: 2, projectId: OTHER_PROJECT_ID, preferAddToBalance: true }); + + fundingCycle = { + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: 0, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata(), + }; + + await mockJBPaymentTerminalStore.mock.recordDistributionFor + .withArgs(PROJECT_ID, AMOUNT_TO_DISTRIBUTE, CURRENCY) + .returns(fundingCycle, AMOUNT_DISTRIBUTED); + + await mockJbDirectory.mock.primaryTerminalOf + .withArgs(OTHER_PROJECT_ID, fakeToken.address) + .returns(mockJbEthPaymentTerminal.address); + + // Protocol project accept the token as fee + await mockJbDirectory.mock.primaryTerminalOf + .withArgs(1, fakeToken.address) + .returns(mockJbEthPaymentTerminal.address); + + await mockJbSplitsStore.mock.splitsOf + .withArgs(PROJECT_ID, timestamp, ETH_PAYOUT_INDEX) + .returns(splits); + + await Promise.all( + splits.map(async (split) => { + await fakeToken.mock.allowance + .withArgs(jbErc20PaymentTerminal.address, mockJbEthPaymentTerminal.address) + .returns(0); + + await fakeToken.mock.approve + .withArgs( + mockJbEthPaymentTerminal.address, + Math.floor((AMOUNT_MINUS_FEES * split.percent) / SPLITS_TOTAL_PERCENT), + ) + .returns(true); + + await mockJbEthPaymentTerminal.mock["addToBalanceOf(uint256,uint256,address,string,bytes)"] + .withArgs( + split.projectId, + /*payoutAmount*/ Math.floor((AMOUNT_MINUS_FEES * split.percent) / SPLITS_TOTAL_PERCENT), + fakeToken.address, + '', + ethers.utils.hexZeroPad(ethers.utils.hexlify(PROJECT_ID), 32), + ) + .returns(); + }), + ); + + // Fee + await mockJbEthPaymentTerminal.mock.pay + .withArgs( + 1, + FEE_AMOUNT, + fakeToken.address, + projectOwner.address, + /*minReturnedToken*/ 0, + false, + '', + ethers.utils.hexZeroPad(ethers.utils.hexlify(PROJECT_ID), 32), + ) + .returns(0); + + await fakeToken.mock.approve + .withArgs(mockJbEthPaymentTerminal.address, FEE_AMOUNT) + .returns(true); + + let tx = await jbErc20PaymentTerminal + .connect(caller) + .distributePayoutsOf( + PROJECT_ID, + AMOUNT_TO_DISTRIBUTE, + ETH_PAYOUT_INDEX, + ethers.constants.AddressZero, + MIN_TOKEN_REQUESTED, + METADATA, + ); + + await Promise.all( + splits.map(async (split) => { + await expect(tx) + .to.emit(jbErc20PaymentTerminal, 'DistributeToPayoutSplit') + .withArgs( + PROJECT_ID, + /*_fundingCycle.configuration*/ timestamp, + ETH_PAYOUT_INDEX, + [ + split.preferClaimed, + split.preferAddToBalance, + split.percent, + split.projectId, + split.beneficiary, + split.lockedUntil, + split.allocator, + ], + /*Amount*/ Math.floor( + (AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT, + ), + /*NetAmount*/ Math.floor((AMOUNT_MINUS_FEES * split.percent) / SPLITS_TOTAL_PERCENT), + caller.address, + ); + }), + ); + + await expect(tx) + .to.emit(jbErc20PaymentTerminal, 'DistributePayouts') + .withArgs( + /*_fundingCycle.configuration*/ timestamp, + /*_fundingCycle.number*/ 1, + PROJECT_ID, + projectOwner.address, + /*_amount*/ AMOUNT_TO_DISTRIBUTE, + /*_distributedAmount*/ AMOUNT_DISTRIBUTED, + /*_feeAmount*/ FEE_AMOUNT, + /*_leftoverDistributionAmount*/ 0, + METADATA, + caller.address, + ); + }); + + it('Should distribute payout and use this terminal if the project set in splits uses it', async function () { + const { + projectOwner, + terminalOwner, + caller, + beneficiaryOne, + beneficiaryTwo, + jbEthPaymentTerminal, + timestamp, + mockJbDirectory, + mockJBPaymentTerminalStore, + mockJbSplitsStore, + } = await setup(); + const splits = makeSplits({ + count: 2, + projectId: OTHER_PROJECT_ID, + beneficiary: [beneficiaryOne.address, beneficiaryTwo.address], + }); + + await jbEthPaymentTerminal.connect(terminalOwner).setFee(0); + + await mockJbDirectory.mock.primaryTerminalOf + .withArgs(OTHER_PROJECT_ID, ETH_ADDRESS) + .returns(jbEthPaymentTerminal.address); + + await mockJbSplitsStore.mock.splitsOf + .withArgs(PROJECT_ID, timestamp, ETH_PAYOUT_INDEX) + .returns(splits); + + await Promise.all( + splits.map(async (split) => { + await mockJBPaymentTerminalStore.mock.recordPaymentFrom + .withArgs( + jbEthPaymentTerminal.address, + [ + /*token*/ '0x000000000000000000000000000000000000eeee', + /*amount paid*/ Math.floor( + (AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT, + ), + /*decimal*/ 18, + CURRENCY, + ], + split.projectId, + CURRENCY, + split.beneficiary, + '', + ethers.utils.hexZeroPad(ethers.utils.hexlify(PROJECT_ID), 32), + ) + .returns(fundingCycle, 0, /* delegateAllocation */[], ''); + }), + ); + + let tx = await jbEthPaymentTerminal + .connect(caller) + .distributePayoutsOf( + PROJECT_ID, + AMOUNT_TO_DISTRIBUTE, + ETH_PAYOUT_INDEX, + ethers.constants.AddressZero, + MIN_TOKEN_REQUESTED, + METADATA, + ); + + await Promise.all( + splits.map(async (split) => { + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'DistributeToPayoutSplit') + .withArgs( + PROJECT_ID, + /*_fundingCycle.configuration*/ timestamp, + ETH_PAYOUT_INDEX, + [ + split.preferClaimed, + split.preferAddToBalance, + split.percent, + split.projectId, + split.beneficiary, + split.lockedUntil, + split.allocator, + ], + /*Amount*/ Math.floor( + (AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT, + ), + /*NetAmount*/ Math.floor( + (AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT, + ), + caller.address, + ) + .and.to.emit(jbEthPaymentTerminal, 'Pay') + .withArgs( + timestamp, + 1, + split.projectId, + jbEthPaymentTerminal.address, + split.beneficiary, + Math.floor((AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT), + 0, + '', + ethers.utils.hexZeroPad(ethers.utils.hexlify(PROJECT_ID), 32), + jbEthPaymentTerminal.address, + ); + }), + ); + + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'DistributePayouts') + .withArgs( + /*_fundingCycle.configuration*/ timestamp, + /*_fundingCycle.number*/ 1, + PROJECT_ID, + projectOwner.address, + /*_amount*/ AMOUNT_TO_DISTRIBUTE, + /*_distributedAmount*/ AMOUNT_DISTRIBUTED, + /*_feeAmount*/ 0, + /*_leftoverDistributionAmount*/ 0, + METADATA, + caller.address, + ); + }); + + it('Should distribute payout and use this terminal if the project set in splits uses it, with no beneficairies', async function () { + const { + projectOwner, + terminalOwner, + caller, + jbEthPaymentTerminal, + timestamp, + mockJbDirectory, + mockJBPaymentTerminalStore, + mockJbSplitsStore, + } = await setup(); + const splits = makeSplits({ + count: 2, + projectId: OTHER_PROJECT_ID, + preferAddToBalance: true, + }); + + await jbEthPaymentTerminal.connect(terminalOwner).setFee(0); + + await mockJbDirectory.mock.primaryTerminalOf + .withArgs(OTHER_PROJECT_ID, ETH_ADDRESS) + .returns(jbEthPaymentTerminal.address); + + await mockJbSplitsStore.mock.splitsOf + .withArgs(PROJECT_ID, timestamp, ETH_PAYOUT_INDEX) + .returns(splits); + + await Promise.all( + splits.map(async (split) => { + await mockJBPaymentTerminalStore.mock.recordAddedBalanceFor + .withArgs( + split.projectId, + /*amount paid*/ Math.floor((AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT), + ) + .returns(); + }), + ); + + let tx = await jbEthPaymentTerminal + .connect(caller) + .distributePayoutsOf( + PROJECT_ID, + AMOUNT_TO_DISTRIBUTE, + ETH_PAYOUT_INDEX, + ethers.constants.AddressZero, + MIN_TOKEN_REQUESTED, + METADATA, + ); + + await Promise.all( + splits.map(async (split) => { + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'DistributeToPayoutSplit') + // .withArgs( + // PROJECT_ID, + // /*_fundingCycle.configuration*/ timestamp, + // ETH_PAYOUT_INDEX, + // [ + // split.preferClaimed, + // split.preferAddToBalance, + // split.percent, + // split.projectId, + // split.beneficiary, + // split.lockedUntil, + // split.allocator, + // ], + // /*payoutAmount*/ Math.floor( + // (AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT, + // ), + // caller.address, + // ) + .and.to.emit(jbEthPaymentTerminal, 'AddToBalance') + .withArgs( + split.projectId, + Math.floor((AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT), + 0, + '', + ethers.utils.hexZeroPad(ethers.utils.hexlify(PROJECT_ID), 32), + jbEthPaymentTerminal.address, + ); + }), + ); + + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'DistributePayouts') + .withArgs( + /*_fundingCycle.configuration*/ timestamp, + /*_fundingCycle.number*/ 1, + PROJECT_ID, + projectOwner.address, + /*_amount*/ AMOUNT_TO_DISTRIBUTE, + /*_distributedAmount*/ AMOUNT_DISTRIBUTED, + /*_feeAmount*/ 0, + /*_leftoverDistributionAmount*/ 0, + METADATA, + caller.address, + ); + }); + + it('Should send any leftover after distributing to the projectOwner', async function () { + const { + projectOwner, + terminalOwner, + caller, + beneficiaryOne, + beneficiaryTwo, + jbEthPaymentTerminal, + timestamp, + mockJbSplitsStore, + } = await setup(); + const PERCENT = SPLITS_TOTAL_PERCENT / 10; + const splits = makeSplits({ + count: 2, + beneficiary: [beneficiaryOne.address, beneficiaryTwo.address], + percent: PERCENT, + }); + + await jbEthPaymentTerminal.connect(terminalOwner).setFee(0); + + await mockJbSplitsStore.mock.splitsOf + .withArgs(PROJECT_ID, timestamp, ETH_PAYOUT_INDEX) + .returns(splits); + + let tx = await jbEthPaymentTerminal + .connect(caller) + .distributePayoutsOf( + PROJECT_ID, + AMOUNT_TO_DISTRIBUTE, + ETH_PAYOUT_INDEX, + ethers.constants.AddressZero, + MIN_TOKEN_REQUESTED, + METADATA, + ); + + await Promise.all( + splits.map(async (split) => { + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'DistributeToPayoutSplit') + .withArgs( + PROJECT_ID, + /*_fundingCycle.configuration*/ timestamp, + ETH_PAYOUT_INDEX, + [ + split.preferClaimed, + split.preferAddToBalance, + split.percent, + split.projectId, + split.beneficiary, + split.lockedUntil, + split.allocator, + ], + /*Amount*/ Math.floor( + (AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT, + ), + /*NetAmount*/ Math.floor( + (AMOUNT_DISTRIBUTED * split.percent) / SPLITS_TOTAL_PERCENT, + ), + caller.address, + ); + }), + ); + + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'DistributePayouts') + .withArgs( + /*_fundingCycle.configuration*/ timestamp, + /*_fundingCycle.number*/ 1, + PROJECT_ID, + projectOwner.address, + /*_amount*/ AMOUNT_TO_DISTRIBUTE, + /*_distributedAmount*/ AMOUNT_DISTRIBUTED, + /*_feeAmount*/ 0, + /*_leftoverDistributionAmount*/ AMOUNT_DISTRIBUTED - + ((AMOUNT_DISTRIBUTED * PERCENT) / SPLITS_TOTAL_PERCENT) * splits.length, + METADATA, + caller.address, + ); + }); + + it('Should not have any leftover (fix rounding error)', async function () { + const { + projectOwner, + terminalOwner, + caller, + beneficiaryOne, + beneficiaryTwo, + jbEthPaymentTerminal, + timestamp, + mockJbSplitsStore, + mockJbDirectory, + mockJBPaymentTerminalStore, + } = await setup(); + + const AMOUNT_TO_DISTRIBUTE = 101; + + const splits = makeSplits({ + count: 2, + projectId: OTHER_PROJECT_ID, + beneficiary: [beneficiaryOne.address, beneficiaryTwo.address], + }); + + await mockJbSplitsStore.mock.splitsOf + .withArgs(PROJECT_ID, timestamp, ETH_PAYOUT_INDEX) + .returns(splits); + + await mockJbDirectory.mock.primaryTerminalOf + .withArgs(OTHER_PROJECT_ID, ETH_ADDRESS) + .returns(jbEthPaymentTerminal.address); + + // ETH distribution + await mockJBPaymentTerminalStore.mock.recordDistributionFor + .withArgs(PROJECT_ID, AMOUNT_TO_DISTRIBUTE, CURRENCY) + .returns(fundingCycle, AMOUNT_TO_DISTRIBUTE); + + await Promise.all( + splits.map(async (split) => { + await mockJBPaymentTerminalStore.mock.recordPaymentFrom + // .withArgs( + // jbEthPaymentTerminal.address, + // [ + // /*token*/ '0x000000000000000000000000000000000000eeee', + // /*amount paid*/ Math.floor( + // (AMOUNT_TO_DISTRIBUTE * split.percent) / SPLITS_TOTAL_PERCENT, + // ), + // /*decimal*/ 18, + // CURRENCY, + // ], + // split.projectId, + // CURRENCY, + // split.beneficiary, + // '', + // ethers.utils.hexZeroPad(ethers.utils.hexlify(PROJECT_ID), 32), + // ) + .returns(fundingCycle, /*count*/ 0, /* delegateAllocation */[], ''); + }), + ); + + // POC Bug: pay 1 wei of fee = + await mockJBPaymentTerminalStore.mock.recordPaymentFrom + .withArgs( + jbEthPaymentTerminal.address, + [ + /*token*/ '0x000000000000000000000000000000000000eeee', + /*amount paid*/ 1, + /*decimal*/ 18, + CURRENCY, + ], + 1, + CURRENCY, + projectOwner.address, + '', + ethers.utils.hexZeroPad(ethers.utils.hexlify(PROJECT_ID), 32), + ) + .returns(fundingCycle, /*count*/ 0, /* delegateAllocation */[], ''); + + let tx = await jbEthPaymentTerminal + .connect(caller) + .distributePayoutsOf( + PROJECT_ID, + AMOUNT_TO_DISTRIBUTE, + ETH_PAYOUT_INDEX, + ethers.constants.AddressZero, + AMOUNT_TO_DISTRIBUTE, + METADATA, + ); + + await Promise.all( + splits.map(async (split, i) => { + // If this is the last split it receives the remainder incl rounding errors + var amountToReceive; + if (i == splits.length - 1) { + // We calc the amount send to the other splits, subtracting that from the total amount will give the amount this split will receive + amountToReceive = + AMOUNT_TO_DISTRIBUTE - + Math.floor( + (AMOUNT_TO_DISTRIBUTE * (1000000000 - split.percent)) / SPLITS_TOTAL_PERCENT, + ); + } else { + amountToReceive = Math.floor( + (AMOUNT_TO_DISTRIBUTE * split.percent) / SPLITS_TOTAL_PERCENT, + ); + } + + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'DistributeToPayoutSplit') + .withArgs( + PROJECT_ID, + /*_fundingCycle.configuration*/ timestamp, + ETH_PAYOUT_INDEX, + [ + split.preferClaimed, + split.preferAddToBalance, + split.percent, + split.projectId, + split.beneficiary, + split.lockedUntil, + split.allocator, + ], + /*Amount*/ amountToReceive, + /*NetAmount*/ amountToReceive, + caller.address, + ); + }), + ); + + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'DistributePayouts') + .withArgs( + /*_fundingCycle.configuration*/ timestamp, + /*_fundingCycle.number*/ 1, + PROJECT_ID, + projectOwner.address, + /*_amount*/ AMOUNT_TO_DISTRIBUTE, + /*_distributedAmount*/ AMOUNT_TO_DISTRIBUTE, + /*_feeAmount*/ 0, + /*_leftoverDistributionAmount*/ 0, + METADATA, + caller.address, + ); + }); + + it('Should distribute payout of 0 and emit event', async function () { + const { + projectOwner, + caller, + beneficiaryOne, + beneficiaryTwo, + jbEthPaymentTerminal, + timestamp, + mockJBPaymentTerminalStore, + mockJbSplitsStore, + } = await setup(); + const splits = makeSplits({ + count: 2, + beneficiary: [beneficiaryOne.address, beneficiaryTwo.address], + }); + + await mockJbSplitsStore.mock.splitsOf + .withArgs(PROJECT_ID, timestamp, ETH_PAYOUT_INDEX) + .returns(splits); + + await mockJBPaymentTerminalStore.mock.recordDistributionFor + .withArgs(PROJECT_ID, AMOUNT_TO_DISTRIBUTE, CURRENCY) + .returns(fundingCycle, 0); + + let tx = await jbEthPaymentTerminal + .connect(caller) + .distributePayoutsOf( + PROJECT_ID, + AMOUNT_TO_DISTRIBUTE, + ETH_PAYOUT_INDEX, + ethers.constants.AddressZero, + 0, + METADATA, + ); + + await Promise.all( + splits.map(async (split) => { + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'DistributeToPayoutSplit') + .withArgs( + PROJECT_ID, + /*_fundingCycle.configuration*/ timestamp, + ETH_PAYOUT_INDEX, + [ + split.preferClaimed, + split.preferAddToBalance, + split.percent, + split.projectId, + split.beneficiary, + split.lockedUntil, + split.allocator, + ], + /*Amount*/ Math.floor((0 * split.percent) / SPLITS_TOTAL_PERCENT), + /*NetAmount*/ Math.floor((0 * split.percent) / SPLITS_TOTAL_PERCENT), + caller.address, + ); + }), + ); + + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'DistributePayouts') + .withArgs( + /*_fundingCycle.configuration*/ timestamp, + /*_fundingCycle.number*/ 1, + PROJECT_ID, + projectOwner.address, + /*_amount*/ AMOUNT_TO_DISTRIBUTE, + /*_distributedAmount*/ 0, + /*_feeAmount*/ 0, + /*_leftoverDistributionAmount*/ 0, + METADATA, + caller.address, + ); + }); + + it('Should distribute payout in ERC20 token and emit event', async function () { + const { + projectOwner, + caller, + CURRENCY_USD, + beneficiaryOne, + beneficiaryTwo, + fakeToken, + jbErc20PaymentTerminal, + terminalOwner, + timestamp, + mockJbDirectory, + mockJBPaymentTerminalStore, + mockJbSplitsStore, + } = await setup(); + const splits = makeSplits({ + count: 2, + beneficiary: [beneficiaryOne.address, beneficiaryTwo.address], + }); + + await jbErc20PaymentTerminal.connect(terminalOwner).setFee(0); + + await mockJbSplitsStore.mock.splitsOf + .withArgs(PROJECT_ID, timestamp, ETH_PAYOUT_INDEX) + .returns(splits); + + await mockJBPaymentTerminalStore.mock.recordDistributionFor + .withArgs(PROJECT_ID, AMOUNT_TO_DISTRIBUTE, CURRENCY) + .returns(fundingCycle, AMOUNT_TO_DISTRIBUTE); + + await Promise.all( + splits.map(async (split) => { + await fakeToken.mock.transfer + .withArgs( + split.beneficiary, + Math.floor((AMOUNT_TO_DISTRIBUTE * split.percent) / SPLITS_TOTAL_PERCENT), + ) + .returns(true); + }), + ); + + let tx = await jbErc20PaymentTerminal + .connect(caller) + .distributePayoutsOf( + PROJECT_ID, + AMOUNT_TO_DISTRIBUTE, + ETH_PAYOUT_INDEX, + ethers.constants.AddressZero, + AMOUNT_TO_DISTRIBUTE, + METADATA, + ); + + await Promise.all( + splits.map(async (split) => { + await expect(tx) + .to.emit(jbErc20PaymentTerminal, 'DistributeToPayoutSplit') + .withArgs( + PROJECT_ID, + /*_fundingCycle.configuration*/ timestamp, + ETH_PAYOUT_INDEX, + [ + split.preferClaimed, + split.preferAddToBalance, + split.percent, + split.projectId, + split.beneficiary, + split.lockedUntil, + split.allocator, + ], + /*Amount*/ Math.floor( + (AMOUNT_TO_DISTRIBUTE * split.percent) / SPLITS_TOTAL_PERCENT, + ), + /*NetAmount*/ Math.floor( + (AMOUNT_TO_DISTRIBUTE * split.percent) / SPLITS_TOTAL_PERCENT, + ), + caller.address, + ); + }), + ); + + await expect(tx) + .to.emit(jbErc20PaymentTerminal, 'DistributePayouts') + .withArgs( + /*_fundingCycle.configuration*/ timestamp, + /*_fundingCycle.number*/ 1, + PROJECT_ID, + projectOwner.address, + /*_amount*/ AMOUNT_TO_DISTRIBUTE, + /*_distributedAmount*/ AMOUNT_TO_DISTRIBUTE, + /*_feeAmount*/ 0, + /*_leftoverDistributionAmount*/ 0, + METADATA, + caller.address, + ); + }); + + // TODO: adapt to be a refund case. + // it('Cannot have a zero address terminal for a project set in split', async function () { + // const { + // terminalOwner, + // caller, + // jbEthPaymentTerminal, + // timestamp, + // mockJbDirectory, + // mockJbEthPaymentTerminal, + // mockJbSplitsStore, + // } = await setup(); + // const splits = makeSplits({ count: 2, projectId: OTHER_PROJECT_ID }); + + // await jbEthPaymentTerminal.connect(terminalOwner).setFee(0); + + // await mockJbDirectory.mock.primaryTerminalOf + // .withArgs(OTHER_PROJECT_ID, ETH_ADDRESS) + // .returns(ethers.constants.AddressZero); + + // await mockJbSplitsStore.mock.splitsOf + // .withArgs(PROJECT_ID, timestamp, ETH_PAYOUT_INDEX) + // .returns(splits); + + // await Promise.all( + // splits.map(async (split) => { + // await mockJbEthPaymentTerminal.mock.pay + // .withArgs( + // split.projectId, + // 0, + // ETH_ADDRESS, + // split.beneficiary, + // 0, + // split.preferClaimed, + // '', + // '0x', + // ) + // .returns(0); + // }), + // ); + + // await expect( + // jbEthPaymentTerminal + // .connect(caller) + // .distributePayoutsOf( + // PROJECT_ID, + // AMOUNT_TO_DISTRIBUTE, + // ETH_PAYOUT_INDEX, + // ethers.constants.AddressZero, + // MIN_TOKEN_REQUESTED, + // METADATA, + // ), + // ).to.be.revertedWith(errors.TERMINAL_IN_SPLIT_ZERO_ADDRESS); + // }); + + it('Cannot distribute payouts of the distributed amount is less than expected', async function () { + const { + terminalOwner, + caller, + beneficiaryOne, + beneficiaryTwo, + jbEthPaymentTerminal, + timestamp, + mockJbSplitsStore, + } = await setup(); + const splits = makeSplits({ + count: 2, + beneficiary: [beneficiaryOne.address, beneficiaryTwo.address], + }); + + await jbEthPaymentTerminal.connect(terminalOwner).setFee(0); + + await mockJbSplitsStore.mock.splitsOf + .withArgs(PROJECT_ID, timestamp, ETH_PAYOUT_INDEX) + .returns(splits); + + await expect( + jbEthPaymentTerminal + .connect(caller) + .distributePayoutsOf( + PROJECT_ID, + AMOUNT_TO_DISTRIBUTE, + ETH_PAYOUT_INDEX, + ethers.constants.AddressZero, + AMOUNT_DISTRIBUTED + 1, + METADATA, + ), + ).to.be.revertedWith(errors.INADEQUATE_DISTRIBUTION_AMOUNT); + }); +}); diff --git a/test/jb_payment_terminal_3_1_1/migrate.test.js b/test/jb_payment_terminal_3_1_1/migrate.test.js new file mode 100644 index 000000000..793914562 --- /dev/null +++ b/test/jb_payment_terminal_3_1_1/migrate.test.js @@ -0,0 +1,274 @@ +import { expect } from 'chai'; +import { ethers } from 'hardhat'; +import { deployMockContract } from '@ethereum-waffle/mock-contract'; +import { setBalance } from '../helpers/utils'; +import errors from '../helpers/errors.json'; + +import jbDirectory from '../../artifacts/contracts/JBDirectory.sol/JBDirectory.json'; +import JBEthPaymentTerminal from '../../artifacts/contracts/JBETHPaymentTerminal3_1_1.sol/JBETHPaymentTerminal3_1_1.json'; +import jbErc20PaymentTerminal from '../../artifacts/contracts/JBERC20PaymentTerminal3_1_1.sol/JBERC20PaymentTerminal3_1_1.json'; +import jbPaymentTerminalStore from '../../artifacts/contracts/JBSingleTokenPaymentTerminalStore3_1_1.sol/JBSingleTokenPaymentTerminalStore3_1_1.json'; +import jbOperatoreStore from '../../artifacts/contracts/JBOperatorStore.sol/JBOperatorStore.json'; +import jbProjects from '../../artifacts/contracts/JBProjects.sol/JBProjects.json'; +import jbSplitsStore from '../../artifacts/contracts/JBSplitsStore.sol/JBSplitsStore.json'; +import jbPrices from '../../artifacts/contracts/JBPrices.sol/JBPrices.json'; +import jbToken from '../../artifacts/contracts/JBToken.sol/JBToken.json'; + +describe('JBPayoutRedemptionPaymentTerminal3_1_1::migrate(...)', function () { + const PROJECT_ID = 2; + const CURRENT_TERMINAL_BALANCE = ethers.utils.parseEther('10'); + + let MIGRATE_TERMINAL_PERMISSION_INDEX; + + before(async function () { + let jbOperationsFactory = await ethers.getContractFactory('JBOperations'); + let jbOperations = await jbOperationsFactory.deploy(); + + MIGRATE_TERMINAL_PERMISSION_INDEX = await jbOperations.MIGRATE_TERMINAL(); + }); + + async function setup() { + let [deployer, projectOwner, terminalOwner, caller, ...addrs] = await ethers.getSigners(); + + let [ + mockJbDirectory, + mockJbEthPaymentTerminal, + mockJBERC20PaymentTerminal, + mockJBPaymentTerminalStore, + mockJbOperatorStore, + mockJbProjects, + mockJbSplitsStore, + mockJbPrices, + mockJbToken, + ] = await Promise.all([ + deployMockContract(deployer, jbDirectory.abi), + deployMockContract(deployer, JBEthPaymentTerminal.abi), + deployMockContract(deployer, jbErc20PaymentTerminal.abi), + deployMockContract(deployer, jbPaymentTerminalStore.abi), + deployMockContract(deployer, jbOperatoreStore.abi), + deployMockContract(deployer, jbProjects.abi), + deployMockContract(deployer, jbSplitsStore.abi), + deployMockContract(deployer, jbPrices.abi), + deployMockContract(deployer, jbToken.abi), + ]); + + const jbCurrenciesFactory = await ethers.getContractFactory('JBCurrencies'); + const jbCurrencies = await jbCurrenciesFactory.deploy(); + const CURRENCY_ETH = await jbCurrencies.ETH(); + + const jbTokensFactory = await ethers.getContractFactory('JBTokens'); + const jbTokens = await jbTokensFactory.deploy(); + const TOKEN_ETH = await jbTokens.ETH(); + const NON_ETH_TOKEN = mockJbToken.address; + + const SPLITS_GROUP = 1; + + let jbEthTerminalFactory = await ethers.getContractFactory( + 'contracts/JBETHPaymentTerminal3_1_1.sol:JBETHPaymentTerminal3_1_1', + deployer, + ); + let jbErc20TerminalFactory = await ethers.getContractFactory( + 'contracts/JBERC20PaymentTerminal3_1_1.sol:JBERC20PaymentTerminal3_1_1', + deployer, + ); + + let jbEthPaymentTerminal = await jbEthTerminalFactory + .connect(deployer) + .deploy( + CURRENCY_ETH, + mockJbOperatorStore.address, + mockJbProjects.address, + mockJbDirectory.address, + mockJbSplitsStore.address, + mockJbPrices.address, + mockJBPaymentTerminalStore.address, + terminalOwner.address, + ); + + const DECIMALS = 1; + + await mockJbToken.mock.decimals.returns(DECIMALS); + + let JBERC20PaymentTerminal = await jbErc20TerminalFactory + .connect(deployer) + .deploy( + NON_ETH_TOKEN, + CURRENCY_ETH, + CURRENCY_ETH, + SPLITS_GROUP, + mockJbOperatorStore.address, + mockJbProjects.address, + mockJbDirectory.address, + mockJbSplitsStore.address, + mockJbPrices.address, + mockJBPaymentTerminalStore.address, + terminalOwner.address, + ); + + await mockJbOperatorStore.mock.hasPermission + .withArgs( + projectOwner.address, + projectOwner.address, + PROJECT_ID, + MIGRATE_TERMINAL_PERMISSION_INDEX, + ) + .returns(true); + + await mockJbProjects.mock.ownerOf.withArgs(PROJECT_ID).returns(projectOwner.address); + + await mockJbEthPaymentTerminal.mock.token.returns(TOKEN_ETH); + await mockJbEthPaymentTerminal.mock.acceptsToken.withArgs(TOKEN_ETH, PROJECT_ID).returns(true); + + await mockJBERC20PaymentTerminal.mock.token.returns(NON_ETH_TOKEN); + await mockJBERC20PaymentTerminal.mock.acceptsToken + .withArgs(NON_ETH_TOKEN, PROJECT_ID) + .returns(true); + + // addToBalanceOf _amount is 0 if ETH terminal + await mockJbEthPaymentTerminal.mock["addToBalanceOf(uint256,uint256,address,string,bytes)"] + .withArgs(PROJECT_ID, CURRENT_TERMINAL_BALANCE, TOKEN_ETH, '', '0x') + .returns(); + await mockJBERC20PaymentTerminal.mock["addToBalanceOf(uint256,uint256,address,string,bytes)"] + .withArgs(PROJECT_ID, CURRENT_TERMINAL_BALANCE, NON_ETH_TOKEN, '', '0x') + .returns(); + + await setBalance(jbEthPaymentTerminal.address, CURRENT_TERMINAL_BALANCE); + await setBalance(JBERC20PaymentTerminal.address, CURRENT_TERMINAL_BALANCE); + + await mockJBPaymentTerminalStore.mock.recordMigration + .withArgs(PROJECT_ID) + .returns(CURRENT_TERMINAL_BALANCE); + + return { + deployer, + projectOwner, + terminalOwner, + caller, + addrs, + jbEthPaymentTerminal, + JBERC20PaymentTerminal, + mockJbEthPaymentTerminal, + mockJBERC20PaymentTerminal, + mockJBPaymentTerminalStore, + mockJbOperatorStore, + mockJbToken, + TOKEN_ETH, + }; + } + + it('Should migrate terminal and emit event if caller is project owner', async function () { + const { projectOwner, jbEthPaymentTerminal, mockJbEthPaymentTerminal } = await setup(); + + expect( + await jbEthPaymentTerminal + .connect(projectOwner) + .migrate(PROJECT_ID, mockJbEthPaymentTerminal.address), + ) + .to.emit(jbEthPaymentTerminal, 'Migrate') + .withArgs( + PROJECT_ID, + mockJbEthPaymentTerminal.address, + CURRENT_TERMINAL_BALANCE, + projectOwner.address, + ); + }); + + it('Should migrate terminal and emit event if caller is authorized', async function () { + const { + projectOwner, + caller, + jbEthPaymentTerminal, + mockJbEthPaymentTerminal, + mockJbOperatorStore, + } = await setup(); + + await mockJbOperatorStore.mock.hasPermission + .withArgs(caller.address, projectOwner.address, PROJECT_ID, MIGRATE_TERMINAL_PERMISSION_INDEX) + .returns(true); + + expect( + await jbEthPaymentTerminal + .connect(caller) + .migrate(PROJECT_ID, mockJbEthPaymentTerminal.address), + ) + .to.emit(jbEthPaymentTerminal, 'Migrate') + .withArgs( + PROJECT_ID, + mockJbEthPaymentTerminal.address, + CURRENT_TERMINAL_BALANCE, + caller.address, + ); + }); + + it('Cannot migrate terminal if caller is not authorized', async function () { + const { + projectOwner, + caller, + jbEthPaymentTerminal, + mockJbEthPaymentTerminal, + mockJbOperatorStore, + } = await setup(); + + await mockJbOperatorStore.mock.hasPermission + .withArgs(caller.address, projectOwner.address, PROJECT_ID, MIGRATE_TERMINAL_PERMISSION_INDEX) + .returns(false); + + await mockJbOperatorStore.mock.hasPermission + .withArgs(caller.address, projectOwner.address, 0, MIGRATE_TERMINAL_PERMISSION_INDEX) + .returns(false); + + await expect( + jbEthPaymentTerminal.connect(caller).migrate(PROJECT_ID, mockJbEthPaymentTerminal.address), + ).to.be.revertedWith(errors.UNAUTHORIZED); + }); + + it('Should migrate non-eth terminal', async function () { + const { projectOwner, JBERC20PaymentTerminal, mockJBERC20PaymentTerminal, mockJbToken } = + await setup(); + + await mockJbToken.mock['allowance(address,address)'] + .withArgs(JBERC20PaymentTerminal.address, mockJBERC20PaymentTerminal.address) + .returns(0); + + await mockJbToken.mock['approve(address,uint256)'] + .withArgs(mockJBERC20PaymentTerminal.address, CURRENT_TERMINAL_BALANCE) + .returns(true); + + await JBERC20PaymentTerminal.connect(projectOwner).migrate( + PROJECT_ID, + mockJBERC20PaymentTerminal.address, + ); + }); + + it('Should migrate terminal with empty balance and emit event if caller is project owner', async function () { + const { + projectOwner, + jbEthPaymentTerminal, + mockJbEthPaymentTerminal, + mockJBPaymentTerminalStore, + } = await setup(); + + await mockJBPaymentTerminalStore.mock.recordMigration.withArgs(PROJECT_ID).returns(0); + + expect( + await jbEthPaymentTerminal + .connect(projectOwner) + .migrate(PROJECT_ID, mockJbEthPaymentTerminal.address), + ) + .to.emit(jbEthPaymentTerminal, 'Migrate') + .withArgs(PROJECT_ID, mockJbEthPaymentTerminal.address, 0, projectOwner.address); + }); + + it("Can't migrate to a terminal which doesn't accept token", async function () { + const { TOKEN_ETH, projectOwner, jbEthPaymentTerminal, mockJbEthPaymentTerminal } = + await setup(); + + await mockJbEthPaymentTerminal.mock.acceptsToken.withArgs(TOKEN_ETH, PROJECT_ID).returns(false); + + await expect( + jbEthPaymentTerminal + .connect(projectOwner) + .migrate(PROJECT_ID, mockJbEthPaymentTerminal.address), + ).to.be.revertedWith(errors.TERMINAL_TOKENS_INCOMPATIBLE); + }); +}); diff --git a/test/jb_payment_terminal_3_1_1/pay.test.js b/test/jb_payment_terminal_3_1_1/pay.test.js new file mode 100644 index 000000000..f272c1b86 --- /dev/null +++ b/test/jb_payment_terminal_3_1_1/pay.test.js @@ -0,0 +1,935 @@ +import { expect } from 'chai'; +import { ethers } from 'hardhat'; +import { deployMockContract } from '@ethereum-waffle/mock-contract'; +import { packFundingCycleMetadata } from '../helpers/utils.js'; +import { smock } from '@defi-wonderland/smock'; + +import errors from '../helpers/errors.json'; +import ierc20 from '../../artifacts/@openzeppelin/contracts/token/ERC20/ERC20.sol/ERC20.json'; + +import jbDirectory from '../../artifacts/contracts/JBDirectory.sol/JBDirectory.json'; +import jbController from '../../artifacts/contracts/interfaces/IJBController3_1.sol/IJBController3_1.json'; +import jbPaymentTerminalStore from '../../artifacts/contracts/JBSingleTokenPaymentTerminalStore3_1_1.sol/JBSingleTokenPaymentTerminalStore3_1_1.json'; +import jbOperatoreStore from '../../artifacts/contracts/JBOperatorStore.sol/JBOperatorStore.json'; +import jbProjects from '../../artifacts/contracts/JBProjects.sol/JBProjects.json'; +import jbSplitsStore from '../../artifacts/contracts/JBSplitsStore.sol/JBSplitsStore.json'; +import jbPrices from '../../artifacts/contracts/JBPrices.sol/JBPrices.json'; +import jbPayDelegate from '../../artifacts/contracts/interfaces/IJBPayDelegate3_1_1.sol/IJBPayDelegate3_1_1.json'; + +describe('JBPayoutRedemptionPaymentTerminal3_1_1::pay(...)', function () { + const PROJECT_ID = 1; + const MEMO = 'Memo Test'; + const ADJUSTED_MEMO = 'test test memo'; + const METADATA1 = '0x69'; + const METADATA2 = '0x70'; + const METADATA3 = '0x71'; + const FUNDING_CYCLE_NUMBER = 1; + const ADJUSTED_WEIGHT = 10; + const MIN_TOKEN_REQUESTED = 90; + const TOKEN_TO_MINT = 200; + const TOKEN_RECEIVED = 100; + const ETH_TO_PAY = ethers.utils.parseEther('1'); + const TOKEN_AMOUNT = ethers.utils.parseEther('1'); + const PREFER_CLAIMED_TOKENS = true; + const CURRENCY_ETH = 1; + const DECIMALS = 1; + + let ethToken; + + async function setup() { + let [deployer, terminalOwner, caller, beneficiary, ...addrs] = await ethers.getSigners(); + + const blockNum = await ethers.provider.getBlockNumber(); + const block = await ethers.provider.getBlock(blockNum); + const timestamp = block.timestamp; + const SPLITS_GROUP = 1; + + let [ + mockJbDirectory, + mockJBPaymentTerminalStore, + mockJbOperatorStore, + mockJbProjects, + mockJbSplitsStore, + mockJbPayDelegate, + mockJbPayDelegate2, + mockJbPrices, + mockJbController, + ] = await Promise.all([ + deployMockContract(deployer, jbDirectory.abi), + deployMockContract(deployer, jbPaymentTerminalStore.abi), + deployMockContract(deployer, jbOperatoreStore.abi), + deployMockContract(deployer, jbProjects.abi), + deployMockContract(deployer, jbSplitsStore.abi), + deployMockContract(deployer, jbPayDelegate.abi), + deployMockContract(deployer, jbPayDelegate.abi), + deployMockContract(deployer, jbPrices.abi), + deployMockContract(deployer, jbController.abi), + ]); + + let mockToken = await smock.fake(ierc20.abi); + const NON_ETH_TOKEN = mockToken.address; + + let jbEthTerminalFactory = await ethers.getContractFactory( + 'contracts/JBETHPaymentTerminal3_1_1.sol:JBETHPaymentTerminal3_1_1', + deployer, + ); + let jbErc20TerminalFactory = await ethers.getContractFactory( + 'contracts/JBERC20PaymentTerminal3_1_1.sol:JBERC20PaymentTerminal3_1_1', + deployer, + ); + + let jbEthPaymentTerminal = await jbEthTerminalFactory + .connect(deployer) + .deploy( + CURRENCY_ETH, + mockJbOperatorStore.address, + mockJbProjects.address, + mockJbDirectory.address, + mockJbSplitsStore.address, + mockJbPrices.address, + mockJBPaymentTerminalStore.address, + terminalOwner.address, + ); + + ethToken = await jbEthPaymentTerminal.token(); + + mockToken.decimals.returns(DECIMALS); + + let JBERC20PaymentTerminal = await jbErc20TerminalFactory + .connect(deployer) + .deploy( + NON_ETH_TOKEN, + CURRENCY_ETH, + CURRENCY_ETH, + SPLITS_GROUP, + mockJbOperatorStore.address, + mockJbProjects.address, + mockJbDirectory.address, + mockJbSplitsStore.address, + mockJbPrices.address, + mockJBPaymentTerminalStore.address, + terminalOwner.address, + ); + + await mockJbDirectory.mock.isTerminalOf + .withArgs(PROJECT_ID, jbEthPaymentTerminal.address) + .returns(true); + + await mockJbDirectory.mock.isTerminalOf + .withArgs(PROJECT_ID, JBERC20PaymentTerminal.address) + .returns(true); + + await mockJBPaymentTerminalStore.mock.recordPaymentFrom + .withArgs( + caller.address, + [ + /*token*/ '0x000000000000000000000000000000000000eeee', + /*amount paid*/ ETH_TO_PAY, + /*decimal*/ 18, + CURRENCY_ETH, + ], + PROJECT_ID, + CURRENCY_ETH, + beneficiary.address, + MEMO, + METADATA1, + ) + .returns( + { + // mock JBFundingCycle obj + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: 0, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata(), + }, + TOKEN_TO_MINT, + [], //delegateAllocations + ADJUSTED_MEMO, + ); + + return { + terminalOwner, + caller, + beneficiary, + addrs, + jbEthPaymentTerminal, + JBERC20PaymentTerminal, + mockToken, + mockJbDirectory, + mockJBPaymentTerminalStore, + mockJbPayDelegate, + mockJbPayDelegate2, + mockJbController, + timestamp, + }; + } + + it('Should record payment and emit event', async function () { + const { + caller, + jbEthPaymentTerminal, + mockJbDirectory, + mockJbController, + timestamp, + beneficiary, + } = await setup(); + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + + await mockJbController.mock.mintTokensOf + .withArgs( + PROJECT_ID, + TOKEN_TO_MINT, + beneficiary.address, + '', + PREFER_CLAIMED_TOKENS, + /* useReservedRate */ true, + ) + .returns(TOKEN_RECEIVED); + + expect( + await jbEthPaymentTerminal + .connect(caller) + .pay( + PROJECT_ID, + ETH_TO_PAY, + ethers.constants.AddressZero, + beneficiary.address, + MIN_TOKEN_REQUESTED, + PREFER_CLAIMED_TOKENS, + MEMO, + METADATA1, + { value: ETH_TO_PAY }, + ), + ) + .to.emit(jbEthPaymentTerminal, 'Pay') + .withArgs( + /*fundingCycle.configuration=*/ timestamp, + FUNDING_CYCLE_NUMBER, + PROJECT_ID, + caller.address, + beneficiary.address, + ETH_TO_PAY, + TOKEN_RECEIVED, + ADJUSTED_MEMO, + METADATA1, + caller.address, + ); + }); + + it('Should record payment with delegate and emit delegate event', async function () { + const { + caller, + jbEthPaymentTerminal, + mockJbPayDelegate, + mockJBPaymentTerminalStore, + mockJbDirectory, + mockJbController, + timestamp, + beneficiary, + } = await setup(); + + const DELEGATE_METADATA = 69; + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + + await mockJbController.mock.mintTokensOf + .withArgs( + PROJECT_ID, + TOKEN_TO_MINT, + /* beneficiary */ beneficiary.address, + '', + PREFER_CLAIMED_TOKENS, + /* useReservedRate */ true, + ) + .returns(TOKEN_RECEIVED); + + await mockJBPaymentTerminalStore.mock.recordPaymentFrom + .withArgs( + caller.address, + [ + /*token*/ '0x000000000000000000000000000000000000eeee', + /*amount paid*/ ETH_TO_PAY, + /*decimal*/ 18, + CURRENCY_ETH, + ], + PROJECT_ID, + CURRENCY_ETH, + beneficiary.address, + MEMO, + METADATA1, + ) + .returns( + { + // mock JBFundingCycle obj + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: 0, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata(), + }, + TOKEN_TO_MINT, + [{ delegate: mockJbPayDelegate.address, amount: 0, metadata: METADATA2 }], + ADJUSTED_MEMO, + ); + + await mockJbPayDelegate.mock.didPay + .withArgs({ + // JBDidPayData obj + payer: caller.address, + projectId: PROJECT_ID, + currentFundingCycleConfiguration: timestamp, + amount: { + token: '0x000000000000000000000000000000000000eeee', + value: ETH_TO_PAY, + decimals: 18, + currency: CURRENCY_ETH, + }, + forwardedAmount: { + token: '0x000000000000000000000000000000000000eeee', + value: 0, + decimals: 18, + currency: CURRENCY_ETH, + }, + projectTokenCount: TOKEN_RECEIVED, + beneficiary: beneficiary.address, + preferClaimedTokens: PREFER_CLAIMED_TOKENS, + memo: ADJUSTED_MEMO, + dataSourceMetadata: METADATA2, + payerMetadata: METADATA1 + }) + .returns(); + + const tx = await jbEthPaymentTerminal + .connect(caller) + .pay( + PROJECT_ID, + ETH_TO_PAY, + ethers.constants.AddressZero, + beneficiary.address, + MIN_TOKEN_REQUESTED, + PREFER_CLAIMED_TOKENS, + MEMO, + METADATA1, + { value: ETH_TO_PAY }, + ); + + // AssertionError: expected [ Array(4) ] to equal [ Array(4) ] + await expect(tx).to.emit(jbEthPaymentTerminal, 'DelegateDidPay(address,(address,uint256,uint256,(address,uint256,uint256,uint256),(address,uint256,uint256,uint256),uint256,address,bool,string,bytes,bytes),uint256,address)'); + // .withArgs( + // mockJbPayDelegate.address, + // [ + // // JBDidPayData obj + // caller.address, + // PROJECT_ID, + // timestamp, + // [ + // '0x000000000000000000000000000000000000EEEe', + // ETH_TO_PAY, + // ethers.BigNumber.from(18), + // ethers.BigNumber.from(CURRENCY_ETH), + // ], + // TOKEN_RECEIVED, + // beneficiary.address, + // PREFER_CLAIMED_TOKENS, + // ADJUSTED_MEMO, + // METADATA1, + // ], + // ETH_TO_PAY, + // caller.address, + // ); + + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'Pay') + .withArgs( + /*fundingCycle.configuration=*/ timestamp, + FUNDING_CYCLE_NUMBER, + PROJECT_ID, + caller.address, + beneficiary.address, + ETH_TO_PAY, + TOKEN_RECEIVED, + ADJUSTED_MEMO, + METADATA1, + caller.address, + ); + }); + + it('Should record payment with delegates when sending allocation to them, and emit delegate event', async function () { + const { + caller, + jbEthPaymentTerminal, + mockJbPayDelegate, + mockJbPayDelegate2, + mockJBPaymentTerminalStore, + mockJbDirectory, + mockJbController, + timestamp, + beneficiary, + } = await setup(); + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + + await mockJbController.mock.mintTokensOf + .withArgs( + PROJECT_ID, + TOKEN_TO_MINT, + /* beneficiary */ beneficiary.address, + '', + PREFER_CLAIMED_TOKENS, + /* useReservedRate */ true, + ) + .returns(TOKEN_RECEIVED); + + await mockJBPaymentTerminalStore.mock.recordPaymentFrom + .withArgs( + caller.address, + [ + /*token*/ '0x000000000000000000000000000000000000eeee', + /*amount paid*/ ETH_TO_PAY, + /*decimal*/ 18, + CURRENCY_ETH, + ], + PROJECT_ID, + CURRENCY_ETH, + beneficiary.address, + MEMO, + METADATA1, + ) + .returns( + { + // mock JBFundingCycle obj + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: 0, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata(), + }, + TOKEN_TO_MINT, + [ + { delegate: mockJbPayDelegate.address, amount: ETH_TO_PAY.div(4), metadata: METADATA2 }, + { delegate: mockJbPayDelegate2.address, amount: ETH_TO_PAY.div(2), metadata: METADATA3 }, + ], + ADJUSTED_MEMO, + ); + + await mockJbPayDelegate.mock.didPay + .withArgs({ + // JBDidPayData obj + payer: caller.address, + projectId: PROJECT_ID, + currentFundingCycleConfiguration: timestamp, + amount: { + token: '0x000000000000000000000000000000000000eeee', + value: ETH_TO_PAY, + decimals: 18, + currency: CURRENCY_ETH, + }, + forwardedAmount: { + token: '0x000000000000000000000000000000000000eeee', + value: ETH_TO_PAY.div(4), + decimals: 18, + currency: CURRENCY_ETH, + }, + projectTokenCount: TOKEN_RECEIVED, + beneficiary: beneficiary.address, + preferClaimedTokens: PREFER_CLAIMED_TOKENS, + memo: ADJUSTED_MEMO, + dataSourceMetadata: METADATA2, + payerMetadata: METADATA1, + }) + .returns(); + + await mockJbPayDelegate2.mock.didPay + .withArgs({ + // JBDidPayData obj + payer: caller.address, + projectId: PROJECT_ID, + currentFundingCycleConfiguration: timestamp, + amount: { + token: '0x000000000000000000000000000000000000eeee', + value: ETH_TO_PAY, + decimals: 18, + currency: CURRENCY_ETH, + }, + forwardedAmount: { + token: '0x000000000000000000000000000000000000eeee', + value: ETH_TO_PAY.div(2), + decimals: 18, + currency: CURRENCY_ETH, + }, + projectTokenCount: TOKEN_RECEIVED, + beneficiary: beneficiary.address, + preferClaimedTokens: PREFER_CLAIMED_TOKENS, + memo: ADJUSTED_MEMO, + dataSourceMetadata: METADATA3, + payerMetadata: METADATA1, + }) + .returns(); + + const tx = await jbEthPaymentTerminal + .connect(caller) + .pay( + PROJECT_ID, + ETH_TO_PAY, + ethers.constants.AddressZero, + beneficiary.address, + MIN_TOKEN_REQUESTED, + PREFER_CLAIMED_TOKENS, + MEMO, + METADATA1, + { value: ETH_TO_PAY }, + ); + + // AssertionError: expected [ …(9), …(9) ] to equal { …(9) } + await expect(tx).to.emit(jbEthPaymentTerminal, 'DelegateDidPay(address,(address,uint256,uint256,(address,uint256,uint256,uint256),(address,uint256,uint256,uint256),uint256,address,bool,string,bytes,bytes),uint256,address)'); + // .withArgs( + // mockJbPayDelegate.address, + // { + // // JBDidPayData obj + // payer: caller.address, + // projectId: PROJECT_ID, + // currentFundingCycleConfiguration: timestamp, + // amount: { + // token: '0x000000000000000000000000000000000000EEEe', + // value: ETH_TO_PAY, + // decimals: ethers.BigNumber.from(18), + // currency: ethers.BigNumber.from(CURRENCY_ETH), + // }, + // projectTokenCount: TOKEN_RECEIVED, + // beneficiary: beneficiary.address, + // preferClaimedTokens: PREFER_CLAIMED_TOKENS, + // memo: ADJUSTED_MEMO, + // metadata: METADATA1, + // }, + // ETH_TO_PAY, + // caller.address, + // ); + + // await expect(tx) + // .to.emit(jbEthPaymentTerminal, 'DelegateDidPay(address,(address,uint256,uint256,(address,uint256,uint256,uint256),(address,uint256,uint256,uint256),uint256,address,bool,string,bytes,bytes),uint256,address)') + // .withArgs( + // mockJbPayDelegate2.address, + // [ + // // JBDidPayData obj + // caller.address, + // PROJECT_ID, + // timestamp, + // [ + // '0x000000000000000000000000000000000000EEEe', + // ETH_TO_PAY, + // ethers.BigNumber.from(18), + // ethers.BigNumber.from(CURRENCY_ETH), + // ], + // TOKEN_RECEIVED, + // beneficiary.address, + // PREFER_CLAIMED_TOKENS, + // ADJUSTED_MEMO, + // METADATA1, + // ], + // ETH_TO_PAY.div(2), + // caller.address, + // ); + + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'Pay') + .withArgs( + /*fundingCycle.configuration=*/ timestamp, + FUNDING_CYCLE_NUMBER, + PROJECT_ID, + caller.address, + beneficiary.address, + ETH_TO_PAY, + TOKEN_RECEIVED, + ADJUSTED_MEMO, + METADATA1, + caller.address, + ); + + await expect(tx).to.changeEtherBalances( + [mockJbPayDelegate, mockJbPayDelegate2], + [ETH_TO_PAY.div(4), ETH_TO_PAY.div(2)], + ); + }); + + it('Should work with eth terminal with non msg.value amount sent', async function () { + const { caller, jbEthPaymentTerminal, mockJbDirectory, mockJbController, beneficiary } = + await setup(); + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + + await mockJbController.mock.mintTokensOf + .withArgs( + PROJECT_ID, + TOKEN_TO_MINT, + /* beneficiary */ beneficiary.address, + '', + PREFER_CLAIMED_TOKENS, + /* useReservedRate */ true, + ) + .returns(TOKEN_RECEIVED); + + await jbEthPaymentTerminal + .connect(caller) + .pay( + PROJECT_ID, + ETH_TO_PAY + 1, + ethers.constants.AddressZero, + beneficiary.address, + MIN_TOKEN_REQUESTED, + /*preferClaimedToken=*/ true, + MEMO, + METADATA1, + { value: ETH_TO_PAY }, + ); + }); + + it('Should work with no token amount returned from recording payment', async function () { + const { caller, jbEthPaymentTerminal, mockJBPaymentTerminalStore, beneficiary, timestamp } = + await setup(); + + await mockJBPaymentTerminalStore.mock.recordPaymentFrom + .withArgs( + caller.address, + [ + /*token*/ '0x000000000000000000000000000000000000eeee', + /*amount paid*/ ETH_TO_PAY, + /*decimal*/ 18, + CURRENCY_ETH, + ], + PROJECT_ID, + CURRENCY_ETH, + beneficiary.address, + MEMO, + METADATA1, + ) + .returns( + { + // mock JBFundingCycle obj + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: 0, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata(), + }, + 0, + [], + ADJUSTED_MEMO, + ); + + await jbEthPaymentTerminal + .connect(caller) + .pay( + PROJECT_ID, + ETH_TO_PAY + 1, + ethers.constants.AddressZero, + beneficiary.address, + 0, + PREFER_CLAIMED_TOKENS, + MEMO, + METADATA1, + { value: ETH_TO_PAY }, + ); + }); + + it('Should work with non-eth terminal if no value is sent', async function () { + const { + caller, + JBERC20PaymentTerminal, + mockToken, + mockJbDirectory, + mockJbController, + mockJBPaymentTerminalStore, + beneficiary, + timestamp, + } = await setup(); + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + + await mockJbController.mock.mintTokensOf + .withArgs( + PROJECT_ID, + TOKEN_TO_MINT, + beneficiary.address, + '', + PREFER_CLAIMED_TOKENS, + /* useReservedRate */ true, + ) + .returns(TOKEN_RECEIVED); + + mockToken.balanceOf.returnsAtCall(0, 0); + + mockToken.transferFrom + .whenCalledWith(caller.address, JBERC20PaymentTerminal.address, ETH_TO_PAY) + .returns(true); + + mockToken.balanceOf.returnsAtCall(1, ETH_TO_PAY); + + let tokenAddress = await JBERC20PaymentTerminal.token(); + await mockJBPaymentTerminalStore.mock.recordPaymentFrom + .withArgs( + caller.address, + [/*token*/ tokenAddress, /*amount paid*/ ETH_TO_PAY, /*decimal*/ DECIMALS, CURRENCY_ETH], + PROJECT_ID, + CURRENCY_ETH, + beneficiary.address, + MEMO, + METADATA1, + ) + .returns( + { + // mock JBFundingCycle obj + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: 0, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata(), + }, + TOKEN_TO_MINT, + [], + ADJUSTED_MEMO, + ); + + await JBERC20PaymentTerminal.connect(caller).pay( + PROJECT_ID, + ETH_TO_PAY, + ethers.constants.AddressZero, + beneficiary.address, + MIN_TOKEN_REQUESTED, + PREFER_CLAIMED_TOKENS, + MEMO, + METADATA1, + { value: 0 }, + ); + }); + + it('Should work with non-eth terminal supporting fee on transfer token', async function () { + const { + caller, + JBERC20PaymentTerminal, + mockToken, + mockJbDirectory, + mockJbController, + mockJBPaymentTerminalStore, + beneficiary, + timestamp, + } = await setup(); + + const NET_AMOUNT = TOKEN_AMOUNT.sub(100); + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + + await mockJbController.mock.mintTokensOf + .withArgs( + PROJECT_ID, + TOKEN_TO_MINT, + beneficiary.address, + '', + PREFER_CLAIMED_TOKENS, + /* useReservedRate */ true, + ) + .returns(TOKEN_RECEIVED); + + mockToken.balanceOf.returnsAtCall(0, 0); + + mockToken.transferFrom + .whenCalledWith(caller.address, JBERC20PaymentTerminal.address, TOKEN_AMOUNT) + .returns(true); + + mockToken.balanceOf.returnsAtCall(1, NET_AMOUNT); + + let tokenAddress = await JBERC20PaymentTerminal.token(); + await mockJBPaymentTerminalStore.mock.recordPaymentFrom + .withArgs( + caller.address, + [/*token*/ tokenAddress, /*amount paid*/ NET_AMOUNT, /*decimal*/ DECIMALS, CURRENCY_ETH], + PROJECT_ID, + CURRENCY_ETH, + beneficiary.address, + MEMO, + METADATA1, + ) + .returns( + { + // mock JBFundingCycle obj + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: 0, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata(), + }, + TOKEN_TO_MINT, + [], + ADJUSTED_MEMO, + ); + + await expect( + JBERC20PaymentTerminal.connect(caller).pay( + PROJECT_ID, + ETH_TO_PAY, + ethers.constants.AddressZero, + beneficiary.address, + MIN_TOKEN_REQUESTED, + PREFER_CLAIMED_TOKENS, + MEMO, + METADATA1, + { value: 0 }, + ), + ) + .to.emit(JBERC20PaymentTerminal, 'Pay') + .withArgs( + /*fundingCycle.configuration=*/ timestamp, + FUNDING_CYCLE_NUMBER, + PROJECT_ID, + caller.address, + beneficiary.address, + NET_AMOUNT, + TOKEN_RECEIVED, + ADJUSTED_MEMO, + METADATA1, + caller.address, + ); + }); + + it("Can't pay with value if terminal token isn't ETH", async function () { + const { caller, JBERC20PaymentTerminal } = await setup(); + + await expect( + JBERC20PaymentTerminal.connect(caller).pay( + PROJECT_ID, + ETH_TO_PAY, + ethers.constants.AddressZero, + ethers.constants.AddressZero, + MIN_TOKEN_REQUESTED, + PREFER_CLAIMED_TOKENS, + MEMO, + METADATA1, + { value: ETH_TO_PAY }, + ), + ).to.be.revertedWith(errors.NO_MSG_VALUE_ALLOWED); + }); + + it("Can't send tokens to the zero address", async function () { + const { caller, jbEthPaymentTerminal } = await setup(); + + await expect( + jbEthPaymentTerminal + .connect(caller) + .pay( + PROJECT_ID, + ETH_TO_PAY, + ethers.constants.AddressZero, + ethers.constants.AddressZero, + MIN_TOKEN_REQUESTED, + PREFER_CLAIMED_TOKENS, + MEMO, + METADATA1, + { value: ETH_TO_PAY }, + ), + ).to.be.revertedWith(errors.PAY_TO_ZERO_ADDRESS); + }); + + it("Can't pay if current terminal doesn't belong to project", async function () { + const { caller, jbEthPaymentTerminal, mockJbDirectory } = await setup(); + + const otherProjectId = 18; + await mockJbDirectory.mock.isTerminalOf + .withArgs(otherProjectId, jbEthPaymentTerminal.address) + .returns(false); + + await expect( + jbEthPaymentTerminal + .connect(caller) + .pay( + otherProjectId, + ETH_TO_PAY, + ethers.constants.AddressZero, + ethers.constants.AddressZero, + MIN_TOKEN_REQUESTED, + PREFER_CLAIMED_TOKENS, + MEMO, + METADATA1, + { value: ETH_TO_PAY }, + ), + ).to.be.revertedWith(errors.PROJECT_TERMINAL_MISMATCH); + }); + + it("Can't pay if minted tokens for beneficiary is less than expected", async function () { + const { caller, jbEthPaymentTerminal, mockJBPaymentTerminalStore, beneficiary, timestamp } = + await setup(); + + await mockJBPaymentTerminalStore.mock.recordPaymentFrom + .withArgs( + caller.address, + [ + /*token*/ '0x000000000000000000000000000000000000eeee', + /*amount paid*/ ETH_TO_PAY, + /*decimal*/ 18, + CURRENCY_ETH, + ], + PROJECT_ID, + CURRENCY_ETH, + beneficiary.address, + MEMO, + METADATA1, + ) + .returns( + { + // mock JBFundingCycle obj + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: 0, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata(), + }, + 0, + [], + ADJUSTED_MEMO, + ); + + await expect( + jbEthPaymentTerminal + .connect(caller) + .pay( + PROJECT_ID, + ETH_TO_PAY + 1, + ethers.constants.AddressZero, + beneficiary.address, + MIN_TOKEN_REQUESTED, + PREFER_CLAIMED_TOKENS, + MEMO, + METADATA1, + { value: ETH_TO_PAY }, + ), + ).to.be.revertedWith(errors.INADEQUATE_TOKEN_COUNT); + }); +}); diff --git a/test/jb_payment_terminal_3_1_1/redeem_tokens_of.test.js b/test/jb_payment_terminal_3_1_1/redeem_tokens_of.test.js new file mode 100644 index 000000000..3742eaa6e --- /dev/null +++ b/test/jb_payment_terminal_3_1_1/redeem_tokens_of.test.js @@ -0,0 +1,1481 @@ +import { expect } from 'chai'; +import { ethers } from 'hardhat'; +import { deployMockContract } from '@ethereum-waffle/mock-contract'; + +import { setBalance, packFundingCycleMetadata } from '../helpers/utils'; +import errors from '../helpers/errors.json'; + +import jbController from '../../artifacts/contracts/interfaces/IJBController3_1.sol/IJBController3_1.json'; +import jbDirectory from '../../artifacts/contracts/interfaces/IJBDirectory.sol/IJBDirectory.json'; +import JBETHPaymentTerminal from '../../artifacts/contracts/JBETHPaymentTerminal3_1.sol/JBETHPaymentTerminal3_1.json'; +import jbPaymentTerminalStore from '../../artifacts/contracts/JBSingleTokenPaymentTerminalStore3_1_1.sol/JBSingleTokenPaymentTerminalStore3_1_1.json'; +import jbFeeGauge from '../../artifacts/contracts/interfaces/IJBFeeGauge3_1.sol/IJBFeeGauge3_1.json'; +import jbOperatoreStore from '../../artifacts/contracts/interfaces/IJBOperatorStore.sol/IJBOperatorStore.json'; +import jbProjects from '../../artifacts/contracts/interfaces/IJBProjects.sol/IJBProjects.json'; +import jbSplitsStore from '../../artifacts/contracts/interfaces/IJBSplitsStore.sol/IJBSplitsStore.json'; +import jbPrices from '../../artifacts/contracts/interfaces/IJBPrices.sol/IJBPrices.json'; +import jbRedemptionDelegate from '../../artifacts/contracts/interfaces/IJBRedemptionDelegate3_1_1.sol/IJBRedemptionDelegate3_1_1.json'; + +describe('JBPayoutRedemptionPaymentTerminal3_1_1::redeemTokensOf(...)', function () { + const AMOUNT = 50000; + const RECLAIM_AMOUNT = 40000; + const MIN_RETURNED_AMOUNT = 30000; + const FUNDING_CYCLE_NUM = 1; + const MEMO = 'test memo'; + const ADJUSTED_MEMO = 'test test memo'; + const PROJECT_ID = 13; + const WEIGHT = 1000; + const METADATA1 = '0x69'; + const METADATA2 = '0x70'; + const METADATA3 = '0x71'; + const DECIMALS = 10; + const DECIMALS_ETH = 18; + const DEFAULT_FEE = 25000000; // 2.5% + const FEE_DISCOUNT = 500000000; // 50% + + let CURRENCY_ETH; + let MAX_FEE; + let MAX_FEE_DISCOUNT; + let ETH_ADDRESS; + let token; + + before(async function () { + let jbConstantsFactory = await ethers.getContractFactory('JBConstants'); + let jbTokenFactory = await ethers.getContractFactory('JBTokens'); + let jbConstants = await jbConstantsFactory.deploy(); + let jbToken = await jbTokenFactory.deploy(); + MAX_FEE = (await jbConstants.MAX_FEE()).toNumber(); + MAX_FEE_DISCOUNT = await jbConstants.MAX_FEE_DISCOUNT(); + ETH_ADDRESS = await jbToken.ETH(); + }) + async function setup() { + const [deployer, beneficiary, holder, otherCaller, terminalOwner] = await ethers.getSigners(); + + const blockNum = await ethers.provider.getBlockNumber(); + const block = await ethers.provider.getBlock(blockNum); + const timestamp = block.timestamp; + + const [ + mockJbDirectory, + mockJBPaymentTerminalStore, + mockJbEthPaymentTerminal, + mockJbOperatorStore, + mockJbProjects, + mockJbSplitsStore, + mockJbPrices, + mockJbRedemptionDelegate, + mockJbRedemptionDelegate2, + mockJbController, + mockJbFeeGauge + ] = await Promise.all([ + deployMockContract(deployer, jbDirectory.abi), + deployMockContract(deployer, jbPaymentTerminalStore.abi), + deployMockContract(deployer, JBETHPaymentTerminal.abi), + deployMockContract(deployer, jbOperatoreStore.abi), + deployMockContract(deployer, jbProjects.abi), + deployMockContract(deployer, jbSplitsStore.abi), + deployMockContract(deployer, jbPrices.abi), + deployMockContract(deployer, jbRedemptionDelegate.abi), + deployMockContract(deployer, jbRedemptionDelegate.abi), + deployMockContract(deployer, jbController.abi), + deployMockContract(deployer, jbFeeGauge.abi), + ]); + + const jbCurrenciesFactory = await ethers.getContractFactory('JBCurrencies'); + const jbCurrencies = await jbCurrenciesFactory.deploy(); + CURRENCY_ETH = await jbCurrencies.ETH(); + + const jbTerminalFactory = await ethers.getContractFactory( + 'contracts/JBETHPaymentTerminal3_1_1.sol:JBETHPaymentTerminal3_1_1', + deployer, + ); + + const jbEthPaymentTerminal = await jbTerminalFactory + .connect(deployer) + .deploy( + CURRENCY_ETH, + mockJbOperatorStore.address, + mockJbProjects.address, + mockJbDirectory.address, + mockJbSplitsStore.address, + mockJbPrices.address, + mockJBPaymentTerminalStore.address, + terminalOwner.address, + ); + + token = await jbEthPaymentTerminal.token(); + + /* Lib constants */ + + let jbOperationsFactory = await ethers.getContractFactory('JBOperations'); + let jbOperations = await jbOperationsFactory.deploy(); + const REDEEM_PERMISSION_INDEX = await jbOperations.REDEEM(); + + /* Common mocks */ + + await mockJbOperatorStore.mock.hasPermission + .withArgs(holder.address, holder.address, PROJECT_ID, REDEEM_PERMISSION_INDEX) + .returns(true); + + const fundingCycle = { + number: FUNDING_CYCLE_NUM, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: 0, + }; + + return { + beneficiary, + holder, + terminalOwner, + jbEthPaymentTerminal, + fundingCycle, + mockJBPaymentTerminalStore, + mockJbOperatorStore, + mockJbRedemptionDelegate, + mockJbEthPaymentTerminal, + mockJbRedemptionDelegate2, + mockJbController, + mockJbDirectory, + mockJbFeeGauge, + otherCaller, + timestamp, + }; + } + + it('Should redeem tokens for overflow and emit event', async function () { + const { + beneficiary, + fundingCycle, + holder, + jbEthPaymentTerminal, + mockJBPaymentTerminalStore, + mockJbController, + mockJbDirectory, + timestamp, + } = await setup(); + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + await mockJbController.mock.burnTokensOf + .withArgs(holder.address, PROJECT_ID, AMOUNT, /* memo */ '', /* preferClaimedTokens */ false) + .returns(); + + // Keep it simple and let 1 token exchange for 1 wei + await mockJBPaymentTerminalStore.mock.recordRedemptionFor + .withArgs(holder.address, PROJECT_ID, /* tokenCount */ AMOUNT, MEMO, METADATA1) + .returns( + fundingCycle, + /* reclaimAmount */ RECLAIM_AMOUNT, + /* delegateAllocation */[], + ADJUSTED_MEMO, + ); + + await setBalance(jbEthPaymentTerminal.address, RECLAIM_AMOUNT); + + const initialBeneficiaryBalance = await ethers.provider.getBalance(beneficiary.address); + + const tx = await jbEthPaymentTerminal + .connect(holder) + .redeemTokensOf( + holder.address, + PROJECT_ID, + /* tokenCount */ AMOUNT, + /* token */ ethers.constants.AddressZero, + /* minReturnedTokens */ MIN_RETURNED_AMOUNT, + beneficiary.address, + MEMO, + METADATA1, + ); + + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'RedeemTokens') + .withArgs( + /* _fundingCycle.configuration */ timestamp, + /* _fundingCycle.number */ FUNDING_CYCLE_NUM, + /* _projectId */ PROJECT_ID, + /* _holder */ holder.address, + /* _beneficiary */ beneficiary.address, + /* _tokenCount */ AMOUNT, + /* reclaimAmount */ RECLAIM_AMOUNT, + /* memo */ ADJUSTED_MEMO, + /* metadata */ METADATA1, + /* msg.sender */ holder.address, + ); + + // Terminal should be out of ETH + expect(await ethers.provider.getBalance(jbEthPaymentTerminal.address)).to.equal(0); + + // Beneficiary should have a larger balance + expect(await ethers.provider.getBalance(beneficiary.address)).to.equal( + initialBeneficiaryBalance.add(RECLAIM_AMOUNT), + ); + }); + + it('Should work if no burning necessary', async function () { + const { + beneficiary, + fundingCycle, + holder, + jbEthPaymentTerminal, + mockJBPaymentTerminalStore, + timestamp, + } = await setup(); + + // Keep it simple and let 1 token exchange for 1 wei + await mockJBPaymentTerminalStore.mock.recordRedemptionFor + .withArgs(holder.address, PROJECT_ID, /* tokenCount */ 0, MEMO, METADATA1) + .returns( + fundingCycle, + /* reclaimAmount */ RECLAIM_AMOUNT, + /* delegateAllocation */[], + ADJUSTED_MEMO, + ); + + await setBalance(jbEthPaymentTerminal.address, RECLAIM_AMOUNT); + + const initialBeneficiaryBalance = await ethers.provider.getBalance(beneficiary.address); + + const tx = await jbEthPaymentTerminal + .connect(holder) + .redeemTokensOf( + holder.address, + PROJECT_ID, + /* tokenCount */ 0, + /* token */ ethers.constants.AddressZero, + /* minReturnedTokens */ MIN_RETURNED_AMOUNT, + beneficiary.address, + MEMO, + METADATA1, + ); + + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'RedeemTokens') + .withArgs( + /* _fundingCycle.configuration */ timestamp, + /* _fundingCycle.number */ FUNDING_CYCLE_NUM, + /* _projectId */ PROJECT_ID, + /* _holder */ holder.address, + /* _beneficiary */ beneficiary.address, + /* _tokenCount */ 0, + /* reclaimAmount */ RECLAIM_AMOUNT, + /* memo */ ADJUSTED_MEMO, + /* metadata */ METADATA1, + /* msg.sender */ holder.address, + ); + + // Terminal should be out of ETH + expect(await ethers.provider.getBalance(jbEthPaymentTerminal.address)).to.equal(0); + + // Beneficiary should have a larger balance + expect(await ethers.provider.getBalance(beneficiary.address)).to.equal( + initialBeneficiaryBalance.add(RECLAIM_AMOUNT), + ); + }); + + it('Should redeem tokens, call delegate fn, send appropriate amount and emit delegate event', async function () { + const { + beneficiary, + fundingCycle, + holder, + jbEthPaymentTerminal, + mockJBPaymentTerminalStore, + mockJbRedemptionDelegate, + mockJbDirectory, + mockJbController, + timestamp, + } = await setup(); + + const delegateAmount = RECLAIM_AMOUNT / 2; + const redeemedAmount = RECLAIM_AMOUNT / 2; + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + await mockJbController.mock.burnTokensOf + .withArgs(holder.address, PROJECT_ID, AMOUNT, /* memo */ '', /* preferClaimedTokens */ false) + .returns(); + + await mockJBPaymentTerminalStore.mock.recordRedemptionFor + .withArgs(holder.address, PROJECT_ID, /* tokenCount */ AMOUNT, MEMO, METADATA1) + .returns( + fundingCycle, + /* reclaimAmount */ redeemedAmount, + /* delegateAllocations */[ + { delegate: mockJbRedemptionDelegate.address, amount: delegateAmount, metadata: METADATA2 }, + ], + ADJUSTED_MEMO, + ); + + let tokenAddress = await jbEthPaymentTerminal.token(); + await mockJbRedemptionDelegate.mock.didRedeem + .withArgs({ + // JBDidRedeemData obj + holder: holder.address, + projectId: PROJECT_ID, + currentFundingCycleConfiguration: timestamp, + projectTokenCount: AMOUNT, + reclaimedAmount: { + token: tokenAddress, + value: redeemedAmount, + decimals: DECIMALS_ETH, + currency: CURRENCY_ETH, + }, + forwardedAmount: { + token: tokenAddress, + value: delegateAmount, + decimals: DECIMALS_ETH, + currency: CURRENCY_ETH, + }, + beneficiary: beneficiary.address, + memo: ADJUSTED_MEMO, + dataSourceMetadata: METADATA2, + redeemerMetadata: METADATA1, + }) + .returns(); + + await setBalance(jbEthPaymentTerminal.address, RECLAIM_AMOUNT); // = redeemed + delegate amount + + const initialBeneficiaryBalance = await ethers.provider.getBalance(beneficiary.address); + + const initialDelegateBalance = await ethers.provider.getBalance( + mockJbRedemptionDelegate.address, + ); + + const tx = await jbEthPaymentTerminal + .connect(holder) + .redeemTokensOf( + holder.address, + PROJECT_ID, + /* tokenCount */ AMOUNT, + /* token */ ethers.constants.AddressZero, + /* minReturnedTokens */ redeemedAmount, + beneficiary.address, + MEMO, + METADATA1, + ); + + await expect(tx).to.emit(jbEthPaymentTerminal, 'DelegateDidRedeem(address,(address,uint256,uint256,uint256,(address,uint256,uint256,uint256),(address,uint256,uint256,uint256),address,string, bytes, bytes),uint256,uint256,address)'); + // Uncaught AssertionError: expected [ Array(4) ] to equal [ Array(4) ] + + // .withArgs( + // mockJbRedemptionDelegate.address, + // [ + // // JBDidRedeemData obj + // holder.address, + // PROJECT_ID, + // AMOUNT, + // [ + // tokenAddress, + // ethers.BigNumber.from(RECLAIM_AMOUNT), + // ethers.BigNumber.from(DECIMALS_ETH), + // CURRENCY_ETH + // ], + // beneficiary.address, + // ADJUSTED_MEMO, + // METADATA1, + // ], + // /* msg.sender */ holder.address, + // ); + + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'RedeemTokens') + .withArgs( + /* _fundingCycle.configuration */ timestamp, + /* _fundingCycle.number */ FUNDING_CYCLE_NUM, + /* _projectId */ PROJECT_ID, + /* _holder */ holder.address, + /* _beneficiary */ beneficiary.address, + /* _tokenCount */ AMOUNT, + /* reclaimAmount */ redeemedAmount, + /* memo */ ADJUSTED_MEMO, + /* metadata */ METADATA1, + /* msg.sender */ holder.address, + ); + + // Terminal should be out of ETH + expect(await ethers.provider.getBalance(jbEthPaymentTerminal.address)).to.equal(0); + + // Beneficiary should have a larger balance + expect(await ethers.provider.getBalance(beneficiary.address)).to.equal( + initialBeneficiaryBalance.add(redeemedAmount), + ); + + // Delegate should have a larger balance + expect(await ethers.provider.getBalance(mockJbRedemptionDelegate.address)).to.equal( + initialDelegateBalance.add(delegateAmount), + ); + }); + + it('Should redeem tokens, call multiple delegate and send the appropriate amount to them', async function () { + const { + beneficiary, + fundingCycle, + holder, + jbEthPaymentTerminal, + mockJBPaymentTerminalStore, + mockJbRedemptionDelegate, + mockJbRedemptionDelegate2, + mockJbDirectory, + mockJbController, + timestamp, + } = await setup(); + + const delegate1Amount = RECLAIM_AMOUNT / 2; + const delegate2Amount = RECLAIM_AMOUNT / 4; + const redeemedAmount = RECLAIM_AMOUNT - delegate1Amount - delegate2Amount; + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + await mockJbController.mock.burnTokensOf + .withArgs(holder.address, PROJECT_ID, AMOUNT, /* memo */ '', /* preferClaimedTokens */ false) + .returns(); + + // Keep it simple and let 1 token exchange for 1 wei + await mockJBPaymentTerminalStore.mock.recordRedemptionFor + .withArgs(holder.address, PROJECT_ID, /* tokenCount */ AMOUNT, MEMO, METADATA1) + .returns( + fundingCycle, + /* reclaimAmount */ redeemedAmount, + /* delegate */[ + { delegate: mockJbRedemptionDelegate.address, amount: delegate1Amount, metadata: METADATA2 }, + { delegate: mockJbRedemptionDelegate2.address, amount: delegate2Amount, metadata: METADATA3 }, + ], + ADJUSTED_MEMO, + ); + + let tokenAddress = await jbEthPaymentTerminal.token(); + await mockJbRedemptionDelegate.mock.didRedeem + .withArgs({ + // JBDidRedeemData obj + holder: holder.address, + projectId: PROJECT_ID, + currentFundingCycleConfiguration: timestamp, + projectTokenCount: AMOUNT, + reclaimedAmount: { + token: tokenAddress, + value: redeemedAmount, + decimals: DECIMALS_ETH, + currency: CURRENCY_ETH, + }, + forwardedAmount: { + token: tokenAddress, + value: delegate1Amount, + decimals: DECIMALS_ETH, + currency: CURRENCY_ETH, + }, + beneficiary: beneficiary.address, + memo: ADJUSTED_MEMO, + dataSourceMetadata: METADATA2, + redeemerMetadata: METADATA1, + }) + .returns(); + + await mockJbRedemptionDelegate2.mock.didRedeem + .withArgs({ + // JBDidRedeemData obj + holder: holder.address, + projectId: PROJECT_ID, + currentFundingCycleConfiguration: timestamp, + projectTokenCount: AMOUNT, + reclaimedAmount: { + token: tokenAddress, + value: redeemedAmount, + decimals: DECIMALS_ETH, + currency: CURRENCY_ETH, + }, + forwardedAmount: { + token: tokenAddress, + value: delegate2Amount, + decimals: DECIMALS_ETH, + currency: CURRENCY_ETH, + }, + beneficiary: beneficiary.address, + memo: ADJUSTED_MEMO, + dataSourceMetadata: METADATA3, + redeemerMetadata: METADATA1, + }) + .returns(); + + await setBalance(jbEthPaymentTerminal.address, RECLAIM_AMOUNT); + + const initialBeneficiaryBalance = await ethers.provider.getBalance(beneficiary.address); + const initialDelegate1Balance = await ethers.provider.getBalance( + mockJbRedemptionDelegate.address, + ); + const initialDelegate2Balance = await ethers.provider.getBalance( + mockJbRedemptionDelegate2.address, + ); + + const tx = await jbEthPaymentTerminal + .connect(holder) + .redeemTokensOf( + holder.address, + PROJECT_ID, + /* tokenCount */ AMOUNT, + /* token */ ethers.constants.AddressZero, + /* minReturnedTokens */ redeemedAmount, + beneficiary.address, + MEMO, + METADATA1, + ); + + // Uncaught AssertionError: expected [ Array(4) ] to equal [ Array(4) ] + await expect(tx).to.emit(jbEthPaymentTerminal, 'DelegateDidRedeem(address,(address,uint256,uint256,uint256,(address,uint256,uint256,uint256),(address,uint256,uint256,uint256),address,string,bytes,bytes),uint256,uint256,address)'); + // .withArgs( + // mockJbRedemptionDelegate.address, + // [ + // // JBDidRedeemData obj + // holder.address, + // PROJECT_ID, + // AMOUNT, + // [ + // tokenAddress, + // ethers.BigNumber.from(RECLAIM_AMOUNT), + // ethers.BigNumber.from(DECIMALS_ETH), + // CURRENCY_ETH, + // ], + // beneficiary.address, + // ADJUSTED_MEMO, + // METADATA1, + // ], + // /* msg.sender */ holder.address, + // ); + + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'RedeemTokens') + .withArgs( + /* _fundingCycle.configuration */ timestamp, + /* _fundingCycle.number */ FUNDING_CYCLE_NUM, + /* _projectId */ PROJECT_ID, + /* _holder */ holder.address, + /* _beneficiary */ beneficiary.address, + /* _tokenCount */ AMOUNT, + /* reclaimAmount */ redeemedAmount, + /* memo */ ADJUSTED_MEMO, + /* metadata */ METADATA1, + /* msg.sender */ holder.address, + ); + + // Terminal should be out of ETH + expect(await ethers.provider.getBalance(jbEthPaymentTerminal.address)).to.equal(0); + + // Beneficiary should have a larger balance + expect(await ethers.provider.getBalance(beneficiary.address)).to.equal( + initialBeneficiaryBalance.add(redeemedAmount), + ); + + // Delegate1 should have a larger balance + expect(await ethers.provider.getBalance(mockJbRedemptionDelegate.address)).to.equal( + initialDelegate1Balance.add(delegate1Amount), + ); + + // Delegate2 should have a larger balance + expect(await ethers.provider.getBalance(mockJbRedemptionDelegate2.address)).to.equal( + initialDelegate2Balance.add(delegate2Amount), + ); + }); + + it('Should redeem tokens, call multiple delegate and send the appropriate amount to them, with a sub-100% redemption rate that incurrs fees', async function () { + const { + beneficiary, + fundingCycle, + holder, + jbEthPaymentTerminal, + mockJbEthPaymentTerminal, + mockJBPaymentTerminalStore, + mockJbRedemptionDelegate, + mockJbRedemptionDelegate2, + mockJbDirectory, + mockJbController, + timestamp, + } = await setup(); + + fundingCycle.metadata = packFundingCycleMetadata({ + redemptionRate: 9000, // 90% redemption rate + }); + + const delegate1Amount = RECLAIM_AMOUNT / 2; + const delegate2Amount = RECLAIM_AMOUNT / 4; + const redeemedAmount = RECLAIM_AMOUNT - delegate1Amount - delegate2Amount; + + let DELEGATE_1_FEE = + delegate1Amount - Math.floor((delegate1Amount * MAX_FEE) / (DEFAULT_FEE + MAX_FEE)); + let DELEGATE_2_FEE = + delegate2Amount - Math.floor((delegate2Amount * MAX_FEE) / (DEFAULT_FEE + MAX_FEE)); + let REDEEM_FEE = + redeemedAmount - Math.floor((redeemedAmount * MAX_FEE) / (DEFAULT_FEE + MAX_FEE)); + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + await mockJbController.mock.burnTokensOf + .withArgs(holder.address, PROJECT_ID, AMOUNT, /* memo */ '', /* preferClaimedTokens */ false) + .returns(); + + // Keep it simple and let 1 token exchange for 1 wei + await mockJBPaymentTerminalStore.mock.recordRedemptionFor + .withArgs(holder.address, PROJECT_ID, /* tokenCount */ AMOUNT, MEMO, METADATA1) + .returns( + fundingCycle, + /* reclaimAmount */ redeemedAmount, + /* delegate */[ + { delegate: mockJbRedemptionDelegate.address, amount: delegate1Amount, metadata: METADATA2 }, + { delegate: mockJbRedemptionDelegate2.address, amount: delegate2Amount, metadata: METADATA3 }, + ], + ADJUSTED_MEMO, + ); + + await mockJBPaymentTerminalStore.mock.recordAddedBalanceFor.returns(); + + let tokenAddress = await jbEthPaymentTerminal.token(); + await mockJbRedemptionDelegate.mock.didRedeem + .withArgs({ + // JBDidRedeemData obj + holder: holder.address, + projectId: PROJECT_ID, + currentFundingCycleConfiguration: timestamp, + projectTokenCount: AMOUNT, + reclaimedAmount: { + token: tokenAddress, + value: redeemedAmount, + decimals: DECIMALS_ETH, + currency: CURRENCY_ETH, + }, + forwardedAmount: { + token: tokenAddress, + value: delegate1Amount - DELEGATE_1_FEE, + decimals: DECIMALS_ETH, + currency: CURRENCY_ETH, + }, + beneficiary: beneficiary.address, + memo: ADJUSTED_MEMO, + dataSourceMetadata: METADATA2, + redeemerMetadata: METADATA1, + }) + .returns(); + + await mockJbRedemptionDelegate2.mock.didRedeem + .withArgs({ + // JBDidRedeemData obj + holder: holder.address, + projectId: PROJECT_ID, + currentFundingCycleConfiguration: timestamp, + projectTokenCount: AMOUNT, + reclaimedAmount: { + token: tokenAddress, + value: redeemedAmount, + decimals: DECIMALS_ETH, + currency: CURRENCY_ETH, + }, + forwardedAmount: { + token: tokenAddress, + value: delegate2Amount - DELEGATE_2_FEE, + decimals: DECIMALS_ETH, + currency: CURRENCY_ETH, + }, + beneficiary: beneficiary.address, + memo: ADJUSTED_MEMO, + dataSourceMetadata: METADATA3, + redeemerMetadata: METADATA1, + }) + .returns(); + + await setBalance(jbEthPaymentTerminal.address, RECLAIM_AMOUNT); + + const initialBeneficiaryBalance = await ethers.provider.getBalance(beneficiary.address); + const initialDelegate1Balance = await ethers.provider.getBalance( + mockJbRedemptionDelegate.address, + ); + const initialDelegate2Balance = await ethers.provider.getBalance( + mockJbRedemptionDelegate2.address, + ); + + // Used with hardcoded one to get JBDao terminal + await mockJbDirectory.mock.primaryTerminalOf + .withArgs(1, ETH_ADDRESS) + .returns(mockJbEthPaymentTerminal.address); + + await mockJbEthPaymentTerminal.mock.pay + .withArgs( + 1, //JBX Dao + REDEEM_FEE + DELEGATE_1_FEE + DELEGATE_2_FEE, + ETH_ADDRESS, + beneficiary.address, + 0, + false, + '', + ethers.utils.hexZeroPad(ethers.utils.hexlify(PROJECT_ID), 32), + ) + .returns(0); + + const tx = await jbEthPaymentTerminal + .connect(holder) + .redeemTokensOf( + holder.address, + PROJECT_ID, + /* tokenCount */ AMOUNT, + /* token */ ethers.constants.AddressZero, + /* minReturnedTokens */ redeemedAmount, + beneficiary.address, + MEMO, + METADATA1, + ); + + // Uncaught AssertionError: expected [ Array(4) ] to equal [ Array(4) ] + await expect(tx).to.emit(jbEthPaymentTerminal, 'DelegateDidRedeem(address,(address,uint256,uint256,uint256,(address,uint256,uint256,uint256),(address,uint256,uint256,uint256),address,string,bytes,bytes),uint256,uint256,address)'); + // .withArgs( + // mockJbRedemptionDelegate.address, + // [ + // // JBDidRedeemData obj + // holder.address, + // PROJECT_ID, + // AMOUNT, + // [ + // tokenAddress, + // ethers.BigNumber.from(RECLAIM_AMOUNT), + // ethers.BigNumber.from(DECIMALS_ETH), + // CURRENCY_ETH, + // ], + // beneficiary.address, + // ADJUSTED_MEMO, + // METADATA1, + // ], + // /* msg.sender */ holder.address, + // ); + + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'RedeemTokens') + .withArgs( + /* _fundingCycle.configuration */ timestamp, + /* _fundingCycle.number */ FUNDING_CYCLE_NUM, + /* _projectId */ PROJECT_ID, + /* _holder */ holder.address, + /* _beneficiary */ beneficiary.address, + /* _tokenCount */ AMOUNT, + /* reclaimAmount */ redeemedAmount - REDEEM_FEE, + /* memo */ ADJUSTED_MEMO, + /* metadata */ METADATA1, + /* msg.sender */ holder.address, + ); + + // Terminal should be out of ETH + expect(await ethers.provider.getBalance(jbEthPaymentTerminal.address)).to.equal(0); + + // Beneficiary should have a larger balance + expect(await ethers.provider.getBalance(beneficiary.address)).to.equal( + initialBeneficiaryBalance.add(redeemedAmount - REDEEM_FEE), + ); + + // Delegate1 should have a larger balance + expect(await ethers.provider.getBalance(mockJbRedemptionDelegate.address)).to.equal( + initialDelegate1Balance.add(delegate1Amount - DELEGATE_1_FEE), + ); + + // Delegate2 should have a larger balance + expect(await ethers.provider.getBalance(mockJbRedemptionDelegate2.address)).to.equal( + initialDelegate2Balance.add(delegate2Amount - DELEGATE_2_FEE), + ); + }); + + it('Should redeem tokens, call multiple delegate and send the appropriate amount to them, with a sub-100% redemption rate that incurrs fees with gauge', async function () { + const { + beneficiary, + fundingCycle, + holder, + terminalOwner, + jbEthPaymentTerminal, + mockJbEthPaymentTerminal, + mockJBPaymentTerminalStore, + mockJbRedemptionDelegate, + mockJbRedemptionDelegate2, + mockJbDirectory, + mockJbController, + mockJbFeeGauge, + timestamp, + } = await setup(); + + fundingCycle.metadata = packFundingCycleMetadata({ + redemptionRate: 9000, // 90% redemption rate + }); + + const delegate1Amount = RECLAIM_AMOUNT / 2; + const delegate2Amount = RECLAIM_AMOUNT / 4; + const redeemedAmount = RECLAIM_AMOUNT - delegate1Amount - delegate2Amount; + + const DISCOUNTED_FEE = + DEFAULT_FEE - Math.floor((DEFAULT_FEE * FEE_DISCOUNT) / MAX_FEE_DISCOUNT); + + let DELEGATE_1_FEE = + delegate1Amount - Math.floor((delegate1Amount * MAX_FEE) / (DISCOUNTED_FEE + MAX_FEE)); + let DELEGATE_2_FEE = + delegate2Amount - Math.floor((delegate2Amount * MAX_FEE) / (DISCOUNTED_FEE + MAX_FEE)); + let REDEEM_FEE = + redeemedAmount - Math.floor((redeemedAmount * MAX_FEE) / (DISCOUNTED_FEE + MAX_FEE)); + + await jbEthPaymentTerminal.connect(terminalOwner).setFeeGauge(mockJbFeeGauge.address); + await mockJbFeeGauge.mock.currentDiscountFor.withArgs(PROJECT_ID, 2).returns(FEE_DISCOUNT); + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + await mockJbController.mock.burnTokensOf + .withArgs(holder.address, PROJECT_ID, AMOUNT, /* memo */ '', /* preferClaimedTokens */ false) + .returns(); + + // Keep it simple and let 1 token exchange for 1 wei + await mockJBPaymentTerminalStore.mock.recordRedemptionFor + .withArgs(holder.address, PROJECT_ID, /* tokenCount */ AMOUNT, MEMO, METADATA1) + .returns( + fundingCycle, + /* reclaimAmount */ redeemedAmount, + /* delegate */[ + { delegate: mockJbRedemptionDelegate.address, amount: delegate1Amount, metadata: METADATA2 }, + { delegate: mockJbRedemptionDelegate2.address, amount: delegate2Amount, metadata: METADATA3 }, + ], + ADJUSTED_MEMO, + ); + + await mockJBPaymentTerminalStore.mock.recordAddedBalanceFor.returns(); + + let tokenAddress = await jbEthPaymentTerminal.token(); + await mockJbRedemptionDelegate.mock.didRedeem + .withArgs({ + // JBDidRedeemData obj + holder: holder.address, + projectId: PROJECT_ID, + currentFundingCycleConfiguration: timestamp, + projectTokenCount: AMOUNT, + reclaimedAmount: { + token: tokenAddress, + value: redeemedAmount, + decimals: DECIMALS_ETH, + currency: CURRENCY_ETH, + }, + forwardedAmount: { + token: tokenAddress, + value: delegate1Amount - DELEGATE_1_FEE, + decimals: DECIMALS_ETH, + currency: CURRENCY_ETH, + }, + beneficiary: beneficiary.address, + memo: ADJUSTED_MEMO, + dataSourceMetadata: METADATA2, + redeemerMetadata: METADATA1, + }) + .returns(); + + await mockJbRedemptionDelegate2.mock.didRedeem + .withArgs({ + // JBDidRedeemData obj + holder: holder.address, + projectId: PROJECT_ID, + currentFundingCycleConfiguration: timestamp, + projectTokenCount: AMOUNT, + reclaimedAmount: { + token: tokenAddress, + value: redeemedAmount, + decimals: DECIMALS_ETH, + currency: CURRENCY_ETH, + }, + forwardedAmount: { + token: tokenAddress, + value: delegate2Amount - DELEGATE_2_FEE, + decimals: DECIMALS_ETH, + currency: CURRENCY_ETH, + }, + beneficiary: beneficiary.address, + memo: ADJUSTED_MEMO, + dataSourceMetadata: METADATA3, + redeemerMetadata: METADATA1, + }) + .returns(); + + await setBalance(jbEthPaymentTerminal.address, RECLAIM_AMOUNT); + + const initialBeneficiaryBalance = await ethers.provider.getBalance(beneficiary.address); + const initialDelegate1Balance = await ethers.provider.getBalance( + mockJbRedemptionDelegate.address, + ); + const initialDelegate2Balance = await ethers.provider.getBalance( + mockJbRedemptionDelegate2.address, + ); + + // Used with hardcoded one to get JBDao terminal + await mockJbDirectory.mock.primaryTerminalOf + .withArgs(1, ETH_ADDRESS) + .returns(mockJbEthPaymentTerminal.address); + + const tx = await jbEthPaymentTerminal + .connect(holder) + .redeemTokensOf( + holder.address, + PROJECT_ID, + /* tokenCount */ AMOUNT, + /* token */ ethers.constants.AddressZero, + /* minReturnedTokens */ redeemedAmount, + beneficiary.address, + MEMO, + METADATA1, + ); + + // Uncaught AssertionError: expected [ Array(4) ] to equal [ Array(4) ] + await expect(tx).to.emit(jbEthPaymentTerminal, 'DelegateDidRedeem(address,(address,uint256,uint256,uint256,(address,uint256,uint256,uint256),(address,uint256,uint256,uint256),address,string,bytes,bytes),uint256,uint256,address)'); + // .withArgs( + // mockJbRedemptionDelegate.address, + // [ + // // JBDidRedeemData obj + // holder.address, + // PROJECT_ID, + // AMOUNT, + // [ + // tokenAddress, + // ethers.BigNumber.from(RECLAIM_AMOUNT), + // ethers.BigNumber.from(DECIMALS_ETH), + // CURRENCY_ETH, + // ], + // beneficiary.address, + // ADJUSTED_MEMO, + // METADATA1, + // ], + // /* msg.sender */ holder.address, + // ); + + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'RedeemTokens') + .withArgs( + /* _fundingCycle.configuration */ timestamp, + /* _fundingCycle.number */ FUNDING_CYCLE_NUM, + /* _projectId */ PROJECT_ID, + /* _holder */ holder.address, + /* _beneficiary */ beneficiary.address, + /* _tokenCount */ AMOUNT, + /* reclaimAmount */ redeemedAmount - REDEEM_FEE, + /* memo */ ADJUSTED_MEMO, + /* metadata */ METADATA1, + /* msg.sender */ holder.address, + ); + + // Terminal should be out of ETH + expect(await ethers.provider.getBalance(jbEthPaymentTerminal.address)).to.equal(REDEEM_FEE + DELEGATE_1_FEE + DELEGATE_2_FEE); + + // Beneficiary should have a larger balance + expect(await ethers.provider.getBalance(beneficiary.address)).to.equal( + initialBeneficiaryBalance.add(redeemedAmount - REDEEM_FEE), + ); + + // Delegate1 should have a larger balance + expect(await ethers.provider.getBalance(mockJbRedemptionDelegate.address)).to.equal( + initialDelegate1Balance.add(delegate1Amount - DELEGATE_1_FEE), + ); + + // Delegate2 should have a larger balance + expect(await ethers.provider.getBalance(mockJbRedemptionDelegate2.address)).to.equal( + initialDelegate2Balance.add(delegate2Amount - DELEGATE_2_FEE), + ); + }); + + it('Should redeem tokens, call multiple delegate and send the appropriate amount to them, with a sub-100% redemption rate that would incurrs fees if the beneficiary wasnt feeless', async function () { + const { + beneficiary, + fundingCycle, + terminalOwner, + holder, + jbEthPaymentTerminal, + mockJBPaymentTerminalStore, + mockJbRedemptionDelegate, + mockJbRedemptionDelegate2, + mockJbDirectory, + mockJbController, + timestamp, + } = await setup(); + + fundingCycle.metadata = packFundingCycleMetadata({ + redemptionRate: 9000, // 90% redemption rate + }); + + const delegate1Amount = RECLAIM_AMOUNT / 2; + const delegate2Amount = RECLAIM_AMOUNT / 4; + const redeemedAmount = RECLAIM_AMOUNT - delegate1Amount - delegate2Amount; + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + await mockJbController.mock.burnTokensOf + .withArgs(holder.address, PROJECT_ID, AMOUNT, /* memo */ '', /* preferClaimedTokens */ false) + .returns(); + + // Keep it simple and let 1 token exchange for 1 wei + await mockJBPaymentTerminalStore.mock.recordRedemptionFor + .withArgs(holder.address, PROJECT_ID, /* tokenCount */ AMOUNT, MEMO, METADATA1) + .returns( + fundingCycle, + /* reclaimAmount */ redeemedAmount, + /* delegate */[ + { delegate: mockJbRedemptionDelegate.address, amount: delegate1Amount, metadata: METADATA2 }, + { delegate: mockJbRedemptionDelegate2.address, amount: delegate2Amount, metadata: METADATA3 }, + ], + ADJUSTED_MEMO, + ); + + // Used with hardcoded one to get JBDao terminal + await mockJbDirectory.mock.primaryTerminalOf + .withArgs(1, ETH_ADDRESS) + .returns(jbEthPaymentTerminal.address); + + await mockJBPaymentTerminalStore.mock.recordAddedBalanceFor.returns(); + + let tokenAddress = await jbEthPaymentTerminal.token(); + await mockJbRedemptionDelegate.mock.didRedeem + .withArgs({ + // JBDidRedeemData obj + holder: holder.address, + projectId: PROJECT_ID, + currentFundingCycleConfiguration: timestamp, + projectTokenCount: AMOUNT, + reclaimedAmount: { + token: tokenAddress, + value: redeemedAmount, + decimals: DECIMALS_ETH, + currency: CURRENCY_ETH, + }, + forwardedAmount: { + token: tokenAddress, + value: delegate1Amount, + decimals: DECIMALS_ETH, + currency: CURRENCY_ETH, + }, + beneficiary: beneficiary.address, + memo: ADJUSTED_MEMO, + dataSourceMetadata: METADATA2, + redeemerMetadata: METADATA1, + }) + .returns(); + + await mockJbRedemptionDelegate2.mock.didRedeem + .withArgs({ + // JBDidRedeemData obj + holder: holder.address, + projectId: PROJECT_ID, + currentFundingCycleConfiguration: timestamp, + projectTokenCount: AMOUNT, + reclaimedAmount: { + token: tokenAddress, + value: redeemedAmount, + decimals: DECIMALS_ETH, + currency: CURRENCY_ETH, + }, + forwardedAmount: { + token: tokenAddress, + value: delegate2Amount, + decimals: DECIMALS_ETH, + currency: CURRENCY_ETH, + }, + beneficiary: beneficiary.address, + memo: ADJUSTED_MEMO, + dataSourceMetadata: METADATA3, + redeemerMetadata: METADATA1, + }) + .returns(); + + await setBalance(jbEthPaymentTerminal.address, RECLAIM_AMOUNT); + + const initialBeneficiaryBalance = await ethers.provider.getBalance(beneficiary.address); + const initialDelegate1Balance = await ethers.provider.getBalance( + mockJbRedemptionDelegate.address, + ); + const initialDelegate2Balance = await ethers.provider.getBalance( + mockJbRedemptionDelegate2.address, + ); + + await jbEthPaymentTerminal + .connect(terminalOwner) + .setFeelessAddress(beneficiary.address, true); + + const tx = await jbEthPaymentTerminal + .connect(holder) + .redeemTokensOf( + holder.address, + PROJECT_ID, + /* tokenCount */ AMOUNT, + /* token */ ethers.constants.AddressZero, + /* minReturnedTokens */ redeemedAmount, + beneficiary.address, + MEMO, + METADATA1, + ); + + // Uncaught AssertionError: expected [ Array(4) ] to equal [ Array(4) ] + await expect(tx).to.emit(jbEthPaymentTerminal, 'DelegateDidRedeem(address,(address,uint256,uint256,uint256,(address,uint256,uint256,uint256),(address,uint256,uint256,uint256),address,string,bytes,bytes),uint256,uint256,address)'); + // .withArgs( + // mockJbRedemptionDelegate.address, + // [ + // // JBDidRedeemData obj + // holder.address, + // PROJECT_ID, + // AMOUNT, + // [ + // tokenAddress, + // ethers.BigNumber.from(RECLAIM_AMOUNT), + // ethers.BigNumber.from(DECIMALS_ETH), + // CURRENCY_ETH, + // ], + // beneficiary.address, + // ADJUSTED_MEMO, + // METADATA1, + // ], + // /* msg.sender */ holder.address, + // ); + + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'RedeemTokens') + .withArgs( + /* _fundingCycle.configuration */ timestamp, + /* _fundingCycle.number */ FUNDING_CYCLE_NUM, + /* _projectId */ PROJECT_ID, + /* _holder */ holder.address, + /* _beneficiary */ beneficiary.address, + /* _tokenCount */ AMOUNT, + /* reclaimAmount */ redeemedAmount, + /* memo */ ADJUSTED_MEMO, + /* metadata */ METADATA1, + /* msg.sender */ holder.address, + ); + + // Terminal should be out of ETH + expect(await ethers.provider.getBalance(jbEthPaymentTerminal.address)).to.equal(0); + + // Beneficiary should have a larger balance + expect(await ethers.provider.getBalance(beneficiary.address)).to.equal( + initialBeneficiaryBalance.add(redeemedAmount), + ); + + // Delegate1 should have a larger balance + expect(await ethers.provider.getBalance(mockJbRedemptionDelegate.address)).to.equal( + initialDelegate1Balance.add(delegate1Amount), + ); + + // Delegate2 should have a larger balance + expect(await ethers.provider.getBalance(mockJbRedemptionDelegate2.address)).to.equal( + initialDelegate2Balance.add(delegate2Amount), + ); + }); + + it('Should redeem tokens, call multiple delegate and send the appropriate amount to them, with a sub-100% redemption rate that would incurrs fees if the fee was non-zero', async function () { + const { + beneficiary, + fundingCycle, + terminalOwner, + holder, + jbEthPaymentTerminal, + mockJBPaymentTerminalStore, + mockJbRedemptionDelegate, + mockJbRedemptionDelegate2, + mockJbDirectory, + mockJbController, + timestamp, + } = await setup(); + + fundingCycle.metadata = packFundingCycleMetadata({ + redemptionRate: 9000, // 90% redemption rate + }); + + const delegate1Amount = RECLAIM_AMOUNT / 2; + const delegate2Amount = RECLAIM_AMOUNT / 4; + const redeemedAmount = RECLAIM_AMOUNT - delegate1Amount - delegate2Amount; + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + await mockJbController.mock.burnTokensOf + .withArgs(holder.address, PROJECT_ID, AMOUNT, /* memo */ '', /* preferClaimedTokens */ false) + .returns(); + + // Keep it simple and let 1 token exchange for 1 wei + await mockJBPaymentTerminalStore.mock.recordRedemptionFor + .withArgs(holder.address, PROJECT_ID, /* tokenCount */ AMOUNT, MEMO, METADATA1) + .returns( + fundingCycle, + /* reclaimAmount */ redeemedAmount, + /* delegate */[ + { delegate: mockJbRedemptionDelegate.address, amount: delegate1Amount, metadata: METADATA2 }, + { delegate: mockJbRedemptionDelegate2.address, amount: delegate2Amount, metadata: METADATA3 }, + ], + ADJUSTED_MEMO, + ); + + // Used with hardcoded one to get JBDao terminal + await mockJbDirectory.mock.primaryTerminalOf + .withArgs(1, ETH_ADDRESS) + .returns(jbEthPaymentTerminal.address); + + await mockJBPaymentTerminalStore.mock.recordAddedBalanceFor.returns(); + + let tokenAddress = await jbEthPaymentTerminal.token(); + await mockJbRedemptionDelegate.mock.didRedeem + .withArgs({ + // JBDidRedeemData obj + holder: holder.address, + projectId: PROJECT_ID, + currentFundingCycleConfiguration: timestamp, + projectTokenCount: AMOUNT, + reclaimedAmount: { + token: tokenAddress, + value: redeemedAmount, + decimals: DECIMALS_ETH, + currency: CURRENCY_ETH, + }, + forwardedAmount: { + token: tokenAddress, + value: delegate1Amount, + decimals: DECIMALS_ETH, + currency: CURRENCY_ETH, + }, + beneficiary: beneficiary.address, + memo: ADJUSTED_MEMO, + dataSourceMetadata: METADATA2, + redeemerMetadata: METADATA1, + }) + .returns(); + + await mockJbRedemptionDelegate2.mock.didRedeem + .withArgs({ + // JBDidRedeemData obj + holder: holder.address, + projectId: PROJECT_ID, + currentFundingCycleConfiguration: timestamp, + projectTokenCount: AMOUNT, + reclaimedAmount: { + token: tokenAddress, + value: redeemedAmount, + decimals: DECIMALS_ETH, + currency: CURRENCY_ETH, + }, + forwardedAmount: { + token: tokenAddress, + value: delegate2Amount, + decimals: DECIMALS_ETH, + currency: CURRENCY_ETH, + }, + beneficiary: beneficiary.address, + memo: ADJUSTED_MEMO, + dataSourceMetadata: METADATA3, + redeemerMetadata: METADATA1, + }) + .returns(); + + await setBalance(jbEthPaymentTerminal.address, RECLAIM_AMOUNT); + + const initialBeneficiaryBalance = await ethers.provider.getBalance(beneficiary.address); + const initialDelegate1Balance = await ethers.provider.getBalance( + mockJbRedemptionDelegate.address, + ); + const initialDelegate2Balance = await ethers.provider.getBalance( + mockJbRedemptionDelegate2.address, + ); + + await jbEthPaymentTerminal.connect(terminalOwner).setFee(0); + + const tx = await jbEthPaymentTerminal + .connect(holder) + .redeemTokensOf( + holder.address, + PROJECT_ID, + /* tokenCount */ AMOUNT, + /* token */ ethers.constants.AddressZero, + /* minReturnedTokens */ redeemedAmount, + beneficiary.address, + MEMO, + METADATA1, + ); + + // Uncaught AssertionError: expected [ Array(4) ] to equal [ Array(4) ] + await expect(tx).to.emit(jbEthPaymentTerminal, 'DelegateDidRedeem(address,(address,uint256,uint256,uint256,(address,uint256,uint256,uint256),(address,uint256,uint256,uint256),address,string,bytes,bytes),uint256,uint256,address)'); + // .withArgs( + // mockJbRedemptionDelegate.address, + // [ + // // JBDidRedeemData obj + // holder.address, + // PROJECT_ID, + // AMOUNT, + // [ + // tokenAddress, + // ethers.BigNumber.from(RECLAIM_AMOUNT), + // ethers.BigNumber.from(DECIMALS_ETH), + // CURRENCY_ETH, + // ], + // beneficiary.address, + // ADJUSTED_MEMO, + // METADATA1, + // ], + // /* msg.sender */ holder.address, + // ); + + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'RedeemTokens') + .withArgs( + /* _fundingCycle.configuration */ timestamp, + /* _fundingCycle.number */ FUNDING_CYCLE_NUM, + /* _projectId */ PROJECT_ID, + /* _holder */ holder.address, + /* _beneficiary */ beneficiary.address, + /* _tokenCount */ AMOUNT, + /* reclaimAmount */ redeemedAmount, + /* memo */ ADJUSTED_MEMO, + /* metadata */ METADATA1, + /* msg.sender */ holder.address, + ); + + // Terminal should be out of ETH + expect(await ethers.provider.getBalance(jbEthPaymentTerminal.address)).to.equal(0); + + // Beneficiary should have a larger balance + expect(await ethers.provider.getBalance(beneficiary.address)).to.equal( + initialBeneficiaryBalance.add(redeemedAmount), + ); + + // Delegate1 should have a larger balance + expect(await ethers.provider.getBalance(mockJbRedemptionDelegate.address)).to.equal( + initialDelegate1Balance.add(delegate1Amount), + ); + + // Delegate2 should have a larger balance + expect(await ethers.provider.getBalance(mockJbRedemptionDelegate2.address)).to.equal( + initialDelegate2Balance.add(delegate2Amount), + ); + }); + + it('Should not perform a transfer and only emit events if claim amount is 0', async function () { + const { + beneficiary, + fundingCycle, + holder, + jbEthPaymentTerminal, + mockJBPaymentTerminalStore, + mockJbDirectory, + mockJbController, + timestamp, + } = await setup(); + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + await mockJbController.mock.burnTokensOf + .withArgs(holder.address, PROJECT_ID, AMOUNT, /* memo */ '', /* preferClaimedTokens */ false) + .returns(); + + // Keep it simple and let 1 token exchange for 1 wei + await mockJBPaymentTerminalStore.mock.recordRedemptionFor + .withArgs(holder.address, PROJECT_ID, /* tokenCount */ AMOUNT, MEMO, METADATA1) + .returns(fundingCycle, /* reclaimAmount */ 0, /* delegateAllocation */[], ADJUSTED_MEMO); // Set reclaimAmount to 0 + + await setBalance(jbEthPaymentTerminal.address, AMOUNT); + + const initialBeneficiaryBalance = await ethers.provider.getBalance(beneficiary.address); + + const tx = await jbEthPaymentTerminal + .connect(holder) + .redeemTokensOf( + holder.address, + PROJECT_ID, + /* tokenCount */ AMOUNT, + /* token */ ethers.constants.AddressZero, + /* minReturnedTokens */ 0, + beneficiary.address, + MEMO, + METADATA1, + ); + + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'RedeemTokens') + .withArgs( + /* _fundingCycle.configuration */ timestamp, + /* _fundingCycle.number */ FUNDING_CYCLE_NUM, + /* _projectId */ PROJECT_ID, + /* _holder */ holder.address, + /* _beneficiary */ beneficiary.address, + /* _tokenCount */ AMOUNT, + /* reclaimAmount */ 0, + /* memo */ ADJUSTED_MEMO, + /* metadata */ METADATA1, + /* msg.sender */ holder.address, + ); + + // Terminal's ETH balance should not have changed + expect(await ethers.provider.getBalance(jbEthPaymentTerminal.address)).to.equal(AMOUNT); + + // Beneficiary should have the same balance + expect(await ethers.provider.getBalance(beneficiary.address)).to.equal( + initialBeneficiaryBalance, + ); + }); + + /* Sad path tests */ + + it(`Can't redeem tokens for overflow without access`, async function () { + const { beneficiary, holder, jbEthPaymentTerminal, mockJbOperatorStore, otherCaller } = + await setup(); + + await mockJbOperatorStore.mock.hasPermission.returns(false); + + await expect( + jbEthPaymentTerminal + .connect(otherCaller) + .redeemTokensOf( + holder.address, + PROJECT_ID, + /* tokenCount */ AMOUNT, + /* token */ ethers.constants.AddressZero, + /* minReturnedTokens */ AMOUNT, + beneficiary.address, + MEMO, + /* delegateMetadata */ 0, + ), + ).to.be.revertedWith(errors.UNAUTHORIZED); + }); + + it(`Can't redeem tokens for overflow if beneficiary is zero address`, async function () { + const { holder, jbEthPaymentTerminal } = await setup(); + + await expect( + jbEthPaymentTerminal.connect(holder).redeemTokensOf( + holder.address, + PROJECT_ID, + /* tokenCount */ AMOUNT, + ethers.constants.AddressZero, + /* minReturnedTokens */ AMOUNT, + /* beneficiary */ ethers.constants.AddressZero, // Beneficiary address is 0 + MEMO, + /* delegateMetadata */ 0, + ), + ).to.be.revertedWith(errors.REDEEM_TO_ZERO_ADDRESS); + }); + it("Can't redeem if reclaim amount is less than expected", async function () { + const { + beneficiary, + fundingCycle, + holder, + jbEthPaymentTerminal, + mockJBPaymentTerminalStore, + mockJbDirectory, + mockJbController, + timestamp, + } = await setup(); + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + await mockJbController.mock.burnTokensOf + .withArgs(holder.address, PROJECT_ID, AMOUNT, /* memo */ '', /* preferClaimedTokens */ false) + .returns(); + + // Keep it simple and let 1 token exchange for 1 wei + await mockJBPaymentTerminalStore.mock.recordRedemptionFor + .withArgs(holder.address, PROJECT_ID, /* tokenCount */ AMOUNT, MEMO, METADATA1) + .returns(fundingCycle, /* reclaimAmount */ 0, /* delegateAllocation */[], ADJUSTED_MEMO); // Set reclaimAmount to 0 + + await expect( + jbEthPaymentTerminal + .connect(holder) + .redeemTokensOf( + holder.address, + PROJECT_ID, + /* tokenCount */ AMOUNT, + /* token */ ethers.constants.AddressZero, + /* minReturnedTokens */ MIN_RETURNED_AMOUNT, + beneficiary.address, + MEMO, + METADATA1, + ), + ).to.be.revertedWith(errors.INADEQUATE_RECLAIM_AMOUNT); + }); +}); diff --git a/test/jb_payment_terminal_3_1_1/set_fee.test.js b/test/jb_payment_terminal_3_1_1/set_fee.test.js new file mode 100644 index 000000000..57bf1ac54 --- /dev/null +++ b/test/jb_payment_terminal_3_1_1/set_fee.test.js @@ -0,0 +1,85 @@ +import { expect } from 'chai'; +import { ethers } from 'hardhat'; +import errors from '../helpers/errors.json'; + +import { deployMockContract } from '@ethereum-waffle/mock-contract'; + +import jbDirectory from '../../artifacts/contracts/interfaces/IJBDirectory.sol/IJBDirectory.json'; +import jbPaymentTerminalStore from '../../artifacts/contracts/JBSingleTokenPaymentTerminalStore3_1_1.sol/JBSingleTokenPaymentTerminalStore3_1_1.json'; +import jbOperatoreStore from '../../artifacts/contracts/interfaces/IJBOperatorStore.sol/IJBOperatorStore.json'; +import jbProjects from '../../artifacts/contracts/interfaces/IJBProjects.sol/IJBProjects.json'; +import jbSplitsStore from '../../artifacts/contracts/interfaces/IJBSplitsStore.sol/IJBSplitsStore.json'; +import jbPrices from '../../artifacts/contracts/interfaces/IJBPrices.sol/IJBPrices.json'; + +describe('JBPayoutRedemptionPaymentTerminal3_1_1::setFee(...)', function () { + const NEW_FEE = 8; // 4% + + async function setup() { + let [deployer, terminalOwner, caller] = await ethers.getSigners(); + + let [ + mockJbDirectory, + mockJBPaymentTerminalStore, + mockJbOperatorStore, + mockJbProjects, + mockJbSplitsStore, + mockJbPrices, + ] = await Promise.all([ + deployMockContract(deployer, jbDirectory.abi), + deployMockContract(deployer, jbPaymentTerminalStore.abi), + deployMockContract(deployer, jbOperatoreStore.abi), + deployMockContract(deployer, jbProjects.abi), + deployMockContract(deployer, jbSplitsStore.abi), + deployMockContract(deployer, jbPrices.abi), + ]); + + const jbCurrenciesFactory = await ethers.getContractFactory('JBCurrencies'); + const jbCurrencies = await jbCurrenciesFactory.deploy(); + const CURRENCY_ETH = await jbCurrencies.ETH(); + + let jbTerminalFactory = await ethers.getContractFactory( + 'contracts/JBETHPaymentTerminal3_1_1.sol:JBETHPaymentTerminal3_1_1', + deployer, + ); + + let jbEthPaymentTerminal = await jbTerminalFactory + .connect(deployer) + .deploy( + CURRENCY_ETH, + mockJbOperatorStore.address, + mockJbProjects.address, + mockJbDirectory.address, + mockJbSplitsStore.address, + mockJbPrices.address, + mockJBPaymentTerminalStore.address, + terminalOwner.address, + ); + + return { + jbEthPaymentTerminal, + terminalOwner, + caller, + }; + } + + it('Should set new fee and emit event if caller is terminal owner', async function () { + const { jbEthPaymentTerminal, terminalOwner } = await setup(); + + await expect(jbEthPaymentTerminal.connect(terminalOwner).setFee(NEW_FEE)) + .to.emit(jbEthPaymentTerminal, 'SetFee') + .withArgs(NEW_FEE, terminalOwner.address); + }); + + it("Can't set fee above 5%", async function () { + const { jbEthPaymentTerminal, terminalOwner } = await setup(); + await expect(jbEthPaymentTerminal.connect(terminalOwner).setFee(50_000_001)) // 5.0000001% (out of 1,000,000,000) + .to.be.revertedWith(errors.FEE_TOO_HIGH); + }); + + it("Can't set fee if caller is not owner", async function () { + const { jbEthPaymentTerminal, caller } = await setup(); + await expect(jbEthPaymentTerminal.connect(caller).setFee(40_000_000)).to.be.revertedWith( + 'Ownable: caller is not the owner', + ); + }); +}); diff --git a/test/jb_payment_terminal_3_1_1/set_fee_gauge.test.js b/test/jb_payment_terminal_3_1_1/set_fee_gauge.test.js new file mode 100644 index 000000000..e7d474472 --- /dev/null +++ b/test/jb_payment_terminal_3_1_1/set_fee_gauge.test.js @@ -0,0 +1,80 @@ +import { expect } from 'chai'; +import { ethers } from 'hardhat'; + +import { deployMockContract } from '@ethereum-waffle/mock-contract'; + +import jbDirectory from '../../artifacts/contracts/interfaces/IJBDirectory.sol/IJBDirectory.json'; +import jbPaymentTerminalStore from '../../artifacts/contracts/JBSingleTokenPaymentTerminalStore3_1_1.sol/JBSingleTokenPaymentTerminalStore3_1_1.json'; +import jbFeeGauge from '../../artifacts/contracts/interfaces/IJBFeeGauge.sol/IJBFeeGauge.json'; +import jbOperatoreStore from '../../artifacts/contracts/interfaces/IJBOperatorStore.sol/IJBOperatorStore.json'; +import jbProjects from '../../artifacts/contracts/interfaces/IJBProjects.sol/IJBProjects.json'; +import jbSplitsStore from '../../artifacts/contracts/interfaces/IJBSplitsStore.sol/IJBSplitsStore.json'; +import jbPrices from '../../artifacts/contracts/interfaces/IJBPrices.sol/IJBPrices.json'; + +describe('JBPayoutRedemptionPaymentTerminal3_1_1::setFeeGauge(...)', function () { + async function setup() { + let [deployer, terminalOwner, caller] = await ethers.getSigners(); + + let [ + mockJbDirectory, + mockJBPaymentTerminalStore, + mockJbFeeGauge, + mockJbOperatorStore, + mockJbProjects, + mockJbSplitsStore, + mockJbPrices, + ] = await Promise.all([ + deployMockContract(deployer, jbDirectory.abi), + deployMockContract(deployer, jbPaymentTerminalStore.abi), + deployMockContract(deployer, jbFeeGauge.abi), + deployMockContract(deployer, jbOperatoreStore.abi), + deployMockContract(deployer, jbProjects.abi), + deployMockContract(deployer, jbSplitsStore.abi), + deployMockContract(deployer, jbPrices.abi), + ]); + + const jbCurrenciesFactory = await ethers.getContractFactory('JBCurrencies'); + const jbCurrencies = await jbCurrenciesFactory.deploy(); + const CURRENCY_ETH = await jbCurrencies.ETH(); + + let jbTerminalFactory = await ethers.getContractFactory( + 'contracts/JBETHPaymentTerminal3_1_1.sol:JBETHPaymentTerminal3_1_1', + deployer, + ); + + let jbEthPaymentTerminal = await jbTerminalFactory + .connect(deployer) + .deploy( + CURRENCY_ETH, + mockJbOperatorStore.address, + mockJbProjects.address, + mockJbDirectory.address, + mockJbSplitsStore.address, + mockJbPrices.address, + mockJBPaymentTerminalStore.address, + terminalOwner.address, + ); + + return { + terminalOwner, + caller, + jbEthPaymentTerminal, + mockJbFeeGauge, + }; + } + + it('Should set the fee gauge and emit event if caller is terminal owner', async function () { + const { terminalOwner, jbEthPaymentTerminal, mockJbFeeGauge } = await setup(); + + await expect(jbEthPaymentTerminal.connect(terminalOwner).setFeeGauge(mockJbFeeGauge.address)) + .to.emit(jbEthPaymentTerminal, 'SetFeeGauge') + .withArgs(mockJbFeeGauge.address, terminalOwner.address); + }); + it("Can't set the fee gauge if caller is not the terminal owner", async function () { + const { caller, jbEthPaymentTerminal, mockJbFeeGauge } = await setup(); + + await expect( + jbEthPaymentTerminal.connect(caller).setFeeGauge(mockJbFeeGauge.address), + ).to.be.revertedWith('Ownable: caller is not the owner'); + }); +}); diff --git a/test/jb_payment_terminal_3_1_1/set_feeless_terminal.test.js b/test/jb_payment_terminal_3_1_1/set_feeless_terminal.test.js new file mode 100644 index 000000000..d9ff9e9c2 --- /dev/null +++ b/test/jb_payment_terminal_3_1_1/set_feeless_terminal.test.js @@ -0,0 +1,108 @@ +import { expect } from 'chai'; +import { ethers } from 'hardhat'; + +import { deployMockContract } from '@ethereum-waffle/mock-contract'; + +import jbDirectory from '../../artifacts/contracts/interfaces/IJBDirectory.sol/IJBDirectory.json'; +import JBEthPaymentTerminal from '../../artifacts/contracts/JBETHPaymentTerminal3_1_1.sol/JBETHPaymentTerminal3_1_1.json'; +import jbPaymentTerminalStore from '../../artifacts/contracts/JBSingleTokenPaymentTerminalStore3_1_1.sol/JBSingleTokenPaymentTerminalStore3_1_1.json'; +import jbOperatoreStore from '../../artifacts/contracts/interfaces/IJBOperatorStore.sol/IJBOperatorStore.json'; +import jbProjects from '../../artifacts/contracts/interfaces/IJBProjects.sol/IJBProjects.json'; +import jbSplitsStore from '../../artifacts/contracts/interfaces/IJBSplitsStore.sol/IJBSplitsStore.json'; +import jbPrices from '../../artifacts/contracts/interfaces/IJBPrices.sol/IJBPrices.json'; + +describe('JBPayoutRedemptionPaymentTerminal3_1_1::setFeelessAddress(...)', function () { + async function setup() { + let [deployer, terminalOwner, caller] = await ethers.getSigners(); + + let [ + mockJbDirectory, + mockJbEthPaymentTerminal, + mockJBPaymentTerminalStore, + mockJbOperatorStore, + mockJbProjects, + mockJbSplitsStore, + mockJbPrices, + ] = await Promise.all([ + deployMockContract(deployer, jbDirectory.abi), + deployMockContract(deployer, JBEthPaymentTerminal.abi), + deployMockContract(deployer, jbPaymentTerminalStore.abi), + deployMockContract(deployer, jbOperatoreStore.abi), + deployMockContract(deployer, jbProjects.abi), + deployMockContract(deployer, jbSplitsStore.abi), + deployMockContract(deployer, jbPrices.abi), + ]); + + const jbCurrenciesFactory = await ethers.getContractFactory('JBCurrencies'); + const jbCurrencies = await jbCurrenciesFactory.deploy(); + const CURRENCY_ETH = await jbCurrencies.ETH(); + + let jbTerminalFactory = await ethers.getContractFactory( + 'contracts/JBETHPaymentTerminal3_1_1.sol:JBETHPaymentTerminal3_1_1', + deployer, + ); + + let jbEthPaymentTerminal = await jbTerminalFactory + .connect(deployer) + .deploy( + CURRENCY_ETH, + mockJbOperatorStore.address, + mockJbProjects.address, + mockJbDirectory.address, + mockJbSplitsStore.address, + mockJbPrices.address, + mockJBPaymentTerminalStore.address, + terminalOwner.address, + ); + + return { + terminalOwner, + caller, + jbEthPaymentTerminal, + mockJbEthPaymentTerminal, + }; + } + + it('Should add a terminal as feeless and emit event', async function () { + const { terminalOwner, jbEthPaymentTerminal, mockJbEthPaymentTerminal } = await setup(); + + expect( + await jbEthPaymentTerminal + .connect(terminalOwner) + .setFeelessAddress(mockJbEthPaymentTerminal.address, true), + ) + .to.emit(jbEthPaymentTerminal, 'SetFeelessAddress') + .withArgs(mockJbEthPaymentTerminal.address, true, terminalOwner.address); + + expect(await jbEthPaymentTerminal.isFeelessAddress(mockJbEthPaymentTerminal.address)).to.be + .true; + }); + + it('Should remove a terminal as feeless and emit event', async function () { + const { terminalOwner, jbEthPaymentTerminal, mockJbEthPaymentTerminal } = await setup(); + + await jbEthPaymentTerminal + .connect(terminalOwner) + .setFeelessAddress(mockJbEthPaymentTerminal.address, true); + + expect( + await jbEthPaymentTerminal + .connect(terminalOwner) + .setFeelessAddress(mockJbEthPaymentTerminal.address, false), + ) + .to.emit(jbEthPaymentTerminal, 'SetFeelessAddress') + .withArgs(mockJbEthPaymentTerminal.address, false, terminalOwner.address); + + expect(await jbEthPaymentTerminal.isFeelessAddress(mockJbEthPaymentTerminal.address)).to.be + .false; + }); + + it('Cannot set a feeless terminal if caller is not the owner', async function () { + const { caller, jbEthPaymentTerminal, mockJbEthPaymentTerminal } = await setup(); + await expect( + jbEthPaymentTerminal + .connect(caller) + .setFeelessAddress(mockJbEthPaymentTerminal.address, true), + ).to.be.revertedWith('Ownable: caller is not the owner'); + }); +}); diff --git a/test/jb_payment_terminal_3_1_1/use_allowance_of.test.js b/test/jb_payment_terminal_3_1_1/use_allowance_of.test.js new file mode 100644 index 000000000..38849a87c --- /dev/null +++ b/test/jb_payment_terminal_3_1_1/use_allowance_of.test.js @@ -0,0 +1,1053 @@ +import { expect } from 'chai'; +import { ethers } from 'hardhat'; +import { deployMockContract } from '@ethereum-waffle/mock-contract'; + +import errors from '../helpers/errors.json'; +import { packFundingCycleMetadata, setBalance } from '../helpers/utils.js'; + +import jbDirectory from '../../artifacts/contracts/interfaces/IJBDirectory.sol/IJBDirectory.json'; +import jbPaymentTerminalStore from '../../artifacts/contracts/JBSingleTokenPaymentTerminalStore3_1_1.sol/JBSingleTokenPaymentTerminalStore3_1_1.json'; +import jbFeeGauge from '../../artifacts/contracts/interfaces/IJBFeeGauge3_1.sol/IJBFeeGauge3_1.json'; +import jbOperatoreStore from '../../artifacts/contracts/interfaces/IJBOperatorStore.sol/IJBOperatorStore.json'; +import jbProjects from '../../artifacts/contracts/interfaces/IJBProjects.sol/IJBProjects.json'; +import jbSplitsStore from '../../artifacts/contracts/interfaces/IJBSplitsStore.sol/IJBSplitsStore.json'; +import jbPrices from '../../artifacts/contracts/interfaces/IJBPrices.sol/IJBPrices.json'; + +describe('JBPayoutRedemptionPaymentTerminal3_1_1::useAllowanceOf(...)', function () { + const AMOUNT_TO_DISTRIBUTE = 40000; + const AMOUNT = 50000; + const DEFAULT_FEE = 50000000; // 5% + const FEE_DISCOUNT = 500000000; // 50% + + const FUNDING_CYCLE_NUM = 1; + const JUICEBOX_PROJECT_ID = 1; + const MEMO = 'test memo'; + const METADATA = '0x69'; + const PROJECT_ID = 13; + const WEIGHT = 1000; + + const ETH_ADDRESS = '0x000000000000000000000000000000000000EEEe'; + + let MAX_FEE; + let MAX_FEE_DISCOUNT; + let AMOUNT_MINUS_FEES; + + let PROCESS_FEES_PERMISSION_INDEX; + + before(async function () { + let jbOperationsFactory = await ethers.getContractFactory('JBOperations'); + let jbOperations = await jbOperationsFactory.deploy(); + + PROCESS_FEES_PERMISSION_INDEX = await jbOperations.PROCESS_FEES(); + }); + + async function setup() { + const [deployer, caller, beneficiary, otherCaller, projectOwner, terminalOwner] = + await ethers.getSigners(); + + const blockNum = await ethers.provider.getBlockNumber(); + const block = await ethers.provider.getBlock(blockNum); + const timestamp = block.timestamp; + + const [ + mockJbDirectory, + mockJBPaymentTerminalStore, + mockJbFeeGauge, + mockJbOperatorStore, + mockJbProjects, + mockJbPrices, + mockJbSplitsStore, + ] = await Promise.all([ + deployMockContract(deployer, jbDirectory.abi), + deployMockContract(deployer, jbPaymentTerminalStore.abi), + deployMockContract(deployer, jbFeeGauge.abi), + deployMockContract(deployer, jbOperatoreStore.abi), + deployMockContract(deployer, jbProjects.abi), + deployMockContract(deployer, jbPrices.abi), + deployMockContract(deployer, jbSplitsStore.abi), + ]); + + const jbCurrenciesFactory = await ethers.getContractFactory('JBCurrencies'); + const jbCurrencies = await jbCurrenciesFactory.deploy(); + const CURRENCY_ETH = await jbCurrencies.ETH(); + + const jbTerminalFactory = await ethers.getContractFactory( + 'contracts/JBETHPaymentTerminal3_1_1.sol:JBETHPaymentTerminal3_1_1', + deployer, + ); + + const jbEthPaymentTerminal = await jbTerminalFactory + .connect(deployer) + .deploy( + CURRENCY_ETH, + mockJbOperatorStore.address, + mockJbProjects.address, + mockJbDirectory.address, + mockJbSplitsStore.address, + mockJbPrices.address, + mockJBPaymentTerminalStore.address, + terminalOwner.address, + ); + + const jbConstantsFactory = await ethers.getContractFactory('JBConstants'); + const jbConstants = await jbConstantsFactory.deploy(); + MAX_FEE_DISCOUNT = await jbConstants.MAX_FEE_DISCOUNT(); + MAX_FEE = (await jbConstants.MAX_FEE()).toNumber(); + + AMOUNT_MINUS_FEES = Math.floor((AMOUNT * MAX_FEE) / (DEFAULT_FEE + MAX_FEE)); + + let jbOperationsFactory = await ethers.getContractFactory('JBOperations'); + let jbOperations = await jbOperationsFactory.deploy(); + const PROCESS_FEES_PERMISSION_INDEX = await jbOperations.PROCESS_FEES(); + const USE_ALLOWANCE_PERMISSION_INDEX = await jbOperations.USE_ALLOWANCE(); + + let jbTokenFactory = await ethers.getContractFactory('JBTokens'); + let jbToken = await jbTokenFactory.deploy(); + const ETH_ADDRESS = await jbToken.ETH(); + + await mockJbDirectory.mock.primaryTerminalOf + .withArgs(JUICEBOX_PROJECT_ID, ETH_ADDRESS) + .returns(jbEthPaymentTerminal.address); + + await mockJbProjects.mock.ownerOf.returns(projectOwner.address); + + await mockJbOperatorStore.mock.hasPermission + .withArgs( + projectOwner.address, + projectOwner.address, + PROJECT_ID, + USE_ALLOWANCE_PERMISSION_INDEX, + ) + .returns(true); + + await mockJbOperatorStore.mock.hasPermission + .withArgs( + projectOwner.address, + projectOwner.address, + PROJECT_ID, + PROCESS_FEES_PERMISSION_INDEX, + ) + .returns(true); + + // JBDAO + await mockJbDirectory.mock.isTerminalOf + .withArgs(1, jbEthPaymentTerminal.address) + .returns(true); + + const fundingCycle = { + number: FUNDING_CYCLE_NUM, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: 0, + }; + + return { + caller, + beneficiary, + CURRENCY_ETH, + ETH_ADDRESS, + jbEthPaymentTerminal, + fundingCycle, + mockJbDirectory, + mockJBPaymentTerminalStore, + mockJbFeeGauge, + mockJbOperatorStore, + otherCaller, + projectOwner, + terminalOwner, + timestamp, + }; + } + + it('Should send funds from overflow, without fees, and emit event', async function () { + const { + beneficiary, + CURRENCY_ETH, + fundingCycle, + jbEthPaymentTerminal, + mockJBPaymentTerminalStore, + projectOwner, + terminalOwner, + timestamp, + } = await setup(); + + await mockJBPaymentTerminalStore.mock.recordUsedAllowanceOf + .withArgs(PROJECT_ID, /* amount */ AMOUNT_TO_DISTRIBUTE, CURRENCY_ETH) + .returns(fundingCycle, AMOUNT); + + // Give terminal sufficient ETH + await setBalance(jbEthPaymentTerminal.address, AMOUNT); + + const initialBeneficiaryBalance = await ethers.provider.getBalance(beneficiary.address); + + // Set fee to zero + await jbEthPaymentTerminal.connect(terminalOwner).setFee(0); + + const tx = await jbEthPaymentTerminal + .connect(projectOwner) + .useAllowanceOf( + PROJECT_ID, + AMOUNT_TO_DISTRIBUTE, + CURRENCY_ETH, + ethers.constants.AddressZero, + /* minReturnedTokens */ AMOUNT, + beneficiary.address, + MEMO, + METADATA, + ); + + expect(tx) + .to.emit(jbEthPaymentTerminal, 'UseAllowance') + .withArgs( + /* _fundingCycle.configuration */ timestamp, + /* _fundingCycle.number */ FUNDING_CYCLE_NUM, + /* _projectId */ PROJECT_ID, + /* _beneficiary */ beneficiary.address, + /* _amount */ AMOUNT_TO_DISTRIBUTE, + /* _distributedAmount */ AMOUNT, + /* _netDistributedAmount */ AMOUNT, + MEMO, + METADATA, + /* msg.sender */ projectOwner.address, + ); + + // Terminal should be out of ETH + expect(await ethers.provider.getBalance(jbEthPaymentTerminal.address)).to.equal(0); + + // Beneficiary should have a larger balance + expect(await ethers.provider.getBalance(beneficiary.address)).to.equal( + initialBeneficiaryBalance.add(AMOUNT), + ); + }); + + it('Should send funds from overflow, without fees if the sender is a feeless address, and emit event', async function () { + const { + beneficiary, + CURRENCY_ETH, + fundingCycle, + jbEthPaymentTerminal, + mockJBPaymentTerminalStore, + projectOwner, + terminalOwner, + timestamp, + } = await setup(); + + await mockJBPaymentTerminalStore.mock.recordUsedAllowanceOf + .withArgs(PROJECT_ID, /* amount */ AMOUNT_TO_DISTRIBUTE, CURRENCY_ETH) + .returns(fundingCycle, AMOUNT); + + // Give terminal sufficient ETH + await setBalance(jbEthPaymentTerminal.address, AMOUNT); + + const initialBeneficiaryBalance = await ethers.provider.getBalance(beneficiary.address); + + // Set recipient as feeless + await jbEthPaymentTerminal.connect(terminalOwner).setFeelessAddress(projectOwner.address, true); + + const tx = await jbEthPaymentTerminal + .connect(projectOwner) + .useAllowanceOf( + PROJECT_ID, + AMOUNT_TO_DISTRIBUTE, + CURRENCY_ETH, + ethers.constants.AddressZero, + /* minReturnedTokens */ AMOUNT, + beneficiary.address, + MEMO, + METADATA, + ); + + expect(tx) + .to.emit(jbEthPaymentTerminal, 'UseAllowance') + .withArgs( + /* _fundingCycle.configuration */ timestamp, + /* _fundingCycle.number */ FUNDING_CYCLE_NUM, + /* _projectId */ PROJECT_ID, + /* _beneficiary */ beneficiary.address, + /* _amount */ AMOUNT_TO_DISTRIBUTE, + /* _distributedAmount */ AMOUNT, + /* _netDistributedAmount */ AMOUNT, + MEMO, + METADATA, + /* msg.sender */ projectOwner.address, + ); + + // Terminal should be out of ETH + expect(await ethers.provider.getBalance(jbEthPaymentTerminal.address)).to.equal(0); + + // Beneficiary should have a larger balance + expect(await ethers.provider.getBalance(beneficiary.address)).to.equal( + initialBeneficiaryBalance.add(AMOUNT), + ); + }); + + it('Should work with no amount', async function () { + const { + beneficiary, + CURRENCY_ETH, + jbEthPaymentTerminal, + mockJBPaymentTerminalStore, + projectOwner, + terminalOwner, + fundingCycle, + } = await setup(); + + await mockJBPaymentTerminalStore.mock.recordUsedAllowanceOf + .withArgs(PROJECT_ID, /* amount */ AMOUNT_TO_DISTRIBUTE, CURRENCY_ETH) + .returns(fundingCycle, 0); + + // Set fee to zero + await jbEthPaymentTerminal.connect(terminalOwner).setFee(0); + + await jbEthPaymentTerminal + .connect(projectOwner) + .useAllowanceOf( + PROJECT_ID, + /* amount */ AMOUNT_TO_DISTRIBUTE, + CURRENCY_ETH, + ethers.constants.AddressZero, + /* minReturnedTokens */ 0, + beneficiary.address, + MEMO, + METADATA, + ); + }); + + it('Should send funds from overflow, with fees applied, and emit event', async function () { + const { + beneficiary, + CURRENCY_ETH, + ETH_ADDRESS, + fundingCycle, + jbEthPaymentTerminal, + mockJbDirectory, + mockJBPaymentTerminalStore, + projectOwner, + terminalOwner, + timestamp, + } = await setup(); + + await mockJBPaymentTerminalStore.mock.recordUsedAllowanceOf + .withArgs(PROJECT_ID, /* amount */ AMOUNT_TO_DISTRIBUTE, CURRENCY_ETH) + .returns(fundingCycle, AMOUNT); + + await mockJBPaymentTerminalStore.mock.recordPaymentFrom + .withArgs( + jbEthPaymentTerminal.address, + { + token: ETH_ADDRESS, + value: AMOUNT - AMOUNT_MINUS_FEES, + decimals: 18, + currency: CURRENCY_ETH, + }, + JUICEBOX_PROJECT_ID, + CURRENCY_ETH, + projectOwner.address, + /* memo */ '', + ethers.utils.hexZeroPad(ethers.utils.hexlify(PROJECT_ID), 32), + ) + .returns(fundingCycle, 0, /* delegateAllocation */[], ''); + + await mockJbDirectory.mock.primaryTerminalOf + .withArgs(1, ETH_ADDRESS) + .returns(jbEthPaymentTerminal.address); + + // Give terminal sufficient ETH + await setBalance(jbEthPaymentTerminal.address, AMOUNT_MINUS_FEES); + + const initialBeneficiaryBalance = await ethers.provider.getBalance(beneficiary.address); + + // Set fee to default 5% + await jbEthPaymentTerminal.connect(terminalOwner).setFee(DEFAULT_FEE); + + const tx = await jbEthPaymentTerminal + .connect(projectOwner) + .useAllowanceOf( + PROJECT_ID, + AMOUNT_TO_DISTRIBUTE, + CURRENCY_ETH, + ethers.constants.AddressZero, + /* minReturnedTokens */ AMOUNT, + beneficiary.address, + MEMO, + METADATA, + ); + + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'UseAllowance') + .withArgs( + /* _fundingCycle.configuration */ timestamp, + /* _fundingCycle.number */ FUNDING_CYCLE_NUM, + /* _projectId */ PROJECT_ID, + /* _beneficiary */ beneficiary.address, + /* _amount */ AMOUNT_TO_DISTRIBUTE, + /* _distributedAmount */ AMOUNT, + /* _netDistributedAmount */ AMOUNT_MINUS_FEES, + MEMO, + METADATA, + /* msg.sender */ projectOwner.address, + ); + + // Terminal should be out of ETH + expect(await ethers.provider.getBalance(jbEthPaymentTerminal.address)).to.equal(0); + + // Beneficiary should have a larger balance + expect(await ethers.provider.getBalance(beneficiary.address)).to.equal( + initialBeneficiaryBalance.add(AMOUNT_MINUS_FEES), + ); + }); + + it('Should send funds from overflow, with discounted fees applied if gauge is set', async function () { + const { + beneficiary, + CURRENCY_ETH, + ETH_ADDRESS, + fundingCycle, + jbEthPaymentTerminal, + mockJbDirectory, + mockJBPaymentTerminalStore, + mockJbFeeGauge, + projectOwner, + terminalOwner, + timestamp, + } = await setup(); + + const DISCOUNTED_FEE = + DEFAULT_FEE - Math.floor((DEFAULT_FEE * FEE_DISCOUNT) / MAX_FEE_DISCOUNT); + const AMOUNT_MINUS_DISCOUNTED_FEES = Math.floor( + (AMOUNT * MAX_FEE) / (MAX_FEE + DISCOUNTED_FEE), + ); + + await mockJbFeeGauge.mock.currentDiscountFor.withArgs(PROJECT_ID, 1).returns(FEE_DISCOUNT); + + await mockJBPaymentTerminalStore.mock.recordUsedAllowanceOf + .withArgs(PROJECT_ID, /* amount */ AMOUNT_TO_DISTRIBUTE, CURRENCY_ETH) + .returns(fundingCycle, AMOUNT); + + await mockJBPaymentTerminalStore.mock.recordPaymentFrom + .withArgs( + jbEthPaymentTerminal.address, + { + token: ETH_ADDRESS, + value: AMOUNT - AMOUNT_MINUS_DISCOUNTED_FEES, + decimals: 18, + currency: CURRENCY_ETH, + }, + JUICEBOX_PROJECT_ID, + CURRENCY_ETH, + projectOwner.address, + /* memo */ '', + ethers.utils.hexZeroPad(ethers.utils.hexlify(PROJECT_ID), 32), + ) + .returns(fundingCycle, 0, /* delegateAllocation */[], ''); + + await mockJbDirectory.mock.primaryTerminalOf + .withArgs(1, ETH_ADDRESS) + .returns(jbEthPaymentTerminal.address); + + // Give terminal sufficient ETH + await setBalance(jbEthPaymentTerminal.address, AMOUNT_MINUS_DISCOUNTED_FEES); + + const initialBeneficiaryBalance = await ethers.provider.getBalance(beneficiary.address); + + // Set fee to default 5% + await jbEthPaymentTerminal.connect(terminalOwner).setFee(DEFAULT_FEE); + + await jbEthPaymentTerminal.connect(terminalOwner).setFeeGauge(mockJbFeeGauge.address); + + const tx = await jbEthPaymentTerminal + .connect(projectOwner) + .useAllowanceOf( + PROJECT_ID, + AMOUNT_TO_DISTRIBUTE, + CURRENCY_ETH, + ethers.constants.AddressZero, + /* minReturnedTokens */ AMOUNT, + beneficiary.address, + MEMO, + METADATA, + ); + + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'UseAllowance') + .withArgs( + /* _fundingCycle.configuration */ timestamp, + /* _fundingCycle.number */ FUNDING_CYCLE_NUM, + /* _projectId */ PROJECT_ID, + /* _beneficiary */ beneficiary.address, + /* _amount */ AMOUNT_TO_DISTRIBUTE, + /* _distributedAmount */ AMOUNT, + /* _netDistributedAmount */ AMOUNT_MINUS_DISCOUNTED_FEES, + MEMO, + METADATA, + /* msg.sender */ projectOwner.address, + ); + + // Terminal should be out of ETH + expect(await ethers.provider.getBalance(jbEthPaymentTerminal.address)).to.equal(0); + + // Beneficiary should have a larger balance + expect(await ethers.provider.getBalance(beneficiary.address)).to.equal( + initialBeneficiaryBalance.add(AMOUNT_MINUS_DISCOUNTED_FEES), + ); + }); + + it('Should send funds from overflow, with non discounted-fees applied if the fee gauge is faulty', async function () { + const { + beneficiary, + CURRENCY_ETH, + ETH_ADDRESS, + fundingCycle, + jbEthPaymentTerminal, + mockJbDirectory, + mockJBPaymentTerminalStore, + mockJbFeeGauge, + projectOwner, + terminalOwner, + timestamp, + } = await setup(); + + await mockJbFeeGauge.mock.currentDiscountFor.withArgs(PROJECT_ID, 1).reverts(); + + await mockJBPaymentTerminalStore.mock.recordUsedAllowanceOf + .withArgs(PROJECT_ID, /* amount */ AMOUNT_TO_DISTRIBUTE, CURRENCY_ETH) + .returns(fundingCycle, AMOUNT); + + await mockJBPaymentTerminalStore.mock.recordPaymentFrom + .withArgs( + jbEthPaymentTerminal.address, + { + token: ETH_ADDRESS, + value: AMOUNT - AMOUNT_MINUS_FEES, + decimals: 18, + currency: CURRENCY_ETH, + }, + JUICEBOX_PROJECT_ID, + CURRENCY_ETH, + projectOwner.address, + /* memo */ '', + ethers.utils.hexZeroPad(ethers.utils.hexlify(PROJECT_ID), 32), + ) + .returns(fundingCycle, 0, /* delegateAllocation */[], ''); + + await mockJbDirectory.mock.primaryTerminalOf + .withArgs(1, ETH_ADDRESS) + .returns(jbEthPaymentTerminal.address); + + // Give terminal sufficient ETH + await setBalance(jbEthPaymentTerminal.address, AMOUNT_MINUS_FEES); + + const initialBeneficiaryBalance = await ethers.provider.getBalance(beneficiary.address); + + await jbEthPaymentTerminal.connect(terminalOwner).setFeeGauge(mockJbFeeGauge.address); + + // Set fee to default 5% + await jbEthPaymentTerminal.connect(terminalOwner).setFee(DEFAULT_FEE); + + const tx = await jbEthPaymentTerminal + .connect(projectOwner) + .useAllowanceOf( + PROJECT_ID, + AMOUNT_TO_DISTRIBUTE, + CURRENCY_ETH, + ethers.constants.AddressZero, + /* minReturnedTokens */ AMOUNT, + beneficiary.address, + MEMO, + METADATA, + ); + + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'UseAllowance') + .withArgs( + /* _fundingCycle.configuration */ timestamp, + /* _fundingCycle.number */ FUNDING_CYCLE_NUM, + /* _projectId */ PROJECT_ID, + /* _beneficiary */ beneficiary.address, + /* _amount */ AMOUNT_TO_DISTRIBUTE, + /* _distributedAmount */ AMOUNT, + /* _netDistributedAmount */ AMOUNT_MINUS_FEES, + MEMO, + METADATA, + /* msg.sender */ projectOwner.address, + ); + + // Terminal should be out of ETH + expect(await ethers.provider.getBalance(jbEthPaymentTerminal.address)).to.equal(0); + + // Beneficiary should have a larger balance + expect(await ethers.provider.getBalance(beneficiary.address)).to.equal( + initialBeneficiaryBalance.add(AMOUNT_MINUS_FEES), + ); + }); + + it('Should send funds from overflow, with non discounted-fees applied if discount is above 100%', async function () { + const { + beneficiary, + CURRENCY_ETH, + ETH_ADDRESS, + fundingCycle, + jbEthPaymentTerminal, + mockJbDirectory, + mockJBPaymentTerminalStore, + mockJbFeeGauge, + projectOwner, + terminalOwner, + timestamp, + } = await setup(); + + await mockJbFeeGauge.mock.currentDiscountFor.withArgs(PROJECT_ID, 1).returns(MAX_FEE_DISCOUNT + 1); + + await mockJBPaymentTerminalStore.mock.recordUsedAllowanceOf + .withArgs(PROJECT_ID, /* amount */ AMOUNT_TO_DISTRIBUTE, CURRENCY_ETH) + .returns(fundingCycle, AMOUNT); + + await mockJBPaymentTerminalStore.mock.recordPaymentFrom + .withArgs( + jbEthPaymentTerminal.address, + { + token: ETH_ADDRESS, + value: AMOUNT - AMOUNT_MINUS_FEES, + decimals: 18, + currency: CURRENCY_ETH, + }, + JUICEBOX_PROJECT_ID, + CURRENCY_ETH, + projectOwner.address, + /* memo */ '', + ethers.utils.hexZeroPad(ethers.utils.hexlify(PROJECT_ID), 32), + ) + .returns(fundingCycle, 0, /* delegateAllocation */[], ''); + + await mockJbDirectory.mock.primaryTerminalOf + .withArgs(1, ETH_ADDRESS) + .returns(jbEthPaymentTerminal.address); + + // Give terminal sufficient ETH + await setBalance(jbEthPaymentTerminal.address, AMOUNT_MINUS_FEES); + + const initialBeneficiaryBalance = await ethers.provider.getBalance(beneficiary.address); + + await jbEthPaymentTerminal.connect(terminalOwner).setFeeGauge(mockJbFeeGauge.address); + + // Set fee to default 5% + await jbEthPaymentTerminal.connect(terminalOwner).setFee(DEFAULT_FEE); + + const tx = await jbEthPaymentTerminal + .connect(projectOwner) + .useAllowanceOf( + PROJECT_ID, + AMOUNT_TO_DISTRIBUTE, + CURRENCY_ETH, + ethers.constants.AddressZero, + /* minReturnedTokens */ AMOUNT, + beneficiary.address, + MEMO, + METADATA, + ); + + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'UseAllowance') + .withArgs( + /* _fundingCycle.configuration */ timestamp, + /* _fundingCycle.number */ FUNDING_CYCLE_NUM, + /* _projectId */ PROJECT_ID, + /* _beneficiary */ beneficiary.address, + /* _amount */ AMOUNT_TO_DISTRIBUTE, + /* _distributedAmount */ AMOUNT, + /* _netDistributedAmount */ AMOUNT_MINUS_FEES, + MEMO, + METADATA, + /* msg.sender */ projectOwner.address, + ); + + // Terminal should be out of ETH + expect(await ethers.provider.getBalance(jbEthPaymentTerminal.address)).to.equal(0); + + // Beneficiary should have a larger balance + expect(await ethers.provider.getBalance(beneficiary.address)).to.equal( + initialBeneficiaryBalance.add(AMOUNT_MINUS_FEES), + ); + }); + + it('Should send funds from overflow, with fees held, then process fees if caller is project owner, and emit event', async function () { + const { + beneficiary, + CURRENCY_ETH, + ETH_ADDRESS, + jbEthPaymentTerminal, + mockJbDirectory, + mockJBPaymentTerminalStore, + projectOwner, + terminalOwner, + timestamp, + } = await setup(); + + const newFundingCycle = { + number: FUNDING_CYCLE_NUM, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ holdFees: 1 }), // Hold fees + }; + + await mockJBPaymentTerminalStore.mock.recordUsedAllowanceOf + .withArgs(PROJECT_ID, /* amount */ AMOUNT_TO_DISTRIBUTE, CURRENCY_ETH) + .returns(newFundingCycle, AMOUNT); + + await mockJBPaymentTerminalStore.mock.recordPaymentFrom + .withArgs( + jbEthPaymentTerminal.address, + { + token: ETH_ADDRESS, + value: AMOUNT - AMOUNT_MINUS_FEES, + decimals: 18, + currency: CURRENCY_ETH, + }, + JUICEBOX_PROJECT_ID, + CURRENCY_ETH, + projectOwner.address, + /* memo */ '', + ethers.utils.hexZeroPad(ethers.utils.hexlify(PROJECT_ID), 32), + ) + .returns(newFundingCycle, 0, /* delegateAllocation */[], ''); + + await mockJbDirectory.mock.primaryTerminalOf + .withArgs(1, ETH_ADDRESS) + .returns(jbEthPaymentTerminal.address); + + // Give terminal sufficient ETH + await setBalance(jbEthPaymentTerminal.address, AMOUNT); + + // Set fee to default 5% + await jbEthPaymentTerminal.connect(terminalOwner).setFee(DEFAULT_FEE); + + // Use allowance and hold fee + expect( + await jbEthPaymentTerminal + .connect(projectOwner) + .useAllowanceOf( + PROJECT_ID, + AMOUNT_TO_DISTRIBUTE, + CURRENCY_ETH, + ethers.constants.AddressZero, + /* minReturnedTokens */ AMOUNT, + beneficiary.address, + MEMO, + METADATA, + ), + ) + .to.emit(jbEthPaymentTerminal, 'HoldFee') + .withArgs( + PROJECT_ID, + AMOUNT, + DEFAULT_FEE, + 0, // discount fee + projectOwner.address, + projectOwner.address, + ); + + // Should be holding fees in the contract + expect(await jbEthPaymentTerminal.heldFeesOf(PROJECT_ID)).to.eql([ + [ethers.BigNumber.from(AMOUNT), DEFAULT_FEE, /*discount*/ 0, projectOwner.address], + ]); + + // Process held fees + const tx = await jbEthPaymentTerminal.connect(projectOwner).processFees(PROJECT_ID); + + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'ProcessFee') + .withArgs( + PROJECT_ID, + ethers.BigNumber.from(AMOUNT).sub( + ethers.BigNumber.from(AMOUNT) + .mul(MAX_FEE) + .div(ethers.BigNumber.from(MAX_FEE).add(DEFAULT_FEE)), + ), + true, + projectOwner.address, + projectOwner.address, + ); + + // Held fees shoudn't exist after being processed + expect(await jbEthPaymentTerminal.heldFeesOf(PROJECT_ID)).to.eql([]); + }); + + it('Should send funds from overflow, with fees held, then process fees if caller is authorized, and emit event', async function () { + const { + beneficiary, + caller, + CURRENCY_ETH, + ETH_ADDRESS, + jbEthPaymentTerminal, + mockJbDirectory, + mockJbOperatorStore, + mockJBPaymentTerminalStore, + projectOwner, + terminalOwner, + timestamp, + } = await setup(); + + const newFundingCycle = { + number: FUNDING_CYCLE_NUM, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ holdFees: 1 }), // Hold fees + }; + + await mockJBPaymentTerminalStore.mock.recordUsedAllowanceOf + .withArgs(PROJECT_ID, /* amount */ AMOUNT_TO_DISTRIBUTE, CURRENCY_ETH) + .returns(newFundingCycle, AMOUNT); + + await mockJBPaymentTerminalStore.mock.recordPaymentFrom + .withArgs( + jbEthPaymentTerminal.address, + { + token: ETH_ADDRESS, + value: AMOUNT - AMOUNT_MINUS_FEES, + decimals: 18, + currency: CURRENCY_ETH, + }, + JUICEBOX_PROJECT_ID, + CURRENCY_ETH, + projectOwner.address, + /* memo */ '', + ethers.utils.hexZeroPad(ethers.utils.hexlify(PROJECT_ID), 32), + ) + .returns(newFundingCycle, 0, /* delegateAllocation */[], ''); + + await mockJbDirectory.mock.primaryTerminalOf + .withArgs(1, ETH_ADDRESS) + .returns(jbEthPaymentTerminal.address); + + // Give terminal sufficient ETH + await setBalance(jbEthPaymentTerminal.address, AMOUNT); + + // Set fee to default 5% + await jbEthPaymentTerminal.connect(terminalOwner).setFee(DEFAULT_FEE); + + // Use allowance and hold fee + expect( + await jbEthPaymentTerminal + .connect(projectOwner) + .useAllowanceOf( + PROJECT_ID, + AMOUNT_TO_DISTRIBUTE, + CURRENCY_ETH, + ethers.constants.AddressZero, + /* minReturnedTokens */ AMOUNT, + beneficiary.address, + MEMO, + METADATA + ), + ) + .to.emit(jbEthPaymentTerminal, 'HoldFee') + .withArgs( + PROJECT_ID, + AMOUNT, + DEFAULT_FEE, + 0, // discount fee + projectOwner.address, + projectOwner.address, + ); + + // Should be holding fees in the contract + expect(await jbEthPaymentTerminal.heldFeesOf(PROJECT_ID)).to.eql([ + [ethers.BigNumber.from(AMOUNT), DEFAULT_FEE, 0, projectOwner.address], + ]); + + await mockJbOperatorStore.mock.hasPermission + .withArgs(caller.address, projectOwner.address, PROJECT_ID, PROCESS_FEES_PERMISSION_INDEX) + .returns(true); + + // Process held fees + const tx = await jbEthPaymentTerminal.connect(caller).processFees(PROJECT_ID); + + await expect(tx) + .to.emit(jbEthPaymentTerminal, 'ProcessFee') + .withArgs( + PROJECT_ID, + ethers.BigNumber.from(AMOUNT).sub( + ethers.BigNumber.from(AMOUNT) + .mul(MAX_FEE) + .div(ethers.BigNumber.from(MAX_FEE).add(DEFAULT_FEE)), + ), + true, + projectOwner.address, + caller.address, + ); + + // Held fees shoudn't exist after being processed + expect(await jbEthPaymentTerminal.heldFeesOf(PROJECT_ID)).to.eql([]); + }); + + it('Cannot process fees if caller is not authorized', async function () { + const { + beneficiary, + caller, + CURRENCY_ETH, + ETH_ADDRESS, + jbEthPaymentTerminal, + mockJbDirectory, + mockJbOperatorStore, + mockJBPaymentTerminalStore, + projectOwner, + terminalOwner, + timestamp, + } = await setup(); + + const newFundingCycle = { + number: FUNDING_CYCLE_NUM, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ holdFees: 1 }), // Hold fees + }; + + await mockJBPaymentTerminalStore.mock.recordUsedAllowanceOf + .withArgs(PROJECT_ID, /* amount */ AMOUNT_TO_DISTRIBUTE, CURRENCY_ETH) + .returns(newFundingCycle, AMOUNT); + + await mockJBPaymentTerminalStore.mock.recordPaymentFrom + .withArgs( + jbEthPaymentTerminal.address, + { + token: ETH_ADDRESS, + value: AMOUNT - AMOUNT_MINUS_FEES, + decimals: 18, + currency: CURRENCY_ETH, + }, + JUICEBOX_PROJECT_ID, + CURRENCY_ETH, + projectOwner.address, + /* memo */ '', + ethers.utils.hexZeroPad(ethers.utils.hexlify(PROJECT_ID), 32), + ) + .returns(newFundingCycle, 0, /* delegateAllocation */[], ''); + + await mockJbDirectory.mock.primaryTerminalOf + .withArgs(1, ETH_ADDRESS) + .returns(jbEthPaymentTerminal.address); + + // Give terminal sufficient ETH + await setBalance(jbEthPaymentTerminal.address, AMOUNT); + + // Set fee to default 5% + await jbEthPaymentTerminal.connect(terminalOwner).setFee(DEFAULT_FEE); + + // Use allowance and hold fee + expect( + await jbEthPaymentTerminal + .connect(projectOwner) + .useAllowanceOf( + PROJECT_ID, + AMOUNT_TO_DISTRIBUTE, + CURRENCY_ETH, + ethers.constants.AddressZero, + /* minReturnedTokens */ AMOUNT, + beneficiary.address, + MEMO, + METADATA + ), + ) + .to.emit(jbEthPaymentTerminal, 'HoldFee') + .withArgs( + PROJECT_ID, + AMOUNT, + DEFAULT_FEE, + 0, // discount fee + projectOwner.address, + projectOwner.address, + ); + + // Should be holding fees in the contract + expect(await jbEthPaymentTerminal.heldFeesOf(PROJECT_ID)).to.eql([ + [ethers.BigNumber.from(AMOUNT), DEFAULT_FEE, 0, projectOwner.address], + ]); + + await mockJbOperatorStore.mock.hasPermission + .withArgs(caller.address, projectOwner.address, PROJECT_ID, PROCESS_FEES_PERMISSION_INDEX) + .returns(false); + + await mockJbOperatorStore.mock.hasPermission + .withArgs(caller.address, projectOwner.address, 0, PROCESS_FEES_PERMISSION_INDEX) + .returns(false); + + await expect(jbEthPaymentTerminal.connect(caller).processFees(PROJECT_ID)).to.be.revertedWith( + errors.UNAUTHORIZED, + ); + }); + + it(`Can't send funds from overflow without project access`, async function () { + const { beneficiary, CURRENCY_ETH, jbEthPaymentTerminal, mockJbOperatorStore, otherCaller } = + await setup(); + + await mockJbOperatorStore.mock.hasPermission.returns(false); + + await expect( + jbEthPaymentTerminal + .connect(otherCaller) + .useAllowanceOf( + PROJECT_ID, + AMOUNT_TO_DISTRIBUTE, + CURRENCY_ETH, + ethers.constants.AddressZero, + /* minReturnedTokens */ AMOUNT, + beneficiary.address, + MEMO, + METADATA + ), + ).to.be.revertedWith(errors.UNAUTHORIZED); + }); + it("Can't distribute if amount is less than expected", async function () { + const { + beneficiary, + CURRENCY_ETH, + jbEthPaymentTerminal, + mockJBPaymentTerminalStore, + projectOwner, + terminalOwner, + fundingCycle, + } = await setup(); + + await mockJBPaymentTerminalStore.mock.recordUsedAllowanceOf + .withArgs(PROJECT_ID, /* amount */ AMOUNT_TO_DISTRIBUTE, CURRENCY_ETH) + .returns(fundingCycle, 0); + + // Set fee to zero + await jbEthPaymentTerminal.connect(terminalOwner).setFee(0); + + await expect( + jbEthPaymentTerminal + .connect(projectOwner) + .useAllowanceOf( + PROJECT_ID, + /* amount */ AMOUNT_TO_DISTRIBUTE, + CURRENCY_ETH, + ethers.constants.AddressZero, + /* minReturnedTokens */ 1, + beneficiary.address, + MEMO, + METADATA + ), + ).to.be.revertedWith(errors.INADEQUATE_DISTRIBUTION_AMOUNT); + }); +}); diff --git a/test/jb_payment_terminal_3_1_1/view.test.js b/test/jb_payment_terminal_3_1_1/view.test.js new file mode 100644 index 000000000..cf0f93c6b --- /dev/null +++ b/test/jb_payment_terminal_3_1_1/view.test.js @@ -0,0 +1,127 @@ +import { expect } from 'chai'; +import { ethers } from 'hardhat'; +import { deployMockContract } from '@ethereum-waffle/mock-contract'; +import { makeSplits, packFundingCycleMetadata, setBalance } from '../helpers/utils.js'; + +import errors from '../helpers/errors.json'; + +import jbDirectory from '../../artifacts/contracts/JBDirectory.sol/JBDirectory.json'; +import JBEthPaymentTerminal from '../../artifacts/contracts/JBETHPaymentTerminal3_1_1.sol/JBETHPaymentTerminal3_1_1.json'; +import jbPaymentTerminalStore from '../../artifacts/contracts/JBSingleTokenPaymentTerminalStore3_1_1.sol/JBSingleTokenPaymentTerminalStore3_1_1.json'; +import jbOperatoreStore from '../../artifacts/contracts/JBOperatorStore.sol/JBOperatorStore.json'; +import jbProjects from '../../artifacts/contracts/JBProjects.sol/JBProjects.json'; +import jbSplitsStore from '../../artifacts/contracts/JBSplitsStore.sol/JBSplitsStore.json'; +import jbToken from '../../artifacts/contracts/JBToken.sol/JBToken.json'; +import jbPrices from '../../artifacts/contracts/JBPrices.sol/JBPrices.json'; + +describe('JBPayoutRedemptionPaymentTerminal3_1_1::getters', function () { + const ETH_ADDRESS = '0x000000000000000000000000000000000000EEEe'; + let CURRENCY_ETH; + + before(async function () { + const jbCurrenciesFactory = await ethers.getContractFactory('JBCurrencies'); + const jbCurrencies = await jbCurrenciesFactory.deploy(); + CURRENCY_ETH = await jbCurrencies.ETH(); + }); + + async function setup() { + let [deployer, terminalOwner] = await ethers.getSigners(); + + const SPLITS_GROUP = 1; + + let [ + mockJbDirectory, + mockJbEthPaymentTerminal, + mockJBPaymentTerminalStore, + mockJbOperatorStore, + mockJbProjects, + mockJbSplitsStore, + mockJbPrices, + mockJbToken, + ] = await Promise.all([ + deployMockContract(deployer, jbDirectory.abi), + deployMockContract(deployer, JBEthPaymentTerminal.abi), + deployMockContract(deployer, jbPaymentTerminalStore.abi), + deployMockContract(deployer, jbOperatoreStore.abi), + deployMockContract(deployer, jbProjects.abi), + deployMockContract(deployer, jbSplitsStore.abi), + deployMockContract(deployer, jbPrices.abi), + deployMockContract(deployer, jbToken.abi), + ]); + + let jbTerminalFactory = await ethers.getContractFactory( + 'contracts/JBETHPaymentTerminal3_1_1.sol:JBETHPaymentTerminal3_1_1', + deployer, + ); + let jbErc20TerminalFactory = await ethers.getContractFactory( + 'contracts/JBERC20PaymentTerminal3_1_1.sol:JBERC20PaymentTerminal3_1_1', + deployer, + ); + const NON_ETH_TOKEN = mockJbToken.address; + + let jbEthPaymentTerminal = await jbTerminalFactory + .connect(deployer) + .deploy( + /*base weight currency*/ CURRENCY_ETH, + mockJbOperatorStore.address, + mockJbProjects.address, + mockJbDirectory.address, + mockJbSplitsStore.address, + mockJbPrices.address, + mockJBPaymentTerminalStore.address, + terminalOwner.address, + ); + + const DECIMALS = 1; + + await mockJbToken.mock.decimals.returns(DECIMALS); + + let JBERC20PaymentTerminal = await jbErc20TerminalFactory + .connect(deployer) + .deploy( + NON_ETH_TOKEN, + CURRENCY_ETH, + CURRENCY_ETH, + SPLITS_GROUP, + mockJbOperatorStore.address, + mockJbProjects.address, + mockJbDirectory.address, + mockJbSplitsStore.address, + mockJbPrices.address, + mockJBPaymentTerminalStore.address, + terminalOwner.address, + ); + + return { + jbEthPaymentTerminal, + JBERC20PaymentTerminal, + NON_ETH_TOKEN, + DECIMALS, + }; + } + + it('Should return true if the terminal accepts a token', async function () { + const { JBERC20PaymentTerminal, jbEthPaymentTerminal, NON_ETH_TOKEN } = await setup(); + expect(await JBERC20PaymentTerminal.acceptsToken(NON_ETH_TOKEN, /*projectId*/ 0)).to.be.true; + + expect(await JBERC20PaymentTerminal.acceptsToken(ETH_ADDRESS, /*projectId*/ 0)).to.be.false; + + expect(await jbEthPaymentTerminal.acceptsToken(ETH_ADDRESS, /*projectId*/ 0)).to.be.true; + + expect(await jbEthPaymentTerminal.acceptsToken(NON_ETH_TOKEN, /*projectId*/ 0)).to.be.false; + }); + + it('Should return the decimals for the token', async function () { + const { JBERC20PaymentTerminal, jbEthPaymentTerminal, NON_ETH_TOKEN, DECIMALS } = await setup(); + expect(await JBERC20PaymentTerminal.decimalsForToken(NON_ETH_TOKEN)).to.equal(DECIMALS); + + expect(await jbEthPaymentTerminal.decimalsForToken(ETH_ADDRESS)).to.equal(18); + }); + + it('Should return the currency for the token', async function () { + const { JBERC20PaymentTerminal, jbEthPaymentTerminal, NON_ETH_TOKEN } = await setup(); + expect(await JBERC20PaymentTerminal.currencyForToken(NON_ETH_TOKEN)).to.equal(CURRENCY_ETH); + + expect(await jbEthPaymentTerminal.currencyForToken(ETH_ADDRESS)).to.equal(CURRENCY_ETH); + }); +}); diff --git a/test/jb_payment_terminal_store_3_1/current_overflow_of.test.js b/test/jb_payment_terminal_store_3_1/current_overflow_of.test.js new file mode 100644 index 000000000..bd6a38774 --- /dev/null +++ b/test/jb_payment_terminal_store_3_1/current_overflow_of.test.js @@ -0,0 +1,194 @@ +import { expect } from 'chai'; +import { ethers } from 'hardhat'; + +import { deployMockContract } from '@ethereum-waffle/mock-contract'; + +import { packFundingCycleMetadata, impersonateAccount } from '../helpers/utils'; + +import jbController from '../../artifacts/contracts/interfaces/IJBController3_1.sol/IJBController3_1.json'; +import jbDirectory from '../../artifacts/contracts/interfaces/IJBDirectory.sol/IJBDirectory.json'; +import jBFundingCycleStore from '../../artifacts/contracts/interfaces/IJBFundingCycleStore.sol/IJBFundingCycleStore.json'; +import jbPrices from '../../artifacts/contracts/interfaces/IJBPrices.sol/IJBPrices.json'; +import jbFundAccessConstraintsStore from '../../artifacts/contracts/interfaces/IJBFundAccessConstraintsStore.sol/IJBFundAccessConstraintsStore.json'; +import jbProjects from '../../artifacts/contracts/interfaces/IJBProjects.sol/IJBProjects.json'; +import jbTerminal from '../../artifacts/contracts/abstract/JBPayoutRedemptionPaymentTerminal3_1.sol/JBPayoutRedemptionPaymentTerminal3_1.json'; +import jbTokenStore from '../../artifacts/contracts/interfaces/IJBTokenStore.sol/IJBTokenStore.json'; + +describe('JBSingleTokenPaymentTerminalStore3_1::currentOverflowOf(...)', function () { + const PROJECT_ID = 2; + const AMOUNT = ethers.FixedNumber.fromString('4398541.345'); + const WEIGHT = ethers.FixedNumber.fromString('900000000.23411'); + const CURRENCY = 1; + const _FIXED_POINT_MAX_FIDELITY = 18; + + async function setup() { + const [deployer] = await ethers.getSigners(); + + const mockJbPrices = await deployMockContract(deployer, jbPrices.abi); + const mockJbProjects = await deployMockContract(deployer, jbProjects.abi); + const mockJbDirectory = await deployMockContract(deployer, jbDirectory.abi); + const mockJbFundingCycleStore = await deployMockContract(deployer, jBFundingCycleStore.abi); + const mockJbTerminal = await deployMockContract(deployer, jbTerminal.abi); + const mockJbTokenStore = await deployMockContract(deployer, jbTokenStore.abi); + const mockJbController = await deployMockContract(deployer, jbController.abi); + const mockJbFundAccessConstraintsStore = await deployMockContract(deployer, jbFundAccessConstraintsStore.abi); + + const jbCurrenciesFactory = await ethers.getContractFactory('JBCurrencies'); + const jbCurrencies = await jbCurrenciesFactory.deploy(); + const CURRENCY_ETH = await jbCurrencies.ETH(); + const CURRENCY_USD = await jbCurrencies.USD(); + + const token = ethers.Wallet.createRandom().address; + + const JBPaymentTerminalStoreFactory = await ethers.getContractFactory( + 'contracts/JBSingleTokenPaymentTerminalStore3_1.sol:JBSingleTokenPaymentTerminalStore3_1', + ); + const JBSingleTokenPaymentTerminalStore = await JBPaymentTerminalStoreFactory.deploy( + mockJbDirectory.address, + mockJbFundingCycleStore.address, + mockJbPrices.address, + ); + + const blockNum = await ethers.provider.getBlockNumber(); + const block = await ethers.provider.getBlock(blockNum); + const timestamp = block.timestamp; + + await mockJbTerminal.mock.currency.returns(CURRENCY); + + return { + mockJbTerminal, + mockJbController, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbPrices, + mockJbFundAccessConstraintsStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + CURRENCY_USD, + }; + } + + it('Should return the current overflowed amount', async function () { + const { + mockJbTerminal, + mockJbController, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbFundAccessConstraintsStore, + mockJbPrices, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + CURRENCY_USD, + } = await setup(); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata(), + }); + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + + await mockJbTerminal.mock.token.returns(token); + + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(AMOUNT, CURRENCY_USD); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + await mockJbPrices.mock.priceFor + .withArgs(CURRENCY_USD, CURRENCY_ETH, _FIXED_POINT_MAX_FIDELITY) + .returns(ethers.FixedNumber.from(1)); + + // Add to balance beforehand to have sufficient overflow + const startingBalance = AMOUNT.mulUnsafe(ethers.FixedNumber.from(2)); + await JBSingleTokenPaymentTerminalStore.connect( + await impersonateAccount(mockJbTerminal.address), + ).recordAddedBalanceFor(PROJECT_ID, startingBalance); + + // Get current overflow + expect( + await JBSingleTokenPaymentTerminalStore.currentOverflowOf(mockJbTerminal.address, PROJECT_ID), + ).to.equal(AMOUNT); + }); + + it('Should return 0 overflow if ETH balance < distribution remaining', async function () { + const { + mockJbTerminal, + mockJbController, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbFundAccessConstraintsStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + } = await setup(); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata(), + }); + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(AMOUNT, CURRENCY_ETH); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + // Get current overflow + expect( + await JBSingleTokenPaymentTerminalStore.currentOverflowOf(mockJbTerminal.address, PROJECT_ID), + ).to.equal(0); + }); + + it('Should return 0 overflow if ETH balance is 0', async function () { + const { + mockJbFundingCycleStore, + mockJbTerminal, + JBSingleTokenPaymentTerminalStore, + timestamp, + } = await setup(); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata(), + }); + + // Get current overflow + expect( + await JBSingleTokenPaymentTerminalStore.currentOverflowOf(mockJbTerminal.address, PROJECT_ID), + ).to.equal(0); + }); +}); diff --git a/test/jb_payment_terminal_store_3_1/current_reclaimable_overflow_of.test.js b/test/jb_payment_terminal_store_3_1/current_reclaimable_overflow_of.test.js new file mode 100644 index 000000000..d2211711d --- /dev/null +++ b/test/jb_payment_terminal_store_3_1/current_reclaimable_overflow_of.test.js @@ -0,0 +1,850 @@ +import { expect } from 'chai'; +import { ethers } from 'hardhat'; + +import { deployMockContract } from '@ethereum-waffle/mock-contract'; + +import { packFundingCycleMetadata, impersonateAccount } from '../helpers/utils'; + +import jbController from '../../artifacts/contracts/interfaces/IJBController3_1.sol/IJBController3_1.json'; +import jbDirectory from '../../artifacts/contracts/interfaces/IJBDirectory.sol/IJBDirectory.json'; +import jBFundingCycleStore from '../../artifacts/contracts/interfaces/IJBFundingCycleStore.sol/IJBFundingCycleStore.json'; +import jbFundAccessConstraintsStore from '../../artifacts/contracts/interfaces/IJBFundAccessConstraintsStore.sol/IJBFundAccessConstraintsStore.json'; +import jbPrices from '../../artifacts/contracts/interfaces/IJBPrices.sol/IJBPrices.json'; +import jbProjects from '../../artifacts/contracts/interfaces/IJBProjects.sol/IJBProjects.json'; +import jbTerminal from '../../artifacts/contracts/abstract/JBPayoutRedemptionPaymentTerminal3_1.sol/JBPayoutRedemptionPaymentTerminal3_1.json'; +import jbTokenStore from '../../artifacts/contracts/interfaces/IJBTokenStore.sol/IJBTokenStore.json'; + +describe('JBSingleTokenPaymentTerminalStore3_1::currentReclaimableOverflowOf(...)', function () { + const PROJECT_ID = 2; + const WEIGHT = ethers.FixedNumber.fromString('900000000.23411'); + const CURRENCY = 1; + + async function setup() { + const [deployer] = await ethers.getSigners(); + + const mockJbPrices = await deployMockContract(deployer, jbPrices.abi); + const mockJbProjects = await deployMockContract(deployer, jbProjects.abi); + const mockJbDirectory = await deployMockContract(deployer, jbDirectory.abi); + const mockJbFundingCycleStore = await deployMockContract(deployer, jBFundingCycleStore.abi); + const mockJbTerminal = await deployMockContract(deployer, jbTerminal.abi); + const mockJbTerminal2 = await deployMockContract(deployer, jbTerminal.abi); + const mockJbTokenStore = await deployMockContract(deployer, jbTokenStore.abi); + const mockJbController = await deployMockContract(deployer, jbController.abi); + const mockJbFundAccessConstraintsStore = await deployMockContract(deployer, jbFundAccessConstraintsStore.abi); + + const jbCurrenciesFactory = await ethers.getContractFactory('JBCurrencies'); + const jbCurrencies = await jbCurrenciesFactory.deploy(); + const CURRENCY_ETH = await jbCurrencies.ETH(); + + const JBPaymentTerminalStoreFactory = await ethers.getContractFactory( + 'contracts/JBSingleTokenPaymentTerminalStore3_1.sol:JBSingleTokenPaymentTerminalStore3_1', + ); + const JBSingleTokenPaymentTerminalStore = await JBPaymentTerminalStoreFactory.deploy( + mockJbDirectory.address, + mockJbFundingCycleStore.address, + mockJbPrices.address, + ); + + const token = ethers.Wallet.createRandom().address; + + const blockNum = await ethers.provider.getBlockNumber(); + const block = await ethers.provider.getBlock(blockNum); + const timestamp = block.timestamp; + + await mockJbTerminal.mock.currency.returns(CURRENCY); + await mockJbTerminal.mock.decimals.returns(18); + + await mockJbTerminal2.mock.currency.returns(CURRENCY); + await mockJbTerminal2.mock.decimals.returns(18); + + const mockJbTerminalSigner = await impersonateAccount(mockJbTerminal.address); + + await mockJbTerminal.mock.token.returns(token); + + return { + mockJbController, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbPrices, + mockJbTerminal, + mockJbTerminal2, + mockJbTerminalSigner, + mockJbFundAccessConstraintsStore, + mockJbTokenStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + }; + } + + it('Should return claimable overflow from this terminal, with rate from active ballot', async function () { + /* + Calculator params for https://www.desmos.com/calculator/sp9ru6zbpk: + o (available overflow) = 100 ETH + s (total token supply) = 100 + r (redemption rate) = .65 + x (token claim amount) = 50 + Should result in a redemption of y = 41.25 ETH + */ + const { + mockJbController, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbTerminal, + mockJbTerminalSigner, + mockJbTokenStore, + mockJbFundAccessConstraintsStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + } = await setup(); + + const overflowAmt = ethers.FixedNumber.from(100); + const tokenAmt = ethers.FixedNumber.from(50); + + const reservedRate = 0; + const fundingCycleMetadata = packFundingCycleMetadata({ + reservedRate: reservedRate, + ballotRedemptionRate: 6500, // 65% redemption rate + }); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: fundingCycleMetadata, + }); + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(overflowAmt, CURRENCY_ETH); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + const totalSupply = tokenAmt.mulUnsafe(ethers.FixedNumber.from(2)); + await mockJbTokenStore.mock.totalSupplyOf.withArgs(PROJECT_ID).returns(totalSupply); // totalSupply of 100 + await mockJbController.mock.totalOutstandingTokensOf + .withArgs(PROJECT_ID) + .returns(totalSupply); + + await mockJbController.mock.reservedTokenBalanceOf + .withArgs(PROJECT_ID) + .returns(0); + + // Use active ballot + await mockJbFundingCycleStore.mock.currentBallotStateOf.withArgs(PROJECT_ID).returns(0); + + // Add to balance beforehand to have an overflow of exactly 100 + const startingBalance = overflowAmt.mulUnsafe(ethers.FixedNumber.from(2)); + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordAddedBalanceFor( + PROJECT_ID, + startingBalance, + ); + + // Get claimable overflow where tokenCount is half the total supply of tokens + expect( + await JBSingleTokenPaymentTerminalStore[ + 'currentReclaimableOverflowOf(address,uint256,uint256,bool)' + ](mockJbTerminalSigner.address, PROJECT_ID, /* tokenCount */ tokenAmt, false), + ).to.equal(ethers.FixedNumber.fromString('41.25')); + }); + + it('Should return claimable overflow with rate from active ballot, accross all terminals using the same currency and decimals', async function () { + /* + Calculator params for https://www.desmos.com/calculator/sp9ru6zbpk: + o (available overflow) = 100 ETH + s (total token supply) = 100 + r (redemption rate) = .65 + x (token claim amount) = 50 + Should result in a redemption of y = 41.25 ETH + */ + const { + mockJbController, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbTerminal, + mockJbTerminal2, + mockJbTerminalSigner, + mockJbFundAccessConstraintsStore, + mockJbTokenStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + } = await setup(); + + const overflowAmt = ethers.FixedNumber.from(100); + const tokenAmt = ethers.FixedNumber.from(50); + + const reservedRate = 0; + const fundingCycleMetadata = packFundingCycleMetadata({ + reservedRate: reservedRate, + ballotRedemptionRate: 6500, // 65% redemption rate + useTotalOverflowForRedemptions: true, + }); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: fundingCycleMetadata, + }); + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(overflowAmt, CURRENCY_ETH); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + await mockJbDirectory.mock.terminalsOf + .withArgs(PROJECT_ID) + .returns([mockJbTerminal.address, mockJbTerminal2.address]); + + await mockJbTerminal.mock.currentEthOverflowOf.withArgs(PROJECT_ID).returns(overflowAmt); + await mockJbTerminal2.mock.currentEthOverflowOf.withArgs(PROJECT_ID).returns(overflowAmt); + + const totalSupply = tokenAmt.mulUnsafe(ethers.FixedNumber.from(2)); + await mockJbTokenStore.mock.totalSupplyOf.withArgs(PROJECT_ID).returns(totalSupply); // totalSupply of 100 + await mockJbController.mock.totalOutstandingTokensOf + .withArgs(PROJECT_ID) + .returns(totalSupply); + + await mockJbController.mock.reservedTokenBalanceOf + .withArgs(PROJECT_ID) + .returns(0); + + // Use active ballot + await mockJbFundingCycleStore.mock.currentBallotStateOf.withArgs(PROJECT_ID).returns(0); + + // Add to balance beforehand to have an overflow of exactly 100 + const startingBalance = overflowAmt.mulUnsafe(ethers.FixedNumber.from(2)); + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordAddedBalanceFor( + PROJECT_ID, + startingBalance, + ); + + // Get claimable overflow where tokenCount is half the total supply of tokens + expect( + await JBSingleTokenPaymentTerminalStore[ + 'currentReclaimableOverflowOf(address,uint256,uint256,bool)' + ](mockJbTerminalSigner.address, PROJECT_ID, /* tokenCount */ tokenAmt, true), + ).to.equal(ethers.FixedNumber.fromString('82.5')); + }); + + it('Should return claimable overflow with rate from active ballot, accross all terminals using different currencies and decimals', async function () { + /* + Calculator params for https://www.desmos.com/calculator/sp9ru6zbpk: + o (available overflow) = 100 ETH + s (total token supply) = 100 + r (redemption rate) = .65 + x (token claim amount) = 50 + Should result in a redemption of y = 41.25 ETH + */ + const { + mockJbController, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbPrices, + mockJbTerminal, + mockJbTerminal2, + mockJbTerminalSigner, + mockJbTokenStore, + mockJbFundAccessConstraintsStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + } = await setup(); + + const overflowAmt = ethers.FixedNumber.from(100); + const tokenAmt = ethers.FixedNumber.from(50); + + const reservedRate = 0; + const fundingCycleMetadata = packFundingCycleMetadata({ + reservedRate: reservedRate, + ballotRedemptionRate: 6500, // 65% redemption rate + useTotalOverflowForRedemptions: true, + }); + + await mockJbTerminal.mock.currency.returns(2); + await mockJbTerminal.mock.decimals.returns(20); // Will divide by 100 to get to 18 decimals + + // Price for eth in currency 2, with 18decimals (will mult by 100) + await mockJbPrices.mock.priceFor.withArgs(1, 2, 18).returns(ethers.FixedNumber.from(100)); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: fundingCycleMetadata, + }); + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(overflowAmt, CURRENCY_ETH); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + await mockJbDirectory.mock.terminalsOf + .withArgs(PROJECT_ID) + .returns([mockJbTerminal.address, mockJbTerminal2.address]); + + await mockJbTerminal.mock.currentEthOverflowOf.withArgs(PROJECT_ID).returns(overflowAmt); + await mockJbTerminal2.mock.currentEthOverflowOf.withArgs(PROJECT_ID).returns(overflowAmt); + + const totalSupply = tokenAmt.mulUnsafe(ethers.FixedNumber.from(2)); + await mockJbTokenStore.mock.totalSupplyOf.withArgs(PROJECT_ID).returns(totalSupply); // totalSupply of 100 + await mockJbController.mock.totalOutstandingTokensOf + .withArgs(PROJECT_ID) + .returns(totalSupply); + + await mockJbController.mock.reservedTokenBalanceOf + .withArgs(PROJECT_ID) + .returns(0); + + // Use active ballot + await mockJbFundingCycleStore.mock.currentBallotStateOf.withArgs(PROJECT_ID).returns(0); + + // Add to balance beforehand to have an overflow of exactly 100 + const startingBalance = overflowAmt.mulUnsafe(ethers.FixedNumber.from(2)); + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordAddedBalanceFor( + PROJECT_ID, + startingBalance, + ); + + // Get claimable overflow where tokenCount is half the total supply of tokens + expect( + await JBSingleTokenPaymentTerminalStore[ + 'currentReclaimableOverflowOf(address,uint256,uint256,bool)' + ](mockJbTerminalSigner.address, PROJECT_ID, /* tokenCount */ tokenAmt, true), + ).to.equal(ethers.FixedNumber.fromString('82.5')); + }); + + it('Should return 0 if there is no overflow in this terminal', async function () { + const { + mockJbTerminal, + mockJbController, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbFundAccessConstraintsStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + } = await setup(); + + const overflowAmt = ethers.FixedNumber.from(100); + const tokenAmt = ethers.FixedNumber.from(50); + + const reservedRate = 0; + const fundingCycleMetadata = packFundingCycleMetadata({ + reservedRate: reservedRate, + ballotRedemptionRate: 6500, // 65% redemption rate + }); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: fundingCycleMetadata, + }); + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(overflowAmt, CURRENCY_ETH); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + // Get claimable overflow + expect( + await JBSingleTokenPaymentTerminalStore[ + 'currentReclaimableOverflowOf(address,uint256,uint256,bool)' + ](mockJbTerminal.address, PROJECT_ID, /* tokenCount */ tokenAmt, false), + ).to.equal(0); + }); + + it('Should return 0 if the number of token > total supply', async function () { + const { + mockJbTerminal, + mockJbTerminalSigner, + mockJbController, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbTokenStore, + mockJbFundAccessConstraintsStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + } = await setup(); + + const overflowAmt = ethers.FixedNumber.from(100); + const tokenAmt = ethers.FixedNumber.from(50); + + const reservedRate = 0; + const fundingCycleMetadata = packFundingCycleMetadata({ + reservedRate: reservedRate, + ballotRedemptionRate: 0, // 0% redemption rate + }); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: fundingCycleMetadata, + }); + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(overflowAmt, CURRENCY_ETH); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + const totalSupply = tokenAmt.subUnsafe(ethers.FixedNumber.from(1)); + await mockJbTokenStore.mock.totalSupplyOf.withArgs(PROJECT_ID).returns(totalSupply); // totalSupply of 100 + await mockJbController.mock.totalOutstandingTokensOf + .withArgs(PROJECT_ID) + .returns(totalSupply); + + await mockJbController.mock.reservedTokenBalanceOf + .withArgs(PROJECT_ID) + .returns(0); + + // Use active ballot + await mockJbFundingCycleStore.mock.currentBallotStateOf.withArgs(PROJECT_ID).returns(1); + + // Add to balance beforehand to have an overflow of exactly 100 + const startingBalance = overflowAmt.mulUnsafe(ethers.FixedNumber.from(2)); + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordAddedBalanceFor( + PROJECT_ID, + startingBalance, + ); + + // Get claimable overflow + expect( + await JBSingleTokenPaymentTerminalStore[ + 'currentReclaimableOverflowOf(address,uint256,uint256,bool)' + ]( + mockJbTerminalSigner.address, + PROJECT_ID, + /* tokenCount */ totalSupply.addUnsafe(ethers.FixedNumber.from(1)), + false, + ), + ).to.equal(0); + }); + + it('Should return 0 if claiming more than the total supply', async function () { + const { JBSingleTokenPaymentTerminalStore } = await setup(); + + const overflowAmt = ethers.FixedNumber.from(100); + const totalSupply = ethers.FixedNumber.from(50); + + // Get claimable overflow + expect( + await JBSingleTokenPaymentTerminalStore[ + 'currentReclaimableOverflowOf(uint256,uint256,uint256,uint256)' + ]( + PROJECT_ID, + /* tokenCount */ totalSupply.addUnsafe(ethers.FixedNumber.from(1)), + totalSupply, + overflowAmt, + ), + ).to.equal(0); + }); + + it('Should return 0 if redemption rate is 0', async function () { + const { + mockJbTerminal, + mockJbTerminalSigner, + mockJbController, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbFundAccessConstraintsStore, + mockJbTokenStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + } = await setup(); + + const overflowAmt = ethers.FixedNumber.from(100); + const tokenAmt = ethers.FixedNumber.from(50); + + const reservedRate = 0; + const fundingCycleMetadata = packFundingCycleMetadata({ + reservedRate: reservedRate, + ballotRedemptionRate: 0, // 0% redemption rate + }); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: fundingCycleMetadata, + }); + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(overflowAmt, CURRENCY_ETH); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + const totalSupply = tokenAmt.mulUnsafe(ethers.FixedNumber.from(2)); + await mockJbTokenStore.mock.totalSupplyOf.withArgs(PROJECT_ID).returns(totalSupply); // totalSupply of 100 + await mockJbController.mock.totalOutstandingTokensOf + .withArgs(PROJECT_ID) + .returns(totalSupply); + + await mockJbController.mock.reservedTokenBalanceOf + .withArgs(PROJECT_ID) + .returns(0); + + // Use active ballot + await mockJbFundingCycleStore.mock.currentBallotStateOf.withArgs(PROJECT_ID).returns(0); + + // Add to balance beforehand to have an overflow of exactly 100 + const startingBalance = overflowAmt.mulUnsafe(ethers.FixedNumber.from(2)); + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordAddedBalanceFor( + PROJECT_ID, + startingBalance, + ); + + // Get claimable overflow + expect( + await JBSingleTokenPaymentTerminalStore[ + 'currentReclaimableOverflowOf(address,uint256,uint256,bool)' + ](mockJbTerminalSigner.address, PROJECT_ID, /* tokenCount */ tokenAmt, false), + ).to.equal(0); + }); + + it('Should return claimable overflow amount of this terminal if redemption rate is 100%', async function () { + /* + Calculator params for https://www.desmos.com/calculator/sp9ru6zbpk: + o (available overflow) = 100 ETH + s (total token supply) = 100 + r (redemption rate) = 1.0 + x (token claim amount) = 50 + Should result in a redemption of y = 50 ETH + */ + const { + mockJbTerminal, + mockJbTerminalSigner, + mockJbController, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbFundAccessConstraintsStore, + mockJbTokenStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + } = await setup(); + + const overflowAmt = ethers.FixedNumber.from(100); + const tokenAmt = ethers.FixedNumber.from(50); + + const reservedRate = 10; + const fundingCycleMetadata = packFundingCycleMetadata({ + reservedRate: reservedRate, + redemptionRate: 10000, // 100% redemption rate + }); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: fundingCycleMetadata, + }); + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(overflowAmt, CURRENCY_ETH); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + await mockJbTokenStore.mock.totalSupplyOf.withArgs(PROJECT_ID).returns(tokenAmt); + + await mockJbController.mock.reservedTokenBalanceOf + .withArgs(PROJECT_ID) + .returns(ethers.FixedNumber.from(50)); // added to tokenSupply + + // Use regular redemption rate + await mockJbFundingCycleStore.mock.currentBallotStateOf.withArgs(PROJECT_ID).returns(0); + + // Add to balance beforehand to have an overflow of exactly 100 + const startingBalance = overflowAmt.mulUnsafe(ethers.FixedNumber.from(2)); + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordAddedBalanceFor( + PROJECT_ID, + startingBalance, + ); + + await mockJbController.mock.totalOutstandingTokensOf + .withArgs(PROJECT_ID) + .returns(overflowAmt); + + // Get claimable overflow where tokenCount is half the total supply of tokens + expect( + await JBSingleTokenPaymentTerminalStore[ + 'currentReclaimableOverflowOf(address,uint256,uint256,bool)' + ](mockJbTerminalSigner.address, PROJECT_ID, /* tokenCount */ tokenAmt, false), + ).to.equal(ethers.FixedNumber.from(50)); + }); + + it('Should return claimable overflow when no terminal is passed, with rate from active ballot', async function () { + /* + Calculator params for https://www.desmos.com/calculator/sp9ru6zbpk: + o (available overflow) = 100 ETH + s (total token supply) = 100 + r (redemption rate) = .65 + x (token claim amount) = 50 + Should result in a redemption of y = 41.25 ETH + */ + const { + mockJbController, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbTerminal, + mockJbTerminalSigner, + mockJbTokenStore, + mockJbFundAccessConstraintsStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + } = await setup(); + + const overflowAmt = ethers.FixedNumber.from(100); + const tokenAmt = ethers.FixedNumber.from(50); + + const reservedRate = 0; + const fundingCycleMetadata = packFundingCycleMetadata({ + reservedRate: reservedRate, + ballotRedemptionRate: 6500, // 65% redemption rate + }); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: fundingCycleMetadata, + }); + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(overflowAmt, CURRENCY_ETH); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + const totalSupply = tokenAmt.mulUnsafe(ethers.FixedNumber.from(2)); + await mockJbTokenStore.mock.totalSupplyOf.withArgs(PROJECT_ID).returns(totalSupply); // totalSupply of 100 + await mockJbController.mock.totalOutstandingTokensOf + .withArgs(PROJECT_ID) + .returns(totalSupply); + + await mockJbController.mock.reservedTokenBalanceOf + .withArgs(PROJECT_ID) + .returns(0); + + // Use active ballot + await mockJbFundingCycleStore.mock.currentBallotStateOf.withArgs(PROJECT_ID).returns(0); + + // Add to balance beforehand to have an overflow of exactly 100 + const startingBalance = overflowAmt.mulUnsafe(ethers.FixedNumber.from(2)); + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordAddedBalanceFor( + PROJECT_ID, + startingBalance, + ); + + // Get claimable overflow where tokenCount is half the total supply of tokens + expect( + await JBSingleTokenPaymentTerminalStore[ + 'currentReclaimableOverflowOf(uint256,uint256,uint256,uint256)' + ]( + PROJECT_ID, + /* tokenCount */ tokenAmt, + /* totalSupply */ totalSupply, + /* overflow */ overflowAmt, + ), + ).to.equal(ethers.FixedNumber.fromString('41.25')); + }); + it('Should return claimable overflow when no terminal is passed, with rate from the current cycle', async function () { + /* + Calculator params for https://www.desmos.com/calculator/sp9ru6zbpk: + o (available overflow) = 100 ETH + s (total token supply) = 100 + r (redemption rate) = .65 + x (token claim amount) = 50 + Should result in a redemption of y = 41.25 ETH + */ + const { + mockJbController, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbTerminal, + mockJbTerminalSigner, + mockJbTokenStore, + mockJbFundAccessConstraintsStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + } = await setup(); + + const overflowAmt = ethers.FixedNumber.from(100); + const tokenAmt = ethers.FixedNumber.from(50); + + const reservedRate = 0; + const fundingCycleMetadata = packFundingCycleMetadata({ + reservedRate: reservedRate, + redemptionRate: 6500, + ballotRedemptionRate: 0, + }); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: fundingCycleMetadata, + }); + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(overflowAmt, CURRENCY_ETH); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + const totalSupply = tokenAmt.mulUnsafe(ethers.FixedNumber.from(2)); + await mockJbTokenStore.mock.totalSupplyOf.withArgs(PROJECT_ID).returns(totalSupply); // totalSupply of 100 + await mockJbController.mock.totalOutstandingTokensOf + .withArgs(PROJECT_ID) + .returns(totalSupply); + + await mockJbController.mock.reservedTokenBalanceOf + .withArgs(PROJECT_ID) + .returns(0); + + // Do not use active ballot + await mockJbFundingCycleStore.mock.currentBallotStateOf.withArgs(PROJECT_ID).returns(2); // Failed + + // Add to balance beforehand to have an overflow of exactly 100 + const startingBalance = overflowAmt.mulUnsafe(ethers.FixedNumber.from(2)); + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordAddedBalanceFor( + PROJECT_ID, + startingBalance, + ); + + // Get claimable overflow where tokenCount is half the total supply of tokens + expect( + await JBSingleTokenPaymentTerminalStore[ + 'currentReclaimableOverflowOf(uint256,uint256,uint256,uint256)' + ]( + PROJECT_ID, + /* tokenCount */ tokenAmt, + /* totalSupply */ totalSupply, + /* overflow */ overflowAmt, + ), + ).to.equal(ethers.FixedNumber.fromString('41.25')); + }); + it('Should return claimable overflow when no terminal is passed, with 0 overflow', async function () { + const { JBSingleTokenPaymentTerminalStore } = await setup(); + + const overflowAmt = ethers.FixedNumber.from(0); + const tokenAmt = ethers.FixedNumber.from(50); + const totalSupply = ethers.FixedNumber.from(50); + + // Get claimable overflow where tokenCount is half the total supply of tokens + expect( + await JBSingleTokenPaymentTerminalStore[ + 'currentReclaimableOverflowOf(uint256,uint256,uint256,uint256)' + ]( + PROJECT_ID, + /* tokenCount */ tokenAmt, + /* totalSupply */ totalSupply, + /* overflow */ overflowAmt, + ), + ).to.equal(0); + }); +}); diff --git a/test/jb_payment_terminal_store_3_1/current_total_overflow_of.test.js b/test/jb_payment_terminal_store_3_1/current_total_overflow_of.test.js new file mode 100644 index 000000000..34403f26b --- /dev/null +++ b/test/jb_payment_terminal_store_3_1/current_total_overflow_of.test.js @@ -0,0 +1,199 @@ +import { expect } from 'chai'; +import { ethers } from 'hardhat'; + +import { deployMockContract } from '@ethereum-waffle/mock-contract'; + +import { packFundingCycleMetadata } from '../helpers/utils'; + +import jbController from '../../artifacts/contracts/interfaces/IJBController3_1.sol/IJBController3_1.json'; +import jbDirectory from '../../artifacts/contracts/interfaces/IJBDirectory.sol/IJBDirectory.json'; +import jBFundingCycleStore from '../../artifacts/contracts/interfaces/IJBFundingCycleStore.sol/IJBFundingCycleStore.json'; +import jbPrices from '../../artifacts/contracts/interfaces/IJBPrices.sol/IJBPrices.json'; +import jbProjects from '../../artifacts/contracts/interfaces/IJBProjects.sol/IJBProjects.json'; +import jbPaymentTerminal from '../../artifacts/contracts/abstract/JBPayoutRedemptionPaymentTerminal3_1.sol/JBPayoutRedemptionPaymentTerminal3_1.json'; +import jbTokenStore from '../../artifacts/contracts/interfaces/IJBTokenStore.sol/IJBTokenStore.json'; + +describe('JBSingleTokenPaymentTerminalStore3_1::currentTotalOverflowOf(...)', function () { + const PROJECT_ID = 2; + const WEIGHT = ethers.BigNumber.from('1' + '0'.repeat(17)); + + const ETH_OVERFLOW_A = ethers.utils.parseEther('69000'); + const ETH_OVERFLOW_B = ethers.utils.parseEther('420'); + const PRICE = ethers.BigNumber.from('100'); + const DECIMAL = 18; + const NON_18_DECIMAL = 12; + + async function setup() { + const [deployer] = await ethers.getSigners(); + + const mockJbPrices = await deployMockContract(deployer, jbPrices.abi); + const mockJbProjects = await deployMockContract(deployer, jbProjects.abi); + const mockJbDirectory = await deployMockContract(deployer, jbDirectory.abi); + const mockJbFundingCycleStore = await deployMockContract(deployer, jBFundingCycleStore.abi); + const mockJbTokenStore = await deployMockContract(deployer, jbTokenStore.abi); + const mockJbController = await deployMockContract(deployer, jbController.abi); + const mockJbTerminalA = await deployMockContract(deployer, jbPaymentTerminal.abi); + const mockJbTerminalB = await deployMockContract(deployer, jbPaymentTerminal.abi); + + const jbCurrenciesFactory = await ethers.getContractFactory('JBCurrencies'); + const jbCurrencies = await jbCurrenciesFactory.deploy(); + const CURRENCY_ETH = await jbCurrencies.ETH(); + const CURRENCY_USD = await jbCurrencies.USD(); + + const JBPaymentTerminalStoreFactory = await ethers.getContractFactory( + 'contracts/JBSingleTokenPaymentTerminalStore3_1.sol:JBSingleTokenPaymentTerminalStore3_1', + ); + const JBSingleTokenPaymentTerminalStore = await JBPaymentTerminalStoreFactory.deploy( + mockJbDirectory.address, + mockJbFundingCycleStore.address, + mockJbPrices.address, + ); + + const blockNum = await ethers.provider.getBlockNumber(); + const block = await ethers.provider.getBlock(blockNum); + const timestamp = block.timestamp; + + return { + mockJbTerminalA, + mockJbTerminalB, + mockJbController, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbPrices, + JBSingleTokenPaymentTerminalStore, + timestamp, + CURRENCY_ETH, + CURRENCY_USD, + }; + } + + it('Should return total current overflow across multiple terminals with the same currency (18 decimals) as the one passed', async function () { + const { + mockJbTerminalA, + mockJbTerminalB, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbPrices, + JBSingleTokenPaymentTerminalStore, + timestamp, + CURRENCY_ETH, + CURRENCY_USD, + } = await setup(); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ useTotalOverflowForRedemptions: true }), + }); + + await mockJbDirectory.mock.terminalsOf + .withArgs(PROJECT_ID) + .returns([mockJbTerminalA.address, mockJbTerminalB.address]); + + await mockJbTerminalA.mock.currentEthOverflowOf.withArgs(PROJECT_ID).returns(ETH_OVERFLOW_A); + await mockJbTerminalB.mock.currentEthOverflowOf.withArgs(PROJECT_ID).returns(ETH_OVERFLOW_B); + + // Get total overflow across both terminals, in same currency; should equal sum of the overflows + expect( + await JBSingleTokenPaymentTerminalStore.currentTotalOverflowOf( + PROJECT_ID, + DECIMAL, + CURRENCY_ETH, + ), + ).to.equal(ETH_OVERFLOW_A.add(ETH_OVERFLOW_B)); + }); + + it('Should return total current overflow across multiple terminals with the same currency as the one passed, adjusting non-18 decimals', async function () { + const { + mockJbTerminalA, + mockJbTerminalB, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbPrices, + JBSingleTokenPaymentTerminalStore, + timestamp, + CURRENCY_ETH, + CURRENCY_USD, + } = await setup(); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ useTotalOverflowForRedemptions: true }), + }); + + await mockJbDirectory.mock.terminalsOf + .withArgs(PROJECT_ID) + .returns([mockJbTerminalA.address, mockJbTerminalB.address]); + + await mockJbTerminalA.mock.currentEthOverflowOf.withArgs(PROJECT_ID).returns(ETH_OVERFLOW_A); + await mockJbTerminalB.mock.currentEthOverflowOf.withArgs(PROJECT_ID).returns(ETH_OVERFLOW_B); + + // Get total overflow across both terminals, in same currency; should equal sum of the overflows + expect( + await JBSingleTokenPaymentTerminalStore.currentTotalOverflowOf( + PROJECT_ID, + NON_18_DECIMAL, + CURRENCY_ETH, + ), + ).to.equal(ETH_OVERFLOW_A.add(ETH_OVERFLOW_B).div(10 ** (DECIMAL - NON_18_DECIMAL))); + }); + + it('Should return total current overflow across multiple terminals with different currency as the one passed', async function () { + const { + mockJbTerminalA, + mockJbTerminalB, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbPrices, + JBSingleTokenPaymentTerminalStore, + timestamp, + CURRENCY_ETH, + CURRENCY_USD, + } = await setup(); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ useTotalOverflowForRedemptions: true }), + }); + + await mockJbDirectory.mock.terminalsOf + .withArgs(PROJECT_ID) + .returns([mockJbTerminalA.address, mockJbTerminalB.address]); + + await mockJbTerminalA.mock.currentEthOverflowOf.withArgs(PROJECT_ID).returns(ETH_OVERFLOW_A); + await mockJbTerminalB.mock.currentEthOverflowOf.withArgs(PROJECT_ID).returns(ETH_OVERFLOW_B); + + await mockJbPrices.mock.priceFor + .withArgs(CURRENCY_ETH, CURRENCY_USD, 18) // 18-decimal + .returns(100); + + // Get total overflow across both terminals, in a different currency; should equal to the sum of the overflow / price + expect( + await JBSingleTokenPaymentTerminalStore.currentTotalOverflowOf( + PROJECT_ID, + DECIMAL, + CURRENCY_USD, + ), + ).to.equal(ETH_OVERFLOW_A.add(ETH_OVERFLOW_B).mul(ethers.utils.parseEther('1')).div(PRICE)); + }); +}); diff --git a/test/jb_payment_terminal_store_3_1/record_distribution_for.test.js b/test/jb_payment_terminal_store_3_1/record_distribution_for.test.js new file mode 100644 index 000000000..7d82f8e50 --- /dev/null +++ b/test/jb_payment_terminal_store_3_1/record_distribution_for.test.js @@ -0,0 +1,487 @@ +import { expect } from 'chai'; +import { ethers } from 'hardhat'; + +import { deployMockContract } from '@ethereum-waffle/mock-contract'; + +import errors from '../helpers/errors.json'; +import { packFundingCycleMetadata, impersonateAccount } from '../helpers/utils'; + +import jbController from '../../artifacts/contracts/interfaces/IJBController3_1.sol/IJBController3_1.json'; +import jbDirectory from '../../artifacts/contracts/interfaces/IJBDirectory.sol/IJBDirectory.json'; +import jBFundingCycleStore from '../../artifacts/contracts/interfaces/IJBFundingCycleStore.sol/IJBFundingCycleStore.json'; +import jbFundAccessConstraintsStore from '../../artifacts/contracts/interfaces/IJBFundAccessConstraintsStore.sol/IJBFundAccessConstraintsStore.json'; +import jbPrices from '../../artifacts/contracts/interfaces/IJBPrices.sol/IJBPrices.json'; +import jbProjects from '../../artifacts/contracts/interfaces/IJBProjects.sol/IJBProjects.json'; +import jbTerminal from '../../artifacts/contracts/abstract/JBPayoutRedemptionPaymentTerminal3_1.sol/JBPayoutRedemptionPaymentTerminal3_1.json'; +import jbTokenStore from '../../artifacts/contracts/interfaces/IJBTokenStore.sol/IJBTokenStore.json'; + +describe('JBSingleTokenPaymentTerminalStore3_1::recordDistributionFor(...)', function () { + const FUNDING_CYCLE_NUM = 1; + const PROJECT_ID = 2; + const AMOUNT = ethers.FixedNumber.fromString('4398541.345'); + const WEIGHT = ethers.FixedNumber.fromString('900000000.23411'); + const CURRENCY = 1; + const _FIXED_POINT_MAX_FIDELITY = 18; + + async function setup() { + const [deployer, addr] = await ethers.getSigners(); + + const mockJbPrices = await deployMockContract(deployer, jbPrices.abi); + const mockJbProjects = await deployMockContract(deployer, jbProjects.abi); + const mockJbDirectory = await deployMockContract(deployer, jbDirectory.abi); + const mockJbFundingCycleStore = await deployMockContract(deployer, jBFundingCycleStore.abi); + const mockJbTerminal = await deployMockContract(deployer, jbTerminal.abi); + const mockJbTokenStore = await deployMockContract(deployer, jbTokenStore.abi); + const mockJbController = await deployMockContract(deployer, jbController.abi); + const mockJbFundAccessConstraintsStore = await deployMockContract(deployer, jbFundAccessConstraintsStore.abi); + + const jbCurrenciesFactory = await ethers.getContractFactory('JBCurrencies'); + const jbCurrencies = await jbCurrenciesFactory.deploy(); + const CURRENCY_ETH = await jbCurrencies.ETH(); + const CURRENCY_USD = await jbCurrencies.USD(); + + const JBPaymentTerminalStoreFactory = await ethers.getContractFactory( + 'contracts/JBSingleTokenPaymentTerminalStore3_1.sol:JBSingleTokenPaymentTerminalStore3_1', + ); + const JBSingleTokenPaymentTerminalStore = await JBPaymentTerminalStoreFactory.deploy( + mockJbDirectory.address, + mockJbFundingCycleStore.address, + mockJbPrices.address, + ); + + const blockNum = await ethers.provider.getBlockNumber(); + const block = await ethers.provider.getBlock(blockNum); + const timestamp = block.timestamp; + + /* Common mocks */ + + await mockJbTerminal.mock.currency.returns(CURRENCY); + + // Set controller address + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + + const mockJbTerminalSigner = await impersonateAccount(mockJbTerminal.address); + + const token = ethers.Wallet.createRandom().address; + + await mockJbTerminal.mock.token.returns(token); + + return { + mockJbTerminal, + mockJbTerminalSigner, + addr, + mockJbController, + mockJbFundAccessConstraintsStore, + mockJbFundingCycleStore, + mockJbPrices, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + CURRENCY_USD, + }; + } + + it('Should record distribution with mockJbTerminal access, if the amount in expressed in terminal currency', async function () { + const { + mockJbTerminal, + mockJbTerminalSigner, + mockJbController, + mockJbFundingCycleStore, + mockJbFundAccessConstraintsStore, + mockJbPrices, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_USD, + } = await setup(); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + // mock JBFundingCycle obj + number: FUNDING_CYCLE_NUM, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ pauseDistributions: 0 }), + }); + + // Add to balance beforehand + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordAddedBalanceFor( + PROJECT_ID, + AMOUNT, + ); + + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(AMOUNT, CURRENCY_USD); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + await mockJbTerminal.mock.currency.returns(CURRENCY_USD); + + // Pre-checks + expect( + await JBSingleTokenPaymentTerminalStore.usedDistributionLimitOf( + mockJbTerminalSigner.address, + PROJECT_ID, + FUNDING_CYCLE_NUM, + ), + ).to.equal(0); + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(AMOUNT); + + // Record the distributions + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordDistributionFor( + PROJECT_ID, + AMOUNT, + CURRENCY_USD, + ); + + // Post-checks + expect( + await JBSingleTokenPaymentTerminalStore.usedDistributionLimitOf( + mockJbTerminalSigner.address, + PROJECT_ID, + FUNDING_CYCLE_NUM, + ), + ).to.equal(AMOUNT); + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(0); + }); + + it('Should record distribution with mockJbTerminal access, if the amount in another currency', async function () { + const { + mockJbTerminal, + mockJbTerminalSigner, + mockJbController, + mockJbFundingCycleStore, + mockJbPrices, + mockJbFundAccessConstraintsStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + CURRENCY_USD, + } = await setup(); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + // mock JBFundingCycle obj + number: FUNDING_CYCLE_NUM, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ pauseDistributions: 0 }), + }); + + const usdToEthPrice = ethers.FixedNumber.from(10000); + const amountInWei = AMOUNT.divUnsafe(usdToEthPrice); + + // Add to balance beforehand + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordAddedBalanceFor( + PROJECT_ID, + amountInWei, + ); + + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(AMOUNT, CURRENCY_USD); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + await mockJbPrices.mock.priceFor + .withArgs(CURRENCY_USD, CURRENCY_ETH, _FIXED_POINT_MAX_FIDELITY) + .returns(usdToEthPrice); + + await mockJbTerminal.mock.currency.returns(CURRENCY_ETH); + + // Pre-checks + expect( + await JBSingleTokenPaymentTerminalStore.usedDistributionLimitOf( + mockJbTerminalSigner.address, + PROJECT_ID, + FUNDING_CYCLE_NUM, + ), + ).to.equal(0); + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(amountInWei); + + // Record the distributions + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordDistributionFor( + PROJECT_ID, + AMOUNT, + CURRENCY_USD, + ); + + // Post-checks + expect( + await JBSingleTokenPaymentTerminalStore.usedDistributionLimitOf( + mockJbTerminalSigner.address, + PROJECT_ID, + FUNDING_CYCLE_NUM, + ), + ).to.equal(AMOUNT); + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(0); + }); + + /* Sad path tests */ + + it(`Can't record distribution if distributions are paused`, async function () { + const { + mockJbTerminal, + mockJbTerminalSigner, + mockJbFundingCycleStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + CURRENCY_ETH, + } = await setup(); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + // mock JBFundingCycle obj + number: FUNDING_CYCLE_NUM, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ pauseDistributions: 1 }), + }); + + await mockJbTerminal.mock.currency.returns(CURRENCY_ETH); + + // Record the distributions + await expect( + JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordDistributionFor( + PROJECT_ID, + AMOUNT, + CURRENCY_ETH, + ), + ).to.be.revertedWith(errors.FUNDING_CYCLE_DISTRIBUTION_PAUSED); + }); + + it(`Can't record distribution if currency param doesn't match controller's currency`, async function () { + const { + mockJbTerminal, + mockJbTerminalSigner, + mockJbController, + mockJbFundingCycleStore, + mockJbFundAccessConstraintsStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + CURRENCY_USD, + } = await setup(); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + // mock JBFundingCycle obj + number: FUNDING_CYCLE_NUM, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ pauseDistributions: 0 }), + }); + + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(AMOUNT, CURRENCY_USD); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + await mockJbTerminal.mock.currency.returns(CURRENCY_ETH); + + // Record the distributions + await expect( + JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordDistributionFor( + PROJECT_ID, + AMOUNT, + CURRENCY_ETH, + ), // Use ETH instead of expected USD + ).to.be.revertedWith(errors.CURRENCY_MISMATCH); + }); + + it(`Can't record distribution if distributionLimit is exceeded`, async function () { + const { + mockJbTerminal, + mockJbTerminalSigner, + mockJbController, + mockJbFundingCycleStore, + mockJbFundAccessConstraintsStore, + mockJbPrices, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + } = await setup(); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + // mock JBFundingCycle obj + number: FUNDING_CYCLE_NUM, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ pauseDistributions: 0 }), + }); + + // Add to balance beforehand + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordAddedBalanceFor( + PROJECT_ID, + AMOUNT, + ); + + const smallDistributionLimit = AMOUNT.subUnsafe(ethers.FixedNumber.from(1)); + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(smallDistributionLimit, CURRENCY_ETH); // Set intentionally small distribution limit + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + await mockJbTerminal.mock.currency.returns(CURRENCY_ETH); + + // Record the distributions + await expect( + JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordDistributionFor( + PROJECT_ID, + AMOUNT, + CURRENCY_ETH, + ), + ).to.be.revertedWith(errors.DISTRIBUTION_AMOUNT_LIMIT_REACHED); + }); + + it(`Can't record distribution if distributionLimit is 0`, async function () { + const { + mockJbTerminal, + mockJbTerminalSigner, + mockJbController, + mockJbFundingCycleStore, + mockJbFundAccessConstraintsStore, + mockJbPrices, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + } = await setup(); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + // mock JBFundingCycle obj + number: FUNDING_CYCLE_NUM, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ pauseDistributions: 0 }), + }); + + // Add to balance beforehand + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordAddedBalanceFor( + PROJECT_ID, + AMOUNT, + ); + + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(0, CURRENCY_ETH); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + await mockJbTerminal.mock.currency.returns(CURRENCY_ETH); + + // Record the distributions + await expect( + JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordDistributionFor( + PROJECT_ID, + 0, + CURRENCY_ETH, + ), + ).to.be.revertedWith(errors.DISTRIBUTION_AMOUNT_LIMIT_REACHED); + }); + + it(`Can't record distribution if distributedAmount > project's total balance`, async function () { + const { + mockJbTerminal, + mockJbTerminalSigner, + mockJbController, + mockJbFundAccessConstraintsStore, + mockJbFundingCycleStore, + mockJbPrices, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + } = await setup(); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + // mock JBFundingCycle obj + number: FUNDING_CYCLE_NUM, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ pauseDistributions: 0 }), + }); + + // Add intentionally small balance + const smallBalance = AMOUNT.subUnsafe(ethers.FixedNumber.from(1)); + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordAddedBalanceFor( + PROJECT_ID, + smallBalance, + ); + + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(AMOUNT, CURRENCY_ETH); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + await mockJbTerminal.mock.currency.returns(CURRENCY_ETH); + + // Record the distributions + await expect( + JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordDistributionFor( + PROJECT_ID, + AMOUNT, + CURRENCY_ETH, + ), + ).to.be.revertedWith(errors.INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE); + }); +}); diff --git a/test/jb_payment_terminal_store_3_1/record_migration.test.js b/test/jb_payment_terminal_store_3_1/record_migration.test.js new file mode 100644 index 000000000..0013751ec --- /dev/null +++ b/test/jb_payment_terminal_store_3_1/record_migration.test.js @@ -0,0 +1,121 @@ +import { expect } from 'chai'; +import { ethers } from 'hardhat'; + +import { deployMockContract } from '@ethereum-waffle/mock-contract'; + +import errors from '../helpers/errors.json'; +import { packFundingCycleMetadata, impersonateAccount } from '../helpers/utils'; + +import jbDirectory from '../../artifacts/contracts/interfaces/IJBDirectory.sol/IJBDirectory.json'; +import jBFundingCycleStore from '../../artifacts/contracts/interfaces/IJBFundingCycleStore.sol/IJBFundingCycleStore.json'; +import jbPrices from '../../artifacts/contracts/interfaces/IJBPrices.sol/IJBPrices.json'; +import jbProjects from '../../artifacts/contracts/interfaces/IJBProjects.sol/IJBProjects.json'; +import jbTerminal from '../../artifacts/contracts/abstract/JBPayoutRedemptionPaymentTerminal3_1.sol/JBPayoutRedemptionPaymentTerminal3_1.json'; +import jbTokenStore from '../../artifacts/contracts/interfaces/IJBTokenStore.sol/IJBTokenStore.json'; + +describe('JBSingleTokenPaymentTerminalStore3_1::recordMigration(...)', function () { + const PROJECT_ID = 2; + const AMOUNT = ethers.FixedNumber.fromString('4398541.345'); + const WEIGHT = ethers.FixedNumber.fromString('900000000.23411'); + const CURRENCY = 1; + const BASE_CURRENCY = 0; + + async function setup() { + const [deployer] = await ethers.getSigners(); + + const mockJbPrices = await deployMockContract(deployer, jbPrices.abi); + const mockJbProjects = await deployMockContract(deployer, jbProjects.abi); + const mockJbDirectory = await deployMockContract(deployer, jbDirectory.abi); + const mockJbFundingCycleStore = await deployMockContract(deployer, jBFundingCycleStore.abi); + const mockJbTerminal = await deployMockContract(deployer, jbTerminal.abi); + const mockJbTokenStore = await deployMockContract(deployer, jbTokenStore.abi); + + const JBPaymentTerminalStoreFactory = await ethers.getContractFactory( + 'contracts/JBSingleTokenPaymentTerminalStore3_1.sol:JBSingleTokenPaymentTerminalStore3_1', + ); + const JBSingleTokenPaymentTerminalStore = await JBPaymentTerminalStoreFactory.deploy( + mockJbDirectory.address, + mockJbFundingCycleStore.address, + mockJbPrices.address, + ); + + const blockNum = await ethers.provider.getBlockNumber(); + const block = await ethers.provider.getBlock(blockNum); + const timestamp = block.timestamp; + + await mockJbTerminal.mock.currency.returns(CURRENCY); + + const mockJbTerminalSigner = await impersonateAccount(mockJbTerminal.address); + + return { + mockJbTerminal, + mockJbTerminalSigner, + mockJbFundingCycleStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + }; + } + + it('Should record migration with mockJbTerminal access', async function () { + const { + mockJbTerminalSigner, + mockJbFundingCycleStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + } = await setup(); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ allowTerminalMigration: 1 }), + }); + + // Add to balance beforehand + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordAddedBalanceFor( + PROJECT_ID, + AMOUNT, + ); + + // "Record migration" + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordMigration( + PROJECT_ID, + ); + + // Current balance should be set to 0 + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(0); + }); + + it(`Can't record migration with allowTerminalMigration flag disabled`, async function () { + const { + mockJbTerminalSigner, + mockJbFundingCycleStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + } = await setup(); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ allowTerminalMigration: 0 }), + }); + + // Record migration + await expect( + JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordMigration(PROJECT_ID), + ).to.be.revertedWith(errors.PAYMENT_TERMINAL_MIGRATION_NOT_ALLOWED); + }); +}); diff --git a/test/jb_payment_terminal_store_3_1/record_payment_from.test.js b/test/jb_payment_terminal_store_3_1/record_payment_from.test.js new file mode 100644 index 000000000..e4b3b345b --- /dev/null +++ b/test/jb_payment_terminal_store_3_1/record_payment_from.test.js @@ -0,0 +1,512 @@ +import { expect } from 'chai'; +import { ethers } from 'hardhat'; + +import { deployMockContract } from '@ethereum-waffle/mock-contract'; + +import errors from '../helpers/errors.json'; +import { packFundingCycleMetadata, impersonateAccount } from '../helpers/utils'; + +import jbController from '../../artifacts/contracts/interfaces/IJBController3_1.sol/IJBController3_1.json'; +import jbDirectory from '../../artifacts/contracts/interfaces/IJBDirectory.sol/IJBDirectory.json'; +import jBFundingCycleStore from '../../artifacts/contracts/interfaces/IJBFundingCycleStore.sol/IJBFundingCycleStore.json'; +import jbFundingCycleDataSource from '../../artifacts/contracts/interfaces/IJBFundingCycleDataSource.sol/IJBFundingCycleDataSource.json'; +import jbPrices from '../../artifacts/contracts/interfaces/IJBPrices.sol/IJBPrices.json'; +import jbProjects from '../../artifacts/contracts/interfaces/IJBProjects.sol/IJBProjects.json'; +import jbTerminal from '../../artifacts/contracts/abstract/JBPayoutRedemptionPaymentTerminal3_1.sol/JBPayoutRedemptionPaymentTerminal3_1.json'; +import jbTokenStore from '../../artifacts/contracts/interfaces/IJBTokenStore.sol/IJBTokenStore.json'; + +describe('JBSingleTokenPaymentTerminalStore3_1::recordPaymentFrom(...)', function () { + const PROJECT_ID = 2; + + const AMOUNT = ethers.utils.parseEther('4351'); + const WEIGHT = ethers.utils.parseEther('900'); + + const CURRENCY = 1; + const BASE_CURRENCY = 1; + const METADATA1 = ethers.utils.randomBytes(32); + const METADATA2 = ethers.utils.randomBytes(32); + const _FIXED_POINT_MAX_FIDELITY = 18; + + async function setup() { + const [deployer, payer, beneficiary, ...addrs] = await ethers.getSigners(); + + const mockJbPrices = await deployMockContract(deployer, jbPrices.abi); + const mockJbProjects = await deployMockContract(deployer, jbProjects.abi); + const mockJbFundingCycleStore = await deployMockContract(deployer, jBFundingCycleStore.abi); + const mockJbFundingCycleDataSource = await deployMockContract( + deployer, + jbFundingCycleDataSource.abi, + ); + const mockJbTerminal = await deployMockContract(deployer, jbTerminal.abi); + const mockJbTokenStore = await deployMockContract(deployer, jbTokenStore.abi); + const mockJbController = await deployMockContract(deployer, jbController.abi); + const mockJbDirectory = await deployMockContract(deployer, jbDirectory.abi); + + const JBPaymentTerminalStoreFactory = await ethers.getContractFactory( + 'contracts/JBSingleTokenPaymentTerminalStore3_1.sol:JBSingleTokenPaymentTerminalStore3_1', + ); + const JBSingleTokenPaymentTerminalStore = await JBPaymentTerminalStoreFactory.deploy( + mockJbDirectory.address, + mockJbFundingCycleStore.address, + mockJbPrices.address, + ); + + const blockNum = await ethers.provider.getBlockNumber(); + const block = await ethers.provider.getBlock(blockNum); + const timestamp = block.timestamp; + + /* Common mocks */ + + // await mockJbTerminal.mock.currency.returns(CURRENCY); + // await mockJbTerminal.mock.baseWeightCurrency.returns(BASE_CURRENCY); + + const mockJbTerminalSigner = await impersonateAccount(mockJbTerminal.address); + + return { + mockJbTerminal, + mockJbTerminalSigner, + payer, + beneficiary, + mockJbController, + mockJbPrices, + mockJbFundingCycleStore, + mockJbFundingCycleDataSource, + mockJbPrices, + JBSingleTokenPaymentTerminalStore, + timestamp, + addrs, + }; + } + + /* Happy path tests with mockJbTerminal access */ + + it('Should record payment without a datasource', async function () { + const { + mockJbTerminalSigner, + payer, + beneficiary, + mockJbFundingCycleStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + } = await setup(); + + const reservedRate = 0; + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + // mock JBFundingCycle obj + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ pausePay: 0, reservedRate: reservedRate }), + }); + + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(0); + + // Record the payment + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordPaymentFrom( + payer.address, + ['0x1230000000000000000000000000000000000000', AMOUNT, 18, CURRENCY], + PROJECT_ID, + BASE_CURRENCY, + beneficiary.address, + /* memo */ 'test', + METADATA1, + ); + + // Expect recorded balance to change + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(AMOUNT); + }); + + it('Should record payment with no weight', async function () { + const { + mockJbTerminalSigner, + payer, + beneficiary, + mockJbFundingCycleStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + } = await setup(); + + const reservedRate = 0; + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + // mock JBFundingCycle obj + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: 0, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ pausePay: 0, reservedRate: reservedRate }), + }); + + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(0); + + // Record the payment + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordPaymentFrom( + /* payer */ payer.address, + ['0x1230000000000000000000000000000000000000', AMOUNT, 18, CURRENCY], + PROJECT_ID, + BASE_CURRENCY, + beneficiary.address, + /* memo */ 'test', + METADATA1, + ); + + // Expect recorded balance to change + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(AMOUNT); + }); + + it('Should record payment with a datasource and emit event', async function () { + const { + mockJbTerminalSigner, + payer, + beneficiary, + mockJbFundingCycleStore, + mockJbFundingCycleDataSource, + JBSingleTokenPaymentTerminalStore, + timestamp, + addrs, + } = await setup(); + + const memo = 'test'; + const reservedRate = 0; + const packedMetadata = packFundingCycleMetadata({ + pausePay: 0, + reservedRate: reservedRate, + useDataSourceForPay: 1, + dataSource: mockJbFundingCycleDataSource.address, + }); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + // JBFundingCycle obj + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packedMetadata, + }); + + const newMemo = 'new memo'; + const delegate = addrs[0]; + + await mockJbFundingCycleDataSource.mock.payParams + .withArgs({ + // JBPayParamsData obj + terminal: mockJbTerminalSigner.address, + payer: payer.address, + amount: ['0x1230000000000000000000000000000000000000', AMOUNT, 18, CURRENCY], + decimal: _FIXED_POINT_MAX_FIDELITY, + projectId: PROJECT_ID, + currentFundingCycleConfiguration: timestamp, + beneficiary, + weight: WEIGHT, + reservedRate: reservedRate, + beneficiary: beneficiary.address, + memo: memo, + metadata: METADATA1 + }) + .returns(WEIGHT, newMemo, [{ delegate: delegate.address, amount: 0, metadata: METADATA2 }]); + + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(0); + + // Record the payment + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordPaymentFrom( + /* payer */ payer.address, + /* amount */ + ['0x1230000000000000000000000000000000000000', AMOUNT, 18, CURRENCY], + /* projectId */ PROJECT_ID, + BASE_CURRENCY, + beneficiary.address, + /* memo */ 'test', + METADATA1, + ); + + // Expect recorded balance to change + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(AMOUNT); + }); + + it('Should record payment without a weight', async function () { + const { + mockJbTerminalSigner, + payer, + beneficiary, + mockJbFundingCycleStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + } = await setup(); + + const reservedRate = 0; + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + // mock JBFundingCycle obj + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: 0, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ pausePay: 0, reservedRate: reservedRate }), + }); + + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(0); + + // Record the payment + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordPaymentFrom( + /* payer */ payer.address, + ['0x1230000000000000000000000000000000000000', AMOUNT, 18, CURRENCY], + PROJECT_ID, + BASE_CURRENCY, + beneficiary.address, + /* memo */ 'test', + METADATA1, + ); + + // Expect recorded balance to change + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(AMOUNT); + }); + + it('Should record payment with a base weight currency that differs from the terminal currency', async function () { + const { + mockJbTerminalSigner, + payer, + beneficiary, + mockJbFundingCycleStore, + JBSingleTokenPaymentTerminalStore, + mockJbTerminal, + mockJbPrices, + timestamp, + } = await setup(); + + const reservedRate = 0; + const otherBaseCurrency = 2; + const conversionPrice = ethers.BigNumber.from(2); + await mockJbTerminal.mock.baseWeightCurrency.returns(otherBaseCurrency); + + await mockJbPrices.mock.priceFor + .withArgs(CURRENCY, otherBaseCurrency, _FIXED_POINT_MAX_FIDELITY) + .returns(conversionPrice.mul(ethers.BigNumber.from(10).pow(18))); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + // mock JBFundingCycle obj + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ pausePay: 0, reservedRate: reservedRate }), + }); + + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(0); + + // Record the payment + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordPaymentFrom( + /* payer */ payer.address, + ['0x1230000000000000000000000000000000000000', AMOUNT, 18, CURRENCY], + PROJECT_ID, + otherBaseCurrency, + beneficiary.address, + /* memo */ 'test', + METADATA1, + ); + + // Expect recorded balance to change + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(AMOUNT); + }); + + it(`Should skip minting and recording payment if amount is 0`, async function () { + const { + mockJbTerminalSigner, + payer, + beneficiary, + mockJbFundingCycleStore, + mockJbFundingCycleDataSource, + JBSingleTokenPaymentTerminalStore, + timestamp, + addrs, + } = await setup(); + + const memo = 'test'; + const reservedRate = 0; + const packedMetadata = packFundingCycleMetadata({ + pausePay: 0, + reservedRate: reservedRate, + useDataSourceForPay: 1, + dataSource: mockJbFundingCycleDataSource.address, + }); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + // JBFundingCycle obj + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packedMetadata, + }); + + const newMemo = 'new memo'; + const delegate = addrs[0]; + await mockJbFundingCycleDataSource.mock.payParams + .withArgs({ + // JBPayParamsData obj + terminal: mockJbTerminalSigner.address, + payer: payer.address, + amount: ['0x1230000000000000000000000000000000000000', 0, 18, CURRENCY], + projectId: PROJECT_ID, + currentFundingCycleConfiguration: timestamp, + beneficiary: beneficiary.address, + weight: WEIGHT, + reservedRate: reservedRate, + memo: memo, + metadata: METADATA1, + }) + .returns(WEIGHT, newMemo, [{ delegate: delegate.address, amount: 0, metadata: METADATA2 }]); + + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(0); + + // Record the payment + const returnedValue = await JBSingleTokenPaymentTerminalStore.connect( + mockJbTerminalSigner, + ).callStatic.recordPaymentFrom( + /* payer */ payer.address, + ['0x1230000000000000000000000000000000000000', 0, 18, CURRENCY], + /* projectId */ PROJECT_ID, + BASE_CURRENCY, + beneficiary.address, + /* memo */ memo, + METADATA1, + ); + + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordPaymentFrom( + /* payer */ payer.address, + ['0x1230000000000000000000000000000000000000', 0, 18, CURRENCY], + /* projectId */ PROJECT_ID, + BASE_CURRENCY, + beneficiary.address, + /* memo */ memo, + METADATA1, + ); + + // Recorded balance should not have changed + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(0); + expect(returnedValue.delegateAllocations[0].delegate).to.equal(delegate.address); + }); + + /* Sad path tests */ + + it(`Can't record payment if fundingCycle hasn't been configured`, async function () { + const { + mockJbTerminalSigner, + payer, + beneficiary, + mockJbFundingCycleStore, + JBSingleTokenPaymentTerminalStore, + } = await setup(); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + // empty JBFundingCycle obj + number: 0, // Set bad number + configuration: 0, + basedOn: 0, + start: 0, + duration: 0, + weight: 0, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: 0, + }); + + // Record the payment + await expect( + JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordPaymentFrom( + /* payer */ payer.address, + ['0x1230000000000000000000000000000000000000', AMOUNT, 18, CURRENCY], + PROJECT_ID, + BASE_CURRENCY, + beneficiary.address, + /* memo */ 'test', + METADATA1, + ), + ).to.be.revertedWith(errors.INVALID_FUNDING_CYCLE); + }); + + it(`Can't record payment if fundingCycle has been paused`, async function () { + const { + mockJbTerminalSigner, + payer, + beneficiary, + mockJbFundingCycleStore, + JBSingleTokenPaymentTerminalStore, + } = await setup(); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + // mock JBFundingCycle obj + number: 1, + configuration: 0, + basedOn: 0, + start: 0, + duration: 0, + weight: 0, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ pausePay: 1 }), // Payments paused + }); + + // Record the payment + await expect( + JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordPaymentFrom( + /* payer */ payer.address, + ['0x1230000000000000000000000000000000000000', AMOUNT, 18, CURRENCY], + PROJECT_ID, + BASE_CURRENCY, + beneficiary.address, + /* memo */ 'test', + METADATA1, + ), + ).to.be.revertedWith(errors.FUNDING_CYCLE_PAYMENT_PAUSED); + }); +}); diff --git a/test/jb_payment_terminal_store_3_1/record_redemption_for.test.js b/test/jb_payment_terminal_store_3_1/record_redemption_for.test.js new file mode 100644 index 000000000..59c22c36a --- /dev/null +++ b/test/jb_payment_terminal_store_3_1/record_redemption_for.test.js @@ -0,0 +1,789 @@ +import { expect } from 'chai'; +import { ethers } from 'hardhat'; + +import { deployMockContract } from '@ethereum-waffle/mock-contract'; + +import errors from '../helpers/errors.json'; +import { packFundingCycleMetadata, impersonateAccount } from '../helpers/utils'; + +import jbController from '../../artifacts/contracts/interfaces/IJBController3_1.sol/IJBController3_1.json'; +import jbDirectory from '../../artifacts/contracts/interfaces/IJBDirectory.sol/IJBDirectory.json'; +import jBFundingCycleStore from '../../artifacts/contracts/interfaces/IJBFundingCycleStore.sol/IJBFundingCycleStore.json'; +import jbFundingCycleDataSource from '../../artifacts/contracts/interfaces/IJBFundingCycleDataSource.sol/IJBFundingCycleDataSource.json'; +import jbFundAccessConstraintsStore from '../../artifacts/contracts/interfaces/IJBFundAccessConstraintsStore.sol/IJBFundAccessConstraintsStore.json'; +import jbPrices from '../../artifacts/contracts/interfaces/IJBPrices.sol/IJBPrices.json'; +import jbProjects from '../../artifacts/contracts/interfaces/IJBProjects.sol/IJBProjects.json'; +import jbTerminal from '../../artifacts/contracts/abstract/JBPayoutRedemptionPaymentTerminal3_1.sol/JBPayoutRedemptionPaymentTerminal3_1.json'; +import jbTokenStore from '../../artifacts/contracts/interfaces/IJBTokenStore.sol/IJBTokenStore.json'; + +describe('JBSingleTokenPaymentTerminalStore3_1::recordRedemptionFor(...)', function () { + const PROJECT_ID = 2; + const AMOUNT = ethers.BigNumber.from('4398540'); + const WEIGHT = ethers.BigNumber.from('900000000'); + const CURRENCY = ethers.BigNumber.from(1); + const METADATA1 = ethers.utils.randomBytes(32); + const _FIXED_POINT_MAX_FIDELITY = 18; + + async function setup() { + const [deployer, holder, beneficiary, ...addrs] = await ethers.getSigners(); + + const mockJbPrices = await deployMockContract(deployer, jbPrices.abi); + const mockJbProjects = await deployMockContract(deployer, jbProjects.abi); + const mockJbDirectory = await deployMockContract(deployer, jbDirectory.abi); + const mockJbFundingCycleStore = await deployMockContract(deployer, jBFundingCycleStore.abi); + const mockJbFundAccessConstraintsStore = await deployMockContract(deployer, jbFundAccessConstraintsStore.abi); + const mockJbFundingCycleDataSource = await deployMockContract( + deployer, + jbFundingCycleDataSource.abi, + ); + const mockJbTerminal = await deployMockContract(deployer, jbTerminal.abi); + const mockJbTokenStore = await deployMockContract(deployer, jbTokenStore.abi); + const mockJbController = await deployMockContract(deployer, jbController.abi); + + const jbCurrenciesFactory = await ethers.getContractFactory('JBCurrencies'); + const jbCurrencies = await jbCurrenciesFactory.deploy(); + const CURRENCY_ETH = await jbCurrencies.ETH(); + + const JBPaymentTerminalStoreFactory = await ethers.getContractFactory( + 'contracts/JBSingleTokenPaymentTerminalStore3_1.sol:JBSingleTokenPaymentTerminalStore3_1', + ); + const JBSingleTokenPaymentTerminalStore = await JBPaymentTerminalStoreFactory.deploy( + mockJbDirectory.address, + mockJbFundingCycleStore.address, + mockJbPrices.address, + ); + + const blockNum = await ethers.provider.getBlockNumber(); + const block = await ethers.provider.getBlock(blockNum); + const timestamp = block.timestamp; + + const mockJbTerminalSigner = await impersonateAccount(mockJbTerminal.address); + + const token = ethers.Wallet.createRandom().address; + await mockJbTerminal.mock.token.returns(token); + + return { + holder, + beneficiary, + mockJbController, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbFundingCycleDataSource, + mockJbFundAccessConstraintsStore, + mockJbTerminal, + mockJbTerminalSigner, + mockJbTokenStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + addrs, + }; + } + + /* Happy path tests with mockJbTerminal access */ + + it('Should record redemption without a datasource', async function () { + const { + holder, + beneficiary, + mockJbController, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbTerminal, + mockJbTerminalSigner, + mockJbTokenStore, + mockJbFundAccessConstraintsStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + } = await setup(); + + await mockJbTokenStore.mock.balanceOf.withArgs(holder.address, PROJECT_ID).returns(AMOUNT); + + const reservedRate = 0; + const packedMetadata = packFundingCycleMetadata({ + pauseRedeem: 0, + reservedRate: reservedRate, + }); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + // mock JBFundingCycle obj + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packedMetadata, + }); + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + + /* Mocks for _reclaimableOverflowOf private method */ + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(AMOUNT, CURRENCY_ETH); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + await mockJbTokenStore.mock.totalSupplyOf.withArgs(PROJECT_ID).returns(AMOUNT); + await mockJbController.mock.totalOutstandingTokensOf + .withArgs(PROJECT_ID) + .returns(AMOUNT); + + await mockJbController.mock.reservedTokenBalanceOf + .withArgs(PROJECT_ID) + .returns(0); + /* End of mocks for _reclaimableOverflowOf private method */ + + await mockJbTerminal.mock.token.returns(token); + await mockJbTerminal.mock.decimals.returns(18); + await mockJbTerminal.mock.currency.returns(CURRENCY); + + // Add to balance beforehand to have sufficient overflow + const startingBalance = AMOUNT.mul(ethers.BigNumber.from(2)); + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordAddedBalanceFor( + PROJECT_ID, + startingBalance, + ); + + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(startingBalance); + + // Record redemption + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordRedemptionFor( + /* holder */ holder.address, + /* projectId */ PROJECT_ID, + /* tokenCount */ AMOUNT, + /* memo */ 'test', + METADATA1, + ); + + // Expect recorded balance to decrease by redeemed amount + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(startingBalance.sub(AMOUNT)); + }); + + it('Should record redemption from global overflow', async function () { + const { + holder, + beneficiary, + mockJbController, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbTerminal, + mockJbTerminalSigner, + mockJbTokenStore, + mockJbFundAccessConstraintsStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + } = await setup(); + + await mockJbTokenStore.mock.balanceOf.withArgs(holder.address, PROJECT_ID).returns(AMOUNT); + + const reservedRate = 0; + const packedMetadata = packFundingCycleMetadata({ + pauseRedeem: 0, + reservedRate: reservedRate, + useTotalOverflowForRedemptions: true, + }); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + // mock JBFundingCycle obj + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packedMetadata, + }); + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + + await mockJbDirectory.mock.terminalsOf.withArgs(PROJECT_ID).returns([mockJbTerminal.address]); + await mockJbTerminal.mock.currentEthOverflowOf.withArgs(PROJECT_ID).returns(AMOUNT); + + /* Mocks for _reclaimableOverflowOf private method */ + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(AMOUNT, CURRENCY_ETH); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + await mockJbTokenStore.mock.totalSupplyOf.withArgs(PROJECT_ID).returns(AMOUNT); + await mockJbController.mock.totalOutstandingTokensOf + .withArgs(PROJECT_ID) + .returns(AMOUNT); + + await mockJbController.mock.reservedTokenBalanceOf + .withArgs(PROJECT_ID) + .returns(0); + /* End of mocks for _reclaimableOverflowOf private method */ + + await mockJbTerminal.mock.token.returns(token); + await mockJbTerminal.mock.decimals.returns(18); + await mockJbTerminal.mock.currency.returns(CURRENCY); + + // Add to balance beforehand to have sufficient overflow + const startingBalance = AMOUNT.mul(ethers.BigNumber.from(2)); + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordAddedBalanceFor( + PROJECT_ID, + startingBalance, + ); + + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(startingBalance); + + // Record redemption + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordRedemptionFor( + /* holder */ holder.address, + /* projectId */ PROJECT_ID, + /* tokenCount */ AMOUNT, + /* memo */ 'test', + METADATA1, + ); + + // Expect recorded balance to decrease by redeemed amount + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(startingBalance.sub(AMOUNT)); + }); + + it('Should record redemption without a token count', async function () { + const { + holder, + beneficiary, + mockJbController, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbTerminal, + mockJbTerminalSigner, + mockJbTokenStore, + mockJbFundAccessConstraintsStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + } = await setup(); + + await mockJbTokenStore.mock.balanceOf.withArgs(holder.address, PROJECT_ID).returns(AMOUNT); + + const reservedRate = 0; + const packedMetadata = packFundingCycleMetadata({ + pauseRedeem: 0, + reservedRate: reservedRate, + }); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + // mock JBFundingCycle obj + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packedMetadata, + }); + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + + /* Mocks for _claimableOverflowOf private method */ + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(AMOUNT, CURRENCY_ETH); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + await mockJbTokenStore.mock.totalSupplyOf.withArgs(PROJECT_ID).returns(AMOUNT); + await mockJbController.mock.totalOutstandingTokensOf + .withArgs(PROJECT_ID) + .returns(AMOUNT); + + await mockJbController.mock.reservedTokenBalanceOf + .withArgs(PROJECT_ID) + .returns(0); + + /* End of mocks for _claimableOverflowOf private method */ + + await mockJbTerminal.mock.token.returns(token); + await mockJbTerminal.mock.decimals.returns(18); + await mockJbTerminal.mock.currency.returns(CURRENCY); + + // No balance. + const startingBalance = 0; + + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(startingBalance); + + // Record redemption + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordRedemptionFor( + /* holder */ holder.address, + /* projectId */ PROJECT_ID, + /* tokenCount */ 0, + /* memo */ 'test', + METADATA1, + ); + + // Expect recorded balance to not have changed + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(startingBalance); + }); + + it('Should record redemption without a claim amount', async function () { + const { + holder, + beneficiary, + mockJbController, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbTerminal, + mockJbTerminalSigner, + mockJbTokenStore, + mockJbFundAccessConstraintsStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + } = await setup(); + + await mockJbTokenStore.mock.balanceOf.withArgs(holder.address, PROJECT_ID).returns(AMOUNT); + + const reservedRate = 0; + const packedMetadata = packFundingCycleMetadata({ + pauseRedeem: 0, + reservedRate: reservedRate, + }); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + // mock JBFundingCycle obj + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packedMetadata, + }); + + /* Mocks for _reclaimableOverflowOf private method */ + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(AMOUNT, CURRENCY_ETH); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + await mockJbTokenStore.mock.totalSupplyOf.withArgs(PROJECT_ID).returns(AMOUNT); + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + await mockJbController.mock.totalOutstandingTokensOf + .withArgs(PROJECT_ID) + .returns(AMOUNT); + + await mockJbController.mock.reservedTokenBalanceOf + .withArgs(PROJECT_ID) + .returns(0); + /* End of mocks for _reclaimableOverflowOf private method */ + + await mockJbTerminal.mock.token.returns(token); + await mockJbTerminal.mock.decimals.returns(18); + await mockJbTerminal.mock.currency.returns(CURRENCY); + + // No balance + const startingBalance = 0; + + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(startingBalance); + + // Record redemption + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordRedemptionFor( + /* holder */ holder.address, + /* projectId */ PROJECT_ID, + /* tokenCount */ AMOUNT, + /* memo */ 'test', + METADATA1, + ); + + // Expect recorded balance to not have changed + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(startingBalance); + }); + + it('Should record redemption with a datasource and emit event', async function () { + const { + holder, + beneficiary, + mockJbController, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbTerminal, + mockJbTerminalSigner, + mockJbTokenStore, + mockJbFundAccessConstraintsStore, + mockJbFundingCycleDataSource, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + addrs, + CURRENCY_ETH, + } = await setup(); + + await mockJbTokenStore.mock.balanceOf.withArgs(holder.address, PROJECT_ID).returns(AMOUNT); + + const reservedRate = 0; + const redemptionRate = 10000; + const ballotRedemptionRate = 10000; + + const packedMetadata = packFundingCycleMetadata({ + pauseRedeem: 0, + reservedRate: reservedRate, + redemptionRate: redemptionRate, + ballotRedemptionRate: ballotRedemptionRate, + useDataSourceForRedeem: 1, + dataSource: mockJbFundingCycleDataSource.address, + }); + const delegate = addrs[0]; + const delegateAmount = 10; + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + // mock JBFundingCycle obj + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packedMetadata, + }); + + await mockJbController.mock.totalOutstandingTokensOf + .withArgs(PROJECT_ID) + .returns(AMOUNT); + + await mockJbFundingCycleStore.mock.currentBallotStateOf.withArgs(PROJECT_ID).returns(1); + + const startingBalance = AMOUNT.mul(ethers.BigNumber.from(2)); + + const newMemo = 'new memo'; + await mockJbFundingCycleDataSource.mock.redeemParams + .withArgs([ + // JBRedeemParamsData obj + mockJbTerminalSigner.address, + holder.address, + PROJECT_ID, + timestamp, + /*tokenCount*/ AMOUNT, + /*totalSupply*/ AMOUNT, + /*overflow*/ AMOUNT, + [token, AMOUNT, /*decimals*/ _FIXED_POINT_MAX_FIDELITY, CURRENCY], + false, + redemptionRate, + 'test', + METADATA1, + ]) + .returns(AMOUNT, newMemo, [{ delegate: delegate.address, amount: delegateAmount }]); + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminalSigner.address, token) + .returns(AMOUNT, CURRENCY_ETH); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + await mockJbTerminal.mock.token.returns(token); + await mockJbTerminal.mock.decimals.returns(18); + await mockJbTerminal.mock.currency.returns(CURRENCY); + + // Add to balance beforehand to have sufficient overflow + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordAddedBalanceFor( + PROJECT_ID, + startingBalance, + ); + + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(startingBalance); + + // Record redemption + const returnedValue = await JBSingleTokenPaymentTerminalStore.connect( + mockJbTerminalSigner, + ).callStatic.recordRedemptionFor( + /* holder */ holder.address, + /* projectId */ PROJECT_ID, + /* tokenCount */ AMOUNT, + /* memo */ 'test', + METADATA1, + ); + + expect(returnedValue.reclaimAmount).to.equal(AMOUNT); + expect(returnedValue.delegateAllocations).to.eql([ + [delegate.address, ethers.BigNumber.from(delegateAmount)], + ]); + expect(returnedValue.memo).to.equal(newMemo); + }); + + /* Sad path tests */ + it(`Can't record redemption if redemptions are paused`, async function () { + const { + holder, + beneficiary, + mockJbFundingCycleStore, + mockJbTerminal, + mockJbTerminalSigner, + mockJbTokenStore, + mockJbFundingCycleDataSource, + JBSingleTokenPaymentTerminalStore, + token, + timestamp, + } = await setup(); + + await mockJbTokenStore.mock.balanceOf.withArgs(holder.address, PROJECT_ID).returns(AMOUNT); + + const reservedRate = 0; + const redemptionRate = 10000; + const ballotRedemptionRate = 10000; + const packedMetadata = packFundingCycleMetadata({ + pauseRedeem: 1, // Redemptions paused + reservedRate: reservedRate, + redemptionRate: redemptionRate, + ballotRedemptionRate: ballotRedemptionRate, + useDataSourceForRedeem: 1, + dataSource: mockJbFundingCycleDataSource.address, + }); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + // mock JBFundingCycle obj + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packedMetadata, + }); + + await mockJbTerminal.mock.token.returns(token); + await mockJbTerminal.mock.decimals.returns(18); + await mockJbTerminal.mock.currency.returns(CURRENCY); + + // Record redemption + await expect( + JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordRedemptionFor( + /* holder */ holder.address, + /* projectId */ PROJECT_ID, + /* tokenCount */ AMOUNT, + /* memo */ 'test', + METADATA1, + ), + ).to.be.revertedWith(errors.FUNDING_CYCLE_REDEEM_PAUSED); + }); + + it(`Can't record redemption with claim amount > total supply`, async function () { + const { + holder, + beneficiary, + mockJbController, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbTerminal, + mockJbTerminalSigner, + mockJbTokenStore, + mockJbFundingCycleDataSource, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + addrs, + } = await setup(); + + const reservedRate = 0; + const redemptionRate = 10000; + const ballotRedemptionRate = 10000; + const packedMetadata = packFundingCycleMetadata({ + pauseRedeem: 0, + reservedRate: reservedRate, + redemptionRate: redemptionRate, + ballotRedemptionRate: ballotRedemptionRate, + useDataSourceForRedeem: 1, + dataSource: mockJbFundingCycleDataSource.address, + }); + const delegate = addrs[0]; + + await mockJbTokenStore.mock.balanceOf + .withArgs(holder.address, PROJECT_ID) + .returns(AMOUNT.add(1)); + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + await mockJbController.mock.totalOutstandingTokensOf + .withArgs(PROJECT_ID) + .returns(AMOUNT); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + // mock JBFundingCycle obj + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packedMetadata, + }); + + const newMemo = 'new memo'; + await mockJbFundingCycleDataSource.mock.redeemParams + .withArgs([ + // JBRedeemParamsData obj + mockJbTerminalSigner.address, + holder.address, + PROJECT_ID, + timestamp, + /*tokenCount*/ AMOUNT.add(1), + /*totalSupply*/ AMOUNT, + /*overflow*/ 0, + [token, /*reclaim amount*/ 0, /*decimals*/ _FIXED_POINT_MAX_FIDELITY, CURRENCY], + false, + redemptionRate, + 'test', + METADATA1, + ]) + .returns(AMOUNT, newMemo, [{ delegate: delegate.address, amount: 0 }]); + + await mockJbTerminal.mock.token.returns(token); + await mockJbTerminal.mock.decimals.returns(18); + await mockJbTerminal.mock.currency.returns(CURRENCY); + + // Note: The store has 0 balance because we haven't added anything to it + // Record redemption + await expect( + JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordRedemptionFor( + /* holder */ holder.address, + /* projectId */ PROJECT_ID, + /* tokenCount */ AMOUNT.add(1), + /* memo */ 'test', + METADATA1, + ), + ).to.be.revertedWith(errors.INSUFFICIENT_TOKENS); + }); + + it(`Can't record redemption with claim amount > project's total balance`, async function () { + const { + holder, + beneficiary, + mockJbController, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbTerminal, + mockJbTerminalSigner, + mockJbTokenStore, + mockJbFundingCycleDataSource, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + addrs, + } = await setup(); + + const reservedRate = 0; + const redemptionRate = 10000; + const ballotRedemptionRate = 10000; + const packedMetadata = packFundingCycleMetadata({ + pauseRedeem: 0, + reservedRate: reservedRate, + redemptionRate: redemptionRate, + ballotRedemptionRate: ballotRedemptionRate, + useDataSourceForRedeem: 1, + dataSource: mockJbFundingCycleDataSource.address, + }); + const delegate = addrs[0]; + + await mockJbTokenStore.mock.balanceOf.withArgs(holder.address, PROJECT_ID).returns(AMOUNT); + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + await mockJbController.mock.totalOutstandingTokensOf + .withArgs(PROJECT_ID) + .returns(AMOUNT); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + // mock JBFundingCycle obj + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packedMetadata, + }); + + const newMemo = 'new memo'; + await mockJbFundingCycleDataSource.mock.redeemParams + .withArgs([ + // JBRedeemParamsData obj + mockJbTerminalSigner.address, + holder.address, + PROJECT_ID, + timestamp, + /*tokenCount*/ AMOUNT, + /*totalSupply*/ AMOUNT, + /*overflow*/ 0, + [token, /*reclaim amount*/ 0, /*decimals*/ _FIXED_POINT_MAX_FIDELITY, CURRENCY], + false, + redemptionRate, + 'test', + METADATA1, + ]) + .returns(AMOUNT, newMemo, [{ delegate: delegate.address, amount: 0 }]); + + await mockJbTerminal.mock.token.returns(token); + await mockJbTerminal.mock.decimals.returns(18); + await mockJbTerminal.mock.currency.returns(CURRENCY); + await mockJbFundingCycleStore.mock.currentBallotStateOf.withArgs(PROJECT_ID).returns(1); + + // Note: The store has 0 balance because we haven't added anything to it + // Record redemption + await expect( + JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordRedemptionFor( + /* holder */ holder.address, + /* projectId */ PROJECT_ID, + /* tokenCount */ AMOUNT, + /* memo */ 'test', + METADATA1, + ), + ).to.be.revertedWith(errors.INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE); + }); +}); diff --git a/test/jb_payment_terminal_store_3_1/record_used_allowance_of.test.js b/test/jb_payment_terminal_store_3_1/record_used_allowance_of.test.js new file mode 100644 index 000000000..280cd1152 --- /dev/null +++ b/test/jb_payment_terminal_store_3_1/record_used_allowance_of.test.js @@ -0,0 +1,565 @@ +import { expect } from 'chai'; +import { ethers } from 'hardhat'; + +import { deployMockContract } from '@ethereum-waffle/mock-contract'; + +import errors from '../helpers/errors.json'; +import { packFundingCycleMetadata, impersonateAccount } from '../helpers/utils'; + +import jbController from '../../artifacts/contracts/interfaces/IJBController3_1.sol/IJBController3_1.json'; +import jbDirectory from '../../artifacts/contracts/interfaces/IJBDirectory.sol/IJBDirectory.json'; +import jBFundingCycleStore from '../../artifacts/contracts/interfaces/IJBFundingCycleStore.sol/IJBFundingCycleStore.json'; +import jbFundAccessConstraintsStore from '../../artifacts/contracts/interfaces/IJBFundAccessConstraintsStore.sol/IJBFundAccessConstraintsStore.json'; +import jbPrices from '../../artifacts/contracts/interfaces/IJBPrices.sol/IJBPrices.json'; +import jbProjects from '../../artifacts/contracts/interfaces/IJBProjects.sol/IJBProjects.json'; +import jbTerminal from '../../artifacts/contracts/abstract/JBPayoutRedemptionPaymentTerminal3_1.sol/JBPayoutRedemptionPaymentTerminal3_1.json'; +import jbTokenStore from '../../artifacts/contracts/interfaces/IJBTokenStore.sol/IJBTokenStore.json'; + +describe('JBSingleTokenPaymentTerminalStore3_1::recordUsedAllowanceOf(...)', function () { + const PROJECT_ID = 2; + const AMOUNT = ethers.BigNumber.from('43985411231'); + const WEIGHT = ethers.BigNumber.from('900000000'); + const _FIXED_POINT_MAX_FIDELITY = 18; + + async function setup() { + const [deployer, addr] = await ethers.getSigners(); + + const mockJbPrices = await deployMockContract(deployer, jbPrices.abi); + const mockJbProjects = await deployMockContract(deployer, jbProjects.abi); + const mockJbDirectory = await deployMockContract(deployer, jbDirectory.abi); + const mockJbFundingCycleStore = await deployMockContract(deployer, jBFundingCycleStore.abi); + const mockJbTerminal = await deployMockContract(deployer, jbTerminal.abi); + const mockJbTokenStore = await deployMockContract(deployer, jbTokenStore.abi); + const mockJbController = await deployMockContract(deployer, jbController.abi); + const mockJbFundAccessConstraintsStore = await deployMockContract(deployer, jbFundAccessConstraintsStore.abi); + + const jbCurrenciesFactory = await ethers.getContractFactory('JBCurrencies'); + const jbCurrencies = await jbCurrenciesFactory.deploy(); + const CURRENCY_ETH = await jbCurrencies.ETH(); + const CURRENCY_USD = await jbCurrencies.USD(); + const _FIXED_POINT_MAX_FIDELITY = 18; + + const JBPaymentTerminalStoreFactory = await ethers.getContractFactory( + 'contracts/JBSingleTokenPaymentTerminalStore3_1.sol:JBSingleTokenPaymentTerminalStore3_1', + ); + const JBSingleTokenPaymentTerminalStore = await JBPaymentTerminalStoreFactory.deploy( + mockJbDirectory.address, + mockJbFundingCycleStore.address, + mockJbPrices.address, + ); + + const blockNum = await ethers.provider.getBlockNumber(); + const block = await ethers.provider.getBlock(blockNum); + const timestamp = block.timestamp; + + /* Common mocks */ + + await mockJbTerminal.mock.currency.returns(CURRENCY_USD); + await mockJbTerminal.mock.baseWeightCurrency.returns(CURRENCY_ETH); + + // Set controller address + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + + const packedMetadata = packFundingCycleMetadata(); + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packedMetadata, + }); + + const mockJbTerminalSigner = await impersonateAccount(mockJbTerminal.address); + + const token = ethers.Wallet.createRandom().address; + await mockJbTerminal.mock.token.returns(token); + + return { + addr, + mockJbController, + mockJbPrices, + mockJbTerminal, + mockJbTerminalSigner, + mockJbFundAccessConstraintsStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + CURRENCY_USD, + }; + } + + it('Should record used allowance with terminal access', async function () { + const { + mockJbController, + mockJbPrices, + mockJbTerminal, + mockJbTerminalSigner, + mockJbFundAccessConstraintsStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, // base weight currency + CURRENCY_USD, // terminal currency + } = await setup(); + + // Add to balance beforehand, in USD + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordAddedBalanceFor( + PROJECT_ID, + AMOUNT, + ); + + // Both limit and allowance in USD + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(0, CURRENCY_USD); + + await mockJbFundAccessConstraintsStore.mock.overflowAllowanceOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(AMOUNT, CURRENCY_USD); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + await mockJbTerminal.mock.currency.returns(CURRENCY_USD); + + // Pre-checks + expect( + await JBSingleTokenPaymentTerminalStore.usedOverflowAllowanceOf( + mockJbTerminalSigner.address, + PROJECT_ID, + timestamp, + ), + ).to.equal(0); + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(AMOUNT); // balanceOf is in terminal currency (USD) + + // Record the used allowance + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordUsedAllowanceOf( + PROJECT_ID, + AMOUNT, + CURRENCY_USD, + ); + + // Post-checks + expect( + await JBSingleTokenPaymentTerminalStore.usedOverflowAllowanceOf( + mockJbTerminalSigner.address, + PROJECT_ID, + timestamp, + ), + ).to.equal(AMOUNT); + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(0); // AMOUNT-AMOUNT = 0 + }); + it('Should record used allowance with > 0 distribution limit', async function () { + const { + mockJbController, + mockJbPrices, + mockJbFundAccessConstraintsStore, + mockJbTerminal, + mockJbTerminalSigner, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, // base weight currency + CURRENCY_USD, // terminal currency + } = await setup(); + + const usdToEthPrice = ethers.BigNumber.from(3500); + + // Add to balance beforehand, in USD + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordAddedBalanceFor( + PROJECT_ID, + AMOUNT, + ); + + const distributionLimit = AMOUNT - 1; + + // Both limit and allowance in USD + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(distributionLimit, CURRENCY_USD); + + await mockJbFundAccessConstraintsStore.mock.overflowAllowanceOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(AMOUNT, CURRENCY_USD); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + await mockJbTerminal.mock.currency.returns(CURRENCY_USD); + + // Pre-checks + expect( + await JBSingleTokenPaymentTerminalStore.usedOverflowAllowanceOf( + mockJbTerminalSigner.address, + PROJECT_ID, + timestamp, + ), + ).to.equal(0); + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(AMOUNT); // balanceOf is in terminal currency (USD) + + // Record the used allowance + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordUsedAllowanceOf( + PROJECT_ID, + AMOUNT - distributionLimit, + CURRENCY_USD, + ); + + // Post-checks + expect( + await JBSingleTokenPaymentTerminalStore.usedOverflowAllowanceOf( + mockJbTerminalSigner.address, + PROJECT_ID, + timestamp, + ), + ).to.equal(AMOUNT - distributionLimit); + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(distributionLimit); + }); + it('Should record used allowance with > 0 distribution limit and different distribution currency', async function () { + const { + mockJbController, + mockJbPrices, + mockJbTerminal, + mockJbTerminalSigner, + mockJbFundAccessConstraintsStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, // base weight currency + CURRENCY_USD, // terminal currency + } = await setup(); + + const ethToUsdPrice = ethers.BigNumber.from(2).mul( + ethers.BigNumber.from(10).pow(_FIXED_POINT_MAX_FIDELITY), + ); + + const distributionLimit = ethers.BigNumber.from(10).pow(18); + + const amountToUse = 2345678; // in eth + let amountToUseInDollar = + amountToUse / ethToUsdPrice.div(ethers.BigNumber.from(10).pow(_FIXED_POINT_MAX_FIDELITY)); + + // Add to balance beforehand, in USD + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordAddedBalanceFor( + PROJECT_ID, + distributionLimit.add(amountToUseInDollar), + ); + + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(distributionLimit, CURRENCY_USD); // in usd + + await mockJbFundAccessConstraintsStore.mock.overflowAllowanceOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(amountToUse, CURRENCY_ETH); // in eth + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + await mockJbPrices.mock.priceFor + .withArgs(CURRENCY_ETH, CURRENCY_USD, _FIXED_POINT_MAX_FIDELITY) + .returns(ethToUsdPrice); + + await mockJbTerminal.mock.currency.returns(CURRENCY_USD); + + // Pre-checks + expect( + await JBSingleTokenPaymentTerminalStore.usedOverflowAllowanceOf( + mockJbTerminalSigner.address, + PROJECT_ID, + timestamp, + ), + ).to.equal(0); + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(distributionLimit.add(amountToUseInDollar)); // balanceOf is in terminal currency (USD) + + // Record the used allowance + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordUsedAllowanceOf( + PROJECT_ID, + amountToUse, + CURRENCY_ETH, + ); + + // Post-checks + expect( + await JBSingleTokenPaymentTerminalStore.usedOverflowAllowanceOf( + mockJbTerminalSigner.address, + PROJECT_ID, + timestamp, + ), + ).to.equal(amountToUse); // in usd + + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(distributionLimit); // in usd + }); + + /* Sad path tests */ + + it(`Can't record allowance if currency param doesn't match controller's currency`, async function () { + const { + mockJbController, + mockJbTerminal, + mockJbTerminalSigner, + mockJbFundAccessConstraintsStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + CURRENCY_USD, + } = await setup(); + + await mockJbFundAccessConstraintsStore.mock.overflowAllowanceOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(AMOUNT, CURRENCY_USD); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + await mockJbTerminal.mock.currency.returns(CURRENCY_ETH); + + // Record the used allowance + await expect( + JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordUsedAllowanceOf( + PROJECT_ID, + AMOUNT, + CURRENCY_ETH, + ), + ).to.be.revertedWith(errors.CURRENCY_MISMATCH); + }); + + it(`Can't record allowance if controller's overflowAllowanceOf is exceeded`, async function () { + const { + mockJbController, + mockJbTerminal, + mockJbTerminalSigner, + mockJbFundAccessConstraintsStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_USD, + } = await setup(); + + // Add to balance beforehand + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordAddedBalanceFor( + PROJECT_ID, + AMOUNT, + ); + + const smallTotalAllowance = AMOUNT.sub(ethers.BigNumber.from(1)); + await mockJbFundAccessConstraintsStore.mock.overflowAllowanceOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(smallTotalAllowance, CURRENCY_USD); // Set the controller's overflowAllowance to something small + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + await mockJbTerminal.mock.currency.returns(CURRENCY_USD); + + // Record the used allowance + await expect( + JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordUsedAllowanceOf( + PROJECT_ID, + AMOUNT, + CURRENCY_USD, + ), + ).to.be.revertedWith(errors.INADEQUATE_CONTROLLER_ALLOWANCE); + }); + + it(`Can't record allowance if controller's overflowAllowanceOf is 0`, async function () { + const { + mockJbController, + mockJbTerminal, + mockJbTerminalSigner, + mockJbFundAccessConstraintsStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_USD, + } = await setup(); + + // Add to balance beforehand + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordAddedBalanceFor( + PROJECT_ID, + AMOUNT, + ); + + await mockJbFundAccessConstraintsStore.mock.overflowAllowanceOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(0, CURRENCY_USD); // Set the controller's overflowAllowance to something small + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + await mockJbTerminal.mock.currency.returns(CURRENCY_USD); + + // Record the used allowance + await expect( + JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordUsedAllowanceOf( + PROJECT_ID, + 0, + CURRENCY_USD, + ), + ).to.be.revertedWith(errors.INADEQUATE_CONTROLLER_ALLOWANCE); + }); + + it(`Can't record allowance if _leftToDistribute > balanceOf`, async function () { + const { + mockJbController, + mockJbTerminal, + mockJbTerminalSigner, + mockJbFundAccessConstraintsStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_USD, + } = await setup(); + + // Create a big overflow + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(AMOUNT, CURRENCY_USD); + + await mockJbFundAccessConstraintsStore.mock.overflowAllowanceOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(AMOUNT, CURRENCY_USD); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + await mockJbTerminal.mock.currency.returns(CURRENCY_USD); + + // Note: We didn't add an initial balance to the store + // Record the used allowance + await expect( + JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordUsedAllowanceOf( + PROJECT_ID, + AMOUNT, + CURRENCY_USD, + ), + ).to.be.revertedWith(errors.INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE); + }); + + it(`Can't record allowance if withdrawnAmount > overflow`, async function () { + const { + mockJbController, + mockJbPrices, + mockJbTerminal, + mockJbTerminalSigner, + mockJbFundAccessConstraintsStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + CURRENCY_USD, + } = await setup(); + + // Add to balance beforehand + const smallBalance = AMOUNT.sub(ethers.BigNumber.from(1)); + + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordAddedBalanceFor( + PROJECT_ID, + AMOUNT, + ); + + // Leave a small overflow + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(smallBalance, CURRENCY_ETH); + + await mockJbFundAccessConstraintsStore.mock.overflowAllowanceOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(AMOUNT, CURRENCY_ETH); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + await mockJbPrices.mock.priceFor + .withArgs(CURRENCY_ETH, CURRENCY_USD, _FIXED_POINT_MAX_FIDELITY) + .returns(ethers.BigNumber.from(1)); + + await mockJbTerminal.mock.currency.returns(CURRENCY_USD); + + // Record the used allowance + await expect( + JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordUsedAllowanceOf( + PROJECT_ID, + AMOUNT, + CURRENCY_ETH, + ), + ).to.be.revertedWith(errors.INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE); + }); + it(`Can't record used allowance with > 0 distribution limit and not enough balance outside of this limit`, async function () { + const { + mockJbController, + mockJbPrices, + mockJbTerminal, + mockJbTerminalSigner, + mockJbFundAccessConstraintsStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, // base weight currency + CURRENCY_USD, // terminal currency + } = await setup(); + + const usdToEthPrice = ethers.BigNumber.from(3500); + + // Add to balance beforehand, in USD + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordAddedBalanceFor( + PROJECT_ID, + AMOUNT, + ); + + const distributionLimit = AMOUNT; + + // Both limit and allowance in USD + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(distributionLimit, CURRENCY_USD); + + await mockJbFundAccessConstraintsStore.mock.overflowAllowanceOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(AMOUNT, CURRENCY_USD); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + await mockJbPrices.mock.priceFor + .withArgs(CURRENCY_USD, CURRENCY_ETH, _FIXED_POINT_MAX_FIDELITY) + .returns(usdToEthPrice); + + await mockJbTerminal.mock.currency.returns(CURRENCY_USD); + + // Record the used allowance + await expect( + JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordUsedAllowanceOf( + PROJECT_ID, + AMOUNT, + CURRENCY_USD, + ), + ).to.be.revertedWith(errors.INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE); + }); +}); diff --git a/test/jb_payment_terminal_store_3_1_1/current_overflow_of.test.js b/test/jb_payment_terminal_store_3_1_1/current_overflow_of.test.js new file mode 100644 index 000000000..c5f1b33aa --- /dev/null +++ b/test/jb_payment_terminal_store_3_1_1/current_overflow_of.test.js @@ -0,0 +1,194 @@ +import { expect } from 'chai'; +import { ethers } from 'hardhat'; + +import { deployMockContract } from '@ethereum-waffle/mock-contract'; + +import { packFundingCycleMetadata, impersonateAccount } from '../helpers/utils'; + +import jbController from '../../artifacts/contracts/interfaces/IJBController3_1.sol/IJBController3_1.json'; +import jbDirectory from '../../artifacts/contracts/interfaces/IJBDirectory.sol/IJBDirectory.json'; +import jBFundingCycleStore from '../../artifacts/contracts/interfaces/IJBFundingCycleStore.sol/IJBFundingCycleStore.json'; +import jbPrices from '../../artifacts/contracts/interfaces/IJBPrices.sol/IJBPrices.json'; +import jbFundAccessConstraintsStore from '../../artifacts/contracts/interfaces/IJBFundAccessConstraintsStore.sol/IJBFundAccessConstraintsStore.json'; +import jbProjects from '../../artifacts/contracts/interfaces/IJBProjects.sol/IJBProjects.json'; +import jbTerminal from '../../artifacts/contracts/abstract/JBPayoutRedemptionPaymentTerminal3_1_1.sol/JBPayoutRedemptionPaymentTerminal3_1_1.json'; +import jbTokenStore from '../../artifacts/contracts/interfaces/IJBTokenStore.sol/IJBTokenStore.json'; + +describe('JBSingleTokenPaymentTerminalStore3_1_1::currentOverflowOf(...)', function () { + const PROJECT_ID = 2; + const AMOUNT = ethers.FixedNumber.fromString('4398541.345'); + const WEIGHT = ethers.FixedNumber.fromString('900000000.23411'); + const CURRENCY = 1; + const _FIXED_POINT_MAX_FIDELITY = 18; + + async function setup() { + const [deployer] = await ethers.getSigners(); + + const mockJbPrices = await deployMockContract(deployer, jbPrices.abi); + const mockJbProjects = await deployMockContract(deployer, jbProjects.abi); + const mockJbDirectory = await deployMockContract(deployer, jbDirectory.abi); + const mockJbFundingCycleStore = await deployMockContract(deployer, jBFundingCycleStore.abi); + const mockJbTerminal = await deployMockContract(deployer, jbTerminal.abi); + const mockJbTokenStore = await deployMockContract(deployer, jbTokenStore.abi); + const mockJbController = await deployMockContract(deployer, jbController.abi); + const mockJbFundAccessConstraintsStore = await deployMockContract(deployer, jbFundAccessConstraintsStore.abi); + + const jbCurrenciesFactory = await ethers.getContractFactory('JBCurrencies'); + const jbCurrencies = await jbCurrenciesFactory.deploy(); + const CURRENCY_ETH = await jbCurrencies.ETH(); + const CURRENCY_USD = await jbCurrencies.USD(); + + const token = ethers.Wallet.createRandom().address; + + const JBPaymentTerminalStoreFactory = await ethers.getContractFactory( + 'contracts/JBSingleTokenPaymentTerminalStore3_1_1.sol:JBSingleTokenPaymentTerminalStore3_1_1', + ); + const JBSingleTokenPaymentTerminalStore = await JBPaymentTerminalStoreFactory.deploy( + mockJbDirectory.address, + mockJbFundingCycleStore.address, + mockJbPrices.address, + ); + + const blockNum = await ethers.provider.getBlockNumber(); + const block = await ethers.provider.getBlock(blockNum); + const timestamp = block.timestamp; + + await mockJbTerminal.mock.currency.returns(CURRENCY); + + return { + mockJbTerminal, + mockJbController, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbPrices, + mockJbFundAccessConstraintsStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + CURRENCY_USD, + }; + } + + it('Should return the current overflowed amount', async function () { + const { + mockJbTerminal, + mockJbController, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbFundAccessConstraintsStore, + mockJbPrices, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + CURRENCY_USD, + } = await setup(); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata(), + }); + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + + await mockJbTerminal.mock.token.returns(token); + + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(AMOUNT, CURRENCY_USD); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + await mockJbPrices.mock.priceFor + .withArgs(CURRENCY_USD, CURRENCY_ETH, _FIXED_POINT_MAX_FIDELITY) + .returns(ethers.FixedNumber.from(1)); + + // Add to balance beforehand to have sufficient overflow + const startingBalance = AMOUNT.mulUnsafe(ethers.FixedNumber.from(2)); + await JBSingleTokenPaymentTerminalStore.connect( + await impersonateAccount(mockJbTerminal.address), + ).recordAddedBalanceFor(PROJECT_ID, startingBalance); + + // Get current overflow + expect( + await JBSingleTokenPaymentTerminalStore.currentOverflowOf(mockJbTerminal.address, PROJECT_ID), + ).to.equal(AMOUNT); + }); + + it('Should return 0 overflow if ETH balance < distribution remaining', async function () { + const { + mockJbTerminal, + mockJbController, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbFundAccessConstraintsStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + } = await setup(); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata(), + }); + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(AMOUNT, CURRENCY_ETH); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + // Get current overflow + expect( + await JBSingleTokenPaymentTerminalStore.currentOverflowOf(mockJbTerminal.address, PROJECT_ID), + ).to.equal(0); + }); + + it('Should return 0 overflow if ETH balance is 0', async function () { + const { + mockJbFundingCycleStore, + mockJbTerminal, + JBSingleTokenPaymentTerminalStore, + timestamp, + } = await setup(); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata(), + }); + + // Get current overflow + expect( + await JBSingleTokenPaymentTerminalStore.currentOverflowOf(mockJbTerminal.address, PROJECT_ID), + ).to.equal(0); + }); +}); diff --git a/test/jb_payment_terminal_store_3_1_1/current_reclaimable_overflow_of.test.js b/test/jb_payment_terminal_store_3_1_1/current_reclaimable_overflow_of.test.js new file mode 100644 index 000000000..7b71acffd --- /dev/null +++ b/test/jb_payment_terminal_store_3_1_1/current_reclaimable_overflow_of.test.js @@ -0,0 +1,850 @@ +import { expect } from 'chai'; +import { ethers } from 'hardhat'; + +import { deployMockContract } from '@ethereum-waffle/mock-contract'; + +import { packFundingCycleMetadata, impersonateAccount } from '../helpers/utils'; + +import jbController from '../../artifacts/contracts/interfaces/IJBController3_1.sol/IJBController3_1.json'; +import jbDirectory from '../../artifacts/contracts/interfaces/IJBDirectory.sol/IJBDirectory.json'; +import jBFundingCycleStore from '../../artifacts/contracts/interfaces/IJBFundingCycleStore.sol/IJBFundingCycleStore.json'; +import jbFundAccessConstraintsStore from '../../artifacts/contracts/interfaces/IJBFundAccessConstraintsStore.sol/IJBFundAccessConstraintsStore.json'; +import jbPrices from '../../artifacts/contracts/interfaces/IJBPrices.sol/IJBPrices.json'; +import jbProjects from '../../artifacts/contracts/interfaces/IJBProjects.sol/IJBProjects.json'; +import jbTerminal from '../../artifacts/contracts/abstract/JBPayoutRedemptionPaymentTerminal3_1_1.sol/JBPayoutRedemptionPaymentTerminal3_1_1.json'; +import jbTokenStore from '../../artifacts/contracts/interfaces/IJBTokenStore.sol/IJBTokenStore.json'; + +describe('JBSingleTokenPaymentTerminalStore3_1_1::currentReclaimableOverflowOf(...)', function () { + const PROJECT_ID = 2; + const WEIGHT = ethers.FixedNumber.fromString('900000000.23411'); + const CURRENCY = 1; + + async function setup() { + const [deployer] = await ethers.getSigners(); + + const mockJbPrices = await deployMockContract(deployer, jbPrices.abi); + const mockJbProjects = await deployMockContract(deployer, jbProjects.abi); + const mockJbDirectory = await deployMockContract(deployer, jbDirectory.abi); + const mockJbFundingCycleStore = await deployMockContract(deployer, jBFundingCycleStore.abi); + const mockJbTerminal = await deployMockContract(deployer, jbTerminal.abi); + const mockJbTerminal2 = await deployMockContract(deployer, jbTerminal.abi); + const mockJbTokenStore = await deployMockContract(deployer, jbTokenStore.abi); + const mockJbController = await deployMockContract(deployer, jbController.abi); + const mockJbFundAccessConstraintsStore = await deployMockContract(deployer, jbFundAccessConstraintsStore.abi); + + const jbCurrenciesFactory = await ethers.getContractFactory('JBCurrencies'); + const jbCurrencies = await jbCurrenciesFactory.deploy(); + const CURRENCY_ETH = await jbCurrencies.ETH(); + + const JBPaymentTerminalStoreFactory = await ethers.getContractFactory( + 'contracts/JBSingleTokenPaymentTerminalStore3_1_1.sol:JBSingleTokenPaymentTerminalStore3_1_1', + ); + const JBSingleTokenPaymentTerminalStore = await JBPaymentTerminalStoreFactory.deploy( + mockJbDirectory.address, + mockJbFundingCycleStore.address, + mockJbPrices.address, + ); + + const token = ethers.Wallet.createRandom().address; + + const blockNum = await ethers.provider.getBlockNumber(); + const block = await ethers.provider.getBlock(blockNum); + const timestamp = block.timestamp; + + await mockJbTerminal.mock.currency.returns(CURRENCY); + await mockJbTerminal.mock.decimals.returns(18); + + await mockJbTerminal2.mock.currency.returns(CURRENCY); + await mockJbTerminal2.mock.decimals.returns(18); + + const mockJbTerminalSigner = await impersonateAccount(mockJbTerminal.address); + + await mockJbTerminal.mock.token.returns(token); + + return { + mockJbController, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbPrices, + mockJbTerminal, + mockJbTerminal2, + mockJbTerminalSigner, + mockJbFundAccessConstraintsStore, + mockJbTokenStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + }; + } + + it('Should return claimable overflow from this terminal, with rate from active ballot', async function () { + /* + Calculator params for https://www.desmos.com/calculator/sp9ru6zbpk: + o (available overflow) = 100 ETH + s (total token supply) = 100 + r (redemption rate) = .65 + x (token claim amount) = 50 + Should result in a redemption of y = 41.25 ETH + */ + const { + mockJbController, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbTerminal, + mockJbTerminalSigner, + mockJbTokenStore, + mockJbFundAccessConstraintsStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + } = await setup(); + + const overflowAmt = ethers.FixedNumber.from(100); + const tokenAmt = ethers.FixedNumber.from(50); + + const reservedRate = 0; + const fundingCycleMetadata = packFundingCycleMetadata({ + reservedRate: reservedRate, + ballotRedemptionRate: 6500, // 65% redemption rate + }); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: fundingCycleMetadata, + }); + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(overflowAmt, CURRENCY_ETH); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + const totalSupply = tokenAmt.mulUnsafe(ethers.FixedNumber.from(2)); + await mockJbTokenStore.mock.totalSupplyOf.withArgs(PROJECT_ID).returns(totalSupply); // totalSupply of 100 + await mockJbController.mock.totalOutstandingTokensOf + .withArgs(PROJECT_ID) + .returns(totalSupply); + + await mockJbController.mock.reservedTokenBalanceOf + .withArgs(PROJECT_ID) + .returns(0); + + // Use active ballot + await mockJbFundingCycleStore.mock.currentBallotStateOf.withArgs(PROJECT_ID).returns(0); + + // Add to balance beforehand to have an overflow of exactly 100 + const startingBalance = overflowAmt.mulUnsafe(ethers.FixedNumber.from(2)); + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordAddedBalanceFor( + PROJECT_ID, + startingBalance, + ); + + // Get claimable overflow where tokenCount is half the total supply of tokens + expect( + await JBSingleTokenPaymentTerminalStore[ + 'currentReclaimableOverflowOf(address,uint256,uint256,bool)' + ](mockJbTerminalSigner.address, PROJECT_ID, /* tokenCount */ tokenAmt, false), + ).to.equal(ethers.FixedNumber.fromString('41.25')); + }); + + it('Should return claimable overflow with rate from active ballot, accross all terminals using the same currency and decimals', async function () { + /* + Calculator params for https://www.desmos.com/calculator/sp9ru6zbpk: + o (available overflow) = 100 ETH + s (total token supply) = 100 + r (redemption rate) = .65 + x (token claim amount) = 50 + Should result in a redemption of y = 41.25 ETH + */ + const { + mockJbController, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbTerminal, + mockJbTerminal2, + mockJbTerminalSigner, + mockJbFundAccessConstraintsStore, + mockJbTokenStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + } = await setup(); + + const overflowAmt = ethers.FixedNumber.from(100); + const tokenAmt = ethers.FixedNumber.from(50); + + const reservedRate = 0; + const fundingCycleMetadata = packFundingCycleMetadata({ + reservedRate: reservedRate, + ballotRedemptionRate: 6500, // 65% redemption rate + useTotalOverflowForRedemptions: true, + }); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: fundingCycleMetadata, + }); + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(overflowAmt, CURRENCY_ETH); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + await mockJbDirectory.mock.terminalsOf + .withArgs(PROJECT_ID) + .returns([mockJbTerminal.address, mockJbTerminal2.address]); + + await mockJbTerminal.mock.currentEthOverflowOf.withArgs(PROJECT_ID).returns(overflowAmt); + await mockJbTerminal2.mock.currentEthOverflowOf.withArgs(PROJECT_ID).returns(overflowAmt); + + const totalSupply = tokenAmt.mulUnsafe(ethers.FixedNumber.from(2)); + await mockJbTokenStore.mock.totalSupplyOf.withArgs(PROJECT_ID).returns(totalSupply); // totalSupply of 100 + await mockJbController.mock.totalOutstandingTokensOf + .withArgs(PROJECT_ID) + .returns(totalSupply); + + await mockJbController.mock.reservedTokenBalanceOf + .withArgs(PROJECT_ID) + .returns(0); + + // Use active ballot + await mockJbFundingCycleStore.mock.currentBallotStateOf.withArgs(PROJECT_ID).returns(0); + + // Add to balance beforehand to have an overflow of exactly 100 + const startingBalance = overflowAmt.mulUnsafe(ethers.FixedNumber.from(2)); + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordAddedBalanceFor( + PROJECT_ID, + startingBalance, + ); + + // Get claimable overflow where tokenCount is half the total supply of tokens + expect( + await JBSingleTokenPaymentTerminalStore[ + 'currentReclaimableOverflowOf(address,uint256,uint256,bool)' + ](mockJbTerminalSigner.address, PROJECT_ID, /* tokenCount */ tokenAmt, true), + ).to.equal(ethers.FixedNumber.fromString('82.5')); + }); + + it('Should return claimable overflow with rate from active ballot, accross all terminals using different currencies and decimals', async function () { + /* + Calculator params for https://www.desmos.com/calculator/sp9ru6zbpk: + o (available overflow) = 100 ETH + s (total token supply) = 100 + r (redemption rate) = .65 + x (token claim amount) = 50 + Should result in a redemption of y = 41.25 ETH + */ + const { + mockJbController, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbPrices, + mockJbTerminal, + mockJbTerminal2, + mockJbTerminalSigner, + mockJbTokenStore, + mockJbFundAccessConstraintsStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + } = await setup(); + + const overflowAmt = ethers.FixedNumber.from(100); + const tokenAmt = ethers.FixedNumber.from(50); + + const reservedRate = 0; + const fundingCycleMetadata = packFundingCycleMetadata({ + reservedRate: reservedRate, + ballotRedemptionRate: 6500, // 65% redemption rate + useTotalOverflowForRedemptions: true, + }); + + await mockJbTerminal.mock.currency.returns(2); + await mockJbTerminal.mock.decimals.returns(20); // Will divide by 100 to get to 18 decimals + + // Price for eth in currency 2, with 18decimals (will mult by 100) + await mockJbPrices.mock.priceFor.withArgs(1, 2, 18).returns(ethers.FixedNumber.from(100)); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: fundingCycleMetadata, + }); + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(overflowAmt, CURRENCY_ETH); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + await mockJbDirectory.mock.terminalsOf + .withArgs(PROJECT_ID) + .returns([mockJbTerminal.address, mockJbTerminal2.address]); + + await mockJbTerminal.mock.currentEthOverflowOf.withArgs(PROJECT_ID).returns(overflowAmt); + await mockJbTerminal2.mock.currentEthOverflowOf.withArgs(PROJECT_ID).returns(overflowAmt); + + const totalSupply = tokenAmt.mulUnsafe(ethers.FixedNumber.from(2)); + await mockJbTokenStore.mock.totalSupplyOf.withArgs(PROJECT_ID).returns(totalSupply); // totalSupply of 100 + await mockJbController.mock.totalOutstandingTokensOf + .withArgs(PROJECT_ID) + .returns(totalSupply); + + await mockJbController.mock.reservedTokenBalanceOf + .withArgs(PROJECT_ID) + .returns(0); + + // Use active ballot + await mockJbFundingCycleStore.mock.currentBallotStateOf.withArgs(PROJECT_ID).returns(0); + + // Add to balance beforehand to have an overflow of exactly 100 + const startingBalance = overflowAmt.mulUnsafe(ethers.FixedNumber.from(2)); + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordAddedBalanceFor( + PROJECT_ID, + startingBalance, + ); + + // Get claimable overflow where tokenCount is half the total supply of tokens + expect( + await JBSingleTokenPaymentTerminalStore[ + 'currentReclaimableOverflowOf(address,uint256,uint256,bool)' + ](mockJbTerminalSigner.address, PROJECT_ID, /* tokenCount */ tokenAmt, true), + ).to.equal(ethers.FixedNumber.fromString('82.5')); + }); + + it('Should return 0 if there is no overflow in this terminal', async function () { + const { + mockJbTerminal, + mockJbController, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbFundAccessConstraintsStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + } = await setup(); + + const overflowAmt = ethers.FixedNumber.from(100); + const tokenAmt = ethers.FixedNumber.from(50); + + const reservedRate = 0; + const fundingCycleMetadata = packFundingCycleMetadata({ + reservedRate: reservedRate, + ballotRedemptionRate: 6500, // 65% redemption rate + }); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: fundingCycleMetadata, + }); + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(overflowAmt, CURRENCY_ETH); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + // Get claimable overflow + expect( + await JBSingleTokenPaymentTerminalStore[ + 'currentReclaimableOverflowOf(address,uint256,uint256,bool)' + ](mockJbTerminal.address, PROJECT_ID, /* tokenCount */ tokenAmt, false), + ).to.equal(0); + }); + + it('Should return 0 if the number of token > total supply', async function () { + const { + mockJbTerminal, + mockJbTerminalSigner, + mockJbController, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbTokenStore, + mockJbFundAccessConstraintsStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + } = await setup(); + + const overflowAmt = ethers.FixedNumber.from(100); + const tokenAmt = ethers.FixedNumber.from(50); + + const reservedRate = 0; + const fundingCycleMetadata = packFundingCycleMetadata({ + reservedRate: reservedRate, + ballotRedemptionRate: 0, // 0% redemption rate + }); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: fundingCycleMetadata, + }); + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(overflowAmt, CURRENCY_ETH); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + const totalSupply = tokenAmt.subUnsafe(ethers.FixedNumber.from(1)); + await mockJbTokenStore.mock.totalSupplyOf.withArgs(PROJECT_ID).returns(totalSupply); // totalSupply of 100 + await mockJbController.mock.totalOutstandingTokensOf + .withArgs(PROJECT_ID) + .returns(totalSupply); + + await mockJbController.mock.reservedTokenBalanceOf + .withArgs(PROJECT_ID) + .returns(0); + + // Use active ballot + await mockJbFundingCycleStore.mock.currentBallotStateOf.withArgs(PROJECT_ID).returns(1); + + // Add to balance beforehand to have an overflow of exactly 100 + const startingBalance = overflowAmt.mulUnsafe(ethers.FixedNumber.from(2)); + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordAddedBalanceFor( + PROJECT_ID, + startingBalance, + ); + + // Get claimable overflow + expect( + await JBSingleTokenPaymentTerminalStore[ + 'currentReclaimableOverflowOf(address,uint256,uint256,bool)' + ]( + mockJbTerminalSigner.address, + PROJECT_ID, + /* tokenCount */ totalSupply.addUnsafe(ethers.FixedNumber.from(1)), + false, + ), + ).to.equal(0); + }); + + it('Should return 0 if claiming more than the total supply', async function () { + const { JBSingleTokenPaymentTerminalStore } = await setup(); + + const overflowAmt = ethers.FixedNumber.from(100); + const totalSupply = ethers.FixedNumber.from(50); + + // Get claimable overflow + expect( + await JBSingleTokenPaymentTerminalStore[ + 'currentReclaimableOverflowOf(uint256,uint256,uint256,uint256)' + ]( + PROJECT_ID, + /* tokenCount */ totalSupply.addUnsafe(ethers.FixedNumber.from(1)), + totalSupply, + overflowAmt, + ), + ).to.equal(0); + }); + + it('Should return 0 if redemption rate is 0', async function () { + const { + mockJbTerminal, + mockJbTerminalSigner, + mockJbController, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbFundAccessConstraintsStore, + mockJbTokenStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + } = await setup(); + + const overflowAmt = ethers.FixedNumber.from(100); + const tokenAmt = ethers.FixedNumber.from(50); + + const reservedRate = 0; + const fundingCycleMetadata = packFundingCycleMetadata({ + reservedRate: reservedRate, + ballotRedemptionRate: 0, // 0% redemption rate + }); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: fundingCycleMetadata, + }); + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(overflowAmt, CURRENCY_ETH); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + const totalSupply = tokenAmt.mulUnsafe(ethers.FixedNumber.from(2)); + await mockJbTokenStore.mock.totalSupplyOf.withArgs(PROJECT_ID).returns(totalSupply); // totalSupply of 100 + await mockJbController.mock.totalOutstandingTokensOf + .withArgs(PROJECT_ID) + .returns(totalSupply); + + await mockJbController.mock.reservedTokenBalanceOf + .withArgs(PROJECT_ID) + .returns(0); + + // Use active ballot + await mockJbFundingCycleStore.mock.currentBallotStateOf.withArgs(PROJECT_ID).returns(0); + + // Add to balance beforehand to have an overflow of exactly 100 + const startingBalance = overflowAmt.mulUnsafe(ethers.FixedNumber.from(2)); + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordAddedBalanceFor( + PROJECT_ID, + startingBalance, + ); + + // Get claimable overflow + expect( + await JBSingleTokenPaymentTerminalStore[ + 'currentReclaimableOverflowOf(address,uint256,uint256,bool)' + ](mockJbTerminalSigner.address, PROJECT_ID, /* tokenCount */ tokenAmt, false), + ).to.equal(0); + }); + + it('Should return claimable overflow amount of this terminal if redemption rate is 100%', async function () { + /* + Calculator params for https://www.desmos.com/calculator/sp9ru6zbpk: + o (available overflow) = 100 ETH + s (total token supply) = 100 + r (redemption rate) = 1.0 + x (token claim amount) = 50 + Should result in a redemption of y = 50 ETH + */ + const { + mockJbTerminal, + mockJbTerminalSigner, + mockJbController, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbFundAccessConstraintsStore, + mockJbTokenStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + } = await setup(); + + const overflowAmt = ethers.FixedNumber.from(100); + const tokenAmt = ethers.FixedNumber.from(50); + + const reservedRate = 10; + const fundingCycleMetadata = packFundingCycleMetadata({ + reservedRate: reservedRate, + redemptionRate: 10000, // 100% redemption rate + }); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: fundingCycleMetadata, + }); + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(overflowAmt, CURRENCY_ETH); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + await mockJbTokenStore.mock.totalSupplyOf.withArgs(PROJECT_ID).returns(tokenAmt); + + await mockJbController.mock.reservedTokenBalanceOf + .withArgs(PROJECT_ID) + .returns(ethers.FixedNumber.from(50)); // added to tokenSupply + + // Use regular redemption rate + await mockJbFundingCycleStore.mock.currentBallotStateOf.withArgs(PROJECT_ID).returns(0); + + // Add to balance beforehand to have an overflow of exactly 100 + const startingBalance = overflowAmt.mulUnsafe(ethers.FixedNumber.from(2)); + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordAddedBalanceFor( + PROJECT_ID, + startingBalance, + ); + + await mockJbController.mock.totalOutstandingTokensOf + .withArgs(PROJECT_ID) + .returns(overflowAmt); + + // Get claimable overflow where tokenCount is half the total supply of tokens + expect( + await JBSingleTokenPaymentTerminalStore[ + 'currentReclaimableOverflowOf(address,uint256,uint256,bool)' + ](mockJbTerminalSigner.address, PROJECT_ID, /* tokenCount */ tokenAmt, false), + ).to.equal(ethers.FixedNumber.from(50)); + }); + + it('Should return claimable overflow when no terminal is passed, with rate from active ballot', async function () { + /* + Calculator params for https://www.desmos.com/calculator/sp9ru6zbpk: + o (available overflow) = 100 ETH + s (total token supply) = 100 + r (redemption rate) = .65 + x (token claim amount) = 50 + Should result in a redemption of y = 41.25 ETH + */ + const { + mockJbController, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbTerminal, + mockJbTerminalSigner, + mockJbTokenStore, + mockJbFundAccessConstraintsStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + } = await setup(); + + const overflowAmt = ethers.FixedNumber.from(100); + const tokenAmt = ethers.FixedNumber.from(50); + + const reservedRate = 0; + const fundingCycleMetadata = packFundingCycleMetadata({ + reservedRate: reservedRate, + ballotRedemptionRate: 6500, // 65% redemption rate + }); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: fundingCycleMetadata, + }); + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(overflowAmt, CURRENCY_ETH); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + const totalSupply = tokenAmt.mulUnsafe(ethers.FixedNumber.from(2)); + await mockJbTokenStore.mock.totalSupplyOf.withArgs(PROJECT_ID).returns(totalSupply); // totalSupply of 100 + await mockJbController.mock.totalOutstandingTokensOf + .withArgs(PROJECT_ID) + .returns(totalSupply); + + await mockJbController.mock.reservedTokenBalanceOf + .withArgs(PROJECT_ID) + .returns(0); + + // Use active ballot + await mockJbFundingCycleStore.mock.currentBallotStateOf.withArgs(PROJECT_ID).returns(0); + + // Add to balance beforehand to have an overflow of exactly 100 + const startingBalance = overflowAmt.mulUnsafe(ethers.FixedNumber.from(2)); + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordAddedBalanceFor( + PROJECT_ID, + startingBalance, + ); + + // Get claimable overflow where tokenCount is half the total supply of tokens + expect( + await JBSingleTokenPaymentTerminalStore[ + 'currentReclaimableOverflowOf(uint256,uint256,uint256,uint256)' + ]( + PROJECT_ID, + /* tokenCount */ tokenAmt, + /* totalSupply */ totalSupply, + /* overflow */ overflowAmt, + ), + ).to.equal(ethers.FixedNumber.fromString('41.25')); + }); + it('Should return claimable overflow when no terminal is passed, with rate from the current cycle', async function () { + /* + Calculator params for https://www.desmos.com/calculator/sp9ru6zbpk: + o (available overflow) = 100 ETH + s (total token supply) = 100 + r (redemption rate) = .65 + x (token claim amount) = 50 + Should result in a redemption of y = 41.25 ETH + */ + const { + mockJbController, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbTerminal, + mockJbTerminalSigner, + mockJbTokenStore, + mockJbFundAccessConstraintsStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + } = await setup(); + + const overflowAmt = ethers.FixedNumber.from(100); + const tokenAmt = ethers.FixedNumber.from(50); + + const reservedRate = 0; + const fundingCycleMetadata = packFundingCycleMetadata({ + reservedRate: reservedRate, + redemptionRate: 6500, + ballotRedemptionRate: 0, + }); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: fundingCycleMetadata, + }); + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(overflowAmt, CURRENCY_ETH); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + const totalSupply = tokenAmt.mulUnsafe(ethers.FixedNumber.from(2)); + await mockJbTokenStore.mock.totalSupplyOf.withArgs(PROJECT_ID).returns(totalSupply); // totalSupply of 100 + await mockJbController.mock.totalOutstandingTokensOf + .withArgs(PROJECT_ID) + .returns(totalSupply); + + await mockJbController.mock.reservedTokenBalanceOf + .withArgs(PROJECT_ID) + .returns(0); + + // Do not use active ballot + await mockJbFundingCycleStore.mock.currentBallotStateOf.withArgs(PROJECT_ID).returns(2); // Failed + + // Add to balance beforehand to have an overflow of exactly 100 + const startingBalance = overflowAmt.mulUnsafe(ethers.FixedNumber.from(2)); + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordAddedBalanceFor( + PROJECT_ID, + startingBalance, + ); + + // Get claimable overflow where tokenCount is half the total supply of tokens + expect( + await JBSingleTokenPaymentTerminalStore[ + 'currentReclaimableOverflowOf(uint256,uint256,uint256,uint256)' + ]( + PROJECT_ID, + /* tokenCount */ tokenAmt, + /* totalSupply */ totalSupply, + /* overflow */ overflowAmt, + ), + ).to.equal(ethers.FixedNumber.fromString('41.25')); + }); + it('Should return claimable overflow when no terminal is passed, with 0 overflow', async function () { + const { JBSingleTokenPaymentTerminalStore } = await setup(); + + const overflowAmt = ethers.FixedNumber.from(0); + const tokenAmt = ethers.FixedNumber.from(50); + const totalSupply = ethers.FixedNumber.from(50); + + // Get claimable overflow where tokenCount is half the total supply of tokens + expect( + await JBSingleTokenPaymentTerminalStore[ + 'currentReclaimableOverflowOf(uint256,uint256,uint256,uint256)' + ]( + PROJECT_ID, + /* tokenCount */ tokenAmt, + /* totalSupply */ totalSupply, + /* overflow */ overflowAmt, + ), + ).to.equal(0); + }); +}); diff --git a/test/jb_payment_terminal_store_3_1_1/current_total_overflow_of.test.js b/test/jb_payment_terminal_store_3_1_1/current_total_overflow_of.test.js new file mode 100644 index 000000000..279b97ff9 --- /dev/null +++ b/test/jb_payment_terminal_store_3_1_1/current_total_overflow_of.test.js @@ -0,0 +1,199 @@ +import { expect } from 'chai'; +import { ethers } from 'hardhat'; + +import { deployMockContract } from '@ethereum-waffle/mock-contract'; + +import { packFundingCycleMetadata } from '../helpers/utils'; + +import jbController from '../../artifacts/contracts/interfaces/IJBController3_1.sol/IJBController3_1.json'; +import jbDirectory from '../../artifacts/contracts/interfaces/IJBDirectory.sol/IJBDirectory.json'; +import jBFundingCycleStore from '../../artifacts/contracts/interfaces/IJBFundingCycleStore.sol/IJBFundingCycleStore.json'; +import jbPrices from '../../artifacts/contracts/interfaces/IJBPrices.sol/IJBPrices.json'; +import jbProjects from '../../artifacts/contracts/interfaces/IJBProjects.sol/IJBProjects.json'; +import jbPaymentTerminal from '../../artifacts/contracts/abstract/JBPayoutRedemptionPaymentTerminal3_1_1.sol/JBPayoutRedemptionPaymentTerminal3_1_1.json'; +import jbTokenStore from '../../artifacts/contracts/interfaces/IJBTokenStore.sol/IJBTokenStore.json'; + +describe('JBSingleTokenPaymentTerminalStore3_1_1::currentTotalOverflowOf(...)', function () { + const PROJECT_ID = 2; + const WEIGHT = ethers.BigNumber.from('1' + '0'.repeat(17)); + + const ETH_OVERFLOW_A = ethers.utils.parseEther('69000'); + const ETH_OVERFLOW_B = ethers.utils.parseEther('420'); + const PRICE = ethers.BigNumber.from('100'); + const DECIMAL = 18; + const NON_18_DECIMAL = 12; + + async function setup() { + const [deployer] = await ethers.getSigners(); + + const mockJbPrices = await deployMockContract(deployer, jbPrices.abi); + const mockJbProjects = await deployMockContract(deployer, jbProjects.abi); + const mockJbDirectory = await deployMockContract(deployer, jbDirectory.abi); + const mockJbFundingCycleStore = await deployMockContract(deployer, jBFundingCycleStore.abi); + const mockJbTokenStore = await deployMockContract(deployer, jbTokenStore.abi); + const mockJbController = await deployMockContract(deployer, jbController.abi); + const mockJbTerminalA = await deployMockContract(deployer, jbPaymentTerminal.abi); + const mockJbTerminalB = await deployMockContract(deployer, jbPaymentTerminal.abi); + + const jbCurrenciesFactory = await ethers.getContractFactory('JBCurrencies'); + const jbCurrencies = await jbCurrenciesFactory.deploy(); + const CURRENCY_ETH = await jbCurrencies.ETH(); + const CURRENCY_USD = await jbCurrencies.USD(); + + const JBPaymentTerminalStoreFactory = await ethers.getContractFactory( + 'contracts/JBSingleTokenPaymentTerminalStore3_1_1.sol:JBSingleTokenPaymentTerminalStore3_1_1', + ); + const JBSingleTokenPaymentTerminalStore = await JBPaymentTerminalStoreFactory.deploy( + mockJbDirectory.address, + mockJbFundingCycleStore.address, + mockJbPrices.address, + ); + + const blockNum = await ethers.provider.getBlockNumber(); + const block = await ethers.provider.getBlock(blockNum); + const timestamp = block.timestamp; + + return { + mockJbTerminalA, + mockJbTerminalB, + mockJbController, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbPrices, + JBSingleTokenPaymentTerminalStore, + timestamp, + CURRENCY_ETH, + CURRENCY_USD, + }; + } + + it('Should return total current overflow across multiple terminals with the same currency (18 decimals) as the one passed', async function () { + const { + mockJbTerminalA, + mockJbTerminalB, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbPrices, + JBSingleTokenPaymentTerminalStore, + timestamp, + CURRENCY_ETH, + CURRENCY_USD, + } = await setup(); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ useTotalOverflowForRedemptions: true }), + }); + + await mockJbDirectory.mock.terminalsOf + .withArgs(PROJECT_ID) + .returns([mockJbTerminalA.address, mockJbTerminalB.address]); + + await mockJbTerminalA.mock.currentEthOverflowOf.withArgs(PROJECT_ID).returns(ETH_OVERFLOW_A); + await mockJbTerminalB.mock.currentEthOverflowOf.withArgs(PROJECT_ID).returns(ETH_OVERFLOW_B); + + // Get total overflow across both terminals, in same currency; should equal sum of the overflows + expect( + await JBSingleTokenPaymentTerminalStore.currentTotalOverflowOf( + PROJECT_ID, + DECIMAL, + CURRENCY_ETH, + ), + ).to.equal(ETH_OVERFLOW_A.add(ETH_OVERFLOW_B)); + }); + + it('Should return total current overflow across multiple terminals with the same currency as the one passed, adjusting non-18 decimals', async function () { + const { + mockJbTerminalA, + mockJbTerminalB, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbPrices, + JBSingleTokenPaymentTerminalStore, + timestamp, + CURRENCY_ETH, + CURRENCY_USD, + } = await setup(); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ useTotalOverflowForRedemptions: true }), + }); + + await mockJbDirectory.mock.terminalsOf + .withArgs(PROJECT_ID) + .returns([mockJbTerminalA.address, mockJbTerminalB.address]); + + await mockJbTerminalA.mock.currentEthOverflowOf.withArgs(PROJECT_ID).returns(ETH_OVERFLOW_A); + await mockJbTerminalB.mock.currentEthOverflowOf.withArgs(PROJECT_ID).returns(ETH_OVERFLOW_B); + + // Get total overflow across both terminals, in same currency; should equal sum of the overflows + expect( + await JBSingleTokenPaymentTerminalStore.currentTotalOverflowOf( + PROJECT_ID, + NON_18_DECIMAL, + CURRENCY_ETH, + ), + ).to.equal(ETH_OVERFLOW_A.add(ETH_OVERFLOW_B).div(10 ** (DECIMAL - NON_18_DECIMAL))); + }); + + it('Should return total current overflow across multiple terminals with different currency as the one passed', async function () { + const { + mockJbTerminalA, + mockJbTerminalB, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbPrices, + JBSingleTokenPaymentTerminalStore, + timestamp, + CURRENCY_ETH, + CURRENCY_USD, + } = await setup(); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ useTotalOverflowForRedemptions: true }), + }); + + await mockJbDirectory.mock.terminalsOf + .withArgs(PROJECT_ID) + .returns([mockJbTerminalA.address, mockJbTerminalB.address]); + + await mockJbTerminalA.mock.currentEthOverflowOf.withArgs(PROJECT_ID).returns(ETH_OVERFLOW_A); + await mockJbTerminalB.mock.currentEthOverflowOf.withArgs(PROJECT_ID).returns(ETH_OVERFLOW_B); + + await mockJbPrices.mock.priceFor + .withArgs(CURRENCY_ETH, CURRENCY_USD, 18) // 18-decimal + .returns(100); + + // Get total overflow across both terminals, in a different currency; should equal to the sum of the overflow / price + expect( + await JBSingleTokenPaymentTerminalStore.currentTotalOverflowOf( + PROJECT_ID, + DECIMAL, + CURRENCY_USD, + ), + ).to.equal(ETH_OVERFLOW_A.add(ETH_OVERFLOW_B).mul(ethers.utils.parseEther('1')).div(PRICE)); + }); +}); diff --git a/test/jb_payment_terminal_store_3_1_1/record_distribution_for.test.js b/test/jb_payment_terminal_store_3_1_1/record_distribution_for.test.js new file mode 100644 index 000000000..05f72c233 --- /dev/null +++ b/test/jb_payment_terminal_store_3_1_1/record_distribution_for.test.js @@ -0,0 +1,487 @@ +import { expect } from 'chai'; +import { ethers } from 'hardhat'; + +import { deployMockContract } from '@ethereum-waffle/mock-contract'; + +import errors from '../helpers/errors.json'; +import { packFundingCycleMetadata, impersonateAccount } from '../helpers/utils'; + +import jbController from '../../artifacts/contracts/interfaces/IJBController3_1.sol/IJBController3_1.json'; +import jbDirectory from '../../artifacts/contracts/interfaces/IJBDirectory.sol/IJBDirectory.json'; +import jBFundingCycleStore from '../../artifacts/contracts/interfaces/IJBFundingCycleStore.sol/IJBFundingCycleStore.json'; +import jbFundAccessConstraintsStore from '../../artifacts/contracts/interfaces/IJBFundAccessConstraintsStore.sol/IJBFundAccessConstraintsStore.json'; +import jbPrices from '../../artifacts/contracts/interfaces/IJBPrices.sol/IJBPrices.json'; +import jbProjects from '../../artifacts/contracts/interfaces/IJBProjects.sol/IJBProjects.json'; +import jbTerminal from '../../artifacts/contracts/abstract/JBPayoutRedemptionPaymentTerminal3_1_1.sol/JBPayoutRedemptionPaymentTerminal3_1_1.json'; +import jbTokenStore from '../../artifacts/contracts/interfaces/IJBTokenStore.sol/IJBTokenStore.json'; + +describe('JBSingleTokenPaymentTerminalStore3_1_1::recordDistributionFor(...)', function () { + const FUNDING_CYCLE_NUM = 1; + const PROJECT_ID = 2; + const AMOUNT = ethers.FixedNumber.fromString('4398541.345'); + const WEIGHT = ethers.FixedNumber.fromString('900000000.23411'); + const CURRENCY = 1; + const _FIXED_POINT_MAX_FIDELITY = 18; + + async function setup() { + const [deployer, addr] = await ethers.getSigners(); + + const mockJbPrices = await deployMockContract(deployer, jbPrices.abi); + const mockJbProjects = await deployMockContract(deployer, jbProjects.abi); + const mockJbDirectory = await deployMockContract(deployer, jbDirectory.abi); + const mockJbFundingCycleStore = await deployMockContract(deployer, jBFundingCycleStore.abi); + const mockJbTerminal = await deployMockContract(deployer, jbTerminal.abi); + const mockJbTokenStore = await deployMockContract(deployer, jbTokenStore.abi); + const mockJbController = await deployMockContract(deployer, jbController.abi); + const mockJbFundAccessConstraintsStore = await deployMockContract(deployer, jbFundAccessConstraintsStore.abi); + + const jbCurrenciesFactory = await ethers.getContractFactory('JBCurrencies'); + const jbCurrencies = await jbCurrenciesFactory.deploy(); + const CURRENCY_ETH = await jbCurrencies.ETH(); + const CURRENCY_USD = await jbCurrencies.USD(); + + const JBPaymentTerminalStoreFactory = await ethers.getContractFactory( + 'contracts/JBSingleTokenPaymentTerminalStore3_1_1.sol:JBSingleTokenPaymentTerminalStore3_1_1', + ); + const JBSingleTokenPaymentTerminalStore = await JBPaymentTerminalStoreFactory.deploy( + mockJbDirectory.address, + mockJbFundingCycleStore.address, + mockJbPrices.address, + ); + + const blockNum = await ethers.provider.getBlockNumber(); + const block = await ethers.provider.getBlock(blockNum); + const timestamp = block.timestamp; + + /* Common mocks */ + + await mockJbTerminal.mock.currency.returns(CURRENCY); + + // Set controller address + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + + const mockJbTerminalSigner = await impersonateAccount(mockJbTerminal.address); + + const token = ethers.Wallet.createRandom().address; + + await mockJbTerminal.mock.token.returns(token); + + return { + mockJbTerminal, + mockJbTerminalSigner, + addr, + mockJbController, + mockJbFundAccessConstraintsStore, + mockJbFundingCycleStore, + mockJbPrices, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + CURRENCY_USD, + }; + } + + it('Should record distribution with mockJbTerminal access, if the amount in expressed in terminal currency', async function () { + const { + mockJbTerminal, + mockJbTerminalSigner, + mockJbController, + mockJbFundingCycleStore, + mockJbFundAccessConstraintsStore, + mockJbPrices, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_USD, + } = await setup(); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + // mock JBFundingCycle obj + number: FUNDING_CYCLE_NUM, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ pauseDistributions: 0 }), + }); + + // Add to balance beforehand + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordAddedBalanceFor( + PROJECT_ID, + AMOUNT, + ); + + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(AMOUNT, CURRENCY_USD); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + await mockJbTerminal.mock.currency.returns(CURRENCY_USD); + + // Pre-checks + expect( + await JBSingleTokenPaymentTerminalStore.usedDistributionLimitOf( + mockJbTerminalSigner.address, + PROJECT_ID, + FUNDING_CYCLE_NUM, + ), + ).to.equal(0); + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(AMOUNT); + + // Record the distributions + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordDistributionFor( + PROJECT_ID, + AMOUNT, + CURRENCY_USD, + ); + + // Post-checks + expect( + await JBSingleTokenPaymentTerminalStore.usedDistributionLimitOf( + mockJbTerminalSigner.address, + PROJECT_ID, + FUNDING_CYCLE_NUM, + ), + ).to.equal(AMOUNT); + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(0); + }); + + it('Should record distribution with mockJbTerminal access, if the amount in another currency', async function () { + const { + mockJbTerminal, + mockJbTerminalSigner, + mockJbController, + mockJbFundingCycleStore, + mockJbPrices, + mockJbFundAccessConstraintsStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + CURRENCY_USD, + } = await setup(); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + // mock JBFundingCycle obj + number: FUNDING_CYCLE_NUM, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ pauseDistributions: 0 }), + }); + + const usdToEthPrice = ethers.FixedNumber.from(10000); + const amountInWei = AMOUNT.divUnsafe(usdToEthPrice); + + // Add to balance beforehand + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordAddedBalanceFor( + PROJECT_ID, + amountInWei, + ); + + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(AMOUNT, CURRENCY_USD); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + await mockJbPrices.mock.priceFor + .withArgs(CURRENCY_USD, CURRENCY_ETH, _FIXED_POINT_MAX_FIDELITY) + .returns(usdToEthPrice); + + await mockJbTerminal.mock.currency.returns(CURRENCY_ETH); + + // Pre-checks + expect( + await JBSingleTokenPaymentTerminalStore.usedDistributionLimitOf( + mockJbTerminalSigner.address, + PROJECT_ID, + FUNDING_CYCLE_NUM, + ), + ).to.equal(0); + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(amountInWei); + + // Record the distributions + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordDistributionFor( + PROJECT_ID, + AMOUNT, + CURRENCY_USD, + ); + + // Post-checks + expect( + await JBSingleTokenPaymentTerminalStore.usedDistributionLimitOf( + mockJbTerminalSigner.address, + PROJECT_ID, + FUNDING_CYCLE_NUM, + ), + ).to.equal(AMOUNT); + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(0); + }); + + /* Sad path tests */ + + it(`Can't record distribution if distributions are paused`, async function () { + const { + mockJbTerminal, + mockJbTerminalSigner, + mockJbFundingCycleStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + CURRENCY_ETH, + } = await setup(); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + // mock JBFundingCycle obj + number: FUNDING_CYCLE_NUM, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ pauseDistributions: 1 }), + }); + + await mockJbTerminal.mock.currency.returns(CURRENCY_ETH); + + // Record the distributions + await expect( + JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordDistributionFor( + PROJECT_ID, + AMOUNT, + CURRENCY_ETH, + ), + ).to.be.revertedWith(errors.FUNDING_CYCLE_DISTRIBUTION_PAUSED); + }); + + it(`Can't record distribution if currency param doesn't match controller's currency`, async function () { + const { + mockJbTerminal, + mockJbTerminalSigner, + mockJbController, + mockJbFundingCycleStore, + mockJbFundAccessConstraintsStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + CURRENCY_USD, + } = await setup(); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + // mock JBFundingCycle obj + number: FUNDING_CYCLE_NUM, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ pauseDistributions: 0 }), + }); + + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(AMOUNT, CURRENCY_USD); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + await mockJbTerminal.mock.currency.returns(CURRENCY_ETH); + + // Record the distributions + await expect( + JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordDistributionFor( + PROJECT_ID, + AMOUNT, + CURRENCY_ETH, + ), // Use ETH instead of expected USD + ).to.be.revertedWith(errors.CURRENCY_MISMATCH); + }); + + it(`Can't record distribution if distributionLimit is exceeded`, async function () { + const { + mockJbTerminal, + mockJbTerminalSigner, + mockJbController, + mockJbFundingCycleStore, + mockJbFundAccessConstraintsStore, + mockJbPrices, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + } = await setup(); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + // mock JBFundingCycle obj + number: FUNDING_CYCLE_NUM, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ pauseDistributions: 0 }), + }); + + // Add to balance beforehand + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordAddedBalanceFor( + PROJECT_ID, + AMOUNT, + ); + + const smallDistributionLimit = AMOUNT.subUnsafe(ethers.FixedNumber.from(1)); + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(smallDistributionLimit, CURRENCY_ETH); // Set intentionally small distribution limit + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + await mockJbTerminal.mock.currency.returns(CURRENCY_ETH); + + // Record the distributions + await expect( + JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordDistributionFor( + PROJECT_ID, + AMOUNT, + CURRENCY_ETH, + ), + ).to.be.revertedWith(errors.DISTRIBUTION_AMOUNT_LIMIT_REACHED); + }); + + it(`Can't record distribution if distributionLimit is 0`, async function () { + const { + mockJbTerminal, + mockJbTerminalSigner, + mockJbController, + mockJbFundingCycleStore, + mockJbFundAccessConstraintsStore, + mockJbPrices, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + } = await setup(); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + // mock JBFundingCycle obj + number: FUNDING_CYCLE_NUM, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ pauseDistributions: 0 }), + }); + + // Add to balance beforehand + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordAddedBalanceFor( + PROJECT_ID, + AMOUNT, + ); + + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(0, CURRENCY_ETH); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + await mockJbTerminal.mock.currency.returns(CURRENCY_ETH); + + // Record the distributions + await expect( + JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordDistributionFor( + PROJECT_ID, + 0, + CURRENCY_ETH, + ), + ).to.be.revertedWith(errors.DISTRIBUTION_AMOUNT_LIMIT_REACHED); + }); + + it(`Can't record distribution if distributedAmount > project's total balance`, async function () { + const { + mockJbTerminal, + mockJbTerminalSigner, + mockJbController, + mockJbFundAccessConstraintsStore, + mockJbFundingCycleStore, + mockJbPrices, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + } = await setup(); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + // mock JBFundingCycle obj + number: FUNDING_CYCLE_NUM, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ pauseDistributions: 0 }), + }); + + // Add intentionally small balance + const smallBalance = AMOUNT.subUnsafe(ethers.FixedNumber.from(1)); + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordAddedBalanceFor( + PROJECT_ID, + smallBalance, + ); + + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(AMOUNT, CURRENCY_ETH); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + await mockJbTerminal.mock.currency.returns(CURRENCY_ETH); + + // Record the distributions + await expect( + JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordDistributionFor( + PROJECT_ID, + AMOUNT, + CURRENCY_ETH, + ), + ).to.be.revertedWith(errors.INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE); + }); +}); diff --git a/test/jb_payment_terminal_store_3_1_1/record_migration.test.js b/test/jb_payment_terminal_store_3_1_1/record_migration.test.js new file mode 100644 index 000000000..2c69e30b4 --- /dev/null +++ b/test/jb_payment_terminal_store_3_1_1/record_migration.test.js @@ -0,0 +1,121 @@ +import { expect } from 'chai'; +import { ethers } from 'hardhat'; + +import { deployMockContract } from '@ethereum-waffle/mock-contract'; + +import errors from '../helpers/errors.json'; +import { packFundingCycleMetadata, impersonateAccount } from '../helpers/utils'; + +import jbDirectory from '../../artifacts/contracts/interfaces/IJBDirectory.sol/IJBDirectory.json'; +import jBFundingCycleStore from '../../artifacts/contracts/interfaces/IJBFundingCycleStore.sol/IJBFundingCycleStore.json'; +import jbPrices from '../../artifacts/contracts/interfaces/IJBPrices.sol/IJBPrices.json'; +import jbProjects from '../../artifacts/contracts/interfaces/IJBProjects.sol/IJBProjects.json'; +import jbTerminal from '../../artifacts/contracts/abstract/JBPayoutRedemptionPaymentTerminal3_1_1.sol/JBPayoutRedemptionPaymentTerminal3_1_1.json'; +import jbTokenStore from '../../artifacts/contracts/interfaces/IJBTokenStore.sol/IJBTokenStore.json'; + +describe('JBSingleTokenPaymentTerminalStore3_1_1::recordMigration(...)', function () { + const PROJECT_ID = 2; + const AMOUNT = ethers.FixedNumber.fromString('4398541.345'); + const WEIGHT = ethers.FixedNumber.fromString('900000000.23411'); + const CURRENCY = 1; + const BASE_CURRENCY = 0; + + async function setup() { + const [deployer] = await ethers.getSigners(); + + const mockJbPrices = await deployMockContract(deployer, jbPrices.abi); + const mockJbProjects = await deployMockContract(deployer, jbProjects.abi); + const mockJbDirectory = await deployMockContract(deployer, jbDirectory.abi); + const mockJbFundingCycleStore = await deployMockContract(deployer, jBFundingCycleStore.abi); + const mockJbTerminal = await deployMockContract(deployer, jbTerminal.abi); + const mockJbTokenStore = await deployMockContract(deployer, jbTokenStore.abi); + + const JBPaymentTerminalStoreFactory = await ethers.getContractFactory( + 'contracts/JBSingleTokenPaymentTerminalStore3_1_1.sol:JBSingleTokenPaymentTerminalStore3_1_1', + ); + const JBSingleTokenPaymentTerminalStore = await JBPaymentTerminalStoreFactory.deploy( + mockJbDirectory.address, + mockJbFundingCycleStore.address, + mockJbPrices.address, + ); + + const blockNum = await ethers.provider.getBlockNumber(); + const block = await ethers.provider.getBlock(blockNum); + const timestamp = block.timestamp; + + await mockJbTerminal.mock.currency.returns(CURRENCY); + + const mockJbTerminalSigner = await impersonateAccount(mockJbTerminal.address); + + return { + mockJbTerminal, + mockJbTerminalSigner, + mockJbFundingCycleStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + }; + } + + it('Should record migration with mockJbTerminal access', async function () { + const { + mockJbTerminalSigner, + mockJbFundingCycleStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + } = await setup(); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ allowTerminalMigration: 1 }), + }); + + // Add to balance beforehand + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordAddedBalanceFor( + PROJECT_ID, + AMOUNT, + ); + + // "Record migration" + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordMigration( + PROJECT_ID, + ); + + // Current balance should be set to 0 + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(0); + }); + + it(`Can't record migration with allowTerminalMigration flag disabled`, async function () { + const { + mockJbTerminalSigner, + mockJbFundingCycleStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + } = await setup(); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ allowTerminalMigration: 0 }), + }); + + // Record migration + await expect( + JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordMigration(PROJECT_ID), + ).to.be.revertedWith(errors.PAYMENT_TERMINAL_MIGRATION_NOT_ALLOWED); + }); +}); diff --git a/test/jb_payment_terminal_store_3_1_1/record_payment_from.test.js b/test/jb_payment_terminal_store_3_1_1/record_payment_from.test.js new file mode 100644 index 000000000..afb155a6a --- /dev/null +++ b/test/jb_payment_terminal_store_3_1_1/record_payment_from.test.js @@ -0,0 +1,512 @@ +import { expect } from 'chai'; +import { ethers } from 'hardhat'; + +import { deployMockContract } from '@ethereum-waffle/mock-contract'; + +import errors from '../helpers/errors.json'; +import { packFundingCycleMetadata, impersonateAccount } from '../helpers/utils'; + +import jbController from '../../artifacts/contracts/interfaces/IJBController3_1.sol/IJBController3_1.json'; +import jbDirectory from '../../artifacts/contracts/interfaces/IJBDirectory.sol/IJBDirectory.json'; +import jBFundingCycleStore from '../../artifacts/contracts/interfaces/IJBFundingCycleStore.sol/IJBFundingCycleStore.json'; +import jbFundingCycleDataSource from '../../artifacts/contracts/interfaces/IJBFundingCycleDataSource3_1_1.sol/IJBFundingCycleDataSource3_1_1.json'; +import jbPrices from '../../artifacts/contracts/interfaces/IJBPrices.sol/IJBPrices.json'; +import jbProjects from '../../artifacts/contracts/interfaces/IJBProjects.sol/IJBProjects.json'; +import jbTerminal from '../../artifacts/contracts/abstract/JBPayoutRedemptionPaymentTerminal3_1_1.sol/JBPayoutRedemptionPaymentTerminal3_1_1.json'; +import jbTokenStore from '../../artifacts/contracts/interfaces/IJBTokenStore.sol/IJBTokenStore.json'; + +describe('JBSingleTokenPaymentTerminalStore3_1_1::recordPaymentFrom(...)', function () { + const PROJECT_ID = 2; + + const AMOUNT = ethers.utils.parseEther('4351'); + const WEIGHT = ethers.utils.parseEther('900'); + + const CURRENCY = 1; + const BASE_CURRENCY = 1; + const METADATA1 = ethers.utils.randomBytes(32); + const METADATA2 = ethers.utils.randomBytes(32); + const _FIXED_POINT_MAX_FIDELITY = 18; + + async function setup() { + const [deployer, payer, beneficiary, ...addrs] = await ethers.getSigners(); + + const mockJbPrices = await deployMockContract(deployer, jbPrices.abi); + const mockJbProjects = await deployMockContract(deployer, jbProjects.abi); + const mockJbFundingCycleStore = await deployMockContract(deployer, jBFundingCycleStore.abi); + const mockJbFundingCycleDataSource = await deployMockContract( + deployer, + jbFundingCycleDataSource.abi, + ); + const mockJbTerminal = await deployMockContract(deployer, jbTerminal.abi); + const mockJbTokenStore = await deployMockContract(deployer, jbTokenStore.abi); + const mockJbController = await deployMockContract(deployer, jbController.abi); + const mockJbDirectory = await deployMockContract(deployer, jbDirectory.abi); + + const JBPaymentTerminalStoreFactory = await ethers.getContractFactory( + 'contracts/JBSingleTokenPaymentTerminalStore3_1_1.sol:JBSingleTokenPaymentTerminalStore3_1_1', + ); + const JBSingleTokenPaymentTerminalStore = await JBPaymentTerminalStoreFactory.deploy( + mockJbDirectory.address, + mockJbFundingCycleStore.address, + mockJbPrices.address, + ); + + const blockNum = await ethers.provider.getBlockNumber(); + const block = await ethers.provider.getBlock(blockNum); + const timestamp = block.timestamp; + + /* Common mocks */ + + // await mockJbTerminal.mock.currency.returns(CURRENCY); + // await mockJbTerminal.mock.baseWeightCurrency.returns(BASE_CURRENCY); + + const mockJbTerminalSigner = await impersonateAccount(mockJbTerminal.address); + + return { + mockJbTerminal, + mockJbTerminalSigner, + payer, + beneficiary, + mockJbController, + mockJbPrices, + mockJbFundingCycleStore, + mockJbFundingCycleDataSource, + mockJbPrices, + JBSingleTokenPaymentTerminalStore, + timestamp, + addrs, + }; + } + + /* Happy path tests with mockJbTerminal access */ + + it('Should record payment without a datasource', async function () { + const { + mockJbTerminalSigner, + payer, + beneficiary, + mockJbFundingCycleStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + } = await setup(); + + const reservedRate = 0; + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + // mock JBFundingCycle obj + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ pausePay: 0, reservedRate: reservedRate }), + }); + + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(0); + + // Record the payment + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordPaymentFrom( + payer.address, + ['0x1230000000000000000000000000000000000000', AMOUNT, 18, CURRENCY], + PROJECT_ID, + BASE_CURRENCY, + beneficiary.address, + /* memo */ 'test', + METADATA1, + ); + + // Expect recorded balance to change + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(AMOUNT); + }); + + it('Should record payment with no weight', async function () { + const { + mockJbTerminalSigner, + payer, + beneficiary, + mockJbFundingCycleStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + } = await setup(); + + const reservedRate = 0; + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + // mock JBFundingCycle obj + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: 0, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ pausePay: 0, reservedRate: reservedRate }), + }); + + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(0); + + // Record the payment + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordPaymentFrom( + /* payer */ payer.address, + ['0x1230000000000000000000000000000000000000', AMOUNT, 18, CURRENCY], + PROJECT_ID, + BASE_CURRENCY, + beneficiary.address, + /* memo */ 'test', + METADATA1, + ); + + // Expect recorded balance to change + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(AMOUNT); + }); + + it('Should record payment with a datasource and emit event', async function () { + const { + mockJbTerminalSigner, + payer, + beneficiary, + mockJbFundingCycleStore, + mockJbFundingCycleDataSource, + JBSingleTokenPaymentTerminalStore, + timestamp, + addrs, + } = await setup(); + + const memo = 'test'; + const reservedRate = 0; + const packedMetadata = packFundingCycleMetadata({ + pausePay: 0, + reservedRate: reservedRate, + useDataSourceForPay: 1, + dataSource: mockJbFundingCycleDataSource.address, + }); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + // JBFundingCycle obj + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packedMetadata, + }); + + const newMemo = 'new memo'; + const delegate = addrs[0]; + + await mockJbFundingCycleDataSource.mock.payParams + .withArgs({ + // JBPayParamsData obj + terminal: mockJbTerminalSigner.address, + payer: payer.address, + amount: ['0x1230000000000000000000000000000000000000', AMOUNT, 18, CURRENCY], + decimal: _FIXED_POINT_MAX_FIDELITY, + projectId: PROJECT_ID, + currentFundingCycleConfiguration: timestamp, + beneficiary, + weight: WEIGHT, + reservedRate: reservedRate, + beneficiary: beneficiary.address, + memo: memo, + metadata: METADATA1 + }) + .returns(WEIGHT, newMemo, [{ delegate: delegate.address, amount: 0, metadata: METADATA2 }]); + + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(0); + + // Record the payment + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordPaymentFrom( + /* payer */ payer.address, + /* amount */ + ['0x1230000000000000000000000000000000000000', AMOUNT, 18, CURRENCY], + /* projectId */ PROJECT_ID, + BASE_CURRENCY, + beneficiary.address, + /* memo */ 'test', + METADATA1, + ); + + // Expect recorded balance to change + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(AMOUNT); + }); + + it('Should record payment without a weight', async function () { + const { + mockJbTerminalSigner, + payer, + beneficiary, + mockJbFundingCycleStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + } = await setup(); + + const reservedRate = 0; + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + // mock JBFundingCycle obj + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: 0, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ pausePay: 0, reservedRate: reservedRate }), + }); + + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(0); + + // Record the payment + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordPaymentFrom( + /* payer */ payer.address, + ['0x1230000000000000000000000000000000000000', AMOUNT, 18, CURRENCY], + PROJECT_ID, + BASE_CURRENCY, + beneficiary.address, + /* memo */ 'test', + METADATA1, + ); + + // Expect recorded balance to change + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(AMOUNT); + }); + + it('Should record payment with a base weight currency that differs from the terminal currency', async function () { + const { + mockJbTerminalSigner, + payer, + beneficiary, + mockJbFundingCycleStore, + JBSingleTokenPaymentTerminalStore, + mockJbTerminal, + mockJbPrices, + timestamp, + } = await setup(); + + const reservedRate = 0; + const otherBaseCurrency = 2; + const conversionPrice = ethers.BigNumber.from(2); + await mockJbTerminal.mock.baseWeightCurrency.returns(otherBaseCurrency); + + await mockJbPrices.mock.priceFor + .withArgs(CURRENCY, otherBaseCurrency, _FIXED_POINT_MAX_FIDELITY) + .returns(conversionPrice.mul(ethers.BigNumber.from(10).pow(18))); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + // mock JBFundingCycle obj + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ pausePay: 0, reservedRate: reservedRate }), + }); + + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(0); + + // Record the payment + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordPaymentFrom( + /* payer */ payer.address, + ['0x1230000000000000000000000000000000000000', AMOUNT, 18, CURRENCY], + PROJECT_ID, + otherBaseCurrency, + beneficiary.address, + /* memo */ 'test', + METADATA1, + ); + + // Expect recorded balance to change + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(AMOUNT); + }); + + it(`Should skip minting and recording payment if amount is 0`, async function () { + const { + mockJbTerminalSigner, + payer, + beneficiary, + mockJbFundingCycleStore, + mockJbFundingCycleDataSource, + JBSingleTokenPaymentTerminalStore, + timestamp, + addrs, + } = await setup(); + + const memo = 'test'; + const reservedRate = 0; + const packedMetadata = packFundingCycleMetadata({ + pausePay: 0, + reservedRate: reservedRate, + useDataSourceForPay: 1, + dataSource: mockJbFundingCycleDataSource.address, + }); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + // JBFundingCycle obj + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packedMetadata, + }); + + const newMemo = 'new memo'; + const delegate = addrs[0]; + await mockJbFundingCycleDataSource.mock.payParams + .withArgs({ + // JBPayParamsData obj + terminal: mockJbTerminalSigner.address, + payer: payer.address, + amount: ['0x1230000000000000000000000000000000000000', 0, 18, CURRENCY], + projectId: PROJECT_ID, + currentFundingCycleConfiguration: timestamp, + beneficiary: beneficiary.address, + weight: WEIGHT, + reservedRate: reservedRate, + memo: memo, + metadata: METADATA1, + }) + .returns(WEIGHT, newMemo, [{ delegate: delegate.address, amount: 0, metadata: METADATA2 }]); + + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(0); + + // Record the payment + const returnedValue = await JBSingleTokenPaymentTerminalStore.connect( + mockJbTerminalSigner, + ).callStatic.recordPaymentFrom( + /* payer */ payer.address, + ['0x1230000000000000000000000000000000000000', 0, 18, CURRENCY], + /* projectId */ PROJECT_ID, + BASE_CURRENCY, + beneficiary.address, + /* memo */ memo, + METADATA1, + ); + + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordPaymentFrom( + /* payer */ payer.address, + ['0x1230000000000000000000000000000000000000', 0, 18, CURRENCY], + /* projectId */ PROJECT_ID, + BASE_CURRENCY, + beneficiary.address, + /* memo */ memo, + METADATA1, + ); + + // Recorded balance should not have changed + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(0); + expect(returnedValue.delegateAllocations[0].delegate).to.equal(delegate.address); + }); + + /* Sad path tests */ + + it(`Can't record payment if fundingCycle hasn't been configured`, async function () { + const { + mockJbTerminalSigner, + payer, + beneficiary, + mockJbFundingCycleStore, + JBSingleTokenPaymentTerminalStore, + } = await setup(); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + // empty JBFundingCycle obj + number: 0, // Set bad number + configuration: 0, + basedOn: 0, + start: 0, + duration: 0, + weight: 0, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: 0, + }); + + // Record the payment + await expect( + JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordPaymentFrom( + /* payer */ payer.address, + ['0x1230000000000000000000000000000000000000', AMOUNT, 18, CURRENCY], + PROJECT_ID, + BASE_CURRENCY, + beneficiary.address, + /* memo */ 'test', + METADATA1, + ), + ).to.be.revertedWith(errors.INVALID_FUNDING_CYCLE); + }); + + it(`Can't record payment if fundingCycle has been paused`, async function () { + const { + mockJbTerminalSigner, + payer, + beneficiary, + mockJbFundingCycleStore, + JBSingleTokenPaymentTerminalStore, + } = await setup(); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + // mock JBFundingCycle obj + number: 1, + configuration: 0, + basedOn: 0, + start: 0, + duration: 0, + weight: 0, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packFundingCycleMetadata({ pausePay: 1 }), // Payments paused + }); + + // Record the payment + await expect( + JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordPaymentFrom( + /* payer */ payer.address, + ['0x1230000000000000000000000000000000000000', AMOUNT, 18, CURRENCY], + PROJECT_ID, + BASE_CURRENCY, + beneficiary.address, + /* memo */ 'test', + METADATA1, + ), + ).to.be.revertedWith(errors.FUNDING_CYCLE_PAYMENT_PAUSED); + }); +}); diff --git a/test/jb_payment_terminal_store_3_1_1/record_redemption_for.test.js b/test/jb_payment_terminal_store_3_1_1/record_redemption_for.test.js new file mode 100644 index 000000000..d6874a3df --- /dev/null +++ b/test/jb_payment_terminal_store_3_1_1/record_redemption_for.test.js @@ -0,0 +1,790 @@ +import { expect } from 'chai'; +import { ethers } from 'hardhat'; + +import { deployMockContract } from '@ethereum-waffle/mock-contract'; + +import errors from '../helpers/errors.json'; +import { packFundingCycleMetadata, impersonateAccount } from '../helpers/utils'; + +import jbController from '../../artifacts/contracts/interfaces/IJBController3_1.sol/IJBController3_1.json'; +import jbDirectory from '../../artifacts/contracts/interfaces/IJBDirectory.sol/IJBDirectory.json'; +import jBFundingCycleStore from '../../artifacts/contracts/interfaces/IJBFundingCycleStore.sol/IJBFundingCycleStore.json'; +import jbFundingCycleDataSource from '../../artifacts/contracts/interfaces/IJBFundingCycleDataSource3_1_1.sol/IJBFundingCycleDataSource3_1_1.json'; +import jbFundAccessConstraintsStore from '../../artifacts/contracts/interfaces/IJBFundAccessConstraintsStore.sol/IJBFundAccessConstraintsStore.json'; +import jbPrices from '../../artifacts/contracts/interfaces/IJBPrices.sol/IJBPrices.json'; +import jbProjects from '../../artifacts/contracts/interfaces/IJBProjects.sol/IJBProjects.json'; +import jbTerminal from '../../artifacts/contracts/abstract/JBPayoutRedemptionPaymentTerminal3_1_1.sol/JBPayoutRedemptionPaymentTerminal3_1_1.json'; +import jbTokenStore from '../../artifacts/contracts/interfaces/IJBTokenStore.sol/IJBTokenStore.json'; + +describe('JBSingleTokenPaymentTerminalStore3_1_1::recordRedemptionFor(...)', function () { + const PROJECT_ID = 2; + const AMOUNT = ethers.BigNumber.from('4398540'); + const WEIGHT = ethers.BigNumber.from('900000000'); + const CURRENCY = ethers.BigNumber.from(1); + const METADATA1 = ethers.utils.randomBytes(32); + const METADATA2 = ethers.utils.randomBytes(32); + const _FIXED_POINT_MAX_FIDELITY = 18; + + async function setup() { + const [deployer, holder, beneficiary, ...addrs] = await ethers.getSigners(); + + const mockJbPrices = await deployMockContract(deployer, jbPrices.abi); + const mockJbProjects = await deployMockContract(deployer, jbProjects.abi); + const mockJbDirectory = await deployMockContract(deployer, jbDirectory.abi); + const mockJbFundingCycleStore = await deployMockContract(deployer, jBFundingCycleStore.abi); + const mockJbFundAccessConstraintsStore = await deployMockContract(deployer, jbFundAccessConstraintsStore.abi); + const mockJbFundingCycleDataSource = await deployMockContract( + deployer, + jbFundingCycleDataSource.abi, + ); + const mockJbTerminal = await deployMockContract(deployer, jbTerminal.abi); + const mockJbTokenStore = await deployMockContract(deployer, jbTokenStore.abi); + const mockJbController = await deployMockContract(deployer, jbController.abi); + + const jbCurrenciesFactory = await ethers.getContractFactory('JBCurrencies'); + const jbCurrencies = await jbCurrenciesFactory.deploy(); + const CURRENCY_ETH = await jbCurrencies.ETH(); + + const JBPaymentTerminalStoreFactory = await ethers.getContractFactory( + 'contracts/JBSingleTokenPaymentTerminalStore3_1_1.sol:JBSingleTokenPaymentTerminalStore3_1_1', + ); + const JBSingleTokenPaymentTerminalStore = await JBPaymentTerminalStoreFactory.deploy( + mockJbDirectory.address, + mockJbFundingCycleStore.address, + mockJbPrices.address, + ); + + const blockNum = await ethers.provider.getBlockNumber(); + const block = await ethers.provider.getBlock(blockNum); + const timestamp = block.timestamp; + + const mockJbTerminalSigner = await impersonateAccount(mockJbTerminal.address); + + const token = ethers.Wallet.createRandom().address; + await mockJbTerminal.mock.token.returns(token); + + return { + holder, + beneficiary, + mockJbController, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbFundingCycleDataSource, + mockJbFundAccessConstraintsStore, + mockJbTerminal, + mockJbTerminalSigner, + mockJbTokenStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + addrs, + }; + } + + /* Happy path tests with mockJbTerminal access */ + + it('Should record redemption without a datasource', async function () { + const { + holder, + beneficiary, + mockJbController, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbTerminal, + mockJbTerminalSigner, + mockJbTokenStore, + mockJbFundAccessConstraintsStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + } = await setup(); + + await mockJbTokenStore.mock.balanceOf.withArgs(holder.address, PROJECT_ID).returns(AMOUNT); + + const reservedRate = 0; + const packedMetadata = packFundingCycleMetadata({ + pauseRedeem: 0, + reservedRate: reservedRate, + }); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + // mock JBFundingCycle obj + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packedMetadata, + }); + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + + /* Mocks for _reclaimableOverflowOf private method */ + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(AMOUNT, CURRENCY_ETH); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + await mockJbTokenStore.mock.totalSupplyOf.withArgs(PROJECT_ID).returns(AMOUNT); + await mockJbController.mock.totalOutstandingTokensOf + .withArgs(PROJECT_ID) + .returns(AMOUNT); + + await mockJbController.mock.reservedTokenBalanceOf + .withArgs(PROJECT_ID) + .returns(0); + /* End of mocks for _reclaimableOverflowOf private method */ + + await mockJbTerminal.mock.token.returns(token); + await mockJbTerminal.mock.decimals.returns(18); + await mockJbTerminal.mock.currency.returns(CURRENCY); + + // Add to balance beforehand to have sufficient overflow + const startingBalance = AMOUNT.mul(ethers.BigNumber.from(2)); + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordAddedBalanceFor( + PROJECT_ID, + startingBalance, + ); + + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(startingBalance); + + // Record redemption + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordRedemptionFor( + /* holder */ holder.address, + /* projectId */ PROJECT_ID, + /* tokenCount */ AMOUNT, + /* memo */ 'test', + METADATA1, + ); + + // Expect recorded balance to decrease by redeemed amount + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(startingBalance.sub(AMOUNT)); + }); + + it('Should record redemption from global overflow', async function () { + const { + holder, + beneficiary, + mockJbController, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbTerminal, + mockJbTerminalSigner, + mockJbTokenStore, + mockJbFundAccessConstraintsStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + } = await setup(); + + await mockJbTokenStore.mock.balanceOf.withArgs(holder.address, PROJECT_ID).returns(AMOUNT); + + const reservedRate = 0; + const packedMetadata = packFundingCycleMetadata({ + pauseRedeem: 0, + reservedRate: reservedRate, + useTotalOverflowForRedemptions: true, + }); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + // mock JBFundingCycle obj + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packedMetadata, + }); + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + + await mockJbDirectory.mock.terminalsOf.withArgs(PROJECT_ID).returns([mockJbTerminal.address]); + await mockJbTerminal.mock.currentEthOverflowOf.withArgs(PROJECT_ID).returns(AMOUNT); + + /* Mocks for _reclaimableOverflowOf private method */ + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(AMOUNT, CURRENCY_ETH); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + await mockJbTokenStore.mock.totalSupplyOf.withArgs(PROJECT_ID).returns(AMOUNT); + await mockJbController.mock.totalOutstandingTokensOf + .withArgs(PROJECT_ID) + .returns(AMOUNT); + + await mockJbController.mock.reservedTokenBalanceOf + .withArgs(PROJECT_ID) + .returns(0); + /* End of mocks for _reclaimableOverflowOf private method */ + + await mockJbTerminal.mock.token.returns(token); + await mockJbTerminal.mock.decimals.returns(18); + await mockJbTerminal.mock.currency.returns(CURRENCY); + + // Add to balance beforehand to have sufficient overflow + const startingBalance = AMOUNT.mul(ethers.BigNumber.from(2)); + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordAddedBalanceFor( + PROJECT_ID, + startingBalance, + ); + + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(startingBalance); + + // Record redemption + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordRedemptionFor( + /* holder */ holder.address, + /* projectId */ PROJECT_ID, + /* tokenCount */ AMOUNT, + /* memo */ 'test', + METADATA1, + ); + + // Expect recorded balance to decrease by redeemed amount + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(startingBalance.sub(AMOUNT)); + }); + + it('Should record redemption without a token count', async function () { + const { + holder, + beneficiary, + mockJbController, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbTerminal, + mockJbTerminalSigner, + mockJbTokenStore, + mockJbFundAccessConstraintsStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + } = await setup(); + + await mockJbTokenStore.mock.balanceOf.withArgs(holder.address, PROJECT_ID).returns(AMOUNT); + + const reservedRate = 0; + const packedMetadata = packFundingCycleMetadata({ + pauseRedeem: 0, + reservedRate: reservedRate, + }); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + // mock JBFundingCycle obj + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packedMetadata, + }); + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + + /* Mocks for _claimableOverflowOf private method */ + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(AMOUNT, CURRENCY_ETH); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + await mockJbTokenStore.mock.totalSupplyOf.withArgs(PROJECT_ID).returns(AMOUNT); + await mockJbController.mock.totalOutstandingTokensOf + .withArgs(PROJECT_ID) + .returns(AMOUNT); + + await mockJbController.mock.reservedTokenBalanceOf + .withArgs(PROJECT_ID) + .returns(0); + + /* End of mocks for _claimableOverflowOf private method */ + + await mockJbTerminal.mock.token.returns(token); + await mockJbTerminal.mock.decimals.returns(18); + await mockJbTerminal.mock.currency.returns(CURRENCY); + + // No balance. + const startingBalance = 0; + + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(startingBalance); + + // Record redemption + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordRedemptionFor( + /* holder */ holder.address, + /* projectId */ PROJECT_ID, + /* tokenCount */ 0, + /* memo */ 'test', + METADATA1, + ); + + // Expect recorded balance to not have changed + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(startingBalance); + }); + + it('Should record redemption without a claim amount', async function () { + const { + holder, + beneficiary, + mockJbController, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbTerminal, + mockJbTerminalSigner, + mockJbTokenStore, + mockJbFundAccessConstraintsStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + } = await setup(); + + await mockJbTokenStore.mock.balanceOf.withArgs(holder.address, PROJECT_ID).returns(AMOUNT); + + const reservedRate = 0; + const packedMetadata = packFundingCycleMetadata({ + pauseRedeem: 0, + reservedRate: reservedRate, + }); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + // mock JBFundingCycle obj + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packedMetadata, + }); + + /* Mocks for _reclaimableOverflowOf private method */ + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(AMOUNT, CURRENCY_ETH); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + await mockJbTokenStore.mock.totalSupplyOf.withArgs(PROJECT_ID).returns(AMOUNT); + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + await mockJbController.mock.totalOutstandingTokensOf + .withArgs(PROJECT_ID) + .returns(AMOUNT); + + await mockJbController.mock.reservedTokenBalanceOf + .withArgs(PROJECT_ID) + .returns(0); + /* End of mocks for _reclaimableOverflowOf private method */ + + await mockJbTerminal.mock.token.returns(token); + await mockJbTerminal.mock.decimals.returns(18); + await mockJbTerminal.mock.currency.returns(CURRENCY); + + // No balance + const startingBalance = 0; + + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(startingBalance); + + // Record redemption + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordRedemptionFor( + /* holder */ holder.address, + /* projectId */ PROJECT_ID, + /* tokenCount */ AMOUNT, + /* memo */ 'test', + METADATA1, + ); + + // Expect recorded balance to not have changed + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(startingBalance); + }); + + it('Should record redemption with a datasource and emit event', async function () { + const { + holder, + beneficiary, + mockJbController, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbTerminal, + mockJbTerminalSigner, + mockJbTokenStore, + mockJbFundAccessConstraintsStore, + mockJbFundingCycleDataSource, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + addrs, + CURRENCY_ETH, + } = await setup(); + + await mockJbTokenStore.mock.balanceOf.withArgs(holder.address, PROJECT_ID).returns(AMOUNT); + + const reservedRate = 0; + const redemptionRate = 10000; + const ballotRedemptionRate = 10000; + + const packedMetadata = packFundingCycleMetadata({ + pauseRedeem: 0, + reservedRate: reservedRate, + redemptionRate: redemptionRate, + ballotRedemptionRate: ballotRedemptionRate, + useDataSourceForRedeem: 1, + dataSource: mockJbFundingCycleDataSource.address, + }); + const delegate = addrs[0]; + const delegateAmount = 10; + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + // mock JBFundingCycle obj + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packedMetadata, + }); + + await mockJbController.mock.totalOutstandingTokensOf + .withArgs(PROJECT_ID) + .returns(AMOUNT); + + await mockJbFundingCycleStore.mock.currentBallotStateOf.withArgs(PROJECT_ID).returns(1); + + const startingBalance = AMOUNT.mul(ethers.BigNumber.from(2)); + + const newMemo = 'new memo'; + await mockJbFundingCycleDataSource.mock.redeemParams + .withArgs([ + // JBRedeemParamsData obj + mockJbTerminalSigner.address, + holder.address, + PROJECT_ID, + timestamp, + /*tokenCount*/ AMOUNT, + /*totalSupply*/ AMOUNT, + /*overflow*/ AMOUNT, + [token, AMOUNT, /*decimals*/ _FIXED_POINT_MAX_FIDELITY, CURRENCY], + false, + redemptionRate, + 'test', + METADATA1, + ]) + .returns(AMOUNT, newMemo, [{ delegate: delegate.address, amount: delegateAmount, metadata: METADATA2 }]); + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminalSigner.address, token) + .returns(AMOUNT, CURRENCY_ETH); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + await mockJbTerminal.mock.token.returns(token); + await mockJbTerminal.mock.decimals.returns(18); + await mockJbTerminal.mock.currency.returns(CURRENCY); + + // Add to balance beforehand to have sufficient overflow + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordAddedBalanceFor( + PROJECT_ID, + startingBalance, + ); + + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(startingBalance); + + // Record redemption + const returnedValue = await JBSingleTokenPaymentTerminalStore.connect( + mockJbTerminalSigner, + ).callStatic.recordRedemptionFor( + /* holder */ holder.address, + /* projectId */ PROJECT_ID, + /* tokenCount */ AMOUNT, + /* memo */ 'test', + METADATA1, + ); + + expect(returnedValue.reclaimAmount).to.equal(AMOUNT); + expect(returnedValue.delegateAllocations).to.eql([ + [delegate.address, ethers.BigNumber.from(delegateAmount), ethers.utils.hexlify(METADATA2)], + ]); + expect(returnedValue.memo).to.equal(newMemo); + }); + + /* Sad path tests */ + it(`Can't record redemption if redemptions are paused`, async function () { + const { + holder, + beneficiary, + mockJbFundingCycleStore, + mockJbTerminal, + mockJbTerminalSigner, + mockJbTokenStore, + mockJbFundingCycleDataSource, + JBSingleTokenPaymentTerminalStore, + token, + timestamp, + } = await setup(); + + await mockJbTokenStore.mock.balanceOf.withArgs(holder.address, PROJECT_ID).returns(AMOUNT); + + const reservedRate = 0; + const redemptionRate = 10000; + const ballotRedemptionRate = 10000; + const packedMetadata = packFundingCycleMetadata({ + pauseRedeem: 1, // Redemptions paused + reservedRate: reservedRate, + redemptionRate: redemptionRate, + ballotRedemptionRate: ballotRedemptionRate, + useDataSourceForRedeem: 1, + dataSource: mockJbFundingCycleDataSource.address, + }); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + // mock JBFundingCycle obj + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packedMetadata, + }); + + await mockJbTerminal.mock.token.returns(token); + await mockJbTerminal.mock.decimals.returns(18); + await mockJbTerminal.mock.currency.returns(CURRENCY); + + // Record redemption + await expect( + JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordRedemptionFor( + /* holder */ holder.address, + /* projectId */ PROJECT_ID, + /* tokenCount */ AMOUNT, + /* memo */ 'test', + METADATA1, + ), + ).to.be.revertedWith(errors.FUNDING_CYCLE_REDEEM_PAUSED); + }); + + it(`Can't record redemption with claim amount > total supply`, async function () { + const { + holder, + beneficiary, + mockJbController, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbTerminal, + mockJbTerminalSigner, + mockJbTokenStore, + mockJbFundingCycleDataSource, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + addrs, + } = await setup(); + + const reservedRate = 0; + const redemptionRate = 10000; + const ballotRedemptionRate = 10000; + const packedMetadata = packFundingCycleMetadata({ + pauseRedeem: 0, + reservedRate: reservedRate, + redemptionRate: redemptionRate, + ballotRedemptionRate: ballotRedemptionRate, + useDataSourceForRedeem: 1, + dataSource: mockJbFundingCycleDataSource.address, + }); + const delegate = addrs[0]; + + await mockJbTokenStore.mock.balanceOf + .withArgs(holder.address, PROJECT_ID) + .returns(AMOUNT.add(1)); + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + await mockJbController.mock.totalOutstandingTokensOf + .withArgs(PROJECT_ID) + .returns(AMOUNT); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + // mock JBFundingCycle obj + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packedMetadata, + }); + + const newMemo = 'new memo'; + await mockJbFundingCycleDataSource.mock.redeemParams + .withArgs([ + // JBRedeemParamsData obj + mockJbTerminalSigner.address, + holder.address, + PROJECT_ID, + timestamp, + /*tokenCount*/ AMOUNT.add(1), + /*totalSupply*/ AMOUNT, + /*overflow*/ 0, + [token, /*reclaim amount*/ 0, /*decimals*/ _FIXED_POINT_MAX_FIDELITY, CURRENCY], + false, + redemptionRate, + 'test', + METADATA1, + ]) + .returns(AMOUNT, newMemo, [{ delegate: delegate.address, amount: 0, metadata: METADATA2 }]); + + await mockJbTerminal.mock.token.returns(token); + await mockJbTerminal.mock.decimals.returns(18); + await mockJbTerminal.mock.currency.returns(CURRENCY); + + // Note: The store has 0 balance because we haven't added anything to it + // Record redemption + await expect( + JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordRedemptionFor( + /* holder */ holder.address, + /* projectId */ PROJECT_ID, + /* tokenCount */ AMOUNT.add(1), + /* memo */ 'test', + METADATA1, + ), + ).to.be.revertedWith(errors.INSUFFICIENT_TOKENS); + }); + + it(`Can't record redemption with claim amount > project's total balance`, async function () { + const { + holder, + beneficiary, + mockJbController, + mockJbDirectory, + mockJbFundingCycleStore, + mockJbTerminal, + mockJbTerminalSigner, + mockJbTokenStore, + mockJbFundingCycleDataSource, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + addrs, + } = await setup(); + + const reservedRate = 0; + const redemptionRate = 10000; + const ballotRedemptionRate = 10000; + const packedMetadata = packFundingCycleMetadata({ + pauseRedeem: 0, + reservedRate: reservedRate, + redemptionRate: redemptionRate, + ballotRedemptionRate: ballotRedemptionRate, + useDataSourceForRedeem: 1, + dataSource: mockJbFundingCycleDataSource.address, + }); + const delegate = addrs[0]; + + await mockJbTokenStore.mock.balanceOf.withArgs(holder.address, PROJECT_ID).returns(AMOUNT); + + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + await mockJbController.mock.totalOutstandingTokensOf + .withArgs(PROJECT_ID) + .returns(AMOUNT); + + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + // mock JBFundingCycle obj + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packedMetadata, + }); + + const newMemo = 'new memo'; + await mockJbFundingCycleDataSource.mock.redeemParams + .withArgs([ + // JBRedeemParamsData obj + mockJbTerminalSigner.address, + holder.address, + PROJECT_ID, + timestamp, + /*tokenCount*/ AMOUNT, + /*totalSupply*/ AMOUNT, + /*overflow*/ 0, + [token, /*reclaim amount*/ 0, /*decimals*/ _FIXED_POINT_MAX_FIDELITY, CURRENCY], + false, + redemptionRate, + 'test', + METADATA1, + ]) + .returns(AMOUNT, newMemo, [{ delegate: delegate.address, amount: 0, metadata: METADATA2 }]); + + await mockJbTerminal.mock.token.returns(token); + await mockJbTerminal.mock.decimals.returns(18); + await mockJbTerminal.mock.currency.returns(CURRENCY); + await mockJbFundingCycleStore.mock.currentBallotStateOf.withArgs(PROJECT_ID).returns(1); + + // Note: The store has 0 balance because we haven't added anything to it + // Record redemption + await expect( + JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordRedemptionFor( + /* holder */ holder.address, + /* projectId */ PROJECT_ID, + /* tokenCount */ AMOUNT, + /* memo */ 'test', + METADATA1, + ), + ).to.be.revertedWith(errors.INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE); + }); +}); diff --git a/test/jb_payment_terminal_store_3_1_1/record_used_allowance_of.test.js b/test/jb_payment_terminal_store_3_1_1/record_used_allowance_of.test.js new file mode 100644 index 000000000..001988894 --- /dev/null +++ b/test/jb_payment_terminal_store_3_1_1/record_used_allowance_of.test.js @@ -0,0 +1,565 @@ +import { expect } from 'chai'; +import { ethers } from 'hardhat'; + +import { deployMockContract } from '@ethereum-waffle/mock-contract'; + +import errors from '../helpers/errors.json'; +import { packFundingCycleMetadata, impersonateAccount } from '../helpers/utils'; + +import jbController from '../../artifacts/contracts/interfaces/IJBController3_1.sol/IJBController3_1.json'; +import jbDirectory from '../../artifacts/contracts/interfaces/IJBDirectory.sol/IJBDirectory.json'; +import jBFundingCycleStore from '../../artifacts/contracts/interfaces/IJBFundingCycleStore.sol/IJBFundingCycleStore.json'; +import jbFundAccessConstraintsStore from '../../artifacts/contracts/interfaces/IJBFundAccessConstraintsStore.sol/IJBFundAccessConstraintsStore.json'; +import jbPrices from '../../artifacts/contracts/interfaces/IJBPrices.sol/IJBPrices.json'; +import jbProjects from '../../artifacts/contracts/interfaces/IJBProjects.sol/IJBProjects.json'; +import jbTerminal from '../../artifacts/contracts/abstract/JBPayoutRedemptionPaymentTerminal3_1_1.sol/JBPayoutRedemptionPaymentTerminal3_1_1.json'; +import jbTokenStore from '../../artifacts/contracts/interfaces/IJBTokenStore.sol/IJBTokenStore.json'; + +describe('JBSingleTokenPaymentTerminalStore3_1_1::recordUsedAllowanceOf(...)', function () { + const PROJECT_ID = 2; + const AMOUNT = ethers.BigNumber.from('43985411231'); + const WEIGHT = ethers.BigNumber.from('900000000'); + const _FIXED_POINT_MAX_FIDELITY = 18; + + async function setup() { + const [deployer, addr] = await ethers.getSigners(); + + const mockJbPrices = await deployMockContract(deployer, jbPrices.abi); + const mockJbProjects = await deployMockContract(deployer, jbProjects.abi); + const mockJbDirectory = await deployMockContract(deployer, jbDirectory.abi); + const mockJbFundingCycleStore = await deployMockContract(deployer, jBFundingCycleStore.abi); + const mockJbTerminal = await deployMockContract(deployer, jbTerminal.abi); + const mockJbTokenStore = await deployMockContract(deployer, jbTokenStore.abi); + const mockJbController = await deployMockContract(deployer, jbController.abi); + const mockJbFundAccessConstraintsStore = await deployMockContract(deployer, jbFundAccessConstraintsStore.abi); + + const jbCurrenciesFactory = await ethers.getContractFactory('JBCurrencies'); + const jbCurrencies = await jbCurrenciesFactory.deploy(); + const CURRENCY_ETH = await jbCurrencies.ETH(); + const CURRENCY_USD = await jbCurrencies.USD(); + const _FIXED_POINT_MAX_FIDELITY = 18; + + const JBPaymentTerminalStoreFactory = await ethers.getContractFactory( + 'contracts/JBSingleTokenPaymentTerminalStore3_1_1.sol:JBSingleTokenPaymentTerminalStore3_1_1', + ); + const JBSingleTokenPaymentTerminalStore = await JBPaymentTerminalStoreFactory.deploy( + mockJbDirectory.address, + mockJbFundingCycleStore.address, + mockJbPrices.address, + ); + + const blockNum = await ethers.provider.getBlockNumber(); + const block = await ethers.provider.getBlock(blockNum); + const timestamp = block.timestamp; + + /* Common mocks */ + + await mockJbTerminal.mock.currency.returns(CURRENCY_USD); + await mockJbTerminal.mock.baseWeightCurrency.returns(CURRENCY_ETH); + + // Set controller address + await mockJbDirectory.mock.controllerOf.withArgs(PROJECT_ID).returns(mockJbController.address); + + const packedMetadata = packFundingCycleMetadata(); + await mockJbFundingCycleStore.mock.currentOf.withArgs(PROJECT_ID).returns({ + number: 1, + configuration: timestamp, + basedOn: timestamp, + start: timestamp, + duration: 0, + weight: WEIGHT, + discountRate: 0, + ballot: ethers.constants.AddressZero, + metadata: packedMetadata, + }); + + const mockJbTerminalSigner = await impersonateAccount(mockJbTerminal.address); + + const token = ethers.Wallet.createRandom().address; + await mockJbTerminal.mock.token.returns(token); + + return { + addr, + mockJbController, + mockJbPrices, + mockJbTerminal, + mockJbTerminalSigner, + mockJbFundAccessConstraintsStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + CURRENCY_USD, + }; + } + + it('Should record used allowance with terminal access', async function () { + const { + mockJbController, + mockJbPrices, + mockJbTerminal, + mockJbTerminalSigner, + mockJbFundAccessConstraintsStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, // base weight currency + CURRENCY_USD, // terminal currency + } = await setup(); + + // Add to balance beforehand, in USD + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordAddedBalanceFor( + PROJECT_ID, + AMOUNT, + ); + + // Both limit and allowance in USD + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(0, CURRENCY_USD); + + await mockJbFundAccessConstraintsStore.mock.overflowAllowanceOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(AMOUNT, CURRENCY_USD); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + await mockJbTerminal.mock.currency.returns(CURRENCY_USD); + + // Pre-checks + expect( + await JBSingleTokenPaymentTerminalStore.usedOverflowAllowanceOf( + mockJbTerminalSigner.address, + PROJECT_ID, + timestamp, + ), + ).to.equal(0); + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(AMOUNT); // balanceOf is in terminal currency (USD) + + // Record the used allowance + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordUsedAllowanceOf( + PROJECT_ID, + AMOUNT, + CURRENCY_USD, + ); + + // Post-checks + expect( + await JBSingleTokenPaymentTerminalStore.usedOverflowAllowanceOf( + mockJbTerminalSigner.address, + PROJECT_ID, + timestamp, + ), + ).to.equal(AMOUNT); + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(0); // AMOUNT-AMOUNT = 0 + }); + it('Should record used allowance with > 0 distribution limit', async function () { + const { + mockJbController, + mockJbPrices, + mockJbFundAccessConstraintsStore, + mockJbTerminal, + mockJbTerminalSigner, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, // base weight currency + CURRENCY_USD, // terminal currency + } = await setup(); + + const usdToEthPrice = ethers.BigNumber.from(3500); + + // Add to balance beforehand, in USD + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordAddedBalanceFor( + PROJECT_ID, + AMOUNT, + ); + + const distributionLimit = AMOUNT - 1; + + // Both limit and allowance in USD + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(distributionLimit, CURRENCY_USD); + + await mockJbFundAccessConstraintsStore.mock.overflowAllowanceOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(AMOUNT, CURRENCY_USD); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + await mockJbTerminal.mock.currency.returns(CURRENCY_USD); + + // Pre-checks + expect( + await JBSingleTokenPaymentTerminalStore.usedOverflowAllowanceOf( + mockJbTerminalSigner.address, + PROJECT_ID, + timestamp, + ), + ).to.equal(0); + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(AMOUNT); // balanceOf is in terminal currency (USD) + + // Record the used allowance + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordUsedAllowanceOf( + PROJECT_ID, + AMOUNT - distributionLimit, + CURRENCY_USD, + ); + + // Post-checks + expect( + await JBSingleTokenPaymentTerminalStore.usedOverflowAllowanceOf( + mockJbTerminalSigner.address, + PROJECT_ID, + timestamp, + ), + ).to.equal(AMOUNT - distributionLimit); + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(distributionLimit); + }); + it('Should record used allowance with > 0 distribution limit and different distribution currency', async function () { + const { + mockJbController, + mockJbPrices, + mockJbTerminal, + mockJbTerminalSigner, + mockJbFundAccessConstraintsStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, // base weight currency + CURRENCY_USD, // terminal currency + } = await setup(); + + const ethToUsdPrice = ethers.BigNumber.from(2).mul( + ethers.BigNumber.from(10).pow(_FIXED_POINT_MAX_FIDELITY), + ); + + const distributionLimit = ethers.BigNumber.from(10).pow(18); + + const amountToUse = 2345678; // in eth + let amountToUseInDollar = + amountToUse / ethToUsdPrice.div(ethers.BigNumber.from(10).pow(_FIXED_POINT_MAX_FIDELITY)); + + // Add to balance beforehand, in USD + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordAddedBalanceFor( + PROJECT_ID, + distributionLimit.add(amountToUseInDollar), + ); + + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(distributionLimit, CURRENCY_USD); // in usd + + await mockJbFundAccessConstraintsStore.mock.overflowAllowanceOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(amountToUse, CURRENCY_ETH); // in eth + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + await mockJbPrices.mock.priceFor + .withArgs(CURRENCY_ETH, CURRENCY_USD, _FIXED_POINT_MAX_FIDELITY) + .returns(ethToUsdPrice); + + await mockJbTerminal.mock.currency.returns(CURRENCY_USD); + + // Pre-checks + expect( + await JBSingleTokenPaymentTerminalStore.usedOverflowAllowanceOf( + mockJbTerminalSigner.address, + PROJECT_ID, + timestamp, + ), + ).to.equal(0); + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(distributionLimit.add(amountToUseInDollar)); // balanceOf is in terminal currency (USD) + + // Record the used allowance + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordUsedAllowanceOf( + PROJECT_ID, + amountToUse, + CURRENCY_ETH, + ); + + // Post-checks + expect( + await JBSingleTokenPaymentTerminalStore.usedOverflowAllowanceOf( + mockJbTerminalSigner.address, + PROJECT_ID, + timestamp, + ), + ).to.equal(amountToUse); // in usd + + expect( + await JBSingleTokenPaymentTerminalStore.balanceOf(mockJbTerminalSigner.address, PROJECT_ID), + ).to.equal(distributionLimit); // in usd + }); + + /* Sad path tests */ + + it(`Can't record allowance if currency param doesn't match controller's currency`, async function () { + const { + mockJbController, + mockJbTerminal, + mockJbTerminalSigner, + mockJbFundAccessConstraintsStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + CURRENCY_USD, + } = await setup(); + + await mockJbFundAccessConstraintsStore.mock.overflowAllowanceOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(AMOUNT, CURRENCY_USD); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + await mockJbTerminal.mock.currency.returns(CURRENCY_ETH); + + // Record the used allowance + await expect( + JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordUsedAllowanceOf( + PROJECT_ID, + AMOUNT, + CURRENCY_ETH, + ), + ).to.be.revertedWith(errors.CURRENCY_MISMATCH); + }); + + it(`Can't record allowance if controller's overflowAllowanceOf is exceeded`, async function () { + const { + mockJbController, + mockJbTerminal, + mockJbTerminalSigner, + mockJbFundAccessConstraintsStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_USD, + } = await setup(); + + // Add to balance beforehand + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordAddedBalanceFor( + PROJECT_ID, + AMOUNT, + ); + + const smallTotalAllowance = AMOUNT.sub(ethers.BigNumber.from(1)); + await mockJbFundAccessConstraintsStore.mock.overflowAllowanceOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(smallTotalAllowance, CURRENCY_USD); // Set the controller's overflowAllowance to something small + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + await mockJbTerminal.mock.currency.returns(CURRENCY_USD); + + // Record the used allowance + await expect( + JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordUsedAllowanceOf( + PROJECT_ID, + AMOUNT, + CURRENCY_USD, + ), + ).to.be.revertedWith(errors.INADEQUATE_CONTROLLER_ALLOWANCE); + }); + + it(`Can't record allowance if controller's overflowAllowanceOf is 0`, async function () { + const { + mockJbController, + mockJbTerminal, + mockJbTerminalSigner, + mockJbFundAccessConstraintsStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_USD, + } = await setup(); + + // Add to balance beforehand + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordAddedBalanceFor( + PROJECT_ID, + AMOUNT, + ); + + await mockJbFundAccessConstraintsStore.mock.overflowAllowanceOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(0, CURRENCY_USD); // Set the controller's overflowAllowance to something small + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + await mockJbTerminal.mock.currency.returns(CURRENCY_USD); + + // Record the used allowance + await expect( + JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordUsedAllowanceOf( + PROJECT_ID, + 0, + CURRENCY_USD, + ), + ).to.be.revertedWith(errors.INADEQUATE_CONTROLLER_ALLOWANCE); + }); + + it(`Can't record allowance if _leftToDistribute > balanceOf`, async function () { + const { + mockJbController, + mockJbTerminal, + mockJbTerminalSigner, + mockJbFundAccessConstraintsStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_USD, + } = await setup(); + + // Create a big overflow + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(AMOUNT, CURRENCY_USD); + + await mockJbFundAccessConstraintsStore.mock.overflowAllowanceOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(AMOUNT, CURRENCY_USD); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + await mockJbTerminal.mock.currency.returns(CURRENCY_USD); + + // Note: We didn't add an initial balance to the store + // Record the used allowance + await expect( + JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordUsedAllowanceOf( + PROJECT_ID, + AMOUNT, + CURRENCY_USD, + ), + ).to.be.revertedWith(errors.INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE); + }); + + it(`Can't record allowance if withdrawnAmount > overflow`, async function () { + const { + mockJbController, + mockJbPrices, + mockJbTerminal, + mockJbTerminalSigner, + mockJbFundAccessConstraintsStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, + CURRENCY_USD, + } = await setup(); + + // Add to balance beforehand + const smallBalance = AMOUNT.sub(ethers.BigNumber.from(1)); + + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordAddedBalanceFor( + PROJECT_ID, + AMOUNT, + ); + + // Leave a small overflow + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(smallBalance, CURRENCY_ETH); + + await mockJbFundAccessConstraintsStore.mock.overflowAllowanceOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(AMOUNT, CURRENCY_ETH); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + await mockJbPrices.mock.priceFor + .withArgs(CURRENCY_ETH, CURRENCY_USD, _FIXED_POINT_MAX_FIDELITY) + .returns(ethers.BigNumber.from(1)); + + await mockJbTerminal.mock.currency.returns(CURRENCY_USD); + + // Record the used allowance + await expect( + JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordUsedAllowanceOf( + PROJECT_ID, + AMOUNT, + CURRENCY_ETH, + ), + ).to.be.revertedWith(errors.INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE); + }); + it(`Can't record used allowance with > 0 distribution limit and not enough balance outside of this limit`, async function () { + const { + mockJbController, + mockJbPrices, + mockJbTerminal, + mockJbTerminalSigner, + mockJbFundAccessConstraintsStore, + JBSingleTokenPaymentTerminalStore, + timestamp, + token, + CURRENCY_ETH, // base weight currency + CURRENCY_USD, // terminal currency + } = await setup(); + + const usdToEthPrice = ethers.BigNumber.from(3500); + + // Add to balance beforehand, in USD + await JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordAddedBalanceFor( + PROJECT_ID, + AMOUNT, + ); + + const distributionLimit = AMOUNT; + + // Both limit and allowance in USD + await mockJbFundAccessConstraintsStore.mock.distributionLimitOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(distributionLimit, CURRENCY_USD); + + await mockJbFundAccessConstraintsStore.mock.overflowAllowanceOf + .withArgs(PROJECT_ID, timestamp, mockJbTerminal.address, token) + .returns(AMOUNT, CURRENCY_USD); + + await mockJbController.mock.fundAccessConstraintsStore + .withArgs() + .returns(mockJbFundAccessConstraintsStore.address); + + await mockJbPrices.mock.priceFor + .withArgs(CURRENCY_USD, CURRENCY_ETH, _FIXED_POINT_MAX_FIDELITY) + .returns(usdToEthPrice); + + await mockJbTerminal.mock.currency.returns(CURRENCY_USD); + + // Record the used allowance + await expect( + JBSingleTokenPaymentTerminalStore.connect(mockJbTerminalSigner).recordUsedAllowanceOf( + PROJECT_ID, + AMOUNT, + CURRENCY_USD, + ), + ).to.be.revertedWith(errors.INADEQUATE_PAYMENT_TERMINAL_STORE_BALANCE); + }); +});