Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add accesslists contracts #868

Merged
merged 22 commits into from
Aug 13, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions contracts/accesslists/AccessList.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// Copyright BigchainDB GmbH and Ocean Protocol contributors
// SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
// Code is Apache-2.0 and docs are CC-BY-4.0

pragma solidity ^0.8.26;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

/**
* @title AccessList
*
* @dev AccessList is an soul bound ERC721 used to build access lists (allow or deny)
* Only owner can mint and also burn (ie: remove address from a list)
* Each token id has it's own metadata
*/

contract AccessList is Ownable, ERC721Enumerable,ERC721URIStorage {
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;
constructor(string memory _name, string memory _symbol)

Check notice

Code scanning / Slither

Local variable shadowing Low

Check notice

Code scanning / Slither

Local variable shadowing Low

ERC721(_name, _symbol) {

}

function tokenURI(uint256 tokenId)
public
view
override(ERC721, ERC721URIStorage)
returns (string memory)
{
return super.tokenURI(tokenId);
}
function supportsInterface(bytes4 interfaceId)
public
view
override(ERC721, ERC721Enumerable)
returns (bool)
{
return super.supportsInterface(interfaceId);
}
function _beforeTokenTransfer(address from, address to, uint256 tokenId, uint256 batchSize)
internal
override(ERC721,ERC721Enumerable)
{
require(from == address(0) || to == address(0), "Token not transferable");
super._beforeTokenTransfer(from, to, tokenId, batchSize);
}

function _add(address user, string memory tokenURI) private returns (uint256) {

Check notice

Code scanning / Slither

Local variable shadowing Low

_tokenIds.increment();
uint256 newItemId = _tokenIds.current();
_mint(user, newItemId);
_setTokenURI(newItemId, tokenURI);
return newItemId;
}

function mint(address user, string memory tokenURI) external onlyOwner returns (uint256) {

Check notice

Code scanning / Slither

Local variable shadowing Low

return(_add(user,tokenURI));
}


/**
* @notice Batch Mint only for owner
*/
function batchMint(address[] memory user,string[] memory tokenURI) external onlyOwner

Check notice

Code scanning / Slither

Local variable shadowing Low

{
uint256 i;
require(user.length==tokenURI.length);
for(i=0;i<user.length;i++){
_add(user[i],tokenURI[i]);
}
}

function burn(uint256 tokenId) public {
require(_msgSender() == super.owner() || _msgSender()==super._ownerOf(tokenId),"ERC721: Not owner");
_burn(tokenId);
}
// The following functions are overrides required by Solidity.
function _burn(uint256 tokenId) internal override(ERC721URIStorage,ERC721) {
super._burn(tokenId);
}


}
9 changes: 9 additions & 0 deletions hardhat.config.barge.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,15 @@ module.exports = {
},
},
},
{
version: "0.8.26",
settings: {
optimizer: {
enabled: true,
runs: 200,
},
},
},

],
overrides: {},
Expand Down
9 changes: 9 additions & 0 deletions hardhat.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,15 @@ module.exports = {
},
},
},
{
version: "0.8.26",
settings: {
optimizer: {
enabled: true,
runs: 200,
},
},
},

],
overrides: {},
Expand Down
116 changes: 116 additions & 0 deletions test/unit/accesslists/AccessList.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
const { expect } = require('chai');
const { ethers } = require("hardhat");
const { json } = require('hardhat/internal/core/params/argumentTypes');

