Skip to content

Commit

Permalink
Merge pull request #36 from buildship-dev/factory-v2
Browse files Browse the repository at this point in the history
factory: v2
  • Loading branch information
caffeinum authored Mar 28, 2022
2 parents a243255 + 69ed72d commit 6c68b79
Show file tree
Hide file tree
Showing 17 changed files with 651 additions and 130 deletions.
8 changes: 4 additions & 4 deletions contracts/AvatarNFTv2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ contract AvatarNFTv2 is ERC721, ERC721Enumerable, IAvatarNFT, Ownable {
string public PROVENANCE_HASH = "";
string public baseURI;

mapping (address => bool) public isExtensionAllowed;
mapping (address => bool) public isExtensionAdded;

event ExtensionAdded(address indexed extensionAddress);
event ExtensionRevoked(address indexed extensionAddress);
Expand Down Expand Up @@ -91,13 +91,13 @@ contract AvatarNFTv2 is ERC721, ERC721Enumerable, IAvatarNFT, Ownable {

require(ERC165Checker.supportsInterface(_extension, type(INFTExtension).interfaceId), "Not conforms to extension");

isExtensionAllowed[_extension] = true;
isExtensionAdded[_extension] = true;

emit ExtensionAdded(_extension);
}

function revokeExtension(address _extension) public onlyOwner {
isExtensionAllowed[_extension] = false;
isExtensionAdded[_extension] = false;

emit ExtensionRevoked(_extension);
}
Expand Down Expand Up @@ -128,7 +128,7 @@ contract AvatarNFTv2 is ERC721, ERC721Enumerable, IAvatarNFT, Ownable {
}

modifier onlyExtension() {
require(isExtensionAllowed[msg.sender], "Extension should be added to contract before minting");
require(isExtensionAdded[msg.sender], "Extension should be added to contract before minting");
_;
}

Expand Down
6 changes: 3 additions & 3 deletions contracts/MetaverseBaseNFT.sol
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ contract MetaverseBaseNFT is
isFrozen = true;
}

