Skip to content

Commit

Permalink
Merge pull request #17 from blocto/feature/move-spotlight-ip-collection
Browse files Browse the repository at this point in the history
Move spotlight ip collection
  • Loading branch information
scottphc authored Jan 24, 2025
2 parents 8d40bd6 + 26058a3 commit 618e217
Show file tree
Hide file tree
Showing 3 changed files with 394 additions and 0 deletions.
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;
}
}

0 comments on commit 618e217

Please sign in to comment.