let metadata = {"uptime":100,"image":"ipfs://123"}
let signers
// Start test block
describe('AccessLists tests', function () {
before(async function () {
this.tokenID=0
this.accessListContract = await ethers.getContractFactory('AccessList');
this.accessListContract = await this.accessListContract.deploy("AccessList","A");
await this.accessListContract.deployed();

// Get the contractOwner and collector address
signers = await ethers.getSigners();

});


// Test cases
it('Check token name', async function () {
expect(await this.accessListContract.name()).to.exist;

});

it('Check token symbol', async function () {
expect(await this.accessListContract.symbol()).to.exist;
});


it('Mints one token, using mint', async function () {
await this.accessListContract.mint(signers[0].address,JSON.stringify(metadata));
this.tokenID++;
expect(await this.accessListContract.balanceOf(signers[0].address)).to.equal(1);
expect(await this.accessListContract.ownerOf(this.tokenID)).to.equal(signers[0].address);
});

it('Mints several tokens, using batchMint', async function () {
const addresses=[]
const tokenURIs=[]

for (let i = 1; i < 4; i++) {
addresses.push(signers[i].address)
tokenURIs.push(JSON.stringify(metadata))
}
await this.accessListContract.batchMint(addresses,tokenURIs);
expect(await this.accessListContract.balanceOf(signers[1].address)).to.equal(1);
expect(await this.accessListContract.ownerOf(2)).to.equal(signers[1].address);

//signer[4] should not have any nft
expect(await this.accessListContract.balanceOf(signers[4].address)).to.equal(0);
});


it('Only owner can mint', async function () {
await expect(
this.accessListContract.connect(signers[1])
.mint(signers[0].address,JSON.stringify(metadata)))
.to.be.revertedWith("Ownable: caller is not the owner")

await expect(
this.accessListContract.connect(signers[1])
.batchMint([signers[0].address,signers[1].address],[JSON.stringify(metadata),JSON.stringify(metadata)]))
.to.be.revertedWith("Ownable: caller is not the owner")
});

it('Is able to query the NFT tokenURI', async function () {
expect(await this.accessListContract.tokenURI(1)).to.equal(JSON.stringify(metadata));
});

it('Emits a transfer event for newly minted NFTs', async function () {
await expect(this.accessListContract.mint(signers[1].address,JSON.stringify(metadata)))
.to.emit(this.accessListContract, "Transfer")
.withArgs("0x0000000000000000000000000000000000000000", signers[1].address, 5);
});

it('Is not able to transfer NFTs to another wallet when called by user', async function () {
await expect(this.accessListContract["safeTransferFrom(address,address,uint256)"](signers[0].address,signers[2].address,1)).to.be.revertedWith("Token not transferable");
});

it('Is not able to transfer NFTs to another wallet when called by contract owner', async function () {
await expect(this.accessListContract["safeTransferFrom(address,address,uint256)"](signers[0].address,signers[1].address,2)).to.be.revertedWith("ERC721: caller is not token owner or approved");
});

it('Is should mint to test burn', async function () {
await expect(this.accessListContract.mint(signers[1].address,JSON.stringify(metadata)))
.to.emit(this.accessListContract, "Transfer")
.withArgs("0x0000000000000000000000000000000000000000", signers[1].address, 6);
await expect(this.accessListContract.mint(signers[2].address,JSON.stringify(metadata)))
.to.emit(this.accessListContract, "Transfer")
.withArgs("0x0000000000000000000000000000000000000000", signers[2].address, 7);
});

it('Owner should be able to burn', async function () {
const howMany=await this.accessListContract.balanceOf(signers[1].address)
expect(await this.accessListContract.ownerOf(6)).to.equal(signers[1].address);
await this.accessListContract.burn(6);
expect(await this.accessListContract.balanceOf(signers[1].address)).to.equal(howMany-1);


});
it('Other users should not be able to burn', async function () {
expect(await this.accessListContract.ownerOf(7)).to.equal(signers[2].address);
await expect(this.accessListContract.connect(signers[3]).burn(7)).to.be.revertedWith("ERC721: Not owner");

});
it('Token holder should be able to burn', async function () {
expect(await this.accessListContract.ownerOf(7)).to.equal(signers[2].address);
const howMany=await this.accessListContract.balanceOf(signers[2].address)
await this.accessListContract.connect(signers[2]).burn(7);
expect(await this.accessListContract.balanceOf(signers[2].address)).to.equal(howMany-1);

});

});
Loading