Skip to content

Commit

Permalink
NFT metadata and directory with the SFS integration
Browse files Browse the repository at this point in the history
  • Loading branch information
tempe-techie committed Jan 29, 2024
1 parent cff4f2a commit e978dfe
Show file tree
Hide file tree
Showing 13 changed files with 140 additions and 11 deletions.
12 changes: 12 additions & 0 deletions contracts/launchpad/erc721/NftDirectory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ pragma solidity ^0.8.17;

import { OwnableWithManagers } from "../../access/OwnableWithManagers.sol";

interface ISFS {
function assign(uint256 _tokenId) external returns (uint256);
}

/**
@title A directory of ERC-721 NFTs made with a Iggy Launchpad
@author Tempe Techie
Expand All @@ -14,6 +18,14 @@ contract NftDirectory is OwnableWithManagers {
mapping (address => bool) public writers; // writer contracts that can send stats to this contract
mapping (string => address) public nftAddressById; // mapping(uniqueID => NFT contract address) to easily find the NFT contract address

// CONSTRUCTOR
constructor(
address sfsAddress_,
uint256 sfsNftId_
) {
ISFS(sfsAddress_).assign(sfsNftId_);
}

// READ

function getAllFeaturedNftContracts() external view returns(address[] memory) {
Expand Down
12 changes: 12 additions & 0 deletions contracts/launchpad/erc721/NftMetadata.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ interface INFT {
function owner() external view returns(address);
}

interface ISFS {
function assign(uint256 _tokenId) external returns (uint256);
}

/**
@title Default metadata contract for ERC-721 NFTs made with Iggy Launchpad
@author Tempe Techie
Expand All @@ -33,6 +37,14 @@ contract NftMetadata {
// - 2: base url to metadata IPFS or custom API. Token ID of each NFT is appended to the base url to get the metadata and image (ends with .json extension).
// - 3: base url to metadata IPFS or custom API. Token ID of each NFT is appended to the base url to get the metadata and image (does NOT end with .json extension).

// CONSTRUCTOR
constructor(
address sfsAddress_,
uint256 sfsNftId_
) {
ISFS(sfsAddress_).assign(sfsNftId_);
}

// INTERNAL

// get image from the array of image URLs based on the tokenId (use modulo if tokenId is larger than array length)
Expand Down
12 changes: 12 additions & 0 deletions contracts/launchpad/erc721/metadata/NftMetadata2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ interface INFT {
function owner() external view returns(address);
}

interface ISFS {
function assign(uint256 _tokenId) external returns (uint256);
}

/**
* DEPRECATED
@title Default metadata contract for ERC-721 NFTs made with Iggy Launchpad
Expand All @@ -30,6 +34,14 @@ contract NftMetadata2 {
// - 2: base url to metadata IPFS or custom API. Token ID of each NFT is appended to the base url to get the metadata and image (ends with .json extension).
// - 3: base url to metadata IPFS or custom API. Token ID of each NFT is appended to the base url to get the metadata and image (does NOT end with .json extension).

// CONSTRUCTOR
constructor(
address sfsAddress_,
uint256 sfsNftId_
) {
ISFS(sfsAddress_).assign(sfsNftId_);
}

// READ

function getMetadata(address nftAddress_, uint256 tokenId_) external view returns (string memory) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import { OwnableWithManagers } from "../../../access/OwnableWithManagers.sol";
import { Base64 } from "@openzeppelin/contracts/utils/Base64.sol";
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";

interface ISFS {
function assign(uint256 _tokenId) external returns (uint256);
}

/**
@title Metadata contract for a single ERC-721 NFT made with Iggy Launchpad. This contract allows for multiple onchain image URLs.
@author Tempe Techie
Expand All @@ -29,12 +33,15 @@ contract NftMetadataOnchainMultipleImages is OwnableWithManagers {

// CONSTRUCTOR
constructor (
address sfsAddress_,
uint256 sfsNftId_,
string memory collectionPreview_,
string memory description_,
string memory externalUrl_,
string memory image_,
string memory name_
) {
ISFS(sfsAddress_).assign(sfsNftId_);
collectionPreview = collectionPreview_;
description = description_;
externalUrl = externalUrl_;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import { OwnableWithManagers } from "../../../access/OwnableWithManagers.sol";
import { Base64 } from "@openzeppelin/contracts/utils/Base64.sol";
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";

interface ISFS {
function assign(uint256 _tokenId) external returns (uint256);
}

/**
@title Metadata contract for a single ERC-721 NFT made with Iggy Launchpad
@author Tempe Techie
Expand All @@ -29,12 +33,15 @@ contract NftMetadataSingleCollection is OwnableWithManagers {

// CONSTRUCTOR
constructor (
address sfsAddress_,
uint256 sfsNftId_,
string memory collectionPreview_,
string memory description_,
string memory externalUrl_,
string memory image_,
string memory name_
) {
ISFS(sfsAddress_).assign(sfsNftId_);
collectionPreview = collectionPreview_;
description = description_;
externalUrl = externalUrl_;
Expand Down
12 changes: 11 additions & 1 deletion contracts/merkle/MerkleClaimerERC721.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,23 @@ interface INFT is IERC721 {
function mint(address to) external;
}

interface ISFS {
function assign(uint256 _tokenId) external returns (uint256);
}

contract MerkleClaimerERC721 is OwnableWithManagers {
address public immutable nftAddress;
bool public paused = false;
bytes32 public immutable root; // merkle root

// CONSTRUCTOR
constructor(address nftAddress_, bytes32 root_) {
constructor(
address sfsAddress_,
uint256 sfsNftId_,
address nftAddress_,
bytes32 root_
) {
ISFS(sfsAddress_).assign(sfsNftId_);
nftAddress = nftAddress_;
root = root_;
}
Expand Down
15 changes: 13 additions & 2 deletions scripts/launchpad/erc721/1_nftMetadata.deploy.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@

const contractName = "NftMetadata";

const sfsAddress = (network.name == "modeTestnet") ? "0xBBd707815a7F7eb6897C7686274AFabd7B579Ff6" : "0x8680CEaBcb9b56913c519c069Add6Bc3494B7020";
const sfsNftTokenId = 0; // TODO: Enter SFS NFT token ID!!!

if (sfsNftTokenId == 0) {
console.log("Please enter SFS NFT token ID!!!");
return;
}

async function main() {
const [deployer] = await ethers.getSigners();

Expand All @@ -12,12 +20,15 @@ async function main() {
// deploy contract
const contract = await ethers.getContractFactory(contractName);
const instance = await contract.deploy();
await instance.deployed();
await instance.deployed(
sfsAddress,
sfsNftTokenId
);

console.log(contractName + " contract address:", instance.address);

console.log("Wait a minute and then run this command to verify contracts on block explorer:");
console.log("npx hardhat verify --network " + network.name + " " + instance.address);
console.log("npx hardhat verify --network " + network.name + " " + instance.address + " " + sfsAddress + ' "' + sfsNftTokenId + '"');
}

main()
Expand Down
15 changes: 13 additions & 2 deletions scripts/launchpad/erc721/2_nftDirectory.deploy.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@

const contractName = "NftDirectory";

const sfsAddress = (network.name == "modeTestnet") ? "0xBBd707815a7F7eb6897C7686274AFabd7B579Ff6" : "0x8680CEaBcb9b56913c519c069Add6Bc3494B7020";
const sfsNftTokenId = 0; // TODO: Enter SFS NFT token ID!!!

if (sfsNftTokenId == 0) {
console.log("Please enter SFS NFT token ID!!!");
return;
}

async function main() {
const [deployer] = await ethers.getSigners();

Expand All @@ -11,13 +19,16 @@ async function main() {

// deploy contract
const contract = await ethers.getContractFactory(contractName);
const instance = await contract.deploy();
const instance = await contract.deploy(
sfsAddress,
sfsNftTokenId
);
await instance.deployed();

console.log(contractName + " contract address:", instance.address);

console.log("Wait a minute and then run this command to verify contracts on block explorer:");
console.log("npx hardhat verify --network " + network.name + " " + instance.address);
console.log("npx hardhat verify --network " + network.name + " " + instance.address + " " + sfsAddress + ' "' + sfsNftTokenId + '"');
}

main()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ const externalUrl = "https://flr.chat/nft/collection?id=0xC4CFd446b1AD6dc958c6C2
const image = "https://bafkreihn7v7ugcu4yjnapsha3tij4cq7qatj2wjofpvxlkp6s4sl5nujn4.ipfs.w3s.link/"; // 1st image
const nftname = "et_puis BK";

const sfsAddress = (network.name == "modeTestnet") ? "0xBBd707815a7F7eb6897C7686274AFabd7B579Ff6" : "0x8680CEaBcb9b56913c519c069Add6Bc3494B7020";
const sfsNftTokenId = 0; // TODO: Enter SFS NFT token ID!!!

if (sfsNftTokenId == 0) {
console.log("Please enter SFS NFT token ID!!!");
return;
}

const images = [
"https://bafybeidim3mkbj4obd3cbf7fcrolioo2zpeha3xbzg2jvuajrtmvjk5lnq.ipfs.w3s.link/et_puisBK_2.jpg",
"https://bafybeicbrgmgugbmk7g2nofbndysbq4pwezm65t6yjlyo7j32q3hgsxtxm.ipfs.w3s.link/et_puisBK_3.jpg",
Expand Down Expand Up @@ -46,6 +54,8 @@ async function main() {
// deploy contract
const contract = await ethers.getContractFactory(contractName);
const instance = await contract.deploy(
sfsAddress,
sfsNftTokenId,
collectionPreviewImage,
description,
externalUrl,
Expand All @@ -65,7 +75,7 @@ async function main() {
}

console.log("Wait a minute and then run this command to verify contracts on block explorer:");
console.log("npx hardhat verify --network " + network.name + " " + instance.address + ' "' + collectionPreviewImage + '" "' + description + '" "' + externalUrl + '" "' + image + '" "' + nftname + '"');
console.log("npx hardhat verify --network " + network.name + " " + instance.address + " " + sfsAddress + ' "' + sfsNftTokenId + '" "' + collectionPreviewImage + '" "' + description + '" "' + externalUrl + '" "' + image + '" "' + nftname + '"');
}

function sleep(ms) {
Expand Down
12 changes: 11 additions & 1 deletion scripts/merkle/merkleClaimerERC721.deploy.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ const nftContractName = "EarlyStakerNft"; // TODO: Update this contract name

const nftAddress = ""; // TODO: address of deployed nft contract

const sfsAddress = (network.name == "modeTestnet") ? "0xBBd707815a7F7eb6897C7686274AFabd7B579Ff6" : "0x8680CEaBcb9b56913c519c069Add6Bc3494B7020";
const sfsNftTokenId = 0; // TODO: Enter SFS NFT token ID!!!

if (sfsNftTokenId == 0) {
console.log("Please enter SFS NFT token ID!!!");
return;
}

// create merkle tree
tree = StandardMerkleTree.of(data.claimers, ["address", "uint256"]); // TODO: Make sure you have the right data in claimers.json
const merkleRoot = String(tree.root);
Expand All @@ -23,6 +31,8 @@ async function main() {
// deploy contract
const contract = await ethers.getContractFactory(contractName);
const instance = await contract.deploy(
sfsAddress,
sfsNftTokenId,
nftAddress,
merkleRoot
);
Expand All @@ -36,7 +46,7 @@ async function main() {
await nftInstance.changeMinterAddress(instance.address);

console.log("Wait a minute and then run this command to verify contracts on block explorer:");
console.log("npx hardhat verify --network " + network.name + " " + instance.address + " " + nftAddress + " " + merkleRoot);
console.log("npx hardhat verify --network " + network.name + " " + instance.address + " " + sfsAddress + " " + ' "' + sfsNftTokenId + '" ' + nftAddress + " " + merkleRoot);
}

main()
Expand Down
13 changes: 13 additions & 0 deletions test/launchpad/NftMetadataOnchainMultipleImages.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ function calculateGasCosts(testName, receipt) {

describe("NftMetadataOnchainMultipleImages", function () {
let metadataContract;
let feeReceiver;

// NFT contract data
const nftDescription = "Iggy NFT is a new unique NFT project";
Expand Down Expand Up @@ -56,9 +57,21 @@ describe("NftMetadataOnchainMultipleImages", function () {
];

beforeEach(async function () {
[feeReceiver] = await ethers.getSigners();

const MockSFS = await ethers.getContractFactory("MockSFS");
const sfsContract = await MockSFS.deploy();

const SfsNftInitialize = await ethers.getContractFactory("SfsNftInitialize");
const sfsNftInitializeContract = await SfsNftInitialize.deploy(sfsContract.address, feeReceiver.address);

const sfsNftTokenId = await sfsNftInitializeContract.sfsNftTokenId();

const NftMetadata = await ethers.getContractFactory("NftMetadataOnchainMultipleImages");

metadataContract = await NftMetadata.deploy(
sfsContract.address,
sfsNftTokenId,
nftImage, // collectionPreviewImage
nftDescription, // description
externalUrl, // externalUrl
Expand Down
4 changes: 2 additions & 2 deletions test/launchpad/bonding721.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,11 @@ describe("IggyLaunchpad721Bonding", function () {
await statsContract.setStatsWriterAddress(statsMiddlewareContract.address);

const NftMetadata = await ethers.getContractFactory("NftMetadata");
metadataContract = await NftMetadata.deploy();
metadataContract = await NftMetadata.deploy(sfsContract.address, sfsNftTokenId);
await metadataContract.deployed();

const NftDirectory = await ethers.getContractFactory("NftDirectory");
directoryContract = await NftDirectory.deploy();
directoryContract = await NftDirectory.deploy(sfsContract.address, sfsNftTokenId);
await directoryContract.deployed();

const IggyLaunchpad721Bonding = await ethers.getContractFactory("IggyLaunchpad721Bonding");
Expand Down
18 changes: 16 additions & 2 deletions test/merkle/merkleClaimerERC721.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,21 @@ describe("MerkleClaimerERC721", function () {
let user2;
let user3;
let user4;
let feeReceiver;

let claimers;
let tree; // merkle tree

beforeEach(async function () {
[owner, user1, user2, user3, user4] = await ethers.getSigners();
[owner, user1, user2, user3, user4, feeReceiver] = await ethers.getSigners();

const MockSFS = await ethers.getContractFactory("MockSFS");
const sfsContract = await MockSFS.deploy();

const SfsNftInitialize = await ethers.getContractFactory("SfsNftInitialize");
const sfsNftInitializeContract = await SfsNftInitialize.deploy(sfsContract.address, feeReceiver.address);

const sfsNftTokenId = await sfsNftInitializeContract.sfsNftTokenId();

// deploy nft contract
const MockErc721WithMinter = await ethers.getContractFactory("MockErc721WithMinter");
Expand All @@ -54,7 +63,12 @@ describe("MerkleClaimerERC721", function () {

// deploy nft minter
const MerkleClaimerERC721 = await ethers.getContractFactory("MerkleClaimerERC721");
merkleClaimerContract = await MerkleClaimerERC721.deploy(nftContract.address, tree.root);
merkleClaimerContract = await MerkleClaimerERC721.deploy(
sfsContract.address,
sfsNftTokenId,
nftContract.address,
tree.root
);
await merkleClaimerContract.deployed();

// add minter address to nft contract
Expand Down

0 comments on commit e978dfe

Please sign in to comment.