VibeERC721.sol
VibeERC721 Documentation
VibeERC721 is a Solidity contract that implements a customizable ERC721 token with additional features, such as royalties enforcement on OpenSea (using the DefaultOperatorFilterer by OpenSea), as well as implementing the ERC2981 and IDerivativeLicense interfaces. Vibe Labs is the creator of the IDerivativeLicense interface.
Inherited Contracts
DefaultOperatorFilterer
The DefaultOperatorFilterer
by OpenSea allows for the enforcement of royalties on OpenSea but disallows listing on zero-fee exchanges. NFTs with this functionality will be able to freely be listed on SeaPort and other royalty-enforcing exchanges, but they might not take advantage of other proprietary functions of non-enforcing exchanges.
Roles
Minter
The minter role allows addresses to mint new tokens. Only the contract owner can assign or remove the minter role from an address. Minting is restricted to minters through the onlyMinter
modifier.
Owner
The owner role is inherited from OpenZeppelin's Ownable contract. The owner can change the minter status of an address, set royalty information, and change the base URI.
Access Control
Access control is implemented using OpenZeppelin's Ownable contract for the owner role, and a custom mapping (isMinter
) with the onlyMinter
modifier for the minter role.
Interfaces
ERC2981
The ERC2981
interface is used for handling royalty payments on NFTs. VibeERC721 implements royaltyInfo function, allowing users to query royalty information for a specific token.
IDerivativeLicense
The IDerivativeLicense
interface is an invention of Vibe Labs. It is used for handling derivative royalties on NFTs. VibeERC721
implements the derivativeRoyaltyInfo function, allowing users to query royalty information for a specific token when used as a derivative.
Key Functions
setMinter
The setMinter
function allows the contract owner to grant or revoke the minter role from an address.
function setMinter(address minter, bool status) external onlyOwner {
isMinter[minter] = status;
emit LogMinterChange(minter, status);
}
renounceMinter
The renounceMinter
function allows an address with the minter role to renounce it.
function renounceMinter() external {
isMinter[msg.sender] = false;
emit LogMinterChange(msg.sender, false);
}
init
The init
function initializes the contract with a given name, symbol, and base URI.
function init(bytes calldata data) public payable override {
(
string memory _name,
string memory _symbol,
string memory baseURI_
) = abi.decode(data, (string, string, string));
require(bytes(baseURI).length == 0 && bytes(baseURI_).length != 0);
_transferOwnership(msg.sender);
name = _name;
symbol = _symbol;
baseURI = baseURI_;
}
mint
The mint
function allows an address with the minter role to mint a new token to a specified address.
function mint(address to) external onlyMinter returns (uint256 tokenId) {
tokenId = totalSupply++;
_mint(to, tokenId);
}
mintWithId
The mintWithId
function allows an address with the minter role to mint a new token with a specific tokenId to a specified address.
function mintWithId(address to, uint256 tokenId) external onlyMinter {
_mint(to, tokenId);
}
setApprovalForAll
, approve
, transferFrom
, safeTransferFrom
These functions override the corresponding ERC721 functions to ensure that the operator is allowed by the OperatorFilterRegistry
.
function setApprovalForAll(address operator, bool approved) public override onlyAllowedOperatorApproval(operator) {
super.setApprovalForAll(operator, approved);
}
/**
* @dev See {ERC721-approve}.
* In this example the added modifier ensures that the operator is allowed by the OperatorFilterRegistry.
*/
function approve(address operator, uint256 tokenId) public override onlyAllowedOperatorApproval(operator) {
super.approve(operator, tokenId);
}
/**
* @dev See {ERC721-transferFrom}.
* In this example the added modifier ensures that the operator is allowed by the OperatorFilterRegistry.
*/
function transferFrom(address from, address to, uint256 tokenId) public override onlyAllowedOperator(from) {
super.transferFrom(from, to, tokenId);
}
/**
* @dev See {ERC721-safeTransferFrom}.
*/
function safeTransferFrom(address from, address to, uint256 tokenId) public override onlyAllowedOperator(from) {
super.safeTransferFrom(from, to, tokenId);
}
burn
The burn
function allows a token owner or an approved operator to burn a token.
function burn(uint256 id) external {
address oldOwner = _ownerOf[id];
require(
msg.sender == oldOwner ||
msg.sender == getApproved[id] ||
isApprovedForAll[oldOwner][msg.sender],
"NOT_AUTHORIZED"
);
_burn(id);
}
tokenURI
The tokenURI
function returns the URI of a specific token.
function tokenURI(uint256 id) public view override returns (string memory) {
return
bytes(baseURI).length > 0
? string(abi.encodePacked(baseURI, id.toString()))
: "";
}
royaltyInfo
The royaltyInfo
function returns the royalty receiver and royalty amount for a specific token and sale price.
function royaltyInfo(uint256 _tokenId, uint256 _salePrice)
external
view
override
returns (address receiver, uint256 royaltyAmount)
{
return (
royaltyInformation.royaltyReceiver,
(_salePrice * royaltyInformation.royaltyRate) / BPS
);
}
derivativeRoyaltyInfo
The derivativeRoyaltyInfo
function returns the derivative royalty receiver and derivative royalty amount for a specific token and sale price, if derivatives are allowed.
function derivativeRoyaltyInfo(uint256 _tokenId, uint256 _salePrice)
external
view
override
returns (address receiver, uint256 royaltyAmount)
{
require(royaltyInformation.isDerivativeAllowed);
return (
royaltyInformation.royaltyReceiver,
(_salePrice * royaltyInformation.derivativeRoyaltyRate) / BPS
);
}
setRoyalty
The setRoyalty
function allows the contract owner to set royalty information, including the royalty receiver, royalty rate, derivative rate, and whether derivatives are allowed.
function setRoyalty(
address royaltyReceiver_,
uint16 royaltyRate_,
uint16 derivativeRate,
bool isDerivativeAllowed
) external onlyOwner {
require(royaltyReceiver_ != address(0));
// If Derivative Works were turned on in the past, this can not be retracted in the future
isDerivativeAllowed = royaltyInformation.isDerivativeAllowed
? true
: isDerivativeAllowed;
royaltyInformation = RoyaltyData(
royaltyReceiver_,
royaltyRate_,
derivativeRate,
isDerivativeAllowed
);
emit LogSetRoyalty(
royaltyRate_,
royaltyReceiver_,
derivativeRate,
isDerivativeAllowed
);
}
changeBaseURI
The changeBaseURI
function allows the contract owner to change the base URI and its immutability.
function changeBaseURI(string memory baseURI_, bool immutability_)
external
onlyOwner
{
require(immutability == false, "Immutable");
immutability = immutability_;
baseURI = baseURI_;
emit LogChangeBaseURI(baseURI_, immutability_);
}
supportsInterface
The supportsInterface
function checks if the contract supports a specific interface.
function supportsInterface(bytes4 interfaceId)
public
view
override(ERC721, IERC165)
returns (bool)
{
return
interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165
interfaceId == 0x80ac58cd || // ERC165 Interface ID for ERC721
interfaceId == 0x2a55205a || // ERC165 Interface ID for IERC2981
interfaceId == 0x5b5e139f || // ERC165 Interface ID for ERC721Metadata
(interfaceId == 0x15a779f5 &&
royaltyInformation.isDerivativeAllowed);
}
Updated 4 months ago