add Base, Owner, and Master tokens
This commit is contained in:
parent
4eac7f1a69
commit
d0fddfdd73
|
@ -0,0 +1,155 @@
|
|||
// SPDX-License-Identifier: Mozilla Public License 2.0
|
||||
pragma solidity ^0.8.17;
|
||||
|
||||
import "@openzeppelin/contracts/access/Ownable.sol";
|
||||
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
|
||||
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
|
||||
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
|
||||
import "@openzeppelin/contracts/utils/Context.sol";
|
||||
import "@openzeppelin/contracts/utils/Counters.sol";
|
||||
|
||||
abstract contract BaseToken is
|
||||
Context,
|
||||
ERC721Enumerable
|
||||
{
|
||||
using Counters for Counters.Counter;
|
||||
|
||||
// State variables
|
||||
|
||||
Counters.Counter private _tokenIdTracker;
|
||||
|
||||
/**
|
||||
* If we want unlimited total supply we should set maxSupply to 2^256-1.
|
||||
*/
|
||||
uint256 public maxSupply;
|
||||
|
||||
address public ownerToken;
|
||||
address public masterToken;
|
||||
|
||||
/**
|
||||
* If set to true, the contract owner can burn any token.
|
||||
*/
|
||||
bool public remoteBurnable;
|
||||
|
||||
/**
|
||||
* If set to false it acts as a soulbound token.
|
||||
*/
|
||||
bool public transferable;
|
||||
|
||||
string public baseTokenURI;
|
||||
|
||||
constructor(
|
||||
string memory _name,
|
||||
string memory _symbol,
|
||||
uint256 _maxSupply,
|
||||
bool _remoteBurnable,
|
||||
bool _transferable,
|
||||
string memory _baseTokenURI,
|
||||
address _ownerToken,
|
||||
address _masterToken
|
||||
) ERC721(_name, _symbol) {
|
||||
maxSupply = _maxSupply;
|
||||
remoteBurnable = _remoteBurnable;
|
||||
transferable = _transferable;
|
||||
baseTokenURI = _baseTokenURI;
|
||||
ownerToken = _ownerToken;
|
||||
masterToken = _masterToken;
|
||||
|
||||
require(ownerToken != address(0x0) || masterToken != address(0x0), "owner or master tokens required");
|
||||
}
|
||||
|
||||
modifier onlyOwner() {
|
||||
require(
|
||||
(ownerToken == address(0) || IERC721(ownerToken).balanceOf(msg.sender) > 0) ||
|
||||
(masterToken == address(0) || IERC721(masterToken).balanceOf(msg.sender) > 0),
|
||||
"Not authorized"
|
||||
);
|
||||
|
||||
_;
|
||||
}
|
||||
|
||||
// Events
|
||||
|
||||
// External functions
|
||||
|
||||
function setMaxSupply(uint256 newMaxSupply) virtual external onlyOwner {
|
||||
require(newMaxSupply >= totalSupply(), "MAX_SUPPLY_LOWER_THAN_TOTAL_SUPPLY");
|
||||
maxSupply = newMaxSupply;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Creates a new token for each address in `addresses`. Its token ID will be automatically
|
||||
* assigned (and available on the emitted {IERC721-Transfer} event), and the token
|
||||
* URI autogenerated based on the base URI passed at construction.
|
||||
*
|
||||
*/
|
||||
function mintTo(address[] memory addresses) external onlyOwner {
|
||||
// We cannot just use totalSupply() to create the new tokenId because tokens
|
||||
// can be burned so we use a separate counter.
|
||||
require(_tokenIdTracker.current() + addresses.length <= maxSupply, "MAX_SUPPLY_REACHED");
|
||||
|
||||
for (uint256 i = 0; i < addresses.length; i++) {
|
||||
_safeMint(addresses[i], _tokenIdTracker.current(), "");
|
||||
_tokenIdTracker.increment();
|
||||
}
|
||||
}
|
||||
|
||||
// Public functions
|
||||
|
||||
function mintedCount() public view returns (uint256) {
|
||||
return _tokenIdTracker.current();
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice remoteBurn allows the owner to burn a token
|
||||
* @param tokenIds The list of token IDs to be burned
|
||||
*/
|
||||
function remoteBurn(uint256[] memory tokenIds) public onlyOwner {
|
||||
require(remoteBurnable, "NOT_REMOTE_BURNABLE");
|
||||
|
||||
for (uint256 i = 0; i < tokenIds.length; i++) {
|
||||
_burn(tokenIds[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev See {IERC165-supportsInterface}.
|
||||
*/
|
||||
function supportsInterface(bytes4 interfaceId)
|
||||
public
|
||||
view
|
||||
virtual
|
||||
override(ERC721Enumerable)
|
||||
returns (bool)
|
||||
{
|
||||
return super.supportsInterface(interfaceId);
|
||||
}
|
||||
|
||||
// Internal functions
|
||||
|
||||
/**
|
||||
* @notice
|
||||
* @dev
|
||||
*/
|
||||
function _baseURI() internal view virtual override returns (string memory) {
|
||||
return baseTokenURI;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice
|
||||
* @dev
|
||||
*/
|
||||
function _beforeTokenTransfer(
|
||||
address from,
|
||||
address to,
|
||||
uint256 firstTokenId,
|
||||
uint256 batchSize
|
||||
) internal virtual override(ERC721Enumerable) {
|
||||
if (from != address(0) && to != address(0) && !transferable) {
|
||||
revert("not transferable");
|
||||
}
|
||||
super._beforeTokenTransfer(from, to, firstTokenId, batchSize);
|
||||
}
|
||||
|
||||
// Private functions
|
||||
}
|
|
@ -1,136 +1,26 @@
|
|||
// SPDX-License-Identifier: Mozilla Public License 2.0
|
||||
pragma solidity ^0.8.17;
|
||||
|
||||
import "@openzeppelin/contracts/access/Ownable.sol";
|
||||
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
|
||||
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
|
||||
import "@openzeppelin/contracts/utils/Context.sol";
|
||||
import "@openzeppelin/contracts/utils/Counters.sol";
|
||||
|
||||
contract CollectibleV1 is
|
||||
Context,
|
||||
ERC721Enumerable,
|
||||
Ownable
|
||||
{
|
||||
using Counters for Counters.Counter;
|
||||
|
||||
// State variables
|
||||
|
||||
Counters.Counter private _tokenIdTracker;
|
||||
|
||||
/**
|
||||
* If we want unlimited total supply we should set maxSupply to 2^256-1.
|
||||
*/
|
||||
uint256 public maxSupply;
|
||||
|
||||
/**
|
||||
* If set to true, the contract owner can burn any token.
|
||||
*/
|
||||
bool public remoteBurnable;
|
||||
|
||||
/**
|
||||
* If set to false it acts as a soulbound token.
|
||||
*/
|
||||
bool public transferable;
|
||||
|
||||
string public baseTokenURI;
|
||||
import "./BaseToken.sol";
|
||||
|
||||
contract CollectibleV1 is BaseToken {
|
||||
constructor(
|
||||
string memory _name,
|
||||
string memory _symbol,
|
||||
uint256 _maxSupply,
|
||||
bool _remoteBurnable,
|
||||
bool _transferable,
|
||||
string memory _baseTokenURI
|
||||
) ERC721(_name, _symbol) {
|
||||
maxSupply = _maxSupply;
|
||||
remoteBurnable = _remoteBurnable;
|
||||
transferable = _transferable;
|
||||
baseTokenURI = _baseTokenURI;
|
||||
}
|
||||
|
||||
// Events
|
||||
|
||||
// External functions
|
||||
|
||||
function setMaxSupply(uint256 newMaxSupply) external onlyOwner {
|
||||
require(newMaxSupply >= totalSupply(), "MAX_SUPPLY_LOWER_THAN_TOTAL_SUPPLY");
|
||||
maxSupply = newMaxSupply;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Creates a new token for each address in `addresses`. Its token ID will be automatically
|
||||
* assigned (and available on the emitted {IERC721-Transfer} event), and the token
|
||||
* URI autogenerated based on the base URI passed at construction.
|
||||
*
|
||||
*/
|
||||
function mintTo(address[] memory addresses) external onlyOwner {
|
||||
// We cannot just use totalSupply() to create the new tokenId because tokens
|
||||
// can be burned so we use a separate counter.
|
||||
require(_tokenIdTracker.current() + addresses.length <= maxSupply, "MAX_SUPPLY_REACHED");
|
||||
|
||||
for (uint256 i = 0; i < addresses.length; i++) {
|
||||
_safeMint(addresses[i], _tokenIdTracker.current(), "");
|
||||
_tokenIdTracker.increment();
|
||||
string memory _baseTokenURI,
|
||||
address _ownerToken,
|
||||
address _masterToken
|
||||
) BaseToken(
|
||||
_name,
|
||||
_symbol,
|
||||
_maxSupply,
|
||||
_remoteBurnable,
|
||||
_transferable,
|
||||
_baseTokenURI,
|
||||
_ownerToken,
|
||||
_masterToken) {
|
||||
}
|
||||
}
|
||||
|
||||
// Public functions
|
||||
|
||||
function mintedCount() public view returns (uint256) {
|
||||
return _tokenIdTracker.current();
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice remoteBurn allows the owner to burn a token
|
||||
* @param tokenIds The list of token IDs to be burned
|
||||
*/
|
||||
function remoteBurn(uint256[] memory tokenIds) public onlyOwner {
|
||||
require(remoteBurnable, "NOT_REMOTE_BURNABLE");
|
||||
|
||||
for (uint256 i = 0; i < tokenIds.length; i++) {
|
||||
_burn(tokenIds[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev See {IERC165-supportsInterface}.
|
||||
*/
|
||||
function supportsInterface(bytes4 interfaceId)
|
||||
public
|
||||
view
|
||||
virtual
|
||||
override(ERC721Enumerable)
|
||||
returns (bool)
|
||||
{
|
||||
return super.supportsInterface(interfaceId);
|
||||
}
|
||||
|
||||
// Internal functions
|
||||
|
||||
/**
|
||||
* @notice
|
||||
* @dev
|
||||
*/
|
||||
function _baseURI() internal view virtual override returns (string memory) {
|
||||
return baseTokenURI;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice
|
||||
* @dev
|
||||
*/
|
||||
function _beforeTokenTransfer(
|
||||
address from,
|
||||
address to,
|
||||
uint256 firstTokenId,
|
||||
uint256 batchSize
|
||||
) internal virtual override(ERC721Enumerable) {
|
||||
if (from != address(0) && to != address(0) && !transferable) {
|
||||
revert("not transferable");
|
||||
}
|
||||
super._beforeTokenTransfer(from, to, firstTokenId, batchSize);
|
||||
}
|
||||
|
||||
// Private functions
|
||||
}
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
// SPDX-License-Identifier: Mozilla Public License 2.0
|
||||
pragma solidity ^0.8.17;
|
||||
|
||||
import "./BaseToken.sol";
|
||||
|
||||
contract MasterToken is BaseToken {
|
||||
constructor(
|
||||
string memory _name,
|
||||
string memory _symbol,
|
||||
string memory _baseTokenURI,
|
||||
address _ownerToken
|
||||
) BaseToken(
|
||||
_name,
|
||||
_symbol,
|
||||
type(uint256).max,
|
||||
true,
|
||||
false,
|
||||
_baseTokenURI,
|
||||
_ownerToken,
|
||||
address(0x0)) {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
// SPDX-License-Identifier: Mozilla Public License 2.0
|
||||
pragma solidity ^0.8.17;
|
||||
|
||||
import "./BaseToken.sol";
|
||||
import "./MasterToken.sol";
|
||||
|
||||
contract OwnerToken is BaseToken {
|
||||
constructor(
|
||||
string memory _name,
|
||||
string memory _symbol,
|
||||
string memory _baseTokenURI,
|
||||
string memory _masterName,
|
||||
string memory _masterSymbol,
|
||||
string memory _masterBaseTokenURI
|
||||
) BaseToken(
|
||||
_name,
|
||||
_symbol,
|
||||
1,
|
||||
false,
|
||||
true,
|
||||
_baseTokenURI,
|
||||
address(this),
|
||||
address(this))
|
||||
{
|
||||
new MasterToken(_masterName, _masterSymbol, _masterBaseTokenURI, address(this));
|
||||
}
|
||||
|
||||
function setMaxSupply(uint256 _newMaxSupply) override external onlyOwner {
|
||||
revert("max supply locked");
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue