Aere Network public source. Everything here can be checked against the live chain (chain id 2800, https://rpc.aere.network). Scope note, stated up front rather than buried: consensus on chain 2800 is classical secp256k1 ECDSA QBFT. The post-quantum work in this repository is at the signature, precompile, account and transport layers. Nothing here makes the consensus post-quantum, and no document in it should be read as claiming so.
107 lines
3.6 KiB
Solidity
107 lines
3.6 KiB
Solidity
// SPDX-License-Identifier: MIT
|
|
pragma solidity ^0.8.19;
|
|
|
|
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
|
|
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
|
|
import "@openzeppelin/contracts/access/Ownable.sol";
|
|
import "@openzeppelin/contracts/interfaces/IERC2981.sol";
|
|
|
|
/**
|
|
* @title AereNFT
|
|
* @notice Native ERC-721 collection for AERE Network with on-chain royalties (EIP-2981).
|
|
* @dev Permissionless minting: anyone can mint by paying the mint fee in native AERE.
|
|
* Per-token royalty (creator-set, capped at 10%) flows to the original minter.
|
|
* Designed to work with AereNFTMarketplace, but conforms to EIP-2981 for any market.
|
|
*/
|
|
contract AereNFT is ERC721URIStorage, ERC721Enumerable, Ownable, IERC2981 {
|
|
uint96 public constant MAX_ROYALTY_BPS = 1000; // 10%
|
|
uint256 public mintFee = 0.01 ether; // 0.01 AERE
|
|
|
|
address public feeRecipient;
|
|
uint256 private _nextId = 1;
|
|
|
|
struct RoyaltyInfo {
|
|
address receiver;
|
|
uint96 royaltyBps;
|
|
}
|
|
mapping(uint256 => RoyaltyInfo) private _royalties;
|
|
mapping(uint256 => address) public minterOf;
|
|
|
|
event Minted(uint256 indexed tokenId, address indexed minter, string uri, uint96 royaltyBps);
|
|
event MintFeeUpdated(uint256 newFee);
|
|
event FeeRecipientUpdated(address newRecipient);
|
|
|
|
constructor(address _feeRecipient) ERC721("AERE NFT", "AERENFT") {
|
|
feeRecipient = _feeRecipient;
|
|
}
|
|
|
|
function mint(string calldata uri, uint96 royaltyBps) external payable returns (uint256) {
|
|
require(msg.value >= mintFee, "fee");
|
|
require(royaltyBps <= MAX_ROYALTY_BPS, "royalty too high");
|
|
uint256 id = _nextId++;
|
|
_safeMint(msg.sender, id);
|
|
_setTokenURI(id, uri);
|
|
_royalties[id] = RoyaltyInfo(msg.sender, royaltyBps);
|
|
minterOf[id] = msg.sender;
|
|
|
|
if (msg.value > 0) {
|
|
(bool ok, ) = feeRecipient.call{value: msg.value}("");
|
|
require(ok, "fee transfer");
|
|
}
|
|
emit Minted(id, msg.sender, uri, royaltyBps);
|
|
return id;
|
|
}
|
|
|
|
function setMintFee(uint256 newFee) external onlyOwner {
|
|
mintFee = newFee;
|
|
emit MintFeeUpdated(newFee);
|
|
}
|
|
|
|
function setFeeRecipient(address newRecipient) external onlyOwner {
|
|
require(newRecipient != address(0), "zero");
|
|
feeRecipient = newRecipient;
|
|
emit FeeRecipientUpdated(newRecipient);
|
|
}
|
|
|
|
// EIP-2981
|
|
function royaltyInfo(uint256 tokenId, uint256 salePrice)
|
|
external
|
|
view
|
|
override
|
|
returns (address receiver, uint256 royaltyAmount)
|
|
{
|
|
RoyaltyInfo memory r = _royalties[tokenId];
|
|
return (r.receiver, (salePrice * r.royaltyBps) / 10000);
|
|
}
|
|
|
|
// Required overrides for ERC721Enumerable + ERC721URIStorage
|
|
function _beforeTokenTransfer(address from, address to, uint256 firstTokenId, uint256 batchSize)
|
|
internal
|
|
override(ERC721, ERC721Enumerable)
|
|
{
|
|
super._beforeTokenTransfer(from, to, firstTokenId, batchSize);
|
|
}
|
|
|
|
function _burn(uint256 tokenId) internal override(ERC721, ERC721URIStorage) {
|
|
super._burn(tokenId);
|
|
}
|
|
|
|
function tokenURI(uint256 tokenId)
|
|
public
|
|
view
|
|
override(ERC721, ERC721URIStorage)
|
|
returns (string memory)
|
|
{
|
|
return super.tokenURI(tokenId);
|
|
}
|
|
|
|
function supportsInterface(bytes4 interfaceId)
|
|
public
|
|
view
|
|
override(ERC721Enumerable, ERC721URIStorage, IERC165)
|
|
returns (bool)
|
|
{
|
|
return interfaceId == type(IERC2981).interfaceId || super.supportsInterface(interfaceId);
|
|
}
|
|
}
|