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)
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)
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¶
- Marketplace Payment: NFT marketplaces send royalty fees to the contract
- ETH Conversion: If payment is in ETH, it's automatically converted to WETH
- Fee Collection:
distributeCollectedFees()
is called to collect accumulated fees - FeeCollector Integration: Fees are forwarded to FeeCollector using
ROYALTY_FEE
type - Distribution: FeeCollector distributes fees according to configured percentages
Integration with FeeCollector¶
The NFTRoyaltyFeeCollector works with the FeeCollector's pull-based system by:
- Collecting Funds: Receiving royalty fees from marketplaces
- Converting ETH: Automatically converting ETH to WETH for consistency
- Pushing to FeeCollector: Using
collectFee()
to push funds to FeeCollector - 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