test: hardhat (#21)

* chore: update hardhat config

* test: add FleekERC721 tests and remove not used SitesNFTs suit

* test: verify ERC721 compatibility

* Content type on second abi.encodePacked call in tokenURI

* Fix abi encoding on tokenURI

* chore: update hardhat config

* test: add FleekERC721 tests and remove not used SitesNFTs suit

* test: verify ERC721 compatibility

* Content type on second abi.encodePacked call in tokenURI

* test: improve assertion using deep equality

* chore: remove 0.4.24 version from hardhat compilers

* refactor: clear empty bytes from bytes32

* refactor: change properties from bytes32 to string

Co-authored-by: janison <jsonsivar@gmail.com>
This commit is contained in:
Felipe Mendes 2022-12-06 17:39:08 -03:00 committed by GitHub
parent 700293b94b
commit ef8baad617
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 5347 additions and 9290 deletions

View File

@ -16,8 +16,8 @@ contract FleekERC721 is ERC721, FleekAccessControl {
event NewTokenName(uint256 indexed token, string indexed name);
event NewTokenDescription(uint256 indexed token, string indexed description);
event NewTokenImage(uint256 indexed token, string indexed image);
event NewTokenExternalURL(uint256 indexed token, bytes32 indexed external_url);
event NewTokenENS(uint256 indexed token, bytes32 indexed ENS);
event NewTokenExternalURL(uint256 indexed token, string indexed external_url);
event NewTokenENS(uint256 indexed token, string indexed ENS);
struct Build {
string commit_hash;
@ -25,12 +25,17 @@ contract FleekERC721 is ERC721, FleekAccessControl {
string author;
}
/**
* The properties are stored as string to keep consistency with
* other token contracts, we might consider changing for bytes32
* in the future due to gas optimization
*/
struct App {
string name; // Name of the site
string description; // Description about the site
string image; // Preview Image IPFS Link
bytes32 external_url; // Site URL
bytes32 ENS; // ENS ID
string external_url; // Site URL
string ENS; // ENS ID
uint256 current_build; // The current build number (Increments by one with each change, starts at zero)
mapping(uint256 => Build) builds; // Mapping to build details for each build number
}
@ -56,8 +61,8 @@ contract FleekERC721 is ERC721, FleekAccessControl {
string memory name,
string memory description,
string memory image,
bytes32 external_url,
bytes32 ENS,
string memory external_url,
string memory ENS,
string memory commit_hash,
string memory git_repository,
string memory author
@ -77,7 +82,7 @@ contract FleekERC721 is ERC721, FleekAccessControl {
// The mint interaction is considered to be the first build of the site. Updates from now on all increment the current_build by one and update the mapping.
app.current_build = 0;
app.builds[0] = Build(commit_hash, git_repository, author);
return tokenId;
}
@ -97,12 +102,12 @@ contract FleekERC721 is ERC721, FleekAccessControl {
_requireMinted(tokenId);
address owner = ownerOf(tokenId);
App storage app = _apps[tokenId];
bytes memory dataURI = abi.encodePacked(
'{',
'"name":"', app.name, '",',
'"description":"', app.description, '",',
'"owner":"', abi.encodePacked(owner), '",',
'"ENS":"', app.ENS, '",',
'"owner":"', Strings.toHexString(uint160(owner), 20), '",',
'"external_url":"', app.external_url, '",',
'"image":"', app.image, '",',
'"attributes": [',
@ -110,12 +115,12 @@ contract FleekERC721 is ERC721, FleekAccessControl {
'{"trait_type": "Commit Hash", "value":"', app.builds[app.current_build].commit_hash,'"},',
'{"trait_type": "Repository", "value":"', app.builds[app.current_build].git_repository,'"},',
'{"trait_type": "Author", "value":"', app.builds[app.current_build].author,'"},',
'{"trait_type": "Version", "value":"', app.current_build,'"}',
'{"trait_type": "Version", "value":"', Strings.toString(app.current_build),'"}',
']',
'}'
);
return string(abi.encodePacked(_baseURI(), Base64.encode(dataURI)));
return string(abi.encodePacked(_baseURI(), Base64.encode((dataURI))));
}
function addTokenController(
@ -146,8 +151,8 @@ contract FleekERC721 is ERC721, FleekAccessControl {
function setTokenExternalURL(
uint256 tokenId,
bytes32 _tokenExternalURL
) public virtual payable requireTokenController(tokenId) {
string memory _tokenExternalURL
) public virtual requireTokenController(tokenId) {
_requireMinted(tokenId);
_apps[tokenId].external_url = _tokenExternalURL;
emit NewTokenExternalURL(tokenId, _tokenExternalURL);
@ -155,8 +160,8 @@ contract FleekERC721 is ERC721, FleekAccessControl {
function setTokenENS(
uint256 tokenId,
bytes32 _tokenENS
) public virtual payable requireTokenController(tokenId) {
string memory _tokenENS
) public virtual requireTokenController(tokenId) {
_requireMinted(tokenId);
_apps[tokenId].ENS = _tokenENS;
emit NewTokenENS(tokenId, _tokenENS);
@ -165,7 +170,7 @@ contract FleekERC721 is ERC721, FleekAccessControl {
function setTokenName(
uint256 tokenId,
string memory _tokenName
) public virtual payable requireTokenController(tokenId) {
) public virtual requireTokenController(tokenId) {
_requireMinted(tokenId);
_apps[tokenId].name = _tokenName;
emit NewTokenName(tokenId, _tokenName);
@ -174,7 +179,7 @@ contract FleekERC721 is ERC721, FleekAccessControl {
function setTokenDescription(
uint256 tokenId,
string memory _tokenDescription
) public virtual payable requireTokenController(tokenId) {
) public virtual requireTokenController(tokenId) {
_requireMinted(tokenId);
_apps[tokenId].description = _tokenDescription;
emit NewTokenDescription(tokenId, _tokenDescription);
@ -183,7 +188,7 @@ contract FleekERC721 is ERC721, FleekAccessControl {
function setTokenImage(
uint256 tokenId,
string memory _tokenImage
) public virtual payable requireTokenController(tokenId) {
) public virtual requireTokenController(tokenId) {
_requireMinted(tokenId);
_apps[tokenId].image = _tokenImage;
emit NewTokenImage(tokenId, _tokenImage);
@ -194,20 +199,22 @@ contract FleekERC721 is ERC721, FleekAccessControl {
string memory _commit_hash,
string memory _git_repository,
string memory _author
) public virtual payable requireTokenController(tokenId) {
) public virtual requireTokenController(tokenId) {
_requireMinted(tokenId);
_apps[tokenId].builds[++_apps[tokenId].current_build] = Build(_commit_hash, _git_repository, _author);
emit NewBuild(tokenId, _commit_hash);
}
function burn(uint256 tokenId) public virtual payable requireTokenController(tokenId) {
function burn(
uint256 tokenId
) public virtual requireTokenController(tokenId) {
require(
ownerOf(tokenId) == msg.sender,
"FleekERC721: must be token owner"
);
super._burn(tokenId);
if (_apps[tokenId].external_url.length != 0) {
if (bytes(_apps[tokenId].external_url).length != 0) {
delete _apps[tokenId];
}
}

View File

@ -1,123 +0,0 @@
require('@nomiclabs/hardhat-waffle');
require('@nomiclabs/hardhat-etherscan');
require('hardhat-deploy');
require('solidity-coverage');
require('hardhat-gas-reporter');
require('hardhat-contract-sizer');
require('dotenv').config();
/**
* @type import('hardhat/config').HardhatUserConfig
*/
const MAINNET_RPC_URL =
process.env.MAINNET_RPC_URL ||
process.env.ALCHEMY_MAINNET_RPC_URL ||
'https://eth-mainnet.alchemyapi.io/v2/your-api-key';
const GOERLI_RPC_URL =
process.env.GOERLI_RPC_URL ||
'https://eth-goerli.alchemyapi.io/v2/your-api-key';
const API_URL =
process.env.API_URL ||
'https://polygon-mainnet.alchemyapi.io/v2/your-api-key';
const POLYGON_MUMBAI_RPC_URL =
process.env.POLYGON_MUMBAI_RPC_URL ||
'https://polygon-mumbai.g.alchemy.com/v2/aIjNlC4r4aLYOHrdCTFT_JUX6OJsOsu0';
const PRIVATE_KEY = process.env.PRIVATE_KEY || '0x';
// optional
const MNEMONIC = process.env.MNEMONIC || 'your mnemonic';
// Your API key for Etherscan, obtain one at https://etherscan.io/
const ETHERSCAN_API_KEY =
process.env.ETHERSCAN_API_KEY || 'Your etherscan API key';
const POLYGONSCAN_API_KEY =
process.env.POLYGONSCAN_API_KEY || 'Your polygonscan API key';
const REPORT_GAS = process.env.REPORT_GAS || false;
module.exports = {
defaultNetwork: 'hardhat',
networks: {
hardhat: {
// // If you want to do some forking, uncomment this
// forking: {
// url: MAINNET_RPC_URL
// }
chainId: 31337,
},
localhost: {
chainId: 31337,
},
// goerli: {
// url: GOERLI_RPC_URL,
// accounts: PRIVATE_KEY !== undefined ? [PRIVATE_KEY] : [],
// // accounts: {
// // mnemonic: MNEMONIC,
// // },
// saveDeployments: true,
// chainId: 5,
// },
// mainnet: {
// url: MAINNET_RPC_URL,
// accounts: PRIVATE_KEY !== undefined ? [PRIVATE_KEY] : [],
// // accounts: {
// // mnemonic: MNEMONIC,
// // },
// saveDeployments: true,
// chainId: 1,
// },
// polygon: {
// url: POLYGON_MAINNET_RPC_URL,
// accounts: PRIVATE_KEY !== undefined ? [PRIVATE_KEY] : [],
// saveDeployments: true,
// chainId: 137,
// },
polygonMumbai: {
url: API_URL,
accounts: PRIVATE_KEY !== undefined ? [PRIVATE_KEY] : [],
saveDeployments: true,
chainId: 80001,
},
},
etherscan: {
// npx hardhat verify --network <NETWORK> <CONTRACT_ADDRESS> <CONSTRUCTOR_PARAMETERS>
apiKey: {
goerli: ETHERSCAN_API_KEY,
polygon: process.env.POLYSCAN_API,
polygonMumbai: process.env.POLYSCAN_API,
},
},
gasReporter: {
enabled: REPORT_GAS,
currency: 'USD',
outputFile: 'gas-report.txt',
noColors: true,
// coinmarketcap: process.env.COINMARKETCAP_API_KEY,
},
contractSizer: {
runOnCompile: false,
only: ['NftMarketplace'],
},
namedAccounts: {
deployer: {
default: 1, // here this will by default take the first account as deployer
1: 0,
},
privateKey: {
default: `privatekey://${PRIVATE_KEY}`,
},
},
solidity: {
compilers: [
{
version: '0.8.7',
},
{
version: '0.4.24',
},
],
},
mocha: {
timeout: 200000, // 200 seconds max for running tests
},
};

67
hardhat.config.ts Normal file
View File

@ -0,0 +1,67 @@
import '@nomiclabs/hardhat-ethers';
import '@nomiclabs/hardhat-web3';
import '@nomicfoundation/hardhat-chai-matchers';
import 'hardhat-deploy';
import 'solidity-coverage';
import 'hardhat-gas-reporter';
import 'hardhat-contract-sizer';
import * as dotenv from 'dotenv';
import { HardhatUserConfig } from 'hardhat/types';
dotenv.config();
const {
API_URL = 'https://polygon-mainnet.alchemyapi.io/v2/your-api-key',
PRIVATE_KEY,
REPORT_GAS,
} = process.env;
const config: HardhatUserConfig = {
defaultNetwork: 'hardhat',
networks: {
hardhat: {
chainId: 31337,
},
localhost: {
chainId: 31337,
},
polygonMumbai: {
url: API_URL,
accounts: PRIVATE_KEY ? [PRIVATE_KEY] : [],
saveDeployments: true,
chainId: 80001,
},
},
gasReporter: {
enabled: REPORT_GAS === 'true' || false,
currency: 'USD',
outputFile: 'gas-report.txt',
noColors: true,
// coinmarketcap: process.env.COINMARKETCAP_API_KEY,
},
contractSizer: {
runOnCompile: false,
only: ['NftMarketplace'],
},
namedAccounts: {
deployer: {
default: 1, // here this will by default take the first account as deployer
1: 0,
},
privateKey: {
default: `privatekey://${PRIVATE_KEY}`,
},
},
solidity: {
compilers: [
{
version: '0.8.7',
},
],
},
mocha: {
timeout: 200000, // 200 seconds max for running tests
},
};
export default config;

View File

@ -23,14 +23,16 @@
},
"homepage": "https://github.com/FleekHQ/contracts#readme",
"devDependencies": {
"@nomicfoundation/hardhat-chai-matchers": "^1.0.5",
"@nomicfoundation/hardhat-network-helpers": "^1.0.7",
"@nomicfoundation/hardhat-toolbox": "^2.0.0",
"@nomiclabs/hardhat-ethers": "^2.2.1",
"@nomiclabs/hardhat-etherscan": "^3.1.0",
"@nomiclabs/hardhat-waffle": "^2.0.3",
"@nomiclabs/hardhat-web3": "^2.0.0",
"@openzeppelin/contracts": "^4.7.3",
"@types/mocha": "^10.0.1",
"chai": "^4.3.6",
"dotenv": "^16.0.2",
"ethereum-waffle": "^3.4.4",
"ethers": "^5.7.2",
"hardhat": "^2.11.2",
"hardhat-contract-sizer": "^2.6.1",
@ -39,6 +41,9 @@
"minimist": "^1.2.7",
"prettier": "^2.7.1",
"prettier-plugin-solidity": "^1.0.0",
"solidity-coverage": "^0.8.2"
"solidity-coverage": "^0.8.2",
"ts-node": "^10.9.1",
"typescript": "^4.9.3",
"web3": "^1.8.1"
}
}

175
test/FleekERC721.ts Normal file
View File

@ -0,0 +1,175 @@
import { loadFixture } from '@nomicfoundation/hardhat-network-helpers';
import { expect } from 'chai';
import { ethers } from 'hardhat';
import web3 from 'web3';
describe('FleekERC721', () => {
const COLLECTION_OWNER_ROLE = web3.utils.keccak256('COLLECTION_OWNER_ROLE');
const MINT_PARAMS = Object.freeze({
name: 'Fleek Test App',
description: 'Fleek Test App Description',
image: 'https://fleek.co/image.png',
ens: 'fleek.eth',
externalUrl: 'https://fleek.co',
commitHash: 'b72e47171746b6a9e29b801af9cb655ecf4d665c',
gitRepository: 'https://github.com/fleekxyz/contracts',
author: 'author',
});
const COLLECTION_PARAMS = Object.freeze({
name: 'FleekERC721',
symbol: 'FLEEK',
});
const defaultFixture = async () => {
// Contracts are deployed using the first signer/account by default
const [owner, otherAccount] = await ethers.getSigners();
const Contract = await ethers.getContractFactory('FleekERC721');
const contract = await Contract.deploy(
COLLECTION_PARAMS.name,
COLLECTION_PARAMS.symbol
);
return { owner, otherAccount, contract };
};
describe('Deployment', () => {
it('should assign the name and the symbol of the ERC721 contract', async () => {
const { contract } = await loadFixture(defaultFixture);
expect(await contract.name()).to.equal(COLLECTION_PARAMS.name);
expect(await contract.symbol()).to.equal(COLLECTION_PARAMS.symbol);
});
it('should assign the owner of the contract', async () => {
const { owner, contract } = await loadFixture(defaultFixture);
expect(
await contract.hasRole(COLLECTION_OWNER_ROLE, owner.address)
).to.equal(true);
});
it('should support ERC721 interface', async () => {
const { contract } = await loadFixture(defaultFixture);
expect(await contract.supportsInterface('0x80ac58cd')).to.equal(true);
});
});
describe('Minting', () => {
it('should be able to mint a new token', async () => {
const { owner, contract } = await loadFixture(defaultFixture);
const response = await contract.mint(
owner.address,
MINT_PARAMS.name,
MINT_PARAMS.description,
MINT_PARAMS.image,
MINT_PARAMS.externalUrl,
MINT_PARAMS.ens,
MINT_PARAMS.commitHash,
MINT_PARAMS.gitRepository,
MINT_PARAMS.author
);
expect(response.value).to.be.instanceOf(ethers.BigNumber);
expect(response.value.toNumber()).to.equal(0);
});
it('should not be able to mint a new token if not the owner', async () => {
const { otherAccount, contract } = await loadFixture(defaultFixture);
await expect(
contract
.connect(otherAccount)
.mint(
otherAccount.address,
MINT_PARAMS.name,
MINT_PARAMS.description,
MINT_PARAMS.image,
MINT_PARAMS.externalUrl,
MINT_PARAMS.ens,
MINT_PARAMS.commitHash,
MINT_PARAMS.gitRepository,
MINT_PARAMS.author
)
).to.be.revertedWith(
'FleekAccessControl: must have collection owner role'
);
});
});
describe('Token', () => {
let tokenId: number;
let fixture: Awaited<ReturnType<typeof defaultFixture>>;
before(async () => {
fixture = await loadFixture(defaultFixture);
const { contract } = fixture;
const response = await contract.mint(
fixture.owner.address,
MINT_PARAMS.name,
MINT_PARAMS.description,
MINT_PARAMS.image,
MINT_PARAMS.externalUrl,
MINT_PARAMS.ens,
MINT_PARAMS.commitHash,
MINT_PARAMS.gitRepository,
MINT_PARAMS.author
);
tokenId = response.value.toNumber();
});
it('should return the token URI', async () => {
const { contract } = fixture;
const tokenURI = await contract.tokenURI(tokenId);
const tokenURIDecoded = Buffer.from(
tokenURI.replace('data:application/json;base64,', ''),
'base64'
).toString('ascii');
const parsedURI = JSON.parse(tokenURIDecoded);
expect(parsedURI).to.eql({
owner: fixture.owner.address.toLowerCase(),
name: MINT_PARAMS.name,
description: MINT_PARAMS.description,
image: MINT_PARAMS.image,
external_url: MINT_PARAMS.externalUrl,
attributes: [
{
trait_type: 'ENS',
value: MINT_PARAMS.ens,
},
{
trait_type: 'Commit Hash',
value: MINT_PARAMS.commitHash,
},
{
trait_type: 'Repository',
value: MINT_PARAMS.gitRepository,
},
{
trait_type: 'Author',
value: MINT_PARAMS.author,
},
{
trait_type: 'Version',
value: '0',
},
],
});
});
it('should match the token owner', async () => {
const { contract, owner } = fixture;
const tokenOwner = await contract.ownerOf(tokenId);
expect(tokenOwner).to.equal(owner.address);
});
});
});

View File

@ -1,297 +0,0 @@
const { expect } = require('chai');
describe('SitesNFTs contract', function () {
describe('Deployment', () => {
it('Deployment should assign the name and the symbol of the ERC721 contract', async () => {
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 () => {
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 hasAdminRole = await hardhatSitesNFTs.hasRole(
ethers.utils.formatBytes32String(DEFAULT_ADMIN_ROLE_STRING),
await owner.getAddress()
);
expect(hasAdminRole).to.equal(true);
});
it('Deployment should assign initial tokenId to 0', async () => {
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('Access control', () => {
it('User with DEFAULT_ADMIN_ROLE should be able to assign MINTER_ROLE to another user', async () => {
const [owner, address1] = await ethers.getSigners();
const SitesNFTs = await ethers.getContractFactory('SitesNFTs');
const hardhatSitesNFTs = await SitesNFTs.deploy('Sites NFTs', 'SNFT');
const MINTER_ROLE = 'MINTER_ROLE';
await hardhatSitesNFTs.grantRole(
ethers.utils.formatBytes32String(MINTER_ROLE),
await address1.getAddress()
);
const hasMinterRole = await hardhatSitesNFTs.hasRole(
ethers.utils.formatBytes32String(MINTER_ROLE),
await address1.getAddress()
);
expect(hasMinterRole).to.equal(true);
});
it('User with DEFAULT_ADMIN_ROLE should be able to assign MINTER_ROLE to himself and still have DEFAULT_ADMIN_ROLE', async () => {
const [owner] = await ethers.getSigners();
const SitesNFTs = await ethers.getContractFactory('SitesNFTs');
const hardhatSitesNFTs = await SitesNFTs.deploy('Sites NFTs', 'SNFT');
const MINTER_ROLE = 'MINTER_ROLE';
const DEFAULT_ADMIN_ROLE = '';
await hardhatSitesNFTs.grantRole(
ethers.utils.formatBytes32String(MINTER_ROLE),
await owner.getAddress()
);
const hasMinterRole = await hardhatSitesNFTs.hasRole(
ethers.utils.formatBytes32String(MINTER_ROLE),
await owner.getAddress()
);
const hasAdminRole = await hardhatSitesNFTs.hasRole(
ethers.utils.formatBytes32String(DEFAULT_ADMIN_ROLE),
await owner.getAddress()
);
expect(hasMinterRole).to.equal(true);
expect(hasAdminRole).to.equal(true);
});
it('User with DEFAULT_ADMIN_ROLE should be able to assign DEFAULT_ADMIN_ROLE to another user', async () => {
const [owner, address1] = await ethers.getSigners();
const SitesNFTs = await ethers.getContractFactory('SitesNFTs');
const hardhatSitesNFTs = await SitesNFTs.deploy('Sites NFTs', 'SNFT');
const DEFAULT_ADMIN_ROLE = '';
await hardhatSitesNFTs.grantRole(
ethers.utils.formatBytes32String(DEFAULT_ADMIN_ROLE),
await address1.getAddress()
);
const hasAdminRole = await hardhatSitesNFTs.hasRole(
ethers.utils.formatBytes32String(DEFAULT_ADMIN_ROLE),
await address1.getAddress()
);
expect(hasAdminRole).to.equal(true);
});
it('User with DEFAULT_ADMIN_ROLE should be able to assign DEFAULT_ADMIN_ROLE to another user and still have DEFAULT_ADMIN_ROLE', async () => {
const [owner, address1] = await ethers.getSigners();
const SitesNFTs = await ethers.getContractFactory('SitesNFTs');
const hardhatSitesNFTs = await SitesNFTs.deploy('Sites NFTs', 'SNFT');
const DEFAULT_ADMIN_ROLE = '';
await hardhatSitesNFTs.grantRole(
ethers.utils.formatBytes32String(DEFAULT_ADMIN_ROLE),
await address1.getAddress()
);
let hasAdminRole = await hardhatSitesNFTs.hasRole(
ethers.utils.formatBytes32String(DEFAULT_ADMIN_ROLE),
await address1.getAddress()
);
expect(hasAdminRole).to.equal(true);
hasAdminRole = await hardhatSitesNFTs.hasRole(
ethers.utils.formatBytes32String(DEFAULT_ADMIN_ROLE),
await owner.getAddress()
);
expect(hasAdminRole).to.equal(true);
});
it('User without DEFAULT_ADMIN_ROLE shouldnt be able to assign DEFAULT_ADMIN_ROLE to another user', async () => {
const [owner, address1, address2] = await ethers.getSigners();
const SitesNFTs = await ethers.getContractFactory('SitesNFTs');
const hardhatSitesNFTs = await SitesNFTs.deploy('Sites NFTs', 'SNFT');
const DEFAULT_ADMIN_ROLE = '';
try {
await hardhatSitesNFTs
.connect(address1)
.grantRole(
ethers.utils.formatBytes32String(DEFAULT_ADMIN_ROLE),
await address2.getAddress()
);
} catch (e) {}
const hasAdminRole = await hardhatSitesNFTs.hasRole(
ethers.utils.formatBytes32String(DEFAULT_ADMIN_ROLE),
await address2.getAddress()
);
expect(hasAdminRole).to.equal(false);
});
it('User without DEFAULT_ADMIN_ROLE shouldnt be able to assign MINTER_ROLE to another user', async () => {
const [owner, address1, address2] = await ethers.getSigners();
const SitesNFTs = await ethers.getContractFactory('SitesNFTs');
const hardhatSitesNFTs = await SitesNFTs.deploy('Sites NFTs', 'SNFT');
const MINTER_ROLE = 'MINTER_ROLE';
try {
await hardhatSitesNFTs
.connect(address1)
.grantRole(
ethers.utils.formatBytes32String(MINTER_ROLE),
await address2.getAddress()
);
} catch (e) {}
const hasMinterRole = await hardhatSitesNFTs.hasRole(
ethers.utils.formatBytes32String(MINTER_ROLE),
await address2.getAddress()
);
expect(hasMinterRole).to.equal(false);
});
});
describe('Minting', () => {
it('User with DEFAULT_ADMIN_ROLE should be able to mint', async () => {
const [owner, address1] = await ethers.getSigners();
const SitesNFTs = await ethers.getContractFactory('SitesNFTs');
const hardhatSitesNFTs = await SitesNFTs.deploy('Sites NFTs', 'SNFT');
const tokenURI = 'tokenURI';
await hardhatSitesNFTs.mint(tokenURI, await address1.getAddress());
const balance = await hardhatSitesNFTs.balanceOf(
await address1.getAddress()
);
expect(balance).to.equal(1);
});
it('User with MINTER_ROLE should be able to mint', async () => {
const [owner, address1, address2] = await ethers.getSigners();
const SitesNFTs = await ethers.getContractFactory('SitesNFTs');
const hardhatSitesNFTs = await SitesNFTs.deploy('Sites NFTs', 'SNFT');
const MINTER_ROLE = 'MINTER_ROLE';
const tokenURI = 'tokenURI';
await hardhatSitesNFTs.grantRole(
ethers.utils.formatBytes32String(MINTER_ROLE),
await address1.getAddress()
);
await hardhatSitesNFTs.hasRole(
ethers.utils.formatBytes32String(MINTER_ROLE),
await address1.getAddress()
);
await hardhatSitesNFTs
.connect(address1)
.mint(tokenURI, await address2.getAddress());
const balance = await hardhatSitesNFTs.balanceOf(
await address2.getAddress()
);
expect(balance).to.equal(1);
});
it('User without MINTER_ROLE or DEFAULT_ADMIN_ROLE shouldnt be able to mint', async () => {
const [owner, address1, address2] = await ethers.getSigners();
const SitesNFTs = await ethers.getContractFactory('SitesNFTs');
const hardhatSitesNFTs = await SitesNFTs.deploy('Sites NFTs', 'SNFT');
const tokenURI = 'tokenURI';
try {
await hardhatSitesNFTs
.connect(address1)
.mint(tokenURI, await address2.getAddress());
} catch (e) {}
const balance = await hardhatSitesNFTs.balanceOf(
await address2.getAddress()
);
expect(balance).to.equal(0);
});
it('Minted NFT should have data:application/json;base64, baseURI', async () => {
const [owner, address1] = await ethers.getSigners();
const SitesNFTs = await ethers.getContractFactory('SitesNFTs');
const hardhatSitesNFTs = await SitesNFTs.deploy('Sites NFTs', 'SNFT');
const tokenURI = 'tokenURI';
await hardhatSitesNFTs.mint(tokenURI, await address1.getAddress());
const mintedNFT = await hardhatSitesNFTs.tokenURI(0);
expect(mintedNFT.includes('data:application/json;base64,')).to.equal(
true
);
});
});
});

13915
yarn.lock

File diff suppressed because it is too large Load Diff