-
Notifications
You must be signed in to change notification settings - Fork 61
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
Changes from 2 commits
d143e5b
ba56e45
937c9b5
b561abe
fa6c3a9
ac83709
fa2e190
df260a1
b707553
2ac9218
93cdff3
ede0a1e
31db861
80e682a
00c49a2
c0cf5ae
401e759
dd10e04
a1d6069
9e66a03
2ed0099
c49d299
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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 |
||
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
AccessList._add(address,string).tokenURI shadows:
- AccessList.tokenURI(uint256) (function) - ERC721URIStorage.tokenURI(uint256) (function) - ERC721.tokenURI(uint256) (function) - IERC721Metadata.tokenURI(uint256) (function) |
||
_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
AccessList.mint(address,string).tokenURI shadows:
- AccessList.tokenURI(uint256) (function) - ERC721URIStorage.tokenURI(uint256) (function) - ERC721.tokenURI(uint256) (function) - IERC721Metadata.tokenURI(uint256) (function) |
||
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
AccessList.batchMint(address[],string[]).tokenURI shadows:
- AccessList.tokenURI(uint256) (function) - ERC721URIStorage.tokenURI(uint256) (function) - ERC721.tokenURI(uint256) (function) - IERC721Metadata.tokenURI(uint256) (function) |
||
{ | ||
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); | ||
} | ||
|
||
|
||
} |
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); | ||
|
||
}); | ||
|
||
}); |
Check notice
Code scanning / Slither
Local variable shadowing Low