Skip to content

Commit

Permalink
refactor: Enhance HeyPro contract with AccessControl and NFT management
Browse files Browse the repository at this point in the history
  • Loading branch information
bigint committed Mar 2, 2025
1 parent 067a18d commit d024107
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 692 deletions.
1 change: 1 addition & 0 deletions packages/contracts/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
cache-zk/
artifacts-zk/
typechain-types/
deployments-zk/
59 changes: 36 additions & 23 deletions packages/contracts/contracts/HeyPro.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,53 +3,66 @@ pragma solidity ^0.8.28;

import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/access/AccessControl.sol";

contract HeyPro is ERC721Enumerable, Ownable {
contract HeyPro is ERC721Enumerable, Ownable, AccessControl {
struct NFTData {
uint256 expiry;
string name;
}

bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE");

mapping(uint256 => NFTData) public nftDetails;

constructor() ERC721("HeyPro", "PRO") Ownable(msg.sender) {}
constructor() ERC721("HeyPro", "PRO") Ownable(msg.sender) {
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
_grantRole(ADMIN_ROLE, msg.sender);
}

function mint() external {
uint256 tokenId = totalSupply() + 1;
uint256 currentTime = block.timestamp;
uint256 expiry = currentTime + 30 days;

// NFT name derived from epoch timestamp (10 chars)
string memory nftName = _uintToString(currentTime);

_safeMint(msg.sender, tokenId);
nftDetails[tokenId] = NFTData(expiry, nftName);
}

function extendSubscription() external {
uint256 lastTokenId = balanceOf(msg.sender);
require(lastTokenId > 0, "You don't own any NFTs");
function burnExpiredNFTs() external onlyRole(ADMIN_ROLE) {
uint256 total = totalSupply();
uint256 burnedCount = 0;

for (uint256 i = total; i > 0; i--) {
if (_tokenExists(i) && nftDetails[i].expiry <= block.timestamp) {
_burn(i);
delete nftDetails[i];
burnedCount++;
}
}

require(burnedCount > 0, "No expired NFTs to burn");
}

uint256 tokenId = tokenOfOwnerByIndex(msg.sender, lastTokenId - 1);
require(
nftDetails[tokenId].expiry > block.timestamp,
"Subscription expired"
);
function addAdmin(address admin) external onlyOwner {
grantRole(ADMIN_ROLE, admin);
}

// Extend by 30 days
nftDetails[tokenId].expiry += 30 days;
function removeAdmin(address admin) external onlyOwner {
revokeRole(ADMIN_ROLE, admin);
}

function getNFTDetails(
uint256 tokenId
) external view returns (string memory, uint256) {
require(_isValidToken(tokenId), "Token does not exist");
return (nftDetails[tokenId].name, nftDetails[tokenId].expiry);
function _tokenExists(uint256 tokenId) internal view returns (bool) {
try this.ownerOf(tokenId) returns (address) {
return true;
} catch {
return false;
}
}

function _uintToString(
uint256 value
) internal pure returns (string memory) {
function _uintToString(uint256 value) internal pure returns (string memory) {
bytes memory buffer = new bytes(10);
for (uint256 i = 9; i >= 0; i--) {
buffer[i] = bytes1(uint8(48 + (value % 10)));
Expand All @@ -59,7 +72,7 @@ contract HeyPro is ERC721Enumerable, Ownable {
return string(buffer);
}

function _isValidToken(uint256 tokenId) internal view returns (bool) {
return tokenId > 0 && tokenId <= totalSupply();
function supportsInterface(bytes4 interfaceId) public view override(ERC721Enumerable, AccessControl) returns (bool) {
return super.supportsInterface(interfaceId);
}
}

This file was deleted.

Loading

0 comments on commit d024107

Please sign in to comment.