Created
November 13, 2024 20:42
-
-
Save joeblau/27b883ae22c9ee05ceab64f9c409d4ba to your computer and use it in GitHub Desktop.
Subscription NFT
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.0; | |
import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; | |
import "@openzeppelin/contracts/interfaces/IERC20.sol"; | |
contract SubscriptionNFT is ERC721 { | |
IERC20 public usdcToken; | |
address public owner; | |
enum Tier { BASIC, PREMIUM, VIP } | |
struct Subscription { | |
Tier tier; | |
uint256 expiration; | |
} | |
mapping(uint256 => Subscription) private _subscriptions; | |
uint256 private _tokenIds; | |
event SubscriptionMinted(address indexed to, uint256 tokenId, Tier tier, uint256 expiration); | |
event SubscriptionReloaded(uint256 tokenId, uint256 newExpiration); | |
modifier onlyOwner() { | |
require(msg.sender == owner, "Not authorized"); | |
_; | |
} | |
constructor(address _usdcAddress) ERC721("SubscriptionNFT", "SUBNFT") { | |
usdcToken = IERC20(_usdcAddress); | |
owner = msg.sender; | |
} | |
function mint(address to, Tier tier, uint256 amount) external { | |
require(to != address(0), "Invalid address"); | |
require(amount > 0, "Amount must be greater than zero"); | |
// Accept payment | |
require(usdcToken.transferFrom(msg.sender, address(this), amount), "USDC transfer failed"); | |
// Mint NFT | |
_tokenIds++; | |
uint256 newTokenId = _tokenIds; | |
_safeMint(to, newTokenId); | |
// Set subscription details | |
_subscriptions[newTokenId] = Subscription({ | |
tier: tier, | |
expiration: block.timestamp + 365 days | |
}); | |
emit SubscriptionMinted(to, newTokenId, tier, _subscriptions[newTokenId].expiration); | |
} | |
function reloadSubscription(uint256 tokenId, uint256 amount) external { | |
require(_exists(tokenId), "Token does not exist"); | |
require(amount > 0, "Amount must be greater than zero"); | |
// Accept payment | |
require(usdcToken.transferFrom(msg.sender, address(this), amount), "USDC transfer failed"); | |
// Extend expiration | |
_subscriptions[tokenId].expiration += 365 days; | |
emit SubscriptionReloaded(tokenId, _subscriptions[tokenId].expiration); | |
} | |
function isSubscriptionActive(uint256 tokenId) public view returns (bool) { | |
require(_exists(tokenId), "Token does not exist"); | |
return _subscriptions[tokenId].expiration >= block.timestamp; | |
} | |
function getSubscriptionDetails(uint256 tokenId) external view returns (Tier tier, uint256 expiration) { | |
require(_exists(tokenId), "Token does not exist"); | |
Subscription memory sub = _subscriptions[tokenId]; | |
return (sub.tier, sub.expiration); | |
} | |
// Override transfer functions to make tokens soulbound | |
function _transfer(address from, address to, uint256 tokenId) internal override { | |
revert("Soulbound tokens cannot be transferred"); | |
} | |
function approve(address to, uint256 tokenId) public override { | |
revert("Soulbound tokens cannot be approved for transfer"); | |
} | |
function setApprovalForAll(address operator, bool approved) public override { | |
revert("Soulbound tokens cannot be approved for transfer"); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment