Skip to content
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

Move spotlight ip collection #17

Merged
merged 4 commits into from
Jan 24, 2025
Merged
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
23 changes: 23 additions & 0 deletions script/DeployIPCollection.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.13;

import "../lib/forge-std/src/Script.sol";
import {SpotlightIPCollection} from "../src/spotlight-ip-collection/SpotlightIPCollection.sol";

/* Deploy and verify with the following command:
forge script script/DeployIPCollection.s.sol:Deploy --broadcast \
--chain-id 1516 \
--rpc-url https://odyssey.storyrpc.io \
--verify \
--verifier blockscout \
--verifier-url 'https://odyssey.storyscan.xyz/api/'
*/

contract Deploy is Script {
function run() public {
vm.startBroadcast(vm.envUint("PRIVATE_KEY"));
SpotlightIPCollection ipCollection = new SpotlightIPCollection();
ipCollection.setDefaultTokenURI("ipfs://bafkreifsq7jdvvlj7cabklirodim7syc5xt4yzbrny6i4siie4yrnnqzge");
vm.stopBroadcast();
}
}
104 changes: 104 additions & 0 deletions src/spotlight-ip-collection/SpotlightIPCollection.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.13;

import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";

contract SpotlightIPCollection is ERC721, Ownable {
using Strings for uint256;

bool private _isTransferEnabled = false;
bool private _isMintEnabled = false;

uint256 private _nextTokenId;
string private _defaultTokenURI;
string public __baseURI;

modifier onlyTransferEnabled() {
_checkTransferEnabled();
_;
}

modifier onlyMintEnabled() {
_checkMintEnabled();
_;
}

constructor() ERC721("Spotlight IP", "SPIP") Ownable(msg.sender) {}

function totalSupply() external view returns (uint256) {
return _nextTokenId;
}

function _baseURI() internal view override returns (string memory) {
return __baseURI;
}

function tokenURI(uint256 tokenId) public view override returns (string memory) {
_requireOwned(tokenId);
return bytes(_baseURI()).length > 0 ? string.concat(_baseURI(), tokenId.toString()) : _defaultTokenURI;
}

function setBaseURI(string memory baseURI_) public onlyOwner {
__baseURI = baseURI_;
}

function setDefaultTokenURI(string memory defaultTokenURI_) public onlyOwner {
_defaultTokenURI = defaultTokenURI_;
}

function isMintEnabled() public view returns (bool) {
return _isMintEnabled;
}

function _checkMintEnabled() private view {
if (isMintEnabled() != true) {
revert("SpotlightIPCollection: mint is disabled");
}
}

function setMintEnabled(bool enabled) public onlyOwner {
_isMintEnabled = enabled;
}

function mint(address to) public onlyOwner onlyMintEnabled returns (uint256) {
uint256 tokenId = _nextTokenId;
_mint(to, tokenId);
_nextTokenId = _nextTokenId + 1;
return tokenId;
}

function mint() public onlyMintEnabled returns (uint256) {
uint256 tokenId = _nextTokenId;
_mint(msg.sender, tokenId);
_nextTokenId = _nextTokenId + 1;
return tokenId;
}

function isTransferEnabled() public view returns (bool) {
return _isTransferEnabled;
}

function _checkTransferEnabled() private view {
if (isTransferEnabled() != true) {
revert("SpotlightIPCollection: transfer is disabled");
}
}

function setTransferEnabled(bool enabled) public onlyOwner {
_isTransferEnabled = enabled;
}

function transferFrom(address from, address to, uint256 tokenId) public override onlyTransferEnabled {
super.transferFrom(from, to, tokenId);
}

function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data)
public
override
onlyTransferEnabled
{
super.safeTransferFrom(from, to, tokenId, data);
}
}
267 changes: 267 additions & 0 deletions test/SpotlightIPCollection.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,267 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.13;

import "../lib/forge-std/src/Test.sol";
import {SpotlightIPCollection} from "../src/spotlight-ip-collection/SpotlightIPCollection.sol";

abstract contract OwnableError {
error OwnableUnauthorizedAccount(address account);
error OwnableInvalidOwner(address owner);
}

contract SpotlightIPCollectionTest is Test {
address private _ownerAddr;

SpotlightIPCollection private _spotlightIPCollection;
address private _spotlightIPCollectionAddr;

string private originalTokenURI = "https://example.com/original-token/";
string private newTokenURI = "https://example.com/new-token/";

function setUp() public {
_ownerAddr = makeAddr("owner");
vm.startPrank(_ownerAddr);
_spotlightIPCollection = new SpotlightIPCollection();
_spotlightIPCollectionAddr = address(_spotlightIPCollection);
_spotlightIPCollection.setDefaultTokenURI(originalTokenURI);
vm.stopPrank();
}

function test_constructor() public view {
assertEq(_spotlightIPCollection.owner(), _ownerAddr);
assertEq(_spotlightIPCollection.totalSupply(), 0);
assertEq(_spotlightIPCollection.isMintEnabled(), false);
assertEq(_spotlightIPCollection.isTransferEnabled(), false);
assertEq(_spotlightIPCollection.name(), "Spotlight IP");
assertEq(_spotlightIPCollection.symbol(), "SPIP");
}

function test_notOwnerSetMintEnabled() public {
address notOwner = makeAddr("notOwner");
vm.startPrank(notOwner);
vm.expectRevert();
_spotlightIPCollection.setMintEnabled(true);
vm.stopPrank();
}

function test_setMintEnabled() public {
_enableMint();
assert(_spotlightIPCollection.isMintEnabled());
_disableMin();
assert(!_spotlightIPCollection.isMintEnabled());
}

function test_mintBeforeEnabled() public {
address receiver = makeAddr("receiver");
vm.startPrank(receiver);
vm.expectRevert("SpotlightIPCollection: mint is disabled");
_spotlightIPCollection.mint();
vm.stopPrank();
}

function test_notOwnerMintTo() public {
address notOwner = makeAddr("notOwner");
address receiver = makeAddr("receiver");
vm.startPrank(notOwner);
vm.expectRevert();
_mintTo(receiver);
vm.stopPrank();
}

function test_mintToBeforeEnabled() public {
address receiver = makeAddr("receiver");
vm.startPrank(_ownerAddr);
vm.expectRevert("SpotlightIPCollection: mint is disabled");
_spotlightIPCollection.mint(receiver);
vm.stopPrank();
}

function test_mint() public {
uint256 originalTotalSupply = _spotlightIPCollection.totalSupply();
address receiver = makeAddr("receiver");

uint256 tokenId = _mint(receiver);

assertEq(_spotlightIPCollection.totalSupply(), originalTotalSupply + 1);
assertEq(_spotlightIPCollection.ownerOf(tokenId), receiver);
assertEq(_spotlightIPCollection.tokenURI(tokenId), originalTokenURI);
}

function test_mintTo() public {
uint256 originalTotalSupply = _spotlightIPCollection.totalSupply();
address receiver = makeAddr("receiver");

uint256 tokenId = _mintTo(receiver);

assertEq(_spotlightIPCollection.totalSupply(), originalTotalSupply + 1);
assertEq(_spotlightIPCollection.ownerOf(tokenId), receiver);
assertEq(_spotlightIPCollection.tokenURI(tokenId), originalTokenURI);
}

function test_notOwnerSetTransferEnabled() public {
address notOwner = makeAddr("notOwner");
vm.startPrank(notOwner);
vm.expectRevert();
_spotlightIPCollection.setTransferEnabled(true);
vm.stopPrank();
}

function test_setTransferEnabled() public {
_enableTransfer();
assert(_spotlightIPCollection.isTransferEnabled());
_disableTransfer();
assert(!_spotlightIPCollection.isTransferEnabled());
}

function test_notOwnerSetDefaultTokenURI() public {
address notOwner = makeAddr("notOwner");
vm.startPrank(notOwner);
vm.expectRevert();
_spotlightIPCollection.setDefaultTokenURI(newTokenURI);
vm.stopPrank();
}

function test_setDefaultTokenURI() public {
address receiver = makeAddr("receiver");
uint256 tokenId = _mint(receiver);

vm.startPrank(_ownerAddr);
_spotlightIPCollection.setDefaultTokenURI(newTokenURI);
vm.stopPrank();

assertEq(_spotlightIPCollection.tokenURI(tokenId), newTokenURI);
}

function test_notOwnerSetBaseURI() public {
address notOwner = makeAddr("notOwner");
vm.startPrank(notOwner);
vm.expectRevert();
_spotlightIPCollection.setBaseURI(newTokenURI);
vm.stopPrank();
}

function test_setBaseURI() public {
address receiver = makeAddr("receiver");
_mint(receiver);

vm.startPrank(_ownerAddr);
_spotlightIPCollection.setBaseURI(newTokenURI);
vm.stopPrank();

assertEq(_spotlightIPCollection.tokenURI(0), "https://example.com/new-token/0");
}

function test_transferFromBeforeEnabled() public {
address user1 = makeAddr("user1");
address user2 = makeAddr("user2");

uint256 tokenId = _mint(user1);
vm.startPrank(user1);
vm.expectRevert("SpotlightIPCollection: transfer is disabled");
_spotlightIPCollection.transferFrom(user1, user2, tokenId);
vm.stopPrank();
}

function test_safeTransferFromBeforeEnabled() public {
address user1 = makeAddr("user1");
address user2 = makeAddr("user2");

uint256 tokenId = _mint(user1);
vm.startPrank(user1);
vm.expectRevert("SpotlightIPCollection: transfer is disabled");
_spotlightIPCollection.safeTransferFrom(user1, user2, tokenId);
vm.stopPrank();
}

function test_safeTransferFromWithDataBeforeEnabled() public {
address user1 = makeAddr("user1");
address user2 = makeAddr("user2");

uint256 tokenId = _mint(user1);
vm.startPrank(user1);
vm.expectRevert("SpotlightIPCollection: transfer is disabled");
_spotlightIPCollection.safeTransferFrom(user1, user2, tokenId, "");
vm.stopPrank();
}

function test_transferFrom() public {
address user1 = makeAddr("user1");
address user2 = makeAddr("user2");

uint256 tokenId = _mint(user1);
_enableTransfer();
vm.startPrank(user1);
_spotlightIPCollection.transferFrom(user1, user2, tokenId);
vm.stopPrank();

assertEq(_spotlightIPCollection.ownerOf(tokenId), user2);
}

function test_safeTransferFrom() public {
address user1 = makeAddr("user1");
address user2 = makeAddr("user2");

uint256 tokenId = _mint(user1);
_enableTransfer();
vm.startPrank(user1);
_spotlightIPCollection.safeTransferFrom(user1, user2, tokenId);
vm.stopPrank();

assertEq(_spotlightIPCollection.ownerOf(tokenId), user2);
}

function test_safeTransferFromWithData() public {
address user1 = makeAddr("user1");
address user2 = makeAddr("user2");

uint256 tokenId = _mint(user1);
_enableTransfer();
vm.startPrank(user1);
_spotlightIPCollection.safeTransferFrom(user1, user2, tokenId, "");
vm.stopPrank();

assertEq(_spotlightIPCollection.ownerOf(tokenId), user2);
}

// MARK: - Private functions

function _enableTransfer() private {
vm.startPrank(_ownerAddr);
_spotlightIPCollection.setTransferEnabled(true);
vm.stopPrank();
}

function _disableTransfer() private {
vm.startPrank(_ownerAddr);
_spotlightIPCollection.setTransferEnabled(false);
vm.stopPrank();
}

function _enableMint() private {
vm.startPrank(_ownerAddr);
_spotlightIPCollection.setMintEnabled(true);
vm.stopPrank();
}

function _disableMin() private {
vm.startPrank(_ownerAddr);
_spotlightIPCollection.setMintEnabled(false);
vm.stopPrank();
}

function _mint(address _receiver) private returns (uint256) {
_enableMint();
vm.startPrank(_receiver);
uint256 tokenId = _spotlightIPCollection.mint();
vm.stopPrank();
return tokenId;
}

function _mintTo(address _receiver) private returns (uint256) {
_enableMint();
vm.startPrank(_ownerAddr);
uint256 tokenId = _spotlightIPCollection.mint(_receiver);
vm.stopPrank();
return tokenId;
}
}
Loading