Skip to content

Commit

Permalink
feat: unit tests, deployment and interaction with deployed contracts
Browse files Browse the repository at this point in the history
  • Loading branch information
michojekunle committed Sep 16, 2024
1 parent 0e0b112 commit 5d25e69
Show file tree
Hide file tree
Showing 26 changed files with 225,241 additions and 136 deletions.
6 changes: 6 additions & 0 deletions cave-nft-metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "CaveParty",
"description": "CaveParty: party in the woods get into ze event! bamm 🔥💥",
"external_url": "https://pinata.cloud/",
"image": "ipfs://QmNvhC1B8iZwUyJ1eDypfTgZJpJKpzM5cWfaCCvscnmptY"
}
49 changes: 14 additions & 35 deletions contracts/nft-old.sol → contracts/CaveParty.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,25 @@
pragma solidity ^0.8.24;

import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract FluffyFur is ERC721, ERC721URIStorage, Ownable(msg.sender) {
contract CaveParty is ERC721, Ownable(msg.sender) {
// events
event Minted(uint256 tokenId);

// statet variables
uint256 public totalMints = 0;
uint256 public mintPrice = 0.001 ether;
uint256 public maxSupply = 280;
uint256 public mintPrice = 0.0001 ether;
uint256 public maxPerWallet = 1;
string private assetMetadata =
"ipfs://QmfAYUMMB7NE9NQk2P91GbyWrEm1XWTGSoCcTFhZDZgFwD";
string public assetMetadata =
"ipfs://QmeXnyhrkEGfKzQRtusyWNFKcjyZxLcU1puRvxLkK2kTeS";

// mappings
mapping(address => uint256) walletMints;
mapping(address => uint256) public walletMints;

// functions
constructor() ERC721("FluffyFury", "FFY") {}
constructor() ERC721("CaveParty", "CPY") {}

function _baseURI() internal view override returns (string memory) {
return assetMetadata;
Expand All @@ -33,11 +31,10 @@ contract FluffyFur is ERC721, ERC721URIStorage, Ownable(msg.sender) {
totalMints++;

_safeMint(to, tokenId);
_setTokenURI(tokenId, assetMetadata);
}

function mintToken() external payable {
require(mintPrice == msg.value, "wrong amount sent");
require(mintPrice == msg.value, "0.0001 ether required to mint");
require(
walletMints[msg.sender] <= maxPerWallet,
"mints per wallet exceeded"
Expand All @@ -47,43 +44,25 @@ contract FluffyFur is ERC721, ERC721URIStorage, Ownable(msg.sender) {
safeMint(msg.sender);
}

// The following functions are overrides required by Solidity.
function tokenURI(uint256 tokenId)
public
view
override(ERC721, ERC721URIStorage)
returns (string memory)
{
return super.tokenURI(tokenId);
}

function supportsInterface(bytes4 interfaceId)
public
view
override(ERC721, ERC721URIStorage)
returns (bool)
{
return super.supportsInterface(interfaceId);
}

function getMyWalletMints() external view returns (uint256) {
return walletMints[msg.sender];
}

function withdrawFunds() external {
require(msg.sender == owner(), "You're not the owner");

function withdrawFunds() external onlyOwner {
(bool sent, ) = owner().call{value: address(this).balance}("");
require(sent, "withdrawal failed");
}

function updateMetadata(string memory _newAssetMetadata) external {
require(msg.sender == owner(), "You're not the owner");
function updateMetadata(string memory _newAssetMetadata) external onlyOwner {
require(checkMetadata(_newAssetMetadata), "Invalid asset metadata: must include 'ipfs://'");

assetMetadata = _newAssetMetadata;
}

function getAssetMetadata() external view onlyOwner returns(string memory) {
return assetMetadata;
}

function checkMetadata(string memory _newAssetMetadata) private pure returns (bool) {
bytes memory metadataBytes = bytes(_newAssetMetadata);
bytes memory ipfsBytes = bytes("ipfs://");
Expand All @@ -105,4 +84,4 @@ contract FluffyFur is ERC721, ERC721URIStorage, Ownable(msg.sender) {

return false;
}
}
}
10 changes: 6 additions & 4 deletions contracts/FluffyFuryNFT.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ pragma solidity ^0.8.4;
import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

import {Base64} from "./Base64.sol";

contract FluffyFury is ERC721URIStorage, Ownable(msg.sender) {
event Minted(uint256 tokenId);


uint256 private _tokenIdCounter;
uint256 public mintPrice = 0.0001 ether; // Specify the mint price in ether
string public svgData; // The SVG stored in the contract
Expand All @@ -21,19 +23,19 @@ contract FluffyFury is ERC721URIStorage, Ownable(msg.sender) {

// Modifier to check if the payment sent is correct
modifier mintPricePaid() {
require(msg.value == mintPrice, "Incorrect Ether amount sent");
require(msg.value == mintPrice, "0.0001 ether required to mint");
_;
}

// Converts an SVG to a Base64 string
function svgToImageURI(string memory svg) public pure returns (string memory) {
function svgToImageURI(string memory svg) private pure returns (string memory) {
string memory baseURL = "data:image/svg+xml;base64,";
string memory svgBase64Encoded = Base64.encode(bytes(svg));
return string(abi.encodePacked(baseURL, svgBase64Encoded));
}

// Generates a tokenURI using the Base64 string as the image
function formatTokenURI(string memory imageURI) public pure returns (string memory) {
function formatTokenURI(string memory imageURI) private pure returns (string memory) {
return
string(
abi.encodePacked(
Expand Down Expand Up @@ -74,7 +76,7 @@ contract FluffyFury is ERC721URIStorage, Ownable(msg.sender) {
require(sent, "Withdrawal failed");
}

// Allows the owner to update the SVG, after validating that the new SVG contains "ipfs://"
// Allows the owner to update the SVG
function updateSVG(string memory _newSvg) external onlyOwner {
require(bytes(_newSvg).length > 0, "SVG data cannot be empty");
require(bytes(_newSvg).length <= 5000, "SVG data too large"); // Add size validation if needed
Expand Down
100 changes: 77 additions & 23 deletions contracts/NFTGatedEventManager.sol
Original file line number Diff line number Diff line change
@@ -1,29 +1,39 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

import {IERC721} from './interfaces/IERC721.sol';
import {IERC721} from "./interfaces/IERC721.sol";
import {IERC165} from "./interfaces/IERC165.sol";

contract NFTGatedEventManager {
struct Event {
string eventName; // Name of the event
uint256 eventDate; // Event date (timestamp)
address nftRequired; // NFT address required for this event
uint256 maxCapacity; // Maximum number of participants allowed
string eventName; // Name of the event
uint256 eventDate; // Event date (timestamp)
address nftRequired; // NFT address required for this event
bool isActive; // Event status
uint256 maxCapacity; // Maximum number of participants allowed
uint256 registeredCount; // Current number of participants
bool isActive; // Event status
mapping(address => bool) isRegistered; // Tracks users who have registered
}

uint256 public eventIdCounter; // Unique ID counter for events
uint256 public eventIdCounter; // Unique ID counter for events
mapping(uint256 => Event) public events; // Maps event ID to Event struct
address public owner; // Contract owner for event management

modifier onlyOwner() {
require(msg.sender == owner, "Only the contract owner can call this function.");
require(
msg.sender == owner,
"Only the contract owner can call this function."
);
_;
}

event EventCreated(uint256 eventId, string eventName, uint256 eventDate, address nftRequired, uint256 maxCapacity);
event EventCreated(
uint256 eventId,
string eventName,
uint256 eventDate,
address nftRequired,
uint256 maxCapacity
);
event UserRegistered(uint256 eventId, address user);
event EventStatusUpdated(uint256 eventId, bool newStatus);

Expand All @@ -33,22 +43,44 @@ contract NFTGatedEventManager {

// Event creation: Only the owner can create an event
function createEvent(
string memory _eventName,
uint256 _eventDate,
address _nftRequired,
string memory _eventName,
uint256 _eventDate,
address _nftRequired,
uint256 _maxCapacity
) public onlyOwner {
require(_eventDate > block.timestamp, "Event date must be in the future.");
require(
_eventDate > block.timestamp,
"Event date must be in the future."
);
require(_maxCapacity > 0, "Max capacity must be greater than zero.");

// Check if the require nft address is a contract
uint32 size;
assembly {
size := extcodesize(_nftRequired)
}
require(size > 0, "Required NFT address is not a contract");

// Check if the nft contract supports ERC721 interface
require(
IERC165(_nftRequired).supportsInterface(type(IERC721).interfaceId),
"Required NFT Address is not an ERC721 contract"
);

Event storage newEvent = events[eventIdCounter];
newEvent.eventName = _eventName;
newEvent.eventDate = _eventDate;
newEvent.nftRequired = _nftRequired;
newEvent.maxCapacity = _maxCapacity;
newEvent.isActive = true;

emit EventCreated(eventIdCounter, _eventName, _eventDate, _nftRequired, _maxCapacity);
emit EventCreated(
eventIdCounter,
_eventName,
_eventDate,
_nftRequired,
_maxCapacity
);

eventIdCounter++; // Increment event ID counter for the next event
}
Expand All @@ -57,10 +89,22 @@ contract NFTGatedEventManager {
function registerForEvent(uint256 _eventId) external {
Event storage currentEvent = events[_eventId];
require(currentEvent.isActive, "Event is not active.");
require(block.timestamp < currentEvent.eventDate, "Event registration has closed.");
require(currentEvent.registeredCount < currentEvent.maxCapacity, "Event is fully booked.");
require(!currentEvent.isRegistered[msg.sender], "You are already registered for this event.");
require(IERC721(currentEvent.nftRequired).balanceOf(msg.sender) > 0, "You do not own the required NFT.");
require(
block.timestamp < currentEvent.eventDate,
"Event registration has closed."
);
require(
currentEvent.registeredCount < currentEvent.maxCapacity,
"Event is fully booked."
);
require(
!currentEvent.isRegistered[msg.sender],
"You are already registered for this event."
);
require(
IERC721(currentEvent.nftRequired).balanceOf(msg.sender) > 0,
"You do not own the required NFT."
);

// Register the user
currentEvent.isRegistered[msg.sender] = true;
Expand All @@ -70,9 +114,13 @@ contract NFTGatedEventManager {
}

// Get event details by ID
function getEventDetails(uint256 _eventId) external view returns (
string memory, uint256, address, uint256, uint256, bool
) {
function getEventDetails(
uint256 _eventId
)
external
view
returns (string memory, uint256, address, uint256, uint256, bool)
{
Event storage currentEvent = events[_eventId];
return (
currentEvent.eventName,
Expand All @@ -85,15 +133,21 @@ contract NFTGatedEventManager {
}

// Toggle event status (activate/deactivate)
function updateEventStatus(uint256 _eventId, bool _isActive) external onlyOwner {
function updateEventStatus(
uint256 _eventId,
bool _isActive
) external onlyOwner {
Event storage currentEvent = events[_eventId];
currentEvent.isActive = _isActive;

emit EventStatusUpdated(_eventId, _isActive);
}

// Check if a user is registered for an event
function isUserRegistered(uint256 _eventId, address _user) external view returns (bool) {
function isUserRegistered(
uint256 _eventId,
address _user
) external view returns (bool) {
return events[_eventId].isRegistered[_user];
}
}
16 changes: 16 additions & 0 deletions contracts/interfaces/ICaveParty.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import {IERC721} from "./IERC721.sol";

interface ICaveParty is IERC721 {
function getAssetMetadata() external view returns (string memory);

function updateMetadata(string memory _newAssetMetadata) external;

function withdrawFunds() external;

function getMyWalletMints() external view returns (uint256);

function mintToken() external payable;
}
14 changes: 14 additions & 0 deletions contracts/interfaces/IFluffyNft.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.4;

import {IERC721} from "./IERC721.sol";

interface IFluffyFury is IERC721 {
function mint() external payable;

function withdrawFunds() external;

function updateSVG(string memory _newSvg) external;

function transferOwnership(address newOwner) external;
}
Empty file.
32 changes: 32 additions & 0 deletions contracts/interfaces/INFTGatedEventManager.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

interface INFTGatedEventManager {
// Event creation: Only the owner can create an event
function createEvent(
string memory _eventName,
uint256 _eventDate,
address _nftRequired,
uint256 _maxCapacity
) external;

// Register for an event: Verifies NFT ownership
function registerForEvent(uint256 _eventId) external;

// Get event details by ID
function getEventDetails(
uint256 _eventId
)
external
view
returns (string memory, uint256, address, uint256, uint256, bool);

// Toggle event status (activate/deactivate)
function updateEventStatus(uint256 _eventId, bool _isActive) external;

// Check if a user is registered for an event
function isUserRegistered(
uint256 _eventId,
address _user
) external view returns (bool);
}
File renamed without changes.
1 change: 0 additions & 1 deletion hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ module.exports = {
url: `https://sepolia.infura.io/v3/${process.env.INFURA_ID}`,
accounts: [process.env.WALLET_KEY],
}

},
etherscan: {
// Use "123" as a placeholder, because Blockscout doesn't need a real API key, and Hardhat will complain if this property isn't set.
Expand Down
Loading

0 comments on commit 5d25e69

Please sign in to comment.