Skip to content

Instantly share code, notes, and snippets.

@cygaar
Created June 26, 2022 00:04
Show Gist options
  • Save cygaar/e1bff789e6e6b24a3ff82b35bc565cf8 to your computer and use it in GitHub Desktop.
Save cygaar/e1bff789e6e6b24a3ff82b35bc565cf8 to your computer and use it in GitHub Desktop.
ERC2981Optimized.sol
Can be found at: https://www.diffchecker.com/lPIpRFNs
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/common/ERC2981.sol)
pragma solidity ^0.8.0;
import "../../interfaces/IERC2981.sol";
import "../../utils/introspection/ERC165.sol";
/**
* @dev Implementation of the NFT Royalty Standard, a standardized way to retrieve royalty payment information.
*
* Royalty information can be specified globally for all token ids via {_setDefaultRoyalty}, and/or individually for
* specific token ids via {_setTokenRoyalty}. The latter takes precedence over the first.
*
* Royalty is specified as a fraction of sale price. {_feeDenominator} is overridable but defaults to 10000, meaning the
* fee is specified in basis points by default.
*
* IMPORTANT: ERC-2981 only specifies a way to signal royalty information and does not enforce its payment. See
* https://eips.ethereum.org/EIPS/eip-2981#optional-royalty-payments[Rationale] in the EIP. Marketplaces are expected to
* voluntarily pay royalties together with sales, but note that this standard is not yet widely supported.
*
* _Available since v4.5._
*/
abstract contract ERC2981 is IERC2981, ERC165 {
uint256 private _defaultRoyaltyInfo;
mapping(uint256 => uint256) private _tokenRoyaltyInfo;
uint256 private constant ADDRESS_MASK = (1 << 161) - 1;
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC165) returns (bool) {
return interfaceId == type(IERC2981).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @inheritdoc IERC2981
*/
function royaltyInfo(uint256 _tokenId, uint256 _salePrice) public view virtual override returns (address, uint256) {
uint256 packedRoyalty = _tokenRoyaltyInfo[_tokenId];
address receiver = address(uint160(packedRoyalty));
if (receiver == address(0)) {
packedRoyalty = _defaultRoyaltyInfo;
receiver = address(uint160(packedRoyalty));
}
uint96 royaltyFraction = uint96(packedRoyalty >> 160);
uint256 royaltyAmount = (_salePrice * royaltyFraction) / _feeDenominator();
return (receiver, royaltyAmount);
}
/**
* @dev The denominator with which to interpret the fee set in {_setTokenRoyalty} and {_setDefaultRoyalty} as a
* fraction of the sale price. Defaults to 10000 so fees are expressed in basis points, but may be customized by an
* override.
*/
function _feeDenominator() internal pure virtual returns (uint96) {
return 10000;
}
/**
* @dev Sets the royalty information that all ids in this contract will default to.
*
* Requirements:
*
* - `receiver` cannot be the zero address.
* - `feeNumerator` cannot be greater than the fee denominator.
*/
function _setDefaultRoyalty(address receiver, uint96 feeNumerator) internal virtual {
require(feeNumerator <= _feeDenominator(), "ERC2981: royalty fee will exceed salePrice");
require(receiver != address(0), "ERC2981: invalid receiver");
assembly {
sstore(_defaultRoyaltyInfo.slot, or(shl(160, feeNumerator), and(receiver, ADDRESS_MASK)))
}
}
/**
* @dev Removes default royalty information.
*/
function _deleteDefaultRoyalty() internal virtual {
assembly {
sstore(_defaultRoyaltyInfo.slot, 0)
}
}
/**
* @dev Sets the royalty information for a specific token id, overriding the global default.
*
* Requirements:
*
* - `receiver` cannot be the zero address.
* - `feeNumerator` cannot be greater than the fee denominator.
*/
function _setTokenRoyalty(
uint256 tokenId,
address receiver,
uint96 feeNumerator
) internal virtual {
require(feeNumerator <= _feeDenominator(), "ERC2981: royalty fee will exceed salePrice");
require(receiver != address(0), "ERC2981: Invalid parameters");
assembly {
mstore(0x00, tokenId)
mstore(0x20, _tokenRoyaltyInfo.slot)
let hash := keccak256(0, 0x40)
sstore(hash, or(shl(160, feeNumerator), and(receiver, ADDRESS_MASK)))
}
}
/**
* @dev Resets royalty information for the token id back to the global default.
*/
function _resetTokenRoyalty(uint256 tokenId) internal virtual {
assembly {
mstore(0x00, tokenId)
mstore(0x20, _tokenRoyaltyInfo.slot)
let hash := keccak256(0, 0x40)
sstore(hash, 0)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment