Skip to content

Commit

Permalink
add metadata contract for engravings/bootlinks (#5)
Browse files Browse the repository at this point in the history
  • Loading branch information
worm-emoji authored Apr 25, 2023
1 parent 776938a commit 7b8a43f
Show file tree
Hide file tree
Showing 5 changed files with 193 additions and 1 deletion.
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,6 @@
[submodule "lib/recovery-protocol"]
path = lib/recovery-protocol
url = https://github.com/ourzora/recovery-protocol
[submodule "lib/solady"]
path = lib/solady
url = https://github.com/Vectorized/solady
1 change: 1 addition & 0 deletions lib/solady
Submodule solady added at 638276
1 change: 1 addition & 0 deletions remappings.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ base64/=lib/base64/
forge-std/=lib/forge-std/src
zora-drops-contracts/=lib/zora-drops-contracts/
recovery-protocol/=lib/recovery-protocol/src/
solady/=lib/solady/src
114 changes: 114 additions & 0 deletions src/TombMetadata.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// .^7??????????????????????????????????????????????????????????????????7!: .~7????????????????????????????????:
// :#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@Y ^#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@5
// ^@@@@@@#BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB&@@@@@B ~@@@@@@#BBBBBBBBBBBBBBBBBBBBBBBBBBBBB#7
// Y@@@@@# ~@@@@@@ P@@@@@G
// .&@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@&G~ ~@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@Y :@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@&P~
// J&@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#.!B@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@B~ .Y&@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@B
// ...........................B@@@@@5 .7#@@@@@@@#?^.................... ..........................:#@@@@@J
// ^5YYYJJJJJJJJJJJJJJJJJJJJJJJJJJY&@@@@@? .J&@@@@@@&5JJJJJJJJJJJJJJJJJJJYYYYYYYYYYJJJJJJJJJJJJJJJJJJJJJJJJJJY@@@@@@!
// 5@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@? :5&@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@7
// !GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGPY~ ^JPGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGPJ^

// _____________________________________________________ Tomb Series _____________________________________________________

// :!JYYYYJ!. .JYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY?~. 7YYYYYYYYY?~. ^JYYYYYYYYY^
// ~&@@@@@@@@@@#7. ?@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@P &@@@@@@@@@@@@B! :@@@@@@@@@@@5
// ^@@@@@@BB@@@@@@@B! ?@@@@@&PGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG&@@@@@# JGGGGGGG#@@@@@@@G^ !PGGGGGGGGG!
// 5@@@@@5 .7#@@@@@@@P^ ?@@@@@P .@@@@@@. .J&@@@@@@&5:
// Y@@@@@Y .J&@@@@@@&5: ?@@@@@G @@@@@@. :Y&@@@@@@&J.
// Y@@@@@5 :5&@@@@@@&J. ?@@@@@G @@@@@@. ^P@@@@@@@#7.
// Y@@@@@5 ^P@@@@@@@#7. J@@@@@G @@@@@@. ~G@@@@@@@B!
// Y@@@@@5 ~B@@@@@@@BG@@@@@@! PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP#@@@@@# JGPPPPPPPP5: .7#@@@@@@@GPPPPPPG~
// 5@@@@@5 .7#@@@@@@@@@@&! .@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@G &@@@@@@@@@@& .J&@@@@@@@@@@@@5
// ^5YYY5~ .!JYYYYY7: Y5YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYJ~. ?5YYYYYYY5J. :7JYYYYYYYY5^

// ____________________________________________________ Tomb Metadata _____________________________________________________

// ________________________________________________ Deployed by TERRAIN 2022 _______________________________________________

// ____________________________________________ All tombs drawn by David Rudnick ___________________________________________

// ____________________________________________ Contract architect: Luke Miles _____________________________________________

// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

interface IIndexMarker {
function isTomb(address _tokenContract, uint256 _tokenId) external view returns (bool);
}

interface IOwnable {
function ownerOf(uint256 _tokenID) external view returns (address);
}

import "openzeppelin/access/Ownable.sol";
import "solady/utils/Multicallable.sol";

contract TombMetadata is Ownable, Multicallable {
address public IndexMarker;

event EngravingSet(address indexed _tokenContract, uint256 indexed _tokenId, address author, string _engraving);
event BootlinkSet(address indexed _tokenContract, uint256 indexed _tokenId, address author, string _bootLink);

mapping(address => mapping(uint256 => string)) private engravings;
mapping(address => mapping(uint256 => string)) private bootLinks;

constructor(address _indexMarker) {
IndexMarker = _indexMarker;
}

modifier onlyTomb(address _tokenContract, uint256 _tokenId) {
require(IIndexMarker(IndexMarker).isTomb(_tokenContract, _tokenId), "TombMetadata: Not a tomb");
_;
}

modifier onlyTombOwnerOrAdmin(address _tokenContract, uint256 _tokenId) {
if (msg.sender == owner()) {
_;
return;
}

require(IOwnable(_tokenContract).ownerOf(_tokenId) == msg.sender, "TombMetadata: Not tomb owner");
_;
}

function getEngraving(address _tokenContract, uint256 _tokenId)
public
view
onlyTomb(_tokenContract, _tokenId)
returns (string memory)
{
return engravings[_tokenContract][_tokenId];
}

function getBootLink(address _tokenContract, uint256 _tokenId)
public
view
onlyTomb(_tokenContract, _tokenId)
returns (string memory)
{
return bootLinks[_tokenContract][_tokenId];
}

function setBootlink(address _tokenContract, uint256 _tokenId, string memory _bootLink)
public
onlyTomb(_tokenContract, _tokenId)
onlyTombOwnerOrAdmin(_tokenContract, _tokenId)
{
emit BootlinkSet(_tokenContract, _tokenId, msg.sender, _bootLink);
bootLinks[_tokenContract][_tokenId] = _bootLink;
}

function setEngraving(address _tokenContract, uint256 _tokenId, string memory _engraving)
public
onlyTomb(_tokenContract, _tokenId)
onlyTombOwnerOrAdmin(_tokenContract, _tokenId)
{
emit EngravingSet(_tokenContract, _tokenId, msg.sender, _engraving);
engravings[_tokenContract][_tokenId] = _engraving;
}

function updateIndexMarker(address _indexMarker) public onlyOwner {
IndexMarker = _indexMarker;
}
}
75 changes: 74 additions & 1 deletion src/test/IndexMarkerV2.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,35 @@ pragma solidity >=0.8.0;
import {ERC1967Proxy} from "openzeppelin/proxy/ERC1967/ERC1967Proxy.sol";
import {Strings} from "openzeppelin/utils/Strings.sol";
import {OperatorFilterRegistry} from "zora-drops-contracts/test/filter/OperatorFilterRegistry.sol";
import {OperatorFilterRegistryErrorsAndEvents} from "zora-drops-contracts/test/filter/OperatorFilterRegistryErrorsAndEvents.sol";
import {OperatorFilterRegistryErrorsAndEvents} from
"zora-drops-contracts/test/filter/OperatorFilterRegistryErrorsAndEvents.sol";
import {OwnedSubscriptionManager} from "zora-drops-contracts/src/filter/OwnedSubscriptionManager.sol";
import {DSTest} from "ds-test/test.sol";
import {console} from "./utils/Console.sol";
import {Vm} from "forge-std/Vm.sol";
import {IndexMarkerV2} from "../IndexMarkerV2.sol";
import {IndexMarker} from "../IndexMarker.sol";
import {TombIndex} from "../TombIndex.sol";
import {TombMetadata} from "../TombMetadata.sol";
import {ERC721} from "solady/tokens/ERC721.sol";

contract Tomb721 is ERC721 {
function name() public view virtual override returns (string memory) {
return "TOMB";
}

function symbol() public view virtual override returns (string memory) {
return "TOMBT";
}

function mint(address _to, uint256 _tokenId) public {
_mint(_to, _tokenId);
}

function tokenURI(uint256 id) public view virtual override returns (string memory) {
return "";
}
}

contract IndexMarkerV2Test is DSTest {
address payable public constant TOMB_ARTIST = payable(0x4a61d76ea05A758c1db9C9b5a5ad22f445A38C46);
Expand All @@ -23,10 +44,14 @@ contract IndexMarkerV2Test is DSTest {
address internal markerV2;
address internal markerV1;
address internal tombIndex;
Tomb721 internal tombNFT;
TombMetadata internal metadata;
address internal constant OPERATOR_FILTER_REGISTRY = address(0x000000000000AAeB6D7670E522A718067333cd4E);
address internal constant ADMIN = address(0x789);

event Upgraded(address indexed implementation);
event EngravingSet(address indexed _tokenContract, uint256 indexed _tokenId, address author, string _engraving);
event BootlinkSet(address indexed _tokenContract, uint256 indexed _tokenId, address author, string _bootLink);

function setUp() public {
signer = vm.addr(SIGNER_PK);
Expand All @@ -51,6 +76,9 @@ contract IndexMarkerV2Test is DSTest {
);
IndexMarkerV2(markerV2).setMintAllowedAndExpiry(true, 1672531199);
IndexMarkerV2(markerV2).transferOwnership(ADMIN);
tombNFT = new Tomb721();
vm.prank(ADMIN);
metadata = new TombMetadata(address(markerV2));
}

function mintV1(uint256 tokenID, address dest) public {
Expand Down Expand Up @@ -345,4 +373,49 @@ contract IndexMarkerV2Test is DSTest {
emit Upgraded(newImpl);
IndexMarkerV2(markerV2).upgradeTo(newImpl);
}

function testMetadata() public {
address tombOwner = address(123);
address[] memory tombContracts = new address[](1);
tombContracts[0] = address(tombNFT);
bool[] memory isTombContract = new bool[](1);
isTombContract[0] = true;
tombNFT.mint(tombOwner, 1);
tombNFT.mint(tombOwner, 3);

vm.prank(ADMIN);
IndexMarkerV2(markerV2).setTombContracts(tombContracts, isTombContract);

vm.prank(tombOwner, tombOwner);
vm.expectEmit(true, false, false, false);
emit BootlinkSet(address(tombNFT), 1, tombOwner, "google.com");
metadata.setBootlink(address(tombNFT), 1, "google.com");

vm.prank(tombOwner, tombOwner);
vm.expectEmit(true, false, false, false);
emit EngravingSet(address(tombNFT), 1, tombOwner, "Here we go!");
metadata.setEngraving(address(tombNFT), 1, "Here we go!");

vm.prank(ADMIN);
vm.expectEmit(true, false, false, false);
emit BootlinkSet(address(tombNFT), 3, address(ADMIN), "admin.com");
metadata.setBootlink(address(tombNFT), 3, "admin.com");

vm.prank(ADMIN);
vm.expectEmit(true, false, false, false);
emit EngravingSet(address(tombNFT), 3, address(ADMIN), "admin!");
metadata.setEngraving(address(tombNFT), 3, "admin!");

assertEq(metadata.getBootLink(address(tombNFT), 1), "google.com");
assertEq(metadata.getEngraving(address(tombNFT), 1), "Here we go!");
assertEq(metadata.getBootLink(address(tombNFT), 3), "admin.com");
assertEq(metadata.getEngraving(address(tombNFT), 3), "admin!");

vm.prank(address(100));
vm.expectRevert("TombMetadata: Not tomb owner");
metadata.setEngraving(address(tombNFT), 3, "Not my tomb");

vm.expectRevert("TombMetadata: Not a tomb");
metadata.setEngraving(address(100), 3, "Not my tomb");
}
}

0 comments on commit 7b8a43f

Please sign in to comment.