finished contract

This commit is contained in:
miguelToscano 2022-10-11 14:54:52 -03:00
parent c31c466ce9
commit a5381f2d72
12 changed files with 884 additions and 18 deletions

View File

@ -0,0 +1,4 @@
{
"_format": "hh-sol-dbg-1",
"buildInfo": "../../../../build-info/0593067611bf3df2fd92fc9e7ccdc02c.json"
}

View File

@ -0,0 +1,215 @@
{
"_format": "hh-sol-artifact-1",
"contractName": "AccessControl",
"sourceName": "@openzeppelin/contracts/access/AccessControl.sol",
"abi": [
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "bytes32",
"name": "previousAdminRole",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "bytes32",
"name": "newAdminRole",
"type": "bytes32"
}
],
"name": "RoleAdminChanged",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "address",
"name": "account",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "sender",
"type": "address"
}
],
"name": "RoleGranted",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "address",
"name": "account",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "sender",
"type": "address"
}
],
"name": "RoleRevoked",
"type": "event"
},
{
"inputs": [],
"name": "DEFAULT_ADMIN_ROLE",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
}
],
"name": "getRoleAdmin",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "grantRole",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "hasRole",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "renounceRole",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "revokeRole",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes4",
"name": "interfaceId",
"type": "bytes4"
}
],
"name": "supportsInterface",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
}
],
"bytecode": "0x",
"deployedBytecode": "0x",
"linkReferences": {},
"deployedLinkReferences": {}
}

View File

@ -0,0 +1,4 @@
{
"_format": "hh-sol-dbg-1",
"buildInfo": "../../../../build-info/0593067611bf3df2fd92fc9e7ccdc02c.json"
}

View File

@ -0,0 +1,183 @@
{
"_format": "hh-sol-artifact-1",
"contractName": "IAccessControl",
"sourceName": "@openzeppelin/contracts/access/IAccessControl.sol",
"abi": [
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "bytes32",
"name": "previousAdminRole",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "bytes32",
"name": "newAdminRole",
"type": "bytes32"
}
],
"name": "RoleAdminChanged",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "address",
"name": "account",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "sender",
"type": "address"
}
],
"name": "RoleGranted",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "address",
"name": "account",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "sender",
"type": "address"
}
],
"name": "RoleRevoked",
"type": "event"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
}
],
"name": "getRoleAdmin",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "grantRole",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "hasRole",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "renounceRole",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "revokeRole",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
],
"bytecode": "0x",
"deployedBytecode": "0x",
"linkReferences": {},
"deployedLinkReferences": {}
}

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,4 @@
{
"_format": "hh-sol-dbg-1",
"buildInfo": "../../build-info/b529dad98ab8434933b98e1e24265db6.json"
"buildInfo": "../../build-info/0593067611bf3df2fd92fc9e7ccdc02c.json"
}

File diff suppressed because one or more lines are too long

View File

