add Base, Owner, and Master tokens

This commit is contained in:
0xb337r007 2023-07-14 15:05:30 +02:00
parent 4eac7f1a69
commit d0fddfdd73
4 changed files with 222 additions and 124 deletions

155
contracts/mvp/BaseToken.sol Normal file
View File

@ -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
}

View File

@ -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;
string memory _baseTokenURI,
address _ownerToken,
address _masterToken
) BaseToken(
_name,
_symbol,
_maxSupply,
_remoteBurnable,
_transferable,
_baseTokenURI,
_ownerToken,
_masterToken) {
}
// 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();
}
}
// 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
}

View File

@ -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)) {
}
}

View File

@ -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");
}
}