function isExtensionAllowed(address _extension) public view returns (bool) {
function isExtensionAdded(address _extension) public view returns (bool) {

for (uint index = 0; index < extensions.length; index++) {
if (address(extensions[index]) == _extension) {
Expand All @@ -196,7 +196,7 @@ contract MetaverseBaseNFT is
function addExtension(address _extension) public onlyOwner {
require(_extension != address(this), "Cannot add self as extension");

require(!isExtensionAllowed(_extension), "Extension already added");
require(!isExtensionAdded(_extension), "Extension already added");

extensions.push(INFTExtension(_extension));

Expand Down Expand Up @@ -262,7 +262,7 @@ contract MetaverseBaseNFT is
}

modifier onlyExtension() {
require(isExtensionAllowed(msg.sender), "Extension should be added to contract before minting");
require(isExtensionAdded(msg.sender), "Extension should be added to contract before minting");
_;
}

Expand Down
6 changes: 3 additions & 3 deletions contracts/factory/ArtNFT.sol
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ contract ArtNFT is
isFrozen = true;
}

function isExtensionAllowed(address _extension) public view returns (bool) {
function isExtensionAdded(address _extension) public view returns (bool) {
if (!ERC165Checker.supportsInterface(_extension, type(INFTExtension).interfaceId)) {
return false;
}
Expand All @@ -223,7 +223,7 @@ contract ArtNFT is
function addExtension(address _extension) public onlyOwner {
require(_extension != address(this), "Cannot add self as extension");

require(!isExtensionAllowed(_extension), "Extension already added");
require(!isExtensionAdded(_extension), "Extension already added");

extensions.push(INFTExtension(_extension));

Expand Down Expand Up @@ -285,7 +285,7 @@ contract ArtNFT is
}

modifier onlyExtension() {
require(isExtensionAllowed(msg.sender), "Extension should be added to contract before minting");
require(isExtensionAdded(msg.sender), "Extension should be added to contract before minting");
_;
}

Expand Down
2 changes: 1 addition & 1 deletion contracts/factory/IArtNFT.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ interface IArtNFT {

// ------ View functions ------
function saleStarted() external view returns (bool);
function isExtensionAllowed(address extension) external view returns (bool);
function isExtensionAdded(address extension) external view returns (bool);

/**
Extra information stored for each tokenId. Optional, provided on mint
Expand Down
2 changes: 1 addition & 1 deletion contracts/factory/IMetaverseNFT.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ interface IAvatarNFT {

// ------ View functions ------
function saleStarted() external view returns (bool);
function isExtensionAllowed(address extension) external view returns (bool);
function isExtensionAdded(address extension) external view returns (bool);

/**
Extra information stored for each tokenId. Optional, provided on mint
Expand Down
179 changes: 117 additions & 62 deletions contracts/factory/MetaverseNFT.sol

Large diffs are not rendered by default.

138 changes: 129 additions & 9 deletions contracts/factory/MetaverseNFTFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
pragma solidity ^0.8.9;

import "@openzeppelin/contracts/proxy/Clones.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

import "./MetaverseNFT.sol";


/**
* MetaverseNFT is a cloneable contract for your NFT collection.
* It's adapted from OpenZeppeling ERC721 implementation upgradeable versions.
Expand All @@ -17,16 +17,59 @@ import "./MetaverseNFT.sol";
* 3. https://docs.openzeppelin.com/contracts/4.x/api/proxy
*/

contract MetaverseNFTFactory {

address public immutable proxyImplementation;
contract MetaverseNFTFactory is Ownable {

event NFTCreated(address deployedAddress);
address public immutable proxyImplementation;
IERC721 public earlyAccessPass;

// bitmask params
uint32 constant SHOULD_START_AT_ONE = 1 << 1;
uint32 constant SHOULD_START_SALE = 1 << 2;
uint32 constant SHOULD_LOCK_PAYOUT_CHANGE = 1 << 3;

event NFTCreated(
address deployedAddress,
// creation parameters
uint256 price,
uint256 maxSupply,
uint256 nReserved,
string name,
string symbol,
bool shouldUseJSONExtension,
bool shouldStartAtOne,
bool shouldStartSale,
bool shouldLockPayoutChange

);

modifier hasAccess(address creator) {
// check that creator owns NFT
require(address(earlyAccessPass) == address(0) || earlyAccessPass.balanceOf(msg.sender) > 0, "MetaverseNFTFactory: Early Access Pass is required");
_;
}

constructor() {
constructor(address _earlyAccessPass) {
proxyImplementation = address(new MetaverseNFT());

emit NFTCreated(proxyImplementation);
earlyAccessPass = IERC721(_earlyAccessPass);

emit NFTCreated(
proxyImplementation,
0,
0,
0,
"IMPLEMENTATION",
"IMPLEMENTATION",
false,
false,
false,
false
);
}

function updateEarlyAccessPass(address _earlyAccessPass) public onlyOwner {
earlyAccessPass = IERC721(_earlyAccessPass);
}

function createNFT(
Expand All @@ -37,7 +80,7 @@ contract MetaverseNFTFactory {
uint256 _royaltyFee,
string memory _uri,
string memory _name, string memory _symbol
) external {
) external hasAccess(msg.sender) {

address clone = Clones.clone(proxyImplementation);

Expand All @@ -48,13 +91,90 @@ contract MetaverseNFTFactory {
_maxTokensPerMint,
_royaltyFee,
_uri,
_name, _symbol
_name, _symbol,
false
);

MetaverseNFT(payable(clone)).transferOwnership(msg.sender);

emit NFTCreated(clone);
emit NFTCreated(
clone,
_startPrice,
_maxSupply,
_nReserved,
_name,
_symbol,
false,
false,
false,
false
);

}

function createNFTWithSettings(
uint256 _startPrice,
uint256 _maxSupply,
uint256 _nReserved,
uint256 _maxTokensPerMint,
uint256 _royaltyFee,
string memory _uri,
string memory _name, string memory _symbol,
address payoutReceiver,
bool shouldUseJSONExtension,
uint16 miscParams
) external hasAccess(msg.sender) {

address clone = Clones.clone(proxyImplementation);

// params is a bitmask of:

// bool shouldUseJSONExtension = (miscParams & 0x01) == 0x01;
// bool startTokenIdAtOne = (miscParams & 0x02) == 0x02;
// bool shouldStartSale = (miscParams & 0x04) == 0x04;
// bool shouldLockPayoutChange = (miscParams & 0x08) == 0x08;

MetaverseNFT(payable(clone)).initialize(
_startPrice,
_maxSupply,
_nReserved,
_maxTokensPerMint,
_royaltyFee,
_uri,
_name, _symbol,
miscParams & SHOULD_START_AT_ONE != 0
);

if (shouldUseJSONExtension) {
MetaverseNFT(payable(clone)).setPostfixURI(".json");
}

if (miscParams & SHOULD_START_SALE != 0) {
MetaverseNFT(payable(clone)).startSale();
}

if (payoutReceiver != address(0)) {
MetaverseNFT(payable(clone)).setPayoutReceiver(payoutReceiver);
}

if (miscParams & SHOULD_LOCK_PAYOUT_CHANGE != 0) {
MetaverseNFT(payable(clone)).lockPayoutChange();
}

MetaverseNFT(payable(clone)).transferOwnership(msg.sender);

emit NFTCreated(
clone,
_startPrice,
_maxSupply,
_nReserved,
_name,
_symbol,
shouldUseJSONExtension,
miscParams & SHOULD_START_AT_ONE != 0,
miscParams & SHOULD_START_SALE != 0,
miscParams & SHOULD_LOCK_PAYOUT_CHANGE != 0
);
}

}
28 changes: 28 additions & 0 deletions contracts/factory/extensions/JSONTokenURIExtension.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;

import "@openzeppelin/contracts/utils/introspection/ERC165.sol";

import "./INFTExtension.sol";
import "./NFTExtension.sol";
import "../IMetaverseNFT.sol";

contract JSONTokenURIExtension is NFTExtension, INFTURIExtension {

// IMetaverseNFT public immutable nft;

string public suffix;

constructor(address _nft, string memory _suffix) NFTExtension(_nft) {
// nft = IMetaverseNFT(_nft);
suffix = _suffix;
}

function supportsInterface(bytes4 interfaceId) public override(IERC165, NFTExtension) view returns (bool) {
return interfaceId == type(INFTURIExtension).interfaceId || super.supportsInterface(interfaceId);
}

function tokenURI(uint256) public view returns (string memory uri) {
uri = string(abi.encodePacked(uri, suffix));
}
}
4 changes: 2 additions & 2 deletions contracts/factory/extensions/NFTExtension.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ contract NFTExtension is INFTExtension, ERC165 {
}

function beforeMint() internal view {
require(nft.isExtensionAllowed(address(this)), "NFTExtension: this contract is not allowed to be used as an extension");
require(nft.isExtensionAdded(address(this)), "NFTExtension: this contract is not allowed to be used as an extension");
}

function supportsInterface(bytes4 interfaceId) public override(IERC165, ERC165) view returns (bool) {
function supportsInterface(bytes4 interfaceId) public virtual override(IERC165, ERC165) view returns (bool) {
return interfaceId == type(INFTExtension).interfaceId || super.supportsInterface(interfaceId);
}

Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"mocha-junit-reporter": "^2.0.2"
},
"devDependencies": {
"@openzeppelin/test-helpers": "^0.5.13",
"@openzeppelin/test-helpers": "^0.5.15",
"@truffle/hdwallet-provider": "^1.5.0",
"chai": "^4.3.4",
"eth-gas-reporter": "^0.2.23",
Expand Down
2 changes: 1 addition & 1 deletion test/factory/MintPassTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ contract("MintPass – Extension", (accounts) => {
await nft.addExtension(extension.address);

assert.equal(
await nft.isExtensionAllowed(extension.address),
await nft.isExtensionAdded(extension.address),
true,
)
});
Expand Down
4 changes: 2 additions & 2 deletions test/factory/art.js
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ contract("ArtNFT – Implementation", accounts => {

await nft.addExtension(extension.address);
assert.equal(
await nft.isExtensionAllowed(extension.address),
await nft.isExtensionAdded(extension.address),
true,
);
// check that extensions(0) is extension address
Expand All @@ -402,7 +402,7 @@ contract("ArtNFT – Implementation", accounts => {
await nft.revokeExtension(extension.address);

assert.equal(
await nft.isExtensionAllowed(extension.address),
await nft.isExtensionAdded(extension.address),
false,
);

Expand Down
Loading

0 comments on commit 6c68b79

Please sign in to comment.