burnTokensOf
Contract: JBController
Interface: IJBController
- Step by step
 - Code
 - Errors
 - Events
 - Bug bounty
 
Burns a token holder's supply.
Only a token's holder, a designated operator, or a project's terminal can burn it.
Definition
function burnTokensOf(
  address _holder,
  uint256 _projectId,
  uint256 _tokenCount,
  string calldata _memo,
  bool _preferClaimedTokens
)
  external
  virtual
  override
  nonReentrant
  requirePermissionAllowingOverride(
    _holder,
    _projectId,
    JBOperations.BURN,
    directory.isTerminalDelegateOf(_projectId, msg.sender)
  ) { ... }
- Arguments:
_holderis the account that is having its tokens burned._projectIdis the ID of the project to which the tokens being burned belong._tokenCountis the number of tokens to burn._memois a memo to pass along to the emitted event._preferClaimedTokensis flag indicating whether a project's attached token contract should be burned first if they have been issued.
 - Through the 
requirePermissionAllowingOverridemodifier, the function is only accessible by the project's owner, from an operator that has been given theJBOperations.BURNpermission by the project owner for the provided_projectId, or from one of the project's terminal's delegates. - The function can be overriden by inheriting contracts.
 - The function overrides a function definition from the 
IJBControllerinterface. - The function doesn't return anything.
 
Body
- 
Make sure there is a specified number of tokens to burn.
// There should be tokens to burn
if (_tokenCount == 0) revert NO_BURNABLE_TOKENS(); - 
Get a reference to the current funding cycle for the project.
// Get a reference to the project's current funding cycle.
JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);Internal references:
External references:
 - 
Make sure the current funding cycle for the project hasn't paused burning if the request is not coming from one of the project's terminals. If the request is coming from a terminal, allow burning regardless of the pause state because it could be a sub-routine of another operation such as redemption.
// If the message sender is a terminal, the current funding cycle must not be paused.
if (
_fundingCycle.burnPaused() &&
!directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender))
) revert BURN_PAUSED_AND_SENDER_NOT_VALID_TERMINAL_DELEGATE();Internal references:
Library references:
JBFundingCycleMetadataResolver.burnPaused(...)
External references:
 - 
Update the token tracker so that the correct amount of reserved tokens are still mintable after the burn.
// Update the token tracker so that reserved tokens will still be correctly mintable.
_processedTokenTrackerOf[_projectId] =
_processedTokenTrackerOf[_projectId] -
SafeCast.toInt256(_tokenCount);Library references:
SafeCast.toInt256(...)
Internal references:
 - 
Burn the tokens.
// Burn the tokens.
tokenStore.burnFrom(_holder, _projectId, _tokenCount, _preferClaimedTokens);Internal references:
External references:
 - 
Emit a
BurnTokensevent with the relevant parameters.emit BurnTokens(_holder, _projectId, _tokenCount, _memo, msg.sender);Event references:
 
/**
  @notice
  Burns a token holder's supply.
  @dev
  Only a token's holder, a designated operator, or a project's terminal can burn it.
  @param _holder The account that is having its tokens burned.
  @param _projectId The ID of the project to which the tokens being burned belong.
  @param _tokenCount The number of tokens to burn.
  @param _memo A memo to pass along to the emitted event.
  @param _preferClaimedTokens A flag indicating whether a project's attached token contract should be burned first if they have been issued.
*/
function burnTokensOf(
  address _holder,
  uint256 _projectId,
  uint256 _tokenCount,
  string calldata _memo,
  bool _preferClaimedTokens
)
  external
  virtual
  override
  requirePermissionAllowingOverride(
    _holder,
    _projectId,
    JBOperations.BURN,
    directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender))
  )
{
  // There should be tokens to burn
  if (_tokenCount == 0) revert NO_BURNABLE_TOKENS();
  // Get a reference to the project's current funding cycle.
  JBFundingCycle memory _fundingCycle = fundingCycleStore.currentOf(_projectId);
  // If the message sender is a terminal, the current funding cycle must not be paused.
  if (
    _fundingCycle.burnPaused() &&
    !directory.isTerminalOf(_projectId, IJBPaymentTerminal(msg.sender))
  ) revert BURN_PAUSED_AND_SENDER_NOT_VALID_TERMINAL_DELEGATE();
  // Update the token tracker so that reserved tokens will still be correctly mintable.
  _processedTokenTrackerOf[_projectId] =
    _processedTokenTrackerOf[_projectId] -
    SafeCast.toInt256(_tokenCount);
  // Burn the tokens.
  tokenStore.burnFrom(_holder, _projectId, _tokenCount, _preferClaimedTokens);
  emit BurnTokens(_holder, _projectId, _tokenCount, _memo, msg.sender);
}
| String | Description | 
|---|---|
NO_BURNABLE_TOKENS | Thrown if no tokens are being burned. | 
BURN_PAUSED_AND_SENDER_NOT_VALID_TERMINAL_DELEGATE | Thrown if the request is not being made by a payment terminal, and the project's current funding cycle has paused burning. | 
| Name | Data | 
|---|---|
BurnTokens | 
  | 
| Category | Description | Reward | 
|---|---|---|
| Optimization | Help make this operation more efficient. | 0.5ETH | 
| Low severity | Identify a vulnerability in this operation that could lead to an inconvenience for a user of the protocol or for a protocol developer. | 1ETH | 
| High severity | Identify a vulnerability in this operation that could lead to data corruption or loss of funds. | 5+ETH |