@ -2,8 +2,8 @@
"_format": "hh-sol-cache-2",
"files": {
"/Users/migue/Documents/psychedelic/sites_nfts/contracts/SitesNFTs.sol": {
"lastModificationDate": 1664310055206,
"contentHash": "b9a606a499a26970be20c1109ed5a2f0",
"lastModificationDate": 1665508068244,
"contentHash": "e72dc1748efc4646c33553ef83e2462d",
"sourceName": "contracts/SitesNFTs.sol",
"solcConfig": {
"version": "0.8.7",
@ -37,7 +37,8 @@
},
"imports": [
"@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol",
"@openzeppelin/contracts/utils/Counters.sol"
"@openzeppelin/contracts/utils/Counters.sol",
"@openzeppelin/contracts/access/AccessControl.sol"
],
"versionPragmas": [
"^0.8.7"
@ -523,6 +524,95 @@
"artifacts": [
"IERC165"
]
},
"/Users/migue/Documents/psychedelic/sites_nfts/node_modules/@openzeppelin/contracts/access/AccessControl.sol": {
"lastModificationDate": 1664309222608,
"contentHash": "e6ef731d275b1e7b2995f00fa56d9dab",
"sourceName": "@openzeppelin/contracts/access/AccessControl.sol",
"solcConfig": {
"version": "0.8.7",
"settings": {
"optimizer": {
"enabled": false,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"abi",
"evm.bytecode",
"evm.deployedBytecode",
"evm.methodIdentifiers",
"metadata",
"devdoc",
"userdoc",
"storageLayout",
"evm.gasEstimates"
],
"": [
"ast"
]
}
},
"metadata": {
"useLiteralContent": true
}
}
},
"imports": [
"./IAccessControl.sol",
"../utils/Context.sol",
"../utils/Strings.sol",
"../utils/introspection/ERC165.sol"
],
"versionPragmas": [
"^0.8.0"
],
"artifacts": [
"AccessControl"
]
},
"/Users/migue/Documents/psychedelic/sites_nfts/node_modules/@openzeppelin/contracts/access/IAccessControl.sol": {
"lastModificationDate": 1664309222621,
"contentHash": "57c84298234411cea19c7c284d86be8b",
"sourceName": "@openzeppelin/contracts/access/IAccessControl.sol",
"solcConfig": {
"version": "0.8.7",
"settings": {
"optimizer": {
"enabled": false,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"abi",
"evm.bytecode",
"evm.deployedBytecode",
"evm.methodIdentifiers",
"metadata",
"devdoc",
"userdoc",
"storageLayout",
"evm.gasEstimates"
],
"": [
"ast"
]
}
},
"metadata": {
"useLiteralContent": true
}
}
},
"imports": [],
"versionPragmas": [
"^0.8.0"
],
"artifacts": [
"IAccessControl"
]
}
}
}

View File

