From 7b7e8257555cda608b8ab780479d6538702e019a Mon Sep 17 00:00:00 2001 From: Marco Tabasco Date: Mon, 29 Jul 2024 17:12:51 +0200 Subject: [PATCH] add BasicWhitelisting contract --- contracts/whitelisting/BasicWhitelisting.sol | 31 +++++++ test/operators/external-whitelist.ts | 86 ++++++++++++++++++++ 2 files changed, 117 insertions(+) create mode 100644 contracts/whitelisting/BasicWhitelisting.sol create mode 100644 test/operators/external-whitelist.ts diff --git a/contracts/whitelisting/BasicWhitelisting.sol b/contracts/whitelisting/BasicWhitelisting.sol new file mode 100644 index 00000000..bb45d2a8 --- /dev/null +++ b/contracts/whitelisting/BasicWhitelisting.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity 0.8.24; + +import "@openzeppelin/contracts/access/Ownable.sol"; +import "@openzeppelin/contracts/utils/introspection/ERC165.sol"; +import {ISSVWhitelistingContract} from "../interfaces/external/ISSVWhitelistingContract.sol"; + +contract BasicWhitelisting is ISSVWhitelistingContract, ERC165, Ownable { + mapping(address => bool) private whitelisted; + + event AddressWhitelisted(address indexed account); + event AddressRemovedFromWhitelist(address indexed account); + + function addWhitelistedAddress(address account) external onlyOwner { + whitelisted[account] = true; + emit AddressWhitelisted(account); + } + + function removeWhitelistedAddress(address account) external onlyOwner { + whitelisted[account] = false; + emit AddressRemovedFromWhitelist(account); + } + + function isWhitelisted(address account, uint256) external view override returns (bool) { + return whitelisted[account]; + } + + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(ISSVWhitelistingContract).interfaceId || super.supportsInterface(interfaceId); + } +} diff --git a/test/operators/external-whitelist.ts b/test/operators/external-whitelist.ts new file mode 100644 index 00000000..250f6692 --- /dev/null +++ b/test/operators/external-whitelist.ts @@ -0,0 +1,86 @@ +import hre from 'hardhat'; + +import { assertEvent } from '../helpers/utils/test'; +const { expect } = require('chai'); + +describe('BasicWhitelisting', () => { + let basicWhitelisting: any, owners: any; + + beforeEach(async () => { + owners = await hre.viem.getWalletClients(); + + basicWhitelisting = await hre.viem.deployContract('BasicWhitelisting'); + }); + + describe('Deployment', async () => { + it('Should set the right owner', async () => { + expect(await basicWhitelisting.read.owner()).to.deep.equal(owners[0].account.address); + }); + }); + + describe('Whitelisting', async () => { + it('Should whitelist an address', async () => { + const addr1 = owners[2].account.address; + + await basicWhitelisting.write.addWhitelistedAddress([addr1]); + expect(await basicWhitelisting.read.isWhitelisted([addr1, 0])).to.be.true; + }); + + it('Should remove an address from whitelist', async () => { + const addr1 = owners[2].account.address; + + await basicWhitelisting.write.addWhitelistedAddress([addr1]); + await basicWhitelisting.write.removeWhitelistedAddress([addr1]); + expect(await basicWhitelisting.read.isWhitelisted([addr1, 0])).to.be.false; + }); + + it('Should emit AddressWhitelisted event', async () => { + const addr1 = owners[2].account.address; + + await assertEvent(basicWhitelisting.write.addWhitelistedAddress([addr1]), [ + { + contract: basicWhitelisting, + eventName: 'AddressWhitelisted', + argNames: ['account'], + argValuesList: [[addr1]], + }, + ]); + }); + + it('Should emit AddressRemovedFromWhitelist event', async () => { + const addr1 = owners[2].account.address; + + await basicWhitelisting.write.addWhitelistedAddress([addr1]); + + await assertEvent(basicWhitelisting.write.removeWhitelistedAddress([addr1]), [ + { + contract: basicWhitelisting, + eventName: 'AddressRemovedFromWhitelist', + argNames: ['account'], + argValuesList: [[addr1]], + }, + ]); + }); + + it('Should only allow the owner to whitelist addresses', async () => { + const addr1 = owners[2].account.address; + + await expect( + basicWhitelisting.write.addWhitelistedAddress([addr1], { + account: owners[1].account, + }), + ).to.be.rejectedWith('Ownable: caller is not the owner'); + }); + + it('Should only allow the owner to remove addresses from whitelist', async () => { + const addr1 = owners[2].account.address; + + await basicWhitelisting.write.addWhitelistedAddress([addr1]); + await expect( + basicWhitelisting.write.removeWhitelistedAddress([addr1], { + account: owners[1].account, + }), + ).to.be.rejectedWith('Ownable: caller is not the owner'); + }); + }); +});