Skip to content

NFT Royalty Fee Collector

Overview

The NFTRoyaltyFeeCollector is a specialized contract designed to collect royalty fees from NFT marketplaces (such as OpenSea, X2Y2, etc.) for RAACNFT sales and forward them to the centralized FeeCollector for distribution. It handles both native ETH and ERC-20 token collections, automatically converting ETH to WETH when necessary.

Purpose

  • Marketplace Integration: Collect royalty fees from secondary NFT marketplaces
  • Centralized Distribution: Forward collected fees to the FeeCollector for proper distribution
  • ETH/WETH Conversion: Automatically convert native ETH to WETH for consistent handling
  • Pull-Based Architecture: Works with the FeeCollector's pull-based system by collecting funds and then pushing them

Architecture

flowchart TD
    A[NFT Marketplaces] -->|Royalty Fees| B[NFTRoyaltyFeeCollector]
    B -->|ETH| C[Convert to WETH]
    B -->|ERC-20| D[Direct Collection]
    C -->|WETH| E[FeeCollector]
    D -->|ERC-20| E
    E -->|Distribute| F[Protocol Treasury]

    G[RAACNFT] -->|royaltyInfo| A

Key Features

  • Automatic ETH Conversion: Converts received ETH to WETH for consistent processing
  • Multi-Token Support: Handles both native ETH and ERC-20 tokens
  • Emergency Controls: Owner can withdraw funds in emergency situations
  • Fee Type Integration: Uses ROYALTY_FEE fee type for proper categorization

Key Functions

distributeCollectedFees

distributeCollectedFees(address _token) → bool

Summary
Collects accumulated fees from the contract and forwards them to the FeeCollector. Handles both ETH (converts to WETH) and ERC-20 tokens.

Guarded Method
- Callable by any address - Protected by nonReentrant and validation checks

Parameters

Name Type Description
_token address Token address to collect (use address(0) for ETH)

Returns
bool — Always returns true on successful collection

Emits
- FeeCollected(address indexed token, uint256 amount)

Reverts

  • InvalidAddress() — if token address is invalid
  • "NFTRoyaltyFeeCollector: no balance" — if contract has no balance
  • FeeCollector errors if token not supported

Requirements

  • Contract must have balance of the specified token
  • Token must be supported by FeeCollector (for ERC-20 tokens)
  • ETH is automatically converted to WETH before forwarding

Token Support Requirement

If the token is not supported by the FeeCollector, this function will revert until the token is added to the FeeCollector's supported tokens list. In most cases, this is prevented by the protocol supporting the token beforehand.

Example (TypeScript / ethers)
// Collect ETH fees (converts to WETH)
const txEth = await nftRoyaltyFeeCollector.distributeCollectedFees(ethers.ZeroAddress);
await txEth.wait();

// Collect ERC-20 fees
const txToken = await nftRoyaltyFeeCollector.distributeCollectedFees(tokenAddress);
await txToken.wait();
Source code
function distributeCollectedFees(address _token) external nonReentrant returns (bool) {
    if (_token == address(0)) {
        uint256 _balance = address(this).balance;
        require(_balance > 0, "NFTRoyaltyFeeCollector: no balance");
        IWETH10Minimal(weth).deposit{ value: _balance }();
        _token = weth;
    }
    uint256 balance = IERC20(_token).balanceOf(address(this));
    if (balance > 0) {
        IERC20(_token).forceApprove(feeCollector, balance);
        IFeeCollector(feeCollector).collectFee(_token, address(this), balance, keccak256("ROYALTY_FEE"));
        emit FeeCollected(_token, balance);
    }
    return true;
}

emergencyWithdraw

emergencyWithdraw(address _token, address recipient)

Summary
Emergency withdrawal function for the contract owner to withdraw accumulated funds. Handles both ETH and ERC-20 tokens.

Guarded Method
- Callable only by contract owner - Protected by nonReentrant and validation checks

Parameters

Name Type Description
_token address Token address to withdraw (use address(0) for ETH)
recipient address Address to receive the withdrawn funds

Emits
- EmergencyWithdrawal(address indexed token, address indexed to, uint256 amount)

Reverts

  • "NFTRoyaltyFeeCollector: no balance" — if contract has no balance
  • "NFTRoyaltyFeeCollector: transfer failed" — if ETH transfer fails
  • ERC20 transfer failures

Requirements

  • Caller must be contract owner
  • Contract must have balance of the specified token
  • Recipient address must be valid
Example (TypeScript / ethers)
// Emergency withdraw ETH
const txEth = await nftRoyaltyFeeCollector.emergencyWithdraw(
    ethers.ZeroAddress, 
    recipientAddress
);
await txEth.wait();

// Emergency withdraw ERC-20
const txToken = await nftRoyaltyFeeCollector.emergencyWithdraw(
    tokenAddress, 
    recipientAddress
);
await txToken.wait();
Source code
function emergencyWithdraw(address _token, address recipient) 
    external 
    onlyOwner 
    nonReentrant 
{
    uint256 _balance;
    if (_token == address(0)) {
        _balance = address(this).balance;
        require(_balance > 0, "NFTRoyaltyFeeCollector: no balance");
        (bool success, )= payable(recipient).call{value: _balance}("");
        require(success, "NFTRoyaltyFeeCollector: transfer failed");
    } else {
        _balance = IERC20(_token).balanceOf(address(this));
        IERC20(_token).safeTransfer(recipient, _balance);
    }
    emit EmergencyWithdrawal(_token, recipient, _balance);
}

Private Methods (Owner-Only)

Configuration

Function Role Description
setFeeCollector Owner Update the FeeCollector address

Public Read Methods

Configuration Status

Function Returns Description
weth() address Get WETH contract address
feeCollector() address Get FeeCollector contract address
owner() address Get contract owner address

Fee Collection Flow

  1. Marketplace Payment: NFT marketplaces send royalty fees to the contract
  2. ETH Conversion: If payment is in ETH, it's automatically converted to WETH
  3. Fee Collection: distributeCollectedFees() is called to collect accumulated fees
  4. FeeCollector Integration: Fees are forwarded to FeeCollector using ROYALTY_FEE type
  5. Distribution: FeeCollector distributes fees according to configured percentages

Integration with FeeCollector

The NFTRoyaltyFeeCollector works with the FeeCollector's pull-based system by:

  1. Collecting Funds: Receiving royalty fees from marketplaces
  2. Converting ETH: Automatically converting ETH to WETH for consistency
  3. Pushing to FeeCollector: Using collectFee() to push funds to FeeCollector
  4. Proper Categorization: Using ROYALTY_FEE fee type for proper distribution

Important Notes

  • Token Support: Ensure tokens are supported by FeeCollector before collection
  • ETH Handling: Contract automatically converts ETH to WETH for consistency
  • Fee Type: Uses ROYALTY_FEE fee type for proper categorization
  • Marketplace Integration: Designed to work with standard NFT marketplace royalty systems