Skip to content

Genart factory #18

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@
[submodule "lib/openzeppelin-contracts"]
path = lib/openzeppelin-contracts
url = https://github.com/OpenZeppelin/openzeppelin-contracts
[submodule "lib/openzeppelin-contracts-upgradeable"]
path = lib/openzeppelin-contracts-upgradeable
url = https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable
1 change: 1 addition & 0 deletions lib/openzeppelin-contracts-upgradeable
3 changes: 2 additions & 1 deletion remappings.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/
@openzeppelin/contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/
@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/
6 changes: 4 additions & 2 deletions script/BaseGen.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pragma solidity ^0.8.20;
import "forge-std/Script.sol";
import "forge-std/console2.sol";
import "../src/BaseGen.sol";
import "../src/GenArtFactory.sol";

contract MyScript is Script {
function run() external {
Expand All @@ -18,8 +19,9 @@ contract MyScript is Script {
string memory baseURI = "https://dyndata.deno.dev/base/content/";
uint256 maxSupply = 64;
address receiver = 0xE844b2a0a6453250c920BD2b4B7741946aB16C08;

BaseGen nft = new BaseGen(initialOwner, name, symbol, contractURI, baseURI, maxSupply, receiver);
BaseGen baseGen = new BaseGen();
GenArtFactory factory = new GenArtFactory(address(baseGen));
BaseGen nft = BaseGen(factory.createGenArt(initialOwner, name, symbol, contractURI, baseURI, maxSupply, receiver));
console2.log("Contract deployed to %s", address(nft));

vm.stopBroadcast();
Expand Down
35 changes: 23 additions & 12 deletions src/BaseGen.sol
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Royalty.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

import {ERC721Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol";
import {ERC721BurnableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721BurnableUpgradeable.sol";
import {ERC721RoyaltyUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721RoyaltyUpgradeable.sol";
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts/utils/Base64.sol";
import "@openzeppelin/contracts/utils/Strings.sol";

contract BaseGen is ERC721, ERC721Burnable, ERC721Royalty, Ownable {
contract BaseGen is Initializable, ERC721Upgradeable, ERC721BurnableUpgradeable, ERC721RoyaltyUpgradeable, OwnableUpgradeable {
uint256 private _nextTokenId;
string private _contractURI;
string private _generatorURI;
uint256 private _maxSupply;
address private _receiver;
uint256 private _mintPrice = 0.0015 ether;
uint256 private _mintPrice;

mapping(uint256 tokenId => string) private _tokenURIs;

Expand All @@ -32,24 +34,33 @@ contract BaseGen is ERC721, ERC721Burnable, ERC721Royalty, Ownable {

error MintQuantityCannotBeZero();

constructor(
address initialOwner,
function initialize(address initialOwner,
string memory name_,
string memory symbol_,
string memory contractURI_,
string memory baseURI_,
uint256 maxSupply_,
address receiver_
) ERC721(name_, symbol_) Ownable(initialOwner) {
address receiver_,
uint256 mintPrice_
) initializer public {
__ERC721_init(name_, symbol_);
__ERC721Burnable_init();
__ERC721Royalty_init();
__Ownable_init(initialOwner);
// setContractURI(contractURI_);
// setMaxSupply(maxSupply_);
_generatorURI = string.concat(baseURI_, Strings.toHexString(uint160(address(this)), 20), "/");
_contractURI = contractURI_;
_maxSupply = maxSupply_;
_receiver = receiver_;
_mintPrice = mintPrice_;
_setDefaultRoyalty(receiver_, 5e2); //
}

constructor(){
_disableInitializers();
}

function _baseURI() internal view override returns (string memory) {
return _generatorURI;
}
Expand Down Expand Up @@ -166,11 +177,11 @@ contract BaseGen is ERC721, ERC721Burnable, ERC721Royalty, Ownable {
}
}

function tokenURI(uint256 tokenId) public view override(ERC721) returns (string memory) {
function tokenURI(uint256 tokenId) public view override(ERC721Upgradeable) returns (string memory) {
return super.tokenURI(tokenId);
}

function supportsInterface(bytes4 interfaceId) public view override(ERC721, ERC721Royalty) returns (bool) {
function supportsInterface(bytes4 interfaceId) public view override(ERC721Upgradeable, ERC721RoyaltyUpgradeable) returns (bool) {
return super.supportsInterface(interfaceId);
}
}
41 changes: 41 additions & 0 deletions src/GenArtFactory.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

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

import "./BaseGen.sol";

contract GenArtFactory {
address public baseGen;
uint256 private _mintPrice = 0.0015 ether;

event GenArtCreated(address newContract);

constructor(address _baseGen) {
baseGen = _baseGen;
}

function createGenArt(
address initialOwner,
string memory name,
string memory symbol,
string memory contractURI,
string memory baseURI,
uint256 maxSupply,
address receiver
) external returns (address) {
address clone = Clones.clone(baseGen);
BaseGen(clone).initialize(
initialOwner,
name,
symbol,
contractURI,
baseURI,
maxSupply,
receiver,
_mintPrice
);
emit GenArtCreated(clone);
return clone;
}
}
5 changes: 4 additions & 1 deletion test/BaseBatchGen.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ pragma solidity ^0.8.20;

import "forge-std/Test.sol";
import "../src/BaseGen.sol";
import "../src/GenArtFactory.sol";

// https://hackernoon.com/implementing-the-erc-2981-nft-royalty-standard-with-solidity
contract BaseBatchGenTest is Test {
Expand All @@ -19,7 +20,9 @@ contract BaseBatchGenTest is Test {
string memory contractURI = "ipfs://";
string memory baseURI = "https://data.kodadot.xyz/base/"; // suffixed with /?hash=
address receiver = vm.addr(2);
instance = new BaseGen(initialOwner, name, symbol, contractURI, baseURI, maxSupply, receiver);
BaseGen baseGen = new BaseGen();
GenArtFactory factory = new GenArtFactory(address(baseGen));
instance = BaseGen(factory.createGenArt(initialOwner, name, symbol, contractURI, baseURI, maxSupply, receiver));

// instance.safeBatchMint{value: pricePerMint * pieces}(initialOwner, pieces);
// instance.setMaxSupply(128);
Expand Down
5 changes: 4 additions & 1 deletion test/BaseGen.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ pragma solidity ^0.8.20;

import "forge-std/Test.sol";
import "../src/BaseGen.sol";
import "../src/GenArtFactory.sol";

// https://hackernoon.com/implementing-the-erc-2981-nft-royalty-standard-with-solidity
contract BaseGenTest is Test {
Expand All @@ -18,7 +19,9 @@ contract BaseGenTest is Test {
string memory baseURI = "https://data.kodadot.xyz/base/"; // suffixed with /?hash=
uint256 maxSupply = 256;
address receiver = vm.addr(2);
instance = new BaseGen(initialOwner, name, symbol, contractURI, baseURI, maxSupply, receiver);
BaseGen baseGen = new BaseGen();
GenArtFactory factory = new GenArtFactory(address(baseGen));
instance = BaseGen(factory.createGenArt(initialOwner, name, symbol, contractURI, baseURI, maxSupply, receiver));
instance.safeMint{value: pricePerMint}(initialOwner);
}

Expand Down
65 changes: 65 additions & 0 deletions test/GenArtFactory.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "forge-std/Test.sol";
import "../src/BaseGen.sol";
import "../src/GenArtFactory.sol";
import "@openzeppelin/contracts/utils/Strings.sol";

contract GenArtFactoryTest is Test {
GenArtFactory public factory;
uint256 public constant pricePerMint = 0.0015 ether;
uint256 public constant quantity = 10;
uint256 public maxSupply = 20;
string public symbol = "GEN";
string public contractURI = "ipfs://";
string public baseURI = "https://data.kodadot.xyz/base/";
address receiver = vm.addr(20);


function setUp() public {
BaseGen baseGen = new BaseGen();
factory = new GenArtFactory(address(baseGen));

// instance.safeBatchMint{value: pricePerMint * pieces}(initialOwner, pieces);
// instance.setMaxSupply(128);
}

function testCreateGenArt() public {

for (uint256 i = 0; i < quantity; i++) {
address initialOwner = vm.addr(i+1);
string memory name = string.concat("Generative", Strings.toString(i));

vm.expectEmit(true,true,true,false);
emit GenArtFactory.GenArtCreated(address(0));

BaseGen instance = BaseGen(factory.createGenArt(initialOwner, name, symbol, contractURI, baseURI, maxSupply, receiver));

// Assert initial state
assertEq(instance.totalSupply(), 0);
assertEq(instance.name(), name);

// Calculate the total cost for minting
uint256 totalCost = pricePerMint * quantity;
vm.deal(initialOwner, totalCost);

// Prank msg.sender as initialOwner to simulate the mint transaction
vm.prank(initialOwner);

// Send sufficient funds to mint
instance.safeBatchMint{value: totalCost}(initialOwner, quantity);

// Assert that totalSupply is updated correctly
assertEq(instance.totalSupply(), quantity);
// assertEq(instance.ownerOf(i), initialOwner);

// Assert that the contract balance is transferred correctly
uint256 expectedBalance = totalCost / 2;
assertEq(receiver.balance, expectedBalance*(i+1));
assertEq(initialOwner.balance, expectedBalance);
}

}

}
Loading