// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (utils/Address.sol)pragmasolidity ^0.8.1;/**
* @dev Collection of functions related to the address type
*/libraryAddress{
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/functionisContract(address account) internalviewreturns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0// for contracts in construction, since the code is only stored at the end// of the constructor execution.return account.code.length>0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/functionsendValue(addresspayable recipient, uint256 amount) internal{
require(address(this).balance>= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/functionfunctionCall(address target, bytesmemory data) internalreturns (bytesmemory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/functionfunctionCall(address target,
bytesmemory data,
stringmemory errorMessage
) internalreturns (bytesmemory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/functionfunctionCallWithValue(address target,
bytesmemory data,
uint256 value
) internalreturns (bytesmemory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/functionfunctionCallWithValue(address target,
bytesmemory data,
uint256 value,
stringmemory errorMessage
) internalreturns (bytesmemory) {
require(address(this).balance>= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytesmemory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/functionfunctionStaticCall(address target, bytesmemory data) internalviewreturns (bytesmemory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/functionfunctionStaticCall(address target,
bytesmemory data,
stringmemory errorMessage
) internalviewreturns (bytesmemory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytesmemory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/functionfunctionDelegateCall(address target, bytesmemory data) internalreturns (bytesmemory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/functionfunctionDelegateCall(address target,
bytesmemory data,
stringmemory errorMessage
) internalreturns (bytesmemory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytesmemory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason using the provided one.
*
* _Available since v4.3._
*/functionverifyCallResult(bool success,
bytesmemory returndata,
stringmemory errorMessage
) internalpurereturns (bytesmemory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if presentif (returndata.length>0) {
// The easiest way to bubble the revert reason is using memory via assemblyassembly {
let returndata_size :=mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
Contract Source Code
File 2 of 70: Context.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)pragmasolidity ^0.8.0;/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/abstractcontractContext{
function_msgSender() internalviewvirtualreturns (address) {
returnmsg.sender;
}
function_msgData() internalviewvirtualreturns (bytescalldata) {
returnmsg.data;
}
}
Contract Source Code
File 3 of 70: ERC165.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)pragmasolidity ^0.8.0;import"./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/abstractcontractERC165isIERC165{
/**
* @dev See {IERC165-supportsInterface}.
*/functionsupportsInterface(bytes4 interfaceId) publicviewvirtualoverridereturns (bool) {
return interfaceId ==type(IERC165).interfaceId;
}
}
Contract Source Code
File 4 of 70: ERC165Checker.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165Checker.sol)pragmasolidity ^0.8.0;import"./IERC165.sol";
/**
* @dev Library used to query support of an interface declared via {IERC165}.
*
* Note that these functions return the actual result of the query: they do not
* `revert` if an interface is not supported. It is up to the caller to decide
* what to do in these cases.
*/libraryERC165Checker{
// As per the EIP-165 spec, no interface should ever match 0xffffffffbytes4privateconstant _INTERFACE_ID_INVALID =0xffffffff;
/**
* @dev Returns true if `account` supports the {IERC165} interface,
*/functionsupportsERC165(address account) internalviewreturns (bool) {
// Any contract that implements ERC165 must explicitly indicate support of// InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalidreturn
_supportsERC165Interface(account, type(IERC165).interfaceId) &&!_supportsERC165Interface(account, _INTERFACE_ID_INVALID);
}
/**
* @dev Returns true if `account` supports the interface defined by
* `interfaceId`. Support for {IERC165} itself is queried automatically.
*
* See {IERC165-supportsInterface}.
*/functionsupportsInterface(address account, bytes4 interfaceId) internalviewreturns (bool) {
// query support of both ERC165 as per the spec and support of _interfaceIdreturn supportsERC165(account) && _supportsERC165Interface(account, interfaceId);
}
/**
* @dev Returns a boolean array where each value corresponds to the
* interfaces passed in and whether they're supported or not. This allows
* you to batch check interfaces for a contract where your expectation
* is that some interfaces may not be supported.
*
* See {IERC165-supportsInterface}.
*
* _Available since v3.4._
*/functiongetSupportedInterfaces(address account, bytes4[] memory interfaceIds)
internalviewreturns (bool[] memory)
{
// an array of booleans corresponding to interfaceIds and whether they're supported or notbool[] memory interfaceIdsSupported =newbool[](interfaceIds.length);
// query support of ERC165 itselfif (supportsERC165(account)) {
// query support of each interface in interfaceIdsfor (uint256 i =0; i < interfaceIds.length; i++) {
interfaceIdsSupported[i] = _supportsERC165Interface(account, interfaceIds[i]);
}
}
return interfaceIdsSupported;
}
/**
* @dev Returns true if `account` supports all the interfaces defined in
* `interfaceIds`. Support for {IERC165} itself is queried automatically.
*
* Batch-querying can lead to gas savings by skipping repeated checks for
* {IERC165} support.
*
* See {IERC165-supportsInterface}.
*/functionsupportsAllInterfaces(address account, bytes4[] memory interfaceIds) internalviewreturns (bool) {
// query support of ERC165 itselfif (!supportsERC165(account)) {
returnfalse;
}
// query support of each interface in _interfaceIdsfor (uint256 i =0; i < interfaceIds.length; i++) {
if (!_supportsERC165Interface(account, interfaceIds[i])) {
returnfalse;
}
}
// all interfaces supportedreturntrue;
}
/**
* @notice Query if a contract implements an interface, does not check ERC165 support
* @param account The address of the contract to query for support of an interface
* @param interfaceId The interface identifier, as specified in ERC-165
* @return true if the contract at account indicates support of the interface with
* identifier interfaceId, false otherwise
* @dev Assumes that account contains a contract that supports ERC165, otherwise
* the behavior of this method is undefined. This precondition can be checked
* with {supportsERC165}.
* Interface identification is specified in ERC-165.
*/function_supportsERC165Interface(address account, bytes4 interfaceId) privateviewreturns (bool) {
bytesmemory encodedParams =abi.encodeWithSelector(IERC165.supportsInterface.selector, interfaceId);
(bool success, bytesmemory result) = account.staticcall{gas: 30000}(encodedParams);
if (result.length<32) returnfalse;
return success &&abi.decode(result, (bool));
}
}
Contract Source Code
File 5 of 70: IERC165.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)pragmasolidity ^0.8.0;/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/interfaceIERC165{
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/functionsupportsInterface(bytes4 interfaceId) externalviewreturns (bool);
}
Contract Source Code
File 6 of 70: IERC721.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721.sol)pragmasolidity ^0.8.0;import"../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC721 compliant contract.
*/interfaceIERC721isIERC165{
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/eventTransfer(addressindexedfrom, addressindexed to, uint256indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/eventApproval(addressindexed owner, addressindexed approved, uint256indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/eventApprovalForAll(addressindexed owner, addressindexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/functionbalanceOf(address owner) externalviewreturns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/functionownerOf(uint256 tokenId) externalviewreturns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/functionsafeTransferFrom(addressfrom,
address to,
uint256 tokenId
) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/functiontransferFrom(addressfrom,
address to,
uint256 tokenId
) external;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/functionapprove(address to, uint256 tokenId) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/functiongetApproved(uint256 tokenId) externalviewreturns (address operator);
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the caller.
*
* Emits an {ApprovalForAll} event.
*/functionsetApprovalForAll(address operator, bool _approved) external;
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/functionisApprovedForAll(address owner, address operator) externalviewreturns (bool);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/functionsafeTransferFrom(addressfrom,
address to,
uint256 tokenId,
bytescalldata data
) external;
}
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;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)interfaceIJBPayDelegateisIERC165{
/// @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:functiondidPay(JBDidPayData calldata data) externalpayable;
}
Contract Source Code
File 18 of 70: IJBPayDelegate3_1_1.sol
// SPDX-License-Identifier: MITpragmasolidity ^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)interfaceIJBPayDelegate3_1_1isIERC165{
/// @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:functiondidPay(JBDidPayData3_1_1 calldata data) externalpayable;
}
Contract Source Code
File 19 of 70: IJBPaymentTerminal.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;import {IERC165} from'@openzeppelin/contracts/utils/introspection/IERC165.sol';
interfaceIJBPaymentTerminalisIERC165{
functionacceptsToken(address token, uint256 projectId) externalviewreturns (bool);
functioncurrencyForToken(address token) externalviewreturns (uint256);
functiondecimalsForToken(address token) externalviewreturns (uint256);
// Return value must be a fixed point number with 18 decimals.functioncurrentEthOverflowOf(uint256 projectId) externalviewreturns (uint256);
functionpay(uint256 projectId,
uint256 amount,
address token,
address beneficiary,
uint256 minReturnedTokens,
bool preferClaimedTokens,
stringcalldata memo,
bytescalldata metadata
) externalpayablereturns (uint256 beneficiaryTokenCount);
functionaddToBalanceOf(uint256 projectId,
uint256 amount,
address token,
stringcalldata memo,
bytescalldata metadata
) externalpayable;
}
Contract Source Code
File 20 of 70: IJBPayoutRedemptionPaymentTerminal3_1.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;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)interfaceIJBRedemptionDelegateisIERC165{
/// @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:functiondidRedeem(JBDidRedeemData calldata data) externalpayable;
}
Contract Source Code
File 27 of 70: IJBRedemptionDelegate3_1_1.sol
// SPDX-License-Identifier: MITpragmasolidity ^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)interfaceIJBRedemptionDelegate3_1_1isIERC165{
/// @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:functiondidRedeem(JBDidRedeemData3_1_1 calldata data) externalpayable;
}
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;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 The contract address should be set as an allocator in the adequate splitinterfaceIJBSplitAllocatorisIERC165{
/// @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:functionallocate(JBSplitAllocationData calldata data) externalpayable;
}
// SPDX-License-Identifier: MITpragmasolidity ^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 metadata Extra data to send to the delegate.structJBDidPayData {
address payer;
uint256 projectId;
uint256 currentFundingCycleConfiguration;
JBTokenAmount amount;
JBTokenAmount forwardedAmount;
uint256 projectTokenCount;
address beneficiary;
bool preferClaimedTokens;
string memo;
bytes metadata;
}
Contract Source Code
File 40 of 70: JBDidPayData3_1_1.sol
// SPDX-License-Identifier: MITpragmasolidity ^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.structJBDidPayData3_1_1 {
address payer;
uint256 projectId;
uint256 currentFundingCycleConfiguration;
JBTokenAmount amount;
JBTokenAmount forwardedAmount;
uint256 projectTokenCount;
address beneficiary;
bool preferClaimedTokens;
string memo;
bytes dataSourceMetadata;
bytes payerMetadata;
}
Contract Source Code
File 41 of 70: JBDidRedeemData.sol
// SPDX-License-Identifier: MITpragmasolidity ^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 metadata Extra data to send to the delegate.structJBDidRedeemData {
address holder;
uint256 projectId;
uint256 currentFundingCycleConfiguration;
uint256 projectTokenCount;
JBTokenAmount reclaimedAmount;
JBTokenAmount forwardedAmount;
addresspayable beneficiary;
string memo;
bytes metadata;
}
Contract Source Code
File 42 of 70: JBDidRedeemData3_1_1.sol
// SPDX-License-Identifier: MITpragmasolidity ^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.structJBDidRedeemData3_1_1 {
address holder;
uint256 projectId;
uint256 currentFundingCycleConfiguration;
uint256 projectTokenCount;
JBTokenAmount reclaimedAmount;
JBTokenAmount forwardedAmount;
addresspayable beneficiary;
string memo;
bytes dataSourceMetadata;
bytes redeemerMetadata;
}
Contract Source Code
File 43 of 70: JBETHPaymentTerminal3_1_2.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.16;import {Address} from'@openzeppelin/contracts/utils/Address.sol';
import {JBPayoutRedemptionPaymentTerminal3_1_2} from'./abstract/JBPayoutRedemptionPaymentTerminal3_1_2.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.contractJBETHPaymentTerminal3_1_2isJBPayoutRedemptionPaymentTerminal3_1_2{
//*********************************************************************//// -------------------------- 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() internalviewoverridereturns (uint256) {
returnaddress(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_2(
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, addresspayable _to, uint256 _amount) internaloverride{
_from; // Prevents unused var compiler and natspec complaints.
Address.sendValue(_to, _amount);
}
}
Contract Source Code
File 44 of 70: JBFee.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;/// @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.structJBFee {
uint256 amount;
uint32 fee;
uint32 feeDiscount;
address beneficiary;
}
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;import {PRBMath} from'@paulrberg/contracts/math/PRBMath.sol';
import {JBConstants} from'./../libraries/JBConstants.sol';
/// @notice Fee calculations.libraryJBFees{
/// @notice Returns the fee included in the specified _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 _feePercent 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.functionfeeIn(uint256 _amount,
uint256 _feePercent,
uint256 _feeDiscount
) internalpurereturns (uint256) {
// Calculate the discounted fee.uint256 _discountedFeePercent = _feePercent -
PRBMath.mulDiv(_feePercent, _feeDiscount, JBConstants.MAX_FEE_DISCOUNT);
// The amount of tokens from the `_amount` to pay as a fee. If reverse, the fee taken from a payout of `_amount`.return
_amount - PRBMath.mulDiv(_amount, JBConstants.MAX_FEE, _discountedFeePercent + JBConstants.MAX_FEE);
}
/// @notice Returns the fee amount paid from a payouts of _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 _feePercent 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.functionfeeFrom(uint256 _amount,
uint256 _feePercent,
uint256 _feeDiscount
) internalpurereturns (uint256) {
// Calculate the discounted fee.uint256 _discountedFeePercent = _feePercent -
PRBMath.mulDiv(_feePercent, _feeDiscount, JBConstants.MAX_FEE_DISCOUNT);
// The amount of tokens from the `_amount` to pay as a fee. If reverse, the fee taken from a payout of `_amount`.return PRBMath.mulDiv(_amount, _discountedFeePercent, JBConstants.MAX_FEE);
}
}
Contract Source Code
File 47 of 70: JBFixedPointNumber.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.16;libraryJBFixedPointNumber{
functionadjustDecimals(uint256 _value,
uint256 _decimals,
uint256 _targetDecimals
) internalpurereturns (uint256) {
// If decimals need adjusting, multiply or divide the price by the decimal adjuster to get the normalized result.if (_targetDecimals == _decimals) return _value;
elseif (_targetDecimals > _decimals) return _value *10**(_targetDecimals - _decimals);
elsereturn _value /10**(_decimals - _targetDecimals);
}
}
Contract Source Code
File 48 of 70: JBFundAccessConstraints.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;import {IJBPaymentTerminal} from'./../interfaces/IJBPaymentTerminal.sol';
/// @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.structJBFundAccessConstraints {
IJBPaymentTerminal terminal;
address token;
uint256 distributionLimit;
uint256 distributionLimitCurrency;
uint256 overflowAllowance;
uint256 overflowAllowanceCurrency;
}
Contract Source Code
File 49 of 70: JBFundingCycle.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;import {IJBFundingCycleBallot} from'./../interfaces/IJBFundingCycleBallot.sol';
/// @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.structJBFundingCycle {
uint256 number;
uint256 configuration;
uint256 basedOn;
uint256 start;
uint256 duration;
uint256 weight;
uint256 discountRate;
IJBFundingCycleBallot ballot;
uint256 metadata;
}
Contract Source Code
File 50 of 70: JBFundingCycleData.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;import {IJBFundingCycleBallot} from'./../interfaces/IJBFundingCycleBallot.sol';
/// @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.structJBFundingCycleData {
uint256 duration;
uint256 weight;
uint256 discountRate;
IJBFundingCycleBallot ballot;
}
Contract Source Code
File 51 of 70: JBFundingCycleMetadata.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;import {JBGlobalFundingCycleMetadata} from'./JBGlobalFundingCycleMetadata.sol';
/// @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.structJBFundingCycleMetadata {
JBGlobalFundingCycleMetadata global;
uint256 reservedRate;
uint256 redemptionRate;
uint256 ballotRedemptionRate;
bool pausePay;
bool pauseDistributions;
bool pauseRedeem;
bool pauseBurn;
bool allowMinting;
bool allowTerminalMigration;
bool allowControllerMigration;
bool holdFees;
bool preferClaimedTokenOverride;
bool useTotalOverflowForRedemptions;
bool useDataSourceForPay;
bool useDataSourceForRedeem;
address dataSource;
uint256 metadata;
}
Contract Source Code
File 52 of 70: JBFundingCycleMetadataResolver.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.16;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';
libraryJBFundingCycleMetadataResolver{
functionglobal(JBFundingCycle memory _fundingCycle)
internalpurereturns (JBGlobalFundingCycleMetadata memory)
{
return JBGlobalFundingCycleMetadataResolver.expandMetadata(uint8(_fundingCycle.metadata >>8));
}
functionreservedRate(JBFundingCycle memory _fundingCycle) internalpurereturns (uint256) {
returnuint256(uint16(_fundingCycle.metadata >>24));
}
functionredemptionRate(JBFundingCycle memory _fundingCycle) internalpurereturns (uint256) {
// Redemption rate is a number 0-10000. It's inverse was stored so the most common case of 100% results in no storage needs.return JBConstants.MAX_REDEMPTION_RATE -uint256(uint16(_fundingCycle.metadata >>40));
}
functionballotRedemptionRate(JBFundingCycle memory _fundingCycle)
internalpurereturns (uint256)
{
// Redemption rate is a number 0-10000. It's inverse was stored so the most common case of 100% results in no storage needs.return JBConstants.MAX_REDEMPTION_RATE -uint256(uint16(_fundingCycle.metadata >>56));
}
functionpayPaused(JBFundingCycle memory _fundingCycle) internalpurereturns (bool) {
return ((_fundingCycle.metadata >>72) &1) ==1;
}
functiondistributionsPaused(JBFundingCycle memory _fundingCycle) internalpurereturns (bool) {
return ((_fundingCycle.metadata >>73) &1) ==1;
}
functionredeemPaused(JBFundingCycle memory _fundingCycle) internalpurereturns (bool) {
return ((_fundingCycle.metadata >>74) &1) ==1;
}
functionburnPaused(JBFundingCycle memory _fundingCycle) internalpurereturns (bool) {
return ((_fundingCycle.metadata >>75) &1) ==1;
}
functionmintingAllowed(JBFundingCycle memory _fundingCycle) internalpurereturns (bool) {
return ((_fundingCycle.metadata >>76) &1) ==1;
}
functionterminalMigrationAllowed(JBFundingCycle memory _fundingCycle)
internalpurereturns (bool)
{
return ((_fundingCycle.metadata >>77) &1) ==1;
}
functioncontrollerMigrationAllowed(JBFundingCycle memory _fundingCycle)
internalpurereturns (bool)
{
return ((_fundingCycle.metadata >>78) &1) ==1;
}
functionshouldHoldFees(JBFundingCycle memory _fundingCycle) internalpurereturns (bool) {
return ((_fundingCycle.metadata >>79) &1) ==1;
}
functionpreferClaimedTokenOverride(JBFundingCycle memory _fundingCycle)
internalpurereturns (bool)
{
return ((_fundingCycle.metadata >>80) &1) ==1;
}
functionuseTotalOverflowForRedemptions(JBFundingCycle memory _fundingCycle)
internalpurereturns (bool)
{
return ((_fundingCycle.metadata >>81) &1) ==1;
}
functionuseDataSourceForPay(JBFundingCycle memory _fundingCycle) internalpurereturns (bool) {
return (_fundingCycle.metadata >>82) &1==1;
}
functionuseDataSourceForRedeem(JBFundingCycle memory _fundingCycle)
internalpurereturns (bool)
{
return (_fundingCycle.metadata >>83) &1==1;
}
functiondataSource(JBFundingCycle memory _fundingCycle) internalpurereturns (address) {
returnaddress(uint160(_fundingCycle.metadata >>84));
}
functionmetadata(JBFundingCycle memory _fundingCycle) internalpurereturns (uint256) {
returnuint256(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. functionpackFundingCycleMetadata(JBFundingCycleMetadata memory _metadata)
internalpurereturns (uint256 packed)
{
// version 1 in the bits 0-7 (8 bits).
packed =1;
// global metadta in bits 8-23 (16 bits).
packed |=
JBGlobalFundingCycleMetadataResolver.packFundingCycleGlobalMetadata(_metadata.global) <<8;
// reserved rate in bits 24-39 (16 bits).
packed |= _metadata.reservedRate <<24;
// redemption rate in bits 40-55 (16 bits).// redemption rate is a number 0-10000. Store the reverse so the most common case of 100% results in no storage needs.
packed |= (JBConstants.MAX_REDEMPTION_RATE - _metadata.redemptionRate) <<40;
// ballot redemption rate rate in bits 56-71 (16 bits).// ballot redemption rate is a number 0-10000. Store the reverse so the most common case of 100% results in no storage needs.
packed |= (JBConstants.MAX_REDEMPTION_RATE - _metadata.ballotRedemptionRate) <<56;
// pause pay in bit 72.if (_metadata.pausePay) packed |=1<<72;
// pause tap in bit 73.if (_metadata.pauseDistributions) packed |=1<<73;
// pause redeem in bit 74.if (_metadata.pauseRedeem) packed |=1<<74;
// pause burn in bit 75.if (_metadata.pauseBurn) packed |=1<<75;
// allow minting in bit 76.if (_metadata.allowMinting) packed |=1<<76;
// allow terminal migration in bit 77.if (_metadata.allowTerminalMigration) packed |=1<<77;
// allow controller migration in bit 78.if (_metadata.allowControllerMigration) packed |=1<<78;
// hold fees in bit 79.if (_metadata.holdFees) packed |=1<<79;
// prefer claimed token override in bit 80.if (_metadata.preferClaimedTokenOverride) packed |=1<<80;
// useTotalOverflowForRedemptions in bit 81.if (_metadata.useTotalOverflowForRedemptions) packed |=1<<81;
// use pay data source in bit 82.if (_metadata.useDataSourceForPay) packed |=1<<82;
// use redeem data source in bit 83.if (_metadata.useDataSourceForRedeem) packed |=1<<83;
// data source address in bits 84-243.
packed |=uint256(uint160(address(_metadata.dataSource))) <<84;
// metadata in bits 244-252 (8 bits).
packed |= _metadata.metadata <<244;
}
/// @notice Expand the funding cycle metadata./// @param _fundingCycle The funding cycle having its metadata expanded./// @return metadata The metadata object. functionexpandMetadata(JBFundingCycle memory _fundingCycle)
internalpurereturns (JBFundingCycleMetadata memory)
{
return
JBFundingCycleMetadata(
global(_fundingCycle),
reservedRate(_fundingCycle),
redemptionRate(_fundingCycle),
ballotRedemptionRate(_fundingCycle),
payPaused(_fundingCycle),
distributionsPaused(_fundingCycle),
redeemPaused(_fundingCycle),
burnPaused(_fundingCycle),
mintingAllowed(_fundingCycle),
terminalMigrationAllowed(_fundingCycle),
controllerMigrationAllowed(_fundingCycle),
shouldHoldFees(_fundingCycle),
preferClaimedTokenOverride(_fundingCycle),
useTotalOverflowForRedemptions(_fundingCycle),
useDataSourceForPay(_fundingCycle),
useDataSourceForRedeem(_fundingCycle),
dataSource(_fundingCycle),
metadata(_fundingCycle)
);
}
}
Contract Source Code
File 53 of 70: JBGlobalFundingCycleMetadata.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;/// @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.structJBGlobalFundingCycleMetadata {
bool allowSetTerminals;
bool allowSetController;
bool pauseTransfers;
}
Contract Source Code
File 54 of 70: JBGlobalFundingCycleMetadataResolver.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.16;import {JBFundingCycleMetadata} from'./../structs/JBFundingCycleMetadata.sol';
import {JBGlobalFundingCycleMetadata} from'./../structs/JBGlobalFundingCycleMetadata.sol';
libraryJBGlobalFundingCycleMetadataResolver{
functionsetTerminalsAllowed(uint8 _data) internalpurereturns (bool) {
return (_data &1) ==1;
}
functionsetControllerAllowed(uint8 _data) internalpurereturns (bool) {
return ((_data >>1) &1) ==1;
}
functiontransfersPaused(uint8 _data) internalpurereturns (bool) {
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.functionpackFundingCycleGlobalMetadata(
JBGlobalFundingCycleMetadata memory _metadata
) internalpurereturns (uint256 packed) {
// allow set terminals in bit 0.if (_metadata.allowSetTerminals) packed |=1;
// allow set controller in bit 1.if (_metadata.allowSetController) packed |=1<<1;
// pause transfers in bit 2.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.functionexpandMetadata(uint8 _packedMetadata
) internalpurereturns (JBGlobalFundingCycleMetadata memory metadata) {
return
JBGlobalFundingCycleMetadata(
setTerminalsAllowed(_packedMetadata),
setControllerAllowed(_packedMetadata),
transfersPaused(_packedMetadata)
);
}
}
Contract Source Code
File 55 of 70: JBGroupedSplits.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;import {JBSplit} from'./JBSplit.sol';
/// @custom:member group The group indentifier./// @custom:member splits The splits to associate with the group.structJBGroupedSplits {
uint256 group;
JBSplit[] splits;
}
Contract Source Code
File 56 of 70: JBOperatable.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.16;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.abstractcontractJBOperatableisIJBOperatable{
//*********************************************************************//// --------------------------- custom errors -------------------------- ////*********************************************************************//errorUNAUTHORIZED();
//*********************************************************************//// ---------------------------- 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.modifierrequirePermission(address _account,
uint256 _domain,
uint256 _permissionIndex
) {
_requirePermission(_account, _domain, _permissionIndex);
_;
}
/// @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.modifierrequirePermissionAllowingOverride(address _account,
uint256 _domain,
uint256 _permissionIndex,
bool _override
) {
_requirePermissionAllowingOverride(_account, _domain, _permissionIndex, _override);
_;
}
//*********************************************************************//// ---------------- public immutable stored properties --------------- ////*********************************************************************///// @notice A contract storing operator assignments.
IJBOperatorStore publicimmutableoverride operatorStore;
//*********************************************************************//// -------------------------- constructor ---------------------------- ////*********************************************************************///// @param _operatorStore A contract storing operator assignments.constructor(IJBOperatorStore _operatorStore) {
operatorStore = _operatorStore;
}
//*********************************************************************//// -------------------------- 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.function_requirePermission(address _account,
uint256 _domain,
uint256 _permissionIndex
) internalview{
if (
msg.sender!= _account &&!operatorStore.hasPermission(msg.sender, _account, _domain, _permissionIndex) &&!operatorStore.hasPermission(msg.sender, _account, 0, _permissionIndex)
) 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.function_requirePermissionAllowingOverride(address _account,
uint256 _domain,
uint256 _permissionIndex,
bool _override
) internalview{
if (
!_override &&msg.sender!= _account &&!operatorStore.hasPermission(msg.sender, _account, _domain, _permissionIndex) &&!operatorStore.hasPermission(msg.sender, _account, 0, _permissionIndex)
) revert UNAUTHORIZED();
}
}
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;/// @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.structJBOperatorData {
address operator;
uint256 domain;
uint256[] permissionIndexes;
}
Contract Source Code
File 59 of 70: JBPayDelegateAllocation3_1_1.sol
// SPDX-License-Identifier: MITpragmasolidity ^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.structJBPayDelegateAllocation3_1_1 {
IJBPayDelegate3_1_1 delegate;
uint256 amount;
bytes metadata;
}
Contract Source Code
File 60 of 70: JBPayoutRedemptionPaymentTerminal3_1_2.sol
// SPDX-License-Identifier: MITpragmasolidity ^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 {JBFees} from'./../libraries/JBFees.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.abstractcontractJBPayoutRedemptionPaymentTerminal3_1_2isJBSingleTokenPaymentTerminal,
JBOperatable,
Ownable,
IJBPayoutRedemptionPaymentTerminal3_1_1{
// A library that parses the packed funding cycle metadata into a friendlier format.usingJBFundingCycleMetadataResolverforJBFundingCycle;
//*********************************************************************//// --------------------------- custom errors ------------------------- ////*********************************************************************//errorFEE_TOO_HIGH();
errorINADEQUATE_DISTRIBUTION_AMOUNT();
errorINADEQUATE_RECLAIM_AMOUNT();
errorINADEQUATE_TOKEN_COUNT();
errorNO_MSG_VALUE_ALLOWED();
errorPAY_TO_ZERO_ADDRESS();
errorPROJECT_TERMINAL_MISMATCH();
errorREDEEM_TO_ZERO_ADDRESS();
errorTERMINAL_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).uint256internalconstant _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.uint256internalconstant _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 publicimmutableoverride projects;
/// @notice The directory of terminals and controllers for projects.
IJBDirectory publicimmutableoverride directory;
/// @notice The contract that stores splits for each project.
IJBSplitsStore publicimmutableoverride splitsStore;
/// @notice The contract that exposes price feeds.
IJBPrices publicimmutableoverride prices;
/// @notice The contract that stores and manages the terminal's data.addresspublicimmutableoverride 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`.uint256publicimmutableoverride baseWeightCurrency;
/// @notice The group that payout splits coming from this terminal are identified by.uint256publicimmutableoverride payoutSplitsGroup;
//*********************************************************************//// --------------------- public stored properties -------------------- ////*********************************************************************///// @notice The platform fee percent./// @dev Out of MAX_FEE (25_000_000 / 1_000_000_000)uint256publicoverride fee =25_000_000; // 2.5%/// @notice The data source that returns a discount to apply to a project's fee.addresspublicoverride 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) publicoverride 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.functioncurrentEthOverflowOf(uint256 _projectId
) externalviewvirtualoverridereturns (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.functionheldFeesOf(uint256 _projectId) externalviewoverridereturns (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.functionsupportsInterface(bytes4 _interfaceId
) publicviewvirtualoverride(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() internalviewvirtualreturns (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==0address _token,
uint256 _decimals,
uint256 _currency,
uint256 _baseWeightCurrency,
uint256 _payoutSplitsGroup,
IJBOperatorStore _operatorStore,
IJBProjects _projects,
IJBDirectory _directory,
IJBSplitsStore _splitsStore,
IJBPrices _prices,
address _store,
address _owner
)
payableJBSingleTokenPaymentTerminal(_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.functionpay(uint256 _projectId,
uint256 _amount,
address _token,
address _beneficiary,
uint256 _minReturnedTokens,
bool _preferClaimedTokens,
stringcalldata _memo,
bytescalldata _metadata
) externalpayablevirtualoverridereturns (uint256) {
_token; // Prevents unused var compiler and natspec complaints.// 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.functionredeemTokensOf(address _holder,
uint256 _projectId,
uint256 _tokenCount,
address _token,
uint256 _minReturnedTokens,
addresspayable _beneficiary,
stringmemory _memo,
bytesmemory _metadata
)
externalvirtualoverriderequirePermission(_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.functiondistributePayoutsOf(uint256 _projectId,
uint256 _amount,
uint256 _currency,
address _token,
uint256 _minReturnedTokens,
bytescalldata _metadata
) externalvirtualoverridereturns (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.functionuseAllowanceOf(uint256 _projectId,
uint256 _amount,
uint256 _currency,
address _token,
uint256 _minReturnedTokens,
addresspayable _beneficiary,
stringmemory _memo,
bytescalldata _metadata
)
externalvirtualoverriderequirePermission(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.functionmigrate(uint256 _projectId,
IJBPaymentTerminal _to
)
externalvirtualoverriderequirePermission(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.functionaddToBalanceOf(uint256 _projectId,
uint256 _amount,
address _token,
stringcalldata _memo,
bytescalldata _metadata
) externalpayablevirtualoverride{
// 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.functionprocessFees(uint256 _projectId
)
externalvirtualoverriderequirePermissionAllowingOverride(
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 stackuint256 _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
: JBFees.feeIn(_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.functionsetFee(uint256 _fee) externalvirtualoverrideonlyOwner{
// 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.functionsetFeeGauge(address _feeGauge) externalvirtualoverrideonlyOwner{
// 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.functionsetFeelessAddress(address _address, bool _flag) externalvirtualoverrideonlyOwner{
// 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.functionaddToBalanceOf(uint256 _projectId,
uint256 _amount,
address _token,
bool _shouldRefundHeldFees,
stringcalldata _memo,
bytescalldata _metadata
) publicpayablevirtualoverride{
_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, addresspayable _to, uint256 _amount) internalvirtual{
_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) internalvirtual{
_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) internalvirtual{
_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.function_redeemTokensOf(address _holder,
uint256 _projectId,
uint256 _tokenCount,
uint256 _minReturnedTokens,
addresspayable _beneficiary,
stringmemory _memo,
bytesmemory _metadata
) internalreturns (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
: JBFees.feeIn(_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
: JBFees.feeIn(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,
bytescalldata _metadata
) internalreturns (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.addresspayable _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
: JBFees.feeIn(_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,
addresspayable _beneficiary,
stringmemory _memo,
bytescalldata _metadata
) internalreturns (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
) internalreturns (uint256, uint256 feeEligibleDistributionAmount) {
// The total percentage available to splituint256 _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
) internalreturns (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 -= JBFees.feeIn(_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.bytesmemory _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 (bytesmemory __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.
} elseif (_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 -= JBFees.feeIn(_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 (bytesmemory _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);
}
elsetry
_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 (bytesmemory _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 -= JBFees.feeIn(_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
) internalreturns (uint256 feeAmount) {
feeAmount = JBFees.feeIn(_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 (bytesmemory _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,
stringmemory _memo,
bytesmemory _metadata
) internalreturns (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,
stringmemory _memo,
bytesmemory _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 terminalfunction_refundHeldFees(uint256 _projectId,
uint256 _amount
) internalreturns (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 stackuint256 _heldFeesLength = _heldFees.length;
// Process each fee.for (uint256 _i; _i < _heldFeesLength; ) {
if (leftoverAmount ==0) {
_heldFeesOf[_projectId].push(_heldFees[_i]);
} else {
// Notice here we take feeIn the stored .amountuint256 _feeAmount = (
_heldFees[_i].fee ==0|| _heldFees[_i].feeDiscount == JBConstants.MAX_FEE_DISCOUNT
? 0
: JBFees.feeIn(_heldFees[_i].amount, _heldFees[_i].fee, _heldFees[_i].feeDiscount)
);
if (leftoverAmount >= _heldFees[_i].amount - _feeAmount) {
unchecked {
leftoverAmount = leftoverAmount - (_heldFees[_i].amount - _feeAmount);
refundedFees += _feeAmount;
}
} else {
// And here we overwrite with feeFrom the leftoverAmount
_feeAmount = (
_heldFees[_i].fee ==0|| _heldFees[_i].feeDiscount == JBConstants.MAX_FEE_DISCOUNT
? 0
: JBFees.feeFrom(leftoverAmount, _heldFees[_i].fee, _heldFees[_i].feeDiscount)
);
unchecked {
_heldFeesOf[_projectId].push(
JBFee(
_heldFees[_i].amount - (leftoverAmount + _feeAmount),
_heldFees[_i].fee,
_heldFees[_i].feeDiscount,
_heldFees[_i].beneficiary
)
);
refundedFees += _feeAmount;
}
leftoverAmount =0;
}
}
unchecked {
++_i;
}
}
emit RefundHeldFees(_projectId, _amount, refundedFees, leftoverAmount, msg.sender);
}
/// @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
) internalviewreturns (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 valueif (discount <= JBConstants.MAX_FEE_DISCOUNT) return discount;
} catch {
return0;
}
return0;
}
}
Contract Source Code
File 61 of 70: JBProjectMetadata.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;/// @custom:member content The metadata content./// @custom:member domain The domain within which the metadata applies.structJBProjectMetadata {
string content;
uint256 domain;
}
Contract Source Code
File 62 of 70: JBRedemptionDelegateAllocation3_1_1.sol
// SPDX-License-Identifier: MITpragmasolidity ^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.structJBRedemptionDelegateAllocation3_1_1 {
IJBRedemptionDelegate3_1_1 delegate;
uint256 amount;
bytes metadata;
}
Contract Source Code
File 63 of 70: JBSingleTokenPaymentTerminal.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.16;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.abstractcontractJBSingleTokenPaymentTerminalisERC165, IJBSingleTokenPaymentTerminal{
//*********************************************************************//// ---------------- public immutable stored properties --------------- ////*********************************************************************///// @notice The token that this terminal accepts.addresspublicimmutableoverride token;
/// @notice The number of decimals the token fixed point amounts are expected to have.uint256publicimmutableoverride decimals;
/// @notice The currency to use when resolving price feeds for this terminal.uint256publicimmutableoverride 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.functionacceptsToken(address _token, uint256 _projectId) externalviewoverridereturns (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.functiondecimalsForToken(address _token) externalviewoverridereturns (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.functioncurrencyForToken(address _token) externalviewoverridereturns (uint256) {
_token; // Prevents unused var compiler and natspec complaints.return currency;
}
//*********************************************************************//// -------------------------- 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.functionsupportsInterface(bytes4 _interfaceId
) publicviewvirtualoverride(ERC165, IERC165) returns (bool) {
return
_interfaceId ==type(IJBPaymentTerminal).interfaceId||
_interfaceId ==type(IJBSingleTokenPaymentTerminal).interfaceId||super.supportsInterface(_interfaceId);
}
//*********************************************************************//// -------------------------- 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) {
token = _token;
decimals = _decimals;
currency = _currency;
}
}
Contract Source Code
File 64 of 70: JBSplit.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;import {IJBSplitAllocator} from'./../interfaces/IJBSplitAllocator.sol';
/// @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.structJBSplit {
bool preferClaimed;
bool preferAddToBalance;
uint256 percent;
uint256 projectId;
addresspayable beneficiary;
uint256 lockedUntil;
IJBSplitAllocator allocator;
}
Contract Source Code
File 65 of 70: JBSplitAllocationData.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;import {JBSplit} from'./JBSplit.sol';
/// @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.structJBSplitAllocationData {
address token;
uint256 amount;
uint256 decimals;
uint256 projectId;
uint256 group;
JBSplit split;
}
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;/// @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.structJBTokenAmount {
address token;
uint256 value;
uint256 decimals;
uint256 currency;
}
Contract Source Code
File 68 of 70: JBTokens.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;libraryJBTokens{
/// @notice The ETH token address in Juicebox is represented by 0x000000000000000000000000000000000000EEEe.addresspublicconstant ETH =address(0x000000000000000000000000000000000000EEEe);
}
Contract Source Code
File 69 of 70: Ownable.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)pragmasolidity ^0.8.0;import"../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/abstractcontractOwnableisContext{
addressprivate _owner;
eventOwnershipTransferred(addressindexed previousOwner, addressindexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Returns the address of the current owner.
*/functionowner() publicviewvirtualreturns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/modifieronlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
/**
* @dev 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.
*/functionrenounceOwnership() publicvirtualonlyOwner{
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/functiontransferOwnership(address newOwner) publicvirtualonlyOwner{
require(newOwner !=address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/function_transferOwnership(address newOwner) internalvirtual{
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}