-
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 #18 from blocto/feature/spotlight-root-ip-collection
Spotlight root ip collection
- Loading branch information
Showing
3 changed files
with
248 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 {SpotlightRootIPCollection} from "../src/spotlight-root-ip-collection/SpotlightRootIPCollection.sol"; | ||
|
||
/* Deploy and verify with the following command: | ||
forge script script/DeployIPRootCollectionAndMint.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")); | ||
SpotlightRootIPCollection ipCollection = new SpotlightRootIPCollection(); | ||
ipCollection.mint(); | ||
vm.stopBroadcast(); | ||
} | ||
} |
68 changes: 68 additions & 0 deletions
68
src/spotlight-root-ip-collection/SpotlightRootIPCollection.sol
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,68 @@ | ||
// 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 SpotlightRootIPCollection is ERC721, Ownable { | ||
using Strings for uint256; | ||
|
||
bool private _isTransferEnabled = false; | ||
|
||
uint256 private _nextTokenId; | ||
string private _tokenURI = "ipfs://bafkreidsyc4pkxkk7io56uf5hhnvkx2n6ukua4xjg42dsv5n7y2hbb3h3u"; | ||
|
||
modifier onlyTransferEnabled() { | ||
_checkTransferEnabled(); | ||
_; | ||
} | ||
|
||
constructor() ERC721("Spotlight Root IP", "SPRIP") Ownable(msg.sender) {} | ||
|
||
function totalSupply() external view returns (uint256) { | ||
return _nextTokenId; | ||
} | ||
|
||
function tokenURI(uint256 tokenId) public view override returns (string memory) { | ||
_requireOwned(tokenId); | ||
return _tokenURI; | ||
} | ||
|
||
function setTokenURI(string memory tokenURI_) public onlyOwner { | ||
_tokenURI = tokenURI_; | ||
} | ||
|
||
function mint() public onlyOwner 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("SpotlightRootIPCollection: 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,157 @@ | ||
// SPDX-License-Identifier: GPL-3.0 | ||
pragma solidity ^0.8.13; | ||
|
||
import "../lib/forge-std/src/Test.sol"; | ||
import {SpotlightRootIPCollection} from "../src/spotlight-root-ip-collection/SpotlightRootIPCollection.sol"; | ||
|
||
abstract contract OwnableError { | ||
error OwnableUnauthorizedAccount(address account); | ||
error OwnableInvalidOwner(address owner); | ||
} | ||
|
||
contract SpotlightRootIPCollectionTest is Test { | ||
address private _ownerAddr; | ||
|
||
SpotlightRootIPCollection private _spotlightRootIPCollection; | ||
address private _spotlightRootIPCollectionAddr; | ||
|
||
string private newTokenURI = "https://example.com/new-token/"; | ||
|
||
function setUp() public { | ||
_ownerAddr = makeAddr("owner"); | ||
vm.startPrank(_ownerAddr); | ||
_spotlightRootIPCollection = new SpotlightRootIPCollection(); | ||
_spotlightRootIPCollectionAddr = address(_spotlightRootIPCollection); | ||
vm.stopPrank(); | ||
} | ||
|
||
function test_constructor() public view { | ||
assertEq(_spotlightRootIPCollection.owner(), _ownerAddr); | ||
assertEq(_spotlightRootIPCollection.totalSupply(), 0); | ||
assertEq(_spotlightRootIPCollection.isTransferEnabled(), false); | ||
assertEq(_spotlightRootIPCollection.name(), "Spotlight Root IP"); | ||
assertEq(_spotlightRootIPCollection.symbol(), "SPRIP"); | ||
} | ||
|
||
function test_notOownerMint() public { | ||
address receiver = makeAddr("receiver"); | ||
|
||
vm.startPrank(receiver); | ||
vm.expectRevert(); | ||
_spotlightRootIPCollection.mint(); | ||
vm.stopPrank(); | ||
} | ||
|
||
function test_mint() public { | ||
vm.startPrank(_ownerAddr); | ||
uint256 tokenId = _spotlightRootIPCollection.mint(); | ||
vm.stopPrank(); | ||
|
||
assertEq(_spotlightRootIPCollection.totalSupply(), 1); | ||
assertEq(_spotlightRootIPCollection.ownerOf(tokenId), _ownerAddr); | ||
assertEq( | ||
_spotlightRootIPCollection.tokenURI(tokenId), | ||
"ipfs://bafkreidsyc4pkxkk7io56uf5hhnvkx2n6ukua4xjg42dsv5n7y2hbb3h3u" | ||
); | ||
} | ||
|
||
function test_notOwnerSetTransferEnabled() public { | ||
address notOwner = makeAddr("notOwner"); | ||
vm.startPrank(notOwner); | ||
vm.expectRevert(); | ||
_spotlightRootIPCollection.setTransferEnabled(true); | ||
vm.stopPrank(); | ||
} | ||
|
||
function test_setTransferEnabled() public { | ||
vm.startPrank(_ownerAddr); | ||
_spotlightRootIPCollection.setTransferEnabled(true); | ||
assert(_spotlightRootIPCollection.isTransferEnabled()); | ||
_spotlightRootIPCollection.setTransferEnabled(false); | ||
assert(!_spotlightRootIPCollection.isTransferEnabled()); | ||
vm.stopPrank(); | ||
} | ||
|
||
function test_notOwnerSetTokenURI() public { | ||
address notOwner = makeAddr("notOwner"); | ||
vm.startPrank(notOwner); | ||
vm.expectRevert(); | ||
_spotlightRootIPCollection.setTokenURI(newTokenURI); | ||
vm.stopPrank(); | ||
} | ||
|
||
function test_setTokenURI() public { | ||
vm.startPrank(_ownerAddr); | ||
uint256 tokenId = _spotlightRootIPCollection.mint(); | ||
_spotlightRootIPCollection.setTokenURI(newTokenURI); | ||
vm.stopPrank(); | ||
|
||
assertEq(_spotlightRootIPCollection.tokenURI(tokenId), newTokenURI); | ||
} | ||
|
||
function test_transferFromBeforeEnabled() public { | ||
address receiver = makeAddr("receiver"); | ||
|
||
vm.startPrank(_ownerAddr); | ||
uint256 tokenId = _spotlightRootIPCollection.mint(); | ||
vm.expectRevert("SpotlightRootIPCollection: transfer is disabled"); | ||
_spotlightRootIPCollection.transferFrom(_ownerAddr, receiver, tokenId); | ||
vm.stopPrank(); | ||
} | ||
|
||
function test_safeTransferFromBeforeEnabled() public { | ||
address receiver = makeAddr("receiver"); | ||
|
||
vm.startPrank(_ownerAddr); | ||
uint256 tokenId = _spotlightRootIPCollection.mint(); | ||
vm.expectRevert("SpotlightRootIPCollection: transfer is disabled"); | ||
_spotlightRootIPCollection.safeTransferFrom(_ownerAddr, receiver, tokenId); | ||
vm.stopPrank(); | ||
} | ||
|
||
function test_safeTransferFromWithDataBeforeEnabled() public { | ||
address receiver = makeAddr("receiver"); | ||
|
||
vm.startPrank(_ownerAddr); | ||
uint256 tokenId = _spotlightRootIPCollection.mint(); | ||
vm.expectRevert("SpotlightRootIPCollection: transfer is disabled"); | ||
_spotlightRootIPCollection.safeTransferFrom(_ownerAddr, receiver, tokenId, ""); | ||
vm.stopPrank(); | ||
} | ||
|
||
function test_transferFrom() public { | ||
address receiver = makeAddr("receiver"); | ||
|
||
vm.startPrank(_ownerAddr); | ||
uint256 tokenId = _spotlightRootIPCollection.mint(); | ||
_spotlightRootIPCollection.setTransferEnabled(true); | ||
_spotlightRootIPCollection.transferFrom(_ownerAddr, receiver, tokenId); | ||
vm.stopPrank(); | ||
|
||
assertEq(_spotlightRootIPCollection.ownerOf(tokenId), receiver); | ||
} | ||
|
||
function test_safeTransferFrom() public { | ||
address receiver = makeAddr("receiver"); | ||
|
||
vm.startPrank(_ownerAddr); | ||
uint256 tokenId = _spotlightRootIPCollection.mint(); | ||
_spotlightRootIPCollection.setTransferEnabled(true); | ||
_spotlightRootIPCollection.safeTransferFrom(_ownerAddr, receiver, tokenId); | ||
vm.stopPrank(); | ||
|
||
assertEq(_spotlightRootIPCollection.ownerOf(tokenId), receiver); | ||
} | ||
|
||
function test_safeTransferFromWithData() public { | ||
address receiver = makeAddr("receiver"); | ||
|
||
vm.startPrank(_ownerAddr); | ||
uint256 tokenId = _spotlightRootIPCollection.mint(); | ||
_spotlightRootIPCollection.setTransferEnabled(true); | ||
_spotlightRootIPCollection.safeTransferFrom(_ownerAddr, receiver, tokenId, ""); | ||
vm.stopPrank(); | ||
|
||
assertEq(_spotlightRootIPCollection.ownerOf(tokenId), receiver); | ||
} | ||
} |