JBPayoutRedemptionPaymentTerminal diff
40 removals
669 lines
47 additions
676 lines
// SPDX-License-Identifier: MIT
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.16;
pragma solidity ^0.8.16;
import '@openzeppelin/contracts/access/Ownable.sol';
import '@openzeppelin/contracts/access/Ownable.sol';
import '@openzeppelin/contracts/utils/introspection/ERC165Checker.sol';
import '@paulrberg/contracts/math/PRBMath.sol';
import '@paulrberg/contracts/math/PRBMath.sol';
import './../interfaces/IJBController.sol';
import './../interfaces/IJBController.sol';
import './../interfaces/IJBPayoutRedemptionPaymentTerminal.sol';
import './../interfaces/IJBPayoutRedemptionPaymentTerminal3_1.sol';
import './../libraries/JBConstants.sol';
import './../libraries/JBConstants.sol';
import './../libraries/JBCurrencies.sol';
import './../libraries/JBCurrencies.sol';
import './../libraries/JBFixedPointNumber.sol';
import './../libraries/JBFixedPointNumber.sol';
import './../libraries/JBFundingCycleMetadataResolver.sol';
import './../libraries/JBFundingCycleMetadataResolver.sol';
import './../libraries/JBOperations.sol';
import './../libraries/JBOperations.sol';
import './../libraries/JBTokens.sol';
import './../libraries/JBTokens.sol';
import './../structs/JBPayDelegateAllocation.sol';
import './../structs/JBPayDelegateAllocation.sol';
import './../structs/JBTokenAmount.sol';
import './../structs/JBTokenAmount.sol';
import './JBOperatable.sol';
import './JBOperatable.sol';
import './JBSingleTokenPaymentTerminal.sol';
import './JBSingleTokenPaymentTerminal.sol';
/**
/**
@notice
@notice
Generic terminal managing all inflows and outflows of funds into the protocol ecosystem.
Generic terminal managing all inflows and outflows of funds into the protocol ecosystem.
@dev
@dev
A project can transfer its funds, along with the power to reconfigure and mint/burn their tokens, from this contract to another allowed terminal of the same token type contract at any time.
A project can transfer its funds, along with the power to reconfigure and mint/burn their tokens, from this contract to another allowed terminal of the same token type contract at any time.
@dev
@dev
Adheres to -
Adheres to -
IJBPayoutRedemptionPaymentTerminal: General interface for the methods in this contract that interact with the blockchain's state according to the protocol's rules.
IJBPayoutRedemptionPaymentTerminal3_1: General interface for the methods in this contract that interact with the blockchain's state according to the protocol's rules.
@dev
@dev
Inherits from -
Inherits from -
JBSingleTokenPaymentTerminal: Generic terminal managing all inflows of funds into the protocol ecosystem for one token.
JBSingleTokenPaymentTerminal: Generic terminal managing all inflows of funds into the protocol ecosystem for one token.
JBOperatable: Includes convenience functionality for checking a message sender's permissions before executing certain transactions.
JBOperatable: Includes convenience functionality for checking a message sender's permissions before executing certain transactions.
Ownable: Includes convenience functionality for checking a message sender's permissions before executing certain transactions.
Ownable: Includes convenience functionality for checking a message sender's permissions before executing certain transactions.
*/
*/
abstract contract JBPayoutRedemptionPaymentTerminal is
abstract contract JBPayoutRedemptionPaymentTerminal3_1 is
JBSingleTokenPaymentTerminal,
JBSingleTokenPaymentTerminal,
JBOperatable,
JBOperatable,
Ownable,
Ownable,
IJBPayoutRedemptionPaymentTerminal
IJBPayoutRedemptionPaymentTerminal3_1
{
{
// A library that parses the packed funding cycle metadata into a friendlier format.
// A library that parses the packed funding cycle metadata into a friendlier format.
using JBFundingCycleMetadataResolver for JBFundingCycle;
using JBFundingCycleMetadataResolver for JBFundingCycle;
//*********************************************************************//
//*********************************************************************//
// --------------------------- custom errors ------------------------- //
// --------------------------- custom errors ------------------------- //
//*********************************************************************//
//*********************************************************************//
error FEE_TOO_HIGH();
error FEE_TOO_HIGH();
error INADEQUATE_DISTRIBUTION_AMOUNT();
error INADEQUATE_DISTRIBUTION_AMOUNT();
error INADEQUATE_RECLAIM_AMOUNT();
error INADEQUATE_RECLAIM_AMOUNT();
error INADEQUATE_TOKEN_COUNT();
error INADEQUATE_TOKEN_COUNT();
error NO_MSG_VALUE_ALLOWED();
error NO_MSG_VALUE_ALLOWED();
error PAY_TO_ZERO_ADDRESS();
error PAY_TO_ZERO_ADDRESS();
error PROJECT_TERMINAL_MISMATCH();
error PROJECT_TERMINAL_MISMATCH();
error REDEEM_TO_ZERO_ADDRESS();
error REDEEM_TO_ZERO_ADDRESS();
error TERMINAL_IN_SPLIT_ZERO_ADDRESS();
error TERMINAL_IN_SPLIT_ZERO_ADDRESS();
error TERMINAL_TOKENS_INCOMPATIBLE();
error TERMINAL_TOKENS_INCOMPATIBLE();
//*********************************************************************//
//*********************************************************************//
// ---------------------------- modifiers ---------------------------- //
// ---------------------------- modifiers ---------------------------- //
//*********************************************************************//
//*********************************************************************//
/**
/**
@notice
@notice
A modifier that verifies this terminal is a terminal of provided project ID.
A modifier that verifies this terminal is a terminal of provided project ID.
*/
*/
modifier isTerminalOf(uint256 _projectId) {
modifier isTerminalOf(uint256 _projectId) {
if (!directory.isTerminalOf(_projectId, this)) revert PROJECT_TERMINAL_MISMATCH();
if (!directory.isTerminalOf(_projectId, this)) revert PROJECT_TERMINAL_MISMATCH();
_;
_;
}
}
//*********************************************************************//
//*********************************************************************//
// --------------------- internal stored constants ------------------- //
// --------------------- internal stored constants ------------------- //
//*********************************************************************//
//*********************************************************************//
/**
/**
@notice
@notice
Maximum fee that can be set for a funding cycle configuration.
Maximum fee that can be set for a funding cycle configuration.
@dev
@dev
Out of MAX_FEE (50_000_000 / 1_000_000_000).
Out of MAX_FEE (50_000_000 / 1_000_000_000).
*/
*/
uint256 internal constant _FEE_CAP = 50_000_000;
uint256 internal constant _FEE_CAP = 50_000_000;
/**
/**
@notice
@notice
The fee beneficiary project ID is 1, as it should be the first project launched during the deployment process.
The fee beneficiary project ID is 1, as it should be the first project launched during the deployment process.
*/
*/
uint256 internal constant _FEE_BENEFICIARY_PROJECT_ID = 1;
uint256 internal constant _FEE_BENEFICIARY_PROJECT_ID = 1;
//*********************************************************************//
//*********************************************************************//
// --------------------- internal stored properties ------------------ //
// --------------------- internal stored properties ------------------ //
//*********************************************************************//
//*********************************************************************//
/**
/**
@notice
@notice
Fees that are being held to be processed later.
Fees that are being held to be processed later.
_projectId The ID of the project for which fees are being held.
_projectId The ID of the project for which fees are being held.
*/
*/
mapping(uint256 => JBFee[]) internal _heldFeesOf;
mapping(uint256 => JBFee[]) internal _heldFeesOf;
//*********************************************************************//
//*********************************************************************//
// ---------------- public immutable stored properties --------------- //
// ---------------- public immutable stored properties --------------- //
//*********************************************************************//
//*********************************************************************//
/**
/**
@notice
@notice
Mints ERC-721's that represent project ownership and transfers.
Mints ERC-721's that represent project ownership and transfers.
*/
*/
IJBProjects public immutable override projects;
IJBProjects public immutable override projects;
/**
/**
@notice
@notice
The directory of terminals and controllers for projects.
The directory of terminals and controllers for projects.
*/
*/
IJBDirectory public immutable override directory;
IJBDirectory public immutable override directory;
/**
/**
@notice
@notice
The contract that stores splits for each project.
The contract that stores splits for each project.
*/
*/
IJBSplitsStore public immutable override splitsStore;
IJBSplitsStore public immutable override splitsStore;
/**
/**
@notice
@notice
The contract that exposes price feeds.
The contract that exposes price feeds.
*/
*/
IJBPrices public immutable override prices;
IJBPrices public immutable override prices;
/**
/**
@notice
@notice
The contract that stores and manages the terminal's data.
The contract that stores and manages the terminal's data.
*/
*/
IJBSingleTokenPaymentTerminalStore public immutable override store;
IJBSingleTokenPaymentTerminalStore public immutable override store;
/**
/**
@notice
@notice
The currency to base token issuance on.
The currency to base token issuance on.
@dev
@dev
If this differs from `currency`, there must be a price feed available to convert `currency` to `baseWeightCurrency`.
If this differs from `currency`, there must be a price feed available to convert `currency` to `baseWeightCurrency`.
*/
*/
uint256 public immutable override baseWeightCurrency;
uint256 public immutable override baseWeightCurrency;
/**
/**
@notice
@notice
The group that payout splits coming from this terminal are identified by.
The group that payout splits coming from this terminal are identified by.
*/
*/
uint256 public immutable override payoutSplitsGroup;
uint256 public immutable override payoutSplitsGroup;
//*********************************************************************//
//*********************************************************************//
// --------------------- public stored properties -------------------- //
// --------------------- public stored properties -------------------- //
//*********************************************************************//
//*********************************************************************//
/**
/**
@notice
@notice
The platform fee percent.
The platform fee percent.
@dev
@dev
Out of MAX_FEE (25_000_000 / 1_000_000_000)
Out of MAX_FEE (25_000_000 / 1_000_000_000)
*/
*/
uint256 public override fee = 25_000_000; // 2.5%
uint256 public override fee = 25_000_000; // 2.5%
/**
/**
@notice
@notice
The data source that returns a discount to apply to a project's fee.
The data source that returns a discount to apply to a project's fee.
*/
*/
IJBFeeGauge public override feeGauge;
IJBFeeGauge public override feeGauge;
/**
/**
@notice
@notice
Addresses that can be paid towards from this terminal without incurring a fee.
Addresses that can be paid towards from this terminal without incurring a fee.
@dev
@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.
Only addresses that are considered to be contained within the ecosystem can be feeless. Funds sent outside the ecosystem may incur fees despite being stored as feeless.
_address The address that can be paid toward.
_address The address that can be paid toward.
*/
*/
mapping(address => bool) public override isFeelessAddress;
mapping(address => bool) public override isFeelessAddress;
//*********************************************************************//
//*********************************************************************//
// ------------------------- external views -------------------------- //
// ------------------------- external views -------------------------- //
//*********************************************************************//
//*********************************************************************//
/**
/**
@notice
@notice
Gets the current overflowed amount in this terminal for a specified project, in terms of ETH.
Gets the current overflowed amount in this terminal for a specified project, in terms of ETH.
@dev
@dev
The current overflow is represented as a fixed point number with 18 decimals.
The current overflow is represented as a fixed point number with 18 decimals.
@param _projectId The ID of the project to get overflow for.
@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.
@return The current amount of ETH overflow that project has in this terminal, as a fixed point number with 18 decimals.
*/
*/
function currentEthOverflowOf(uint256 _projectId)
function currentEthOverflowOf(uint256 _projectId)
external
external
view
view
virtual
virtual
override
override
returns (uint256)
returns (uint256)
{
{
// Get this terminal's current overflow.
// Get this terminal's current overflow.
uint256 _overflow = store.currentOverflowOf(this, _projectId);
uint256 _overflow = store.currentOverflowOf(this, _projectId);
// Adjust the decimals of the fixed point number if needed to have 18 decimals.
// Adjust the decimals of the fixed point number if needed to have 18 decimals.
uint256 _adjustedOverflow = (decimals == 18)
uint256 _adjustedOverflow = (decimals == 18)
? _overflow
? _overflow
: JBFixedPointNumber.adjustDecimals(_overflow, decimals, 18);
: JBFixedPointNumber.adjustDecimals(_overflow, decimals, 18);
// Return the amount converted to ETH.
// Return the amount converted to ETH.
return
return
(currency == JBCurrencies.ETH)
(currency == JBCurrencies.ETH)
? _adjustedOverflow
? _adjustedOverflow
: PRBMath.mulDiv(
: PRBMath.mulDiv(
_adjustedOverflow,
_adjustedOverflow,
10**decimals,
10**decimals,
prices.priceFor(currency, JBCurrencies.ETH, decimals)
prices.priceFor(currency, JBCurrencies.ETH, decimals)
);
);
}
}
/**
/**
@notice
@notice
The fees that are currently being held to be processed later for each project.
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.
@param _projectId The ID of the project for which fees are being held.
@return An array of fees that are being held.
@return An array of fees that are being held.
*/
*/
function heldFeesOf(uint256 _projectId) external view override returns (JBFee[] memory) {
function heldFeesOf(uint256 _projectId) external view override returns (JBFee[] memory) {
return _heldFeesOf[_projectId];
return _heldFeesOf[_projectId];
}
}
//*********************************************************************//
//*********************************************************************//
// -------------------------- public views --------------------------- //
// -------------------------- public views --------------------------- //
//*********************************************************************//
//*********************************************************************//
/**
/**
@notice
@notice
Indicates if this contract adheres to the specified interface.
Indicates if this contract adheres to the specified interface.
@dev
@dev
See {IERC165-supportsInterface}.
See {IERC165-supportsInterface}.
@param _interfaceId The ID of the interface to check for adherance to.
@param _interfaceId The ID of the interface to check for adherance to.
*/
*/
function supportsInterface(bytes4 _interfaceId)
function supportsInterface(bytes4 _interfaceId)
public
public
view
view
virtual
virtual
override(JBSingleTokenPaymentTerminal, IERC165)
override(JBSingleTokenPaymentTerminal, IERC165)
returns (bool)
returns (bool)
{
{
return
return
_interfaceId == type(IJBPayoutRedemptionPaymentTerminal).interfaceId ||
_interfaceId == type(IJBPayoutRedemptionPaymentTerminal3_1).interfaceId ||
_interfaceId == type(IJBPayoutTerminal).interfaceId ||
_interfaceId == type(IJBPayoutTerminal3_1).interfaceId ||
_interfaceId == type(IJBAllowanceTerminal).interfaceId ||
_interfaceId == type(IJBAllowanceTerminal3_1).interfaceId ||
_interfaceId == type(IJBRedemptionTerminal).interfaceId ||
_interfaceId == type(IJBRedemptionTerminal).interfaceId ||
_interfaceId == type(IJBOperatable).interfaceId ||
_interfaceId == type(IJBOperatable).interfaceId ||
super.supportsInterface(_interfaceId);
super.supportsInterface(_interfaceId);
}
}
//*********************************************************************//
//*********************************************************************//
// -------------------------- internal views ------------------------- //
// -------------------------- internal views ------------------------- //
//*********************************************************************//
//*********************************************************************//
/**
/**
@notice
@notice
Checks the balance of tokens in this contract.
Checks the balance of tokens in this contract.
@return The contract's balance.
@return The contract's balance.
*/
*/
function _balance() internal view virtual returns (uint256);
function _balance() internal view virtual returns (uint256);
//*********************************************************************//
//*********************************************************************//
// -------------------------- constructor ---------------------------- //
// -------------------------- constructor ---------------------------- //
//*********************************************************************//
//*********************************************************************//
/**
/**
@param _token The token that this terminal manages.
@param _token The token that this terminal manages.
@param _decimals The number of decimals the token fixed point amounts are expected to have.
@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 _currency The currency that this terminal's token adheres to for price feeds.
@param _baseWeightCurrency The currency to base token issuance on.
@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 _payoutSplitsGroup The group that denotes payout splits from this terminal in the splits store.
@param _operatorStore A contract storing operator assignments.
@param _operatorStore A contract storing operator assignments.
@param _projects A contract which mints ERC-721's that represent project ownership and transfers.
@param _projects A contract which mints ERC-721's that represent project ownership and transfers.
@param _directory A contract storing directories of terminals and controllers for each project.
@param _directory A contract storing directories of terminals and controllers for each project.
@param _splitsStore A contract that stores splits for each project.
@param _splitsStore A contract that stores splits for each project.
@param _prices A contract that exposes price feeds.
@param _prices A contract that exposes price feeds.
@param _store A contract that stores the terminal's data.
@param _store A contract that stores the terminal's data.
@param _owner The address that will own this contract.
@param _owner The address that will own this contract.
*/
*/
constructor(
constructor(
// payable constructor save the gas used to check msg.value==0
// payable constructor save the gas used to check msg.value==0
address _token,
address _token,
uint256 _decimals,
uint256 _decimals,
uint256 _currency,
uint256 _currency,
uint256 _baseWeightCurrency,
uint256 _baseWeightCurrency,
uint256 _payoutSplitsGroup,
uint256 _payoutSplitsGroup,
IJBOperatorStore _operatorStore,
IJBOperatorStore _operatorStore,
IJBProjects _projects,
IJBProjects _projects,
IJBDirectory _directory,
IJBDirectory _directory,
IJBSplitsStore _splitsStore,
IJBSplitsStore _splitsStore,
IJBPrices _prices,
IJBPrices _prices,
IJBSingleTokenPaymentTerminalStore _store,
IJBSingleTokenPaymentTerminalStore _store,
address _owner
address _owner
)
)
payable
payable
JBSingleTokenPaymentTerminal(_token, _decimals, _currency)
JBSingleTokenPaymentTerminal(_token, _decimals, _currency)
JBOperatable(_operatorStore)
JBOperatable(_operatorStore)
{
{
baseWeightCurrency = _baseWeightCurrency;
baseWeightCurrency = _baseWeightCurrency;
payoutSplitsGroup = _payoutSplitsGroup;
payoutSplitsGroup = _payoutSplitsGroup;
projects = _projects;
projects = _projects;
directory = _directory;
directory = _directory;
splitsStore = _splitsStore;
splitsStore = _splitsStore;
prices = _prices;
prices = _prices;
store = _store;
store = _store;
transferOwnership(_owner);
transferOwnership(_owner);
}
}
//*********************************************************************//
//*********************************************************************//
// ---------------------- external transactions ---------------------- //
// ---------------------- external transactions ---------------------- //
//*********************************************************************//
//*********************************************************************//
/**
/**
@notice
@notice
Contribute tokens to a project.
Contribute tokens to a project.
@param _projectId The ID of the project being paid.
@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 _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 _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 _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 _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 _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 _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.
@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.
@return The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals.
*/
*/
function pay(
function pay(
uint256 _projectId,
uint256 _projectId,
uint256 _amount,
uint256 _amount,
address _token,
address _token,
address _beneficiary,
address _beneficiary,
uint256 _minReturnedTokens,
uint256 _minReturnedTokens,
bool _preferClaimedTokens,
bool _preferClaimedTokens,
string calldata _memo,
string calldata _memo,
bytes calldata _metadata
bytes calldata _metadata
) external payable virtual override isTerminalOf(_projectId) returns (uint256) {
) external payable virtual override isTerminalOf(_projectId) returns (uint256) {
_token; // Prevents unused var compiler and natspec complaints.
_token; // Prevents unused var compiler and natspec complaints.
// ETH shouldn't be sent if this terminal's token isn't ETH.
// ETH shouldn't be sent if this terminal's token isn't ETH.
if (token != JBTokens.ETH) {
if (token != JBTokens.ETH) {
if (msg.value > 0) revert NO_MSG_VALUE_ALLOWED();
if (msg.value > 0) revert NO_MSG_VALUE_ALLOWED();
// Get a reference to the balance before receiving tokens.
// Get a reference to the balance before receiving tokens.
uint256 _balanceBefore = _balance();
uint256 _balanceBefore = _balance();
// Transfer tokens to this terminal from the msg sender.
// Transfer tokens to this terminal from the msg sender.
_transferFrom(msg.sender, payable(address(this)), _amount);
_transferFrom(msg.sender, payable(address(this)), _amount);
// The amount should reflect the change in balance.
// The amount should reflect the change in balance.
_amount = _balance() - _balanceBefore;
_amount = _balance() - _balanceBefore;
}
}
// If this terminal's token is ETH, override _amount with msg.value.
// If this terminal's token is ETH, override _amount with msg.value.
else _amount = msg.value;
else _amount = msg.value;
return
return
_pay(
_pay(
_amount,
_amount,
msg.sender,
msg.sender,
_projectId,
_projectId,
_beneficiary,
_beneficiary,
_minReturnedTokens,
_minReturnedTokens,
_preferClaimedTokens,
_preferClaimedTokens,
_memo,
_memo,
_metadata
_metadata
);
);
}
}
/**
/**
@notice
@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.
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
@dev
Only a token holder or a designated operator can redeem its tokens.
Only a token holder or a designated operator can redeem its tokens.
@param _holder The account to redeem tokens for.
@param _holder The account to redeem tokens for.
@param _projectId The ID of the project to which the tokens being redeemed belong.
@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 _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 _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 _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 _beneficiary The address to send the terminal tokens to.
@param _memo A memo to pass along to the emitted event.
@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.
@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.
@return reclaimAmount The amount of terminal tokens that the project tokens were redeemed for, as a fixed point number with 18 decimals.
*/
*/
function redeemTokensOf(
function redeemTokensOf(
address _holder,
address _holder,
uint256 _projectId,
uint256 _projectId,
uint256 _tokenCount,
uint256 _tokenCount,
address _token,
address _token,
uint256 _minReturnedTokens,
uint256 _minReturnedTokens,
address payable _beneficiary,
address payable _beneficiary,
string memory _memo,
string memory _memo,
bytes memory _metadata
bytes memory _metadata
)
)
external
external
virtual
virtual
override
override
requirePermission(_holder, _projectId, JBOperations.REDEEM)
requirePermission(_holder, _projectId, JBOperations.REDEEM)
returns (uint256 reclaimAmount)
returns (uint256 reclaimAmount)
{
{
_token; // Prevents unused var compiler and natspec complaints.
_token; // Prevents unused var compiler and natspec complaints.
return
return
_redeemTokensOf(
_redeemTokensOf(
_holder,
_holder,
_projectId,
_projectId,
_tokenCount,
_tokenCount,
_minReturnedTokens,
_minReturnedTokens,
_beneficiary,
_beneficiary,
_memo,
_memo,
_metadata
_metadata
);
);
}
}
/**
/**
@notice
@notice
Distributes payouts for a project with the distribution limit of its current funding cycle.
Distributes payouts for a project with the distribution limit of its current funding cycle.
@dev
@dev
Payouts are sent to the preprogrammed splits. Any leftover is sent to the project's owner.
Payouts are sent to the preprogrammed splits. Any leftover is sent to the project's owner.
@dev
@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.
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
@dev
All funds distributed outside of this contract or any feeless terminals incure the protocol fee.
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 _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 _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 _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 _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 _minReturnedTokens The minimum number of terminal tokens that the `_amount` should be valued at in terms of this terminal's currency, as a fixed point number with the same number of decimals as this terminal.
@param _memo A memo to pass along to the emitted event.
@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.
@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(
function distributePayoutsOf(
uint256 _projectId,
uint256 _projectId,
uint256 _amount,
uint256 _amount,
uint256 _currency,
uint256 _currency,
address _token,
address _token,
uint256 _minReturnedTokens,
uint256 _minReturnedTokens,
string calldata _memo
bytes calldata _metadata
) external virtual override returns (uint256 netLeftoverDistributionAmount) {
) external virtual override returns (uint256 netLeftoverDistributionAmount) {
_token; // Prevents unused var compiler and natspec complaints.
_token; // Prevents unused var compiler and natspec complaints.
return _distributePayoutsOf(_projectId, _amount, _currency, _minReturnedTokens, _memo);
return _distributePayoutsOf(_projectId, _amount, _currency, _minReturnedTokens, _metadata);
}
}
/**
/**
@notice
@notice
Allows a project to send funds from its overflow up to the preconfigured allowance.
Allows a project to send funds from its overflow up to the preconfigured allowance.
@dev
@dev
Only a project's owner or a designated operator can use its allowance.
Only a project's owner or a designated operator can use its allowance.
@dev
@dev
Incurs the protocol fee.
Incurs the protocol fee.
@param _projectId The ID of the project to use the allowance of.
@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 _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 _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 _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 _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 _beneficiary The address to send the funds to.
@param _memo A memo to pass along to the emitted event.
@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.
@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(
function useAllowanceOf(
uint256 _projectId,
uint256 _projectId,
uint256 _amount,
uint256 _amount,
uint256 _currency,
uint256 _currency,
address _token,
address _token,
uint256 _minReturnedTokens,
uint256 _minReturnedTokens,
address payable _beneficiary,
address payable _beneficiary,
string memory _memo
string memory _memo,
bytes calldata _metadata
)
)
external
external
virtual
virtual
override
override
requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.USE_ALLOWANCE)
requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.USE_ALLOWANCE)
returns (uint256 netDistributedAmount)
returns (uint256 netDistributedAmount)
{
{
_token; // Prevents unused var compiler and natspec complaints.
_token; // Prevents unused var compiler and natspec complaints.
return _useAllowanceOf(_projectId, _amount, _currency, _minReturnedTokens, _beneficiary, _memo);
return
_useAllowanceOf(
_projectId,
_amount,
_currency,
_minReturnedTokens,
_beneficiary,
_memo,
_metadata
);
}
}
/**
/**
@notice
@notice
Allows a project owner to migrate its funds and operations to a new terminal that accepts the same token type.
Allows a project owner to migrate its funds and operations to a new terminal that accepts the same token type.
@dev
@dev
Only a project's owner or a designated operator can migrate it.
Only a project's owner or a designated operator can migrate it.
@param _projectId The ID of the project being migrated.
@param _projectId The ID of the project being migrated.
@param _to The terminal contract that will gain the project's funds.
@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.
@return balance The amount of funds that were migrated, as a fixed point number with the same amount of decimals as this terminal.
*/
*/
function migrate(uint256 _projectId, IJBPaymentTerminal _to)
function migrate(uint256 _projectId, IJBPaymentTerminal _to)
external
external
virtual
virtual
override
override
requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.MIGRATE_TERMINAL)
requirePermission(projects.ownerOf(_projectId), _projectId, JBOperations.MIGRATE_TERMINAL)
returns (uint256 balance)
returns (uint256 balance)
{
{
// The terminal being migrated to must accept the same token as this terminal.
// The terminal being migrated to must accept the same token as this terminal.
if (!_to.acceptsToken(token, _projectId)) revert TERMINAL_TOKENS_INCOMPATIBLE();
if (!_to.acceptsToken(token, _projectId)) revert TERMINAL_TOKENS_INCOMPATIBLE();
// Record the migration in the store.
// Record the migration in the store.
balance = store.recordMigration(_projectId);
balance = store.recordMigration(_projectId);
// Transfer the balance if needed.
// Transfer the balance if needed.
if (balance > 0) {
if (balance > 0) {
// Trigger any inherited pre-transfer logic.
// Trigger any inherited pre-transfer logic.
_beforeTransferTo(address(_to), balance);
_beforeTransferTo(address(_to), balance);
// If this terminal's token is ETH, send it in msg.value.
// If this terminal's token is ETH, send it in msg.value.
uint256 _payableValue = token == JBTokens.ETH ? balance : 0;
uint256 _payableValue = token == JBTokens.ETH ? balance : 0;
// Withdraw the balance to transfer to the new terminal;
// Withdraw the balance to transfer to the new terminal;
_to.addToBalanceOf{value: _payableValue}(_projectId, balance, token, '', bytes(''));
_to.addToBalanceOf{value: _payableValue}(_projectId, balance, token, '', bytes(''));
}
}
emit Migrate(_projectId, _to, balance, msg.sender);
emit Migrate(_projectId, _to, balance, msg.sender);
}
}
/**
/**
@notice
@notice
Receives funds belonging to the specified project.
Receives funds belonging to the specified project.
@param _projectId The ID of the project to which the funds received belong.
@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 _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 _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 _memo A memo to pass along to the emitted event.
@param _metadata Extra data to pass along to the emitted event.
@param _metadata Extra data to pass along to the emitted event.
*/
*/
function addToBalanceOf(
function addToBalanceOf(
uint256 _projectId,
uint256 _projectId,
uint256 _amount,
uint256 _amount,
address _token,
address _token,
string calldata _memo,
string calldata _memo,
bytes calldata _metadata
bytes calldata _metadata
) external payable virtual override isTerminalOf(_projectId) {
) external payable virtual override isTerminalOf(_projectId) {
_token; // Prevents unused var compiler and natspec complaints.
// Do not refund held fees by default.
addToBalanceOf(_projectId, _amount, _token, false, _memo, _metadata);
// 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 while only refunding held fees if the funds aren't originating from a feeless terminal.
_addToBalanceOf(_projectId, _amount, !isFeelessAddress[msg.sender], _memo, _metadata);
}
}
/**
/**
@notice
@notice
Process any fees that are being held for the project.
Process any fees that are being held for the project.
@dev
@dev
Only a project owner, an operator, or the contract's owner can process held fees.
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.
@param _projectId The ID of the project whos held fees should be processed.
*/
*/
function processFees(uint256 _projectId)
function processFees(uint256 _projectId)
external
external
virtual
virtual
override
override
requirePermissionAllowingOverride(
requirePermissionAllowingOverride(
projects.ownerOf(_projectId),
projects.ownerOf(_projectId),
_projectId,
_projectId,
JBOperations.PROCESS_FEES,
JBOperations.PROCESS_FEES,
msg.sender == owner()
msg.sender == owner()
)
)
{
{
// Get a reference to the project's held fees.
// Get a reference to the project's held fees.
JBFee[] memory _heldFees = _heldFeesOf[_projectId];
JBFee[] memory _heldFees = _heldFeesOf[_projectId];
// Delete the held fees.
// Delete the held fees.
delete _heldFeesOf[_projectId];
delete _heldFeesOf[_projectId];
// Push array length in stack
// Push array length in stack
uint256 _heldFeeLength = _heldFees.length;
uint256 _heldFeeLength = _heldFees.length;
// Process each fee.
// Process each fee.
for (uint256 _i; _i < _heldFeeLength; ) {
for (uint256 _i; _i < _heldFeeLength; ) {
// Get the fee amount.
// Get the fee amount.
uint256 _amount = _feeAmount(
uint256 _amount = _feeAmount(
_heldFees[_i].amount,
_heldFees[_i].amount,
_heldFees[_i].fee,
_heldFees[_i].fee,
_heldFees[_i].feeDiscount
_heldFees[_i].feeDiscount
);
);
// Process the fee.
// Process the fee.
_processFee(_amount, _heldFees[_i].beneficiary);
_processFee(_amount, _heldFees[_i].beneficiary, _projectId);
emit ProcessFee(_projectId, _amount, true, _heldFees[_i].beneficiary, msg.sender);
emit ProcessFee(_projectId, _amount, true, _heldFees[_i].beneficiary, msg.sender);
unchecked {
unchecked {
++_i;
++_i;
}
}
}
}
}
}
/**
/**
@notice
@notice
Allows the fee to be updated.
Allows the fee to be updated.
@dev
@dev
Only the owner of this contract can change the fee.
Only the owner of this contract can change the fee.
@param _fee The new fee, out of MAX_FEE.
@param _fee The new fee, out of MAX_FEE.
*/
*/
function setFee(uint256 _fee) external virtual override onlyOwner {
function setFee(uint256 _fee) external virtual override onlyOwner {
// The provided fee must be within the max.
// The provided fee must be within the max.
if (_fee > _FEE_CAP) revert FEE_TOO_HIGH();
if (_fee > _FEE_CAP) revert FEE_TOO_HIGH();
// Store the new fee.
// Store the new fee.
fee = _fee;
fee = _fee;
emit SetFee(_fee, msg.sender);
emit SetFee(_fee, msg.sender);
}
}
/**
/**
@notice
@notice
Allows the fee gauge to be updated.
Allows the fee gauge to be updated.
@dev
@dev
Only the owner of this contract can change the fee gauge.
Only the owner of this contract can change the fee gauge.
@param _feeGauge The new fee gauge.
@param _feeGauge The new fee gauge.
*/
*/
function setFeeGauge(IJBFeeGauge _feeGauge) external virtual override onlyOwner {
function setFeeGauge(IJBFeeGauge _feeGauge) external virtual override onlyOwner {
// Store the new fee gauge.
// Store the new fee gauge.
feeGauge = _feeGauge;
feeGauge = _feeGauge;
emit SetFeeGauge(_feeGauge, msg.sender);
emit SetFeeGauge(_feeGauge, msg.sender);
}
/**
@notice
Sets whether projects operating on this terminal can pay towards the specified address without incurring a fee.
@dev
Only the owner of this contract can set addresses as feeless.
@param _address The address that can be paid towards while still bypassing fees.
@param _flag A flag indicating whether the terminal should be feeless or not.
*/
function setFeelessAddress(address _address, bool _flag) external virtual override onlyOwner {
// Set the flag value.
isFeelessAddress[_address]