@ -4,17 +4,23 @@ pragma solidity ^0.8.7;
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "base64-sol/base64.sol";
import "@openzeppelin/contracts/access/AccessControl.sol";
contract SitesNFTs is ERC721URIStorage {
contract SitesNFTs is ERC721URIStorage, AccessControl {
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;
string private baseURI;
constructor() ERC721("Fleek Sites NFTs", "SNFT") {}
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
constructor(string memory name, string memory symbol) ERC721(name, symbol) {
baseURI = "data:application/json;base64,";
_setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
}
// Token uri is the Base64 encoded json metadata
function mintNFT(string memory _tokenURI) public returns (uint256) {
function mintNFT(string memory _tokenURI) public onlyRole(MINTER_ROLE) returns (uint256) {
uint256 newItemId = _tokenIds.current();
_safeMint(msg.sender, newItemId);
_setTokenURI(newItemId, _tokenURI);
@ -23,13 +29,15 @@ contract SitesNFTs is ERC721URIStorage {
return newItemId;
}
function _htmlToImageURI(string memory html) internal pure returns (string memory) {
// text/html;charset=UTF-8,
string memory baseURL = "data:text/html;charset=UTF-8,";
return string(abi.encodePacked(baseURL, html));
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721, AccessControl) returns (bool) {
return super.supportsInterface(interfaceId);
}
function _baseURI() internal pure override returns (string memory) {
return "data:application/json;base64,";
function setBaseURI(string memory _newBbaseURI) public {
baseURI = _newBbaseURI;
}
function getCurrentTokenId() public view returns (uint256) {
return _tokenIds.current();
}
}

63
package-lock.json generated
View File

@ -1883,6 +1883,12 @@
"integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==",
"dev": true
},
"assertion-error": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz",
"integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==",
"dev": true
},
"astral-regex": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
@ -2166,6 +2172,21 @@
"nofilter": "^1.0.4"
}
},
"chai": {
"version": "4.3.6",
"resolved": "https://registry.npmjs.org/chai/-/chai-4.3.6.tgz",
"integrity": "sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q==",
"dev": true,
"requires": {
"assertion-error": "^1.1.0",
"check-error": "^1.0.2",
"deep-eql": "^3.0.1",
"get-func-name": "^2.0.0",
"loupe": "^2.3.1",
"pathval": "^1.1.1",
"type-detect": "^4.0.5"
}
},
"chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
@ -2183,6 +2204,12 @@
"integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==",
"dev": true
},
"check-error": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz",
"integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==",
"dev": true
},
"chokidar": {
"version": "3.5.3",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
@ -2466,6 +2493,15 @@
"integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==",
"dev": true
},
"deep-eql": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz",
"integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==",
"dev": true,
"requires": {
"type-detect": "^4.0.0"
}
},
"deep-is": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
@ -12537,6 +12573,12 @@
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
"dev": true
},
"get-func-name": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz",
"integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==",
"dev": true
},
"get-intrinsic": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz",
@ -13677,6 +13719,15 @@
}
}
},
"loupe": {
"version": "2.3.4",
"resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.4.tgz",
"integrity": "sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ==",
"dev": true,
"requires": {
"get-func-name": "^2.0.0"
}
},
"lru-cache": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
@ -14321,6 +14372,12 @@
"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
"dev": true
},
"pathval": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz",
"integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==",
"dev": true
},
"pbkdf2": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz",
@ -15851,6 +15908,12 @@
"prelude-ls": "~1.1.2"
}
},
"type-detect": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
"integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
"dev": true
},
"type-fest": {
"version": "0.21.3",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz",

View File

@ -22,6 +22,7 @@
"@nomiclabs/hardhat-etherscan": "^3.1.0",
"@nomiclabs/hardhat-waffle": "^2.0.3",
"@openzeppelin/contracts": "^4.7.3",
"chai": "^4.3.6",
"dotenv": "^16.0.2",
"ethereum-waffle": "^3.4.4",
"hardhat": "^2.11.2",

62
test/SitesNFTs.js Normal file
View File

@ -0,0 +1,62 @@
const { expect } = require("chai");
describe("SitesNFTs contract", function () {
describe("Deployment", () => {
it("Deployment should assign the name and the symbol of the ERC721 contract", async function () {
const [owner] = await ethers.getSigners();
const name = "Sites NFTs";
const symbol = "SNFT";
const SitesNFTs = await ethers.getContractFactory("SitesNFTs");
const hardhatSitesNFTs = await SitesNFTs.deploy("Sites NFTs", "SNFT");
const contractName = await hardhatSitesNFTs.name();
const contractSymbol = await hardhatSitesNFTs.symbol();
expect(contractName).to.equal(name);
expect(contractSymbol).to.equal(symbol);
});
it("Deployment should assign the deployer DEFAULT_ADMIN_ROLE", async function () {
const [owner] = await ethers.getSigners();
const SitesNFTs = await ethers.getContractFactory("SitesNFTs");
const hardhatSitesNFTs = await SitesNFTs.deploy("Sites NFTs", "SNFT");
const DEFAULT_ADMIN_ROLE_STRING = ""
const userRole = await hardhatSitesNFTs.hasRole(ethers.utils.formatBytes32String(DEFAULT_ADMIN_ROLE_STRING) , await owner.getAddress());
expect(userRole).to.equal(true);
});
it("Deployment should assign initial tokenId to 0", async function () {
const [owner] = await ethers.getSigners();
const SitesNFTs = await ethers.getContractFactory("SitesNFTs");
const hardhatSitesNFTs = await SitesNFTs.deploy("Sites NFTs", "SNFT");
const currentTokenId = await hardhatSitesNFTs.getCurrentTokenId();
expect(currentTokenId).to.equal(0);
});
});
describe("Role management", () => {
it("User with admin role should be able to assign MINTER_ROLE to another user", async function () {
const [owner, address1] = await ethers.getSigners();
const SitesNFTs = await ethers.getContractFactory("SitesNFTs");
const hardhatSitesNFTs = await SitesNFTs.deploy("Sites NFTs", "SNFT");
const currentTokenId = await hardhatSitesNFTs.getCurrentTokenId();
expect(currentTokenId).to.equal(0);
});
});
});