-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #17 from blocto/feature/move-spotlight-ip-collection
Move spotlight ip collection
- Loading branch information
Showing
3 changed files
with
394 additions
and
0 deletions.
There are no files selected for viewing
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
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(); | ||
} | ||
} |
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
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); | ||
} | ||
} |
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
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; | ||
} | ||
} |