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 Whitelist contract #746

Merged
merged 11 commits into from
Mar 8, 2018
14 changes: 14 additions & 0 deletions contracts/mocks/WhitelistMock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
pragma solidity ^0.4.18;

import "../ownership/Whitelist.sol";


contract WhitelistMock is Whitelist {

function onlyWhitelistedCanDoThis()
onlyWhitelisted
view
external
{
}
}
81 changes: 81 additions & 0 deletions contracts/ownership/Whitelist.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
pragma solidity ^0.4.18;


import "./Ownable.sol";


/**
* @title Whitelist
* @dev The Whitelist contract has a whitelist of addresses, and provides basic authorization control
* functions, this simplifies the implementation of "user permissions".
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's add an @dev prefix here for multiple-line dev comments

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

*/
contract Whitelist is Ownable {
mapping(address => bool) public whitelist;

event WhitelistedAddressAdded(address addr);
event WhitelistedAddressRemoved(address addr);

/**
* @dev Throws if called by any account that's not whitelisted.
*/
modifier onlyWhitelisted() {
require(whitelist[msg.sender]);
_;
}

/**
* @dev add an address to the whitelist
* @param addr address
* @return true if the address was added to the whitelist, false if the address was already in the whitelist
*/
function addAddressToWhitelist(address addr) onlyOwner public returns(bool success) {
if (!whitelist[addr]) {
whitelist[addr] = true;
WhitelistedAddressAdded(addr);
success = true;
}
}

/**
* @dev add addresses to the whitelist
* @param addrs addresses
* @return true if at least one address was added to the whitelist,
* false if all addresses were already in the whitelist
*/
function addAddressesToWhitelist(address[] addrs) onlyOwner public returns(bool success) {
for (uint256 i = 0; i < addrs.length; i++) {
if (addAddressToWhitelist(addrs[i])) {
success = true;
}
}
}

/**
* @dev remove an address from the whitelist
* @param addr address
* @return true if the address was removed from the whitelist,
* false if the address wasn't in the whitelist in the first place
*/
function removeAddressFromWhitelist(address addr) onlyOwner public returns(bool success) {
if (whitelist[addr]) {
whitelist[addr] = false;
WhitelistedAddressRemoved(addr);
success = true;
}
}

/**
* @dev remove addresses from the whitelist
* @param addrs addresses
* @return true if at least one address was removed from the whitelist,
* false if all addresses weren't in the whitelist in the first place
*/
function removeAddressesFromWhitelist(address[] addrs) onlyOwner public returns(bool success) {
for (uint256 i = 0; i < addrs.length; i++) {
if (removeAddressFromWhitelist(addrs[i])) {
success = true;
}
}
}

}
103 changes: 103 additions & 0 deletions test/ownership/Whitelist.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import expectThrow from '../helpers/expectThrow';
import expectEvent from '../helpers/expectEvent';

const WhitelistMock = artifacts.require('WhitelistMock');

require('chai')
.use(require('chai-as-promised'))
.should();

contract('Whitelist', function (accounts) {
let mock;

const [
owner,
whitelistedAddress1,
whitelistedAddress2,
anyone,
] = accounts;

const whitelistedAddresses = [whitelistedAddress1, whitelistedAddress2];

before(async function () {
mock = await WhitelistMock.new();
});

context('in normal conditions', () => {
it('should add address to the whitelist', async function () {
await expectEvent.inTransaction(
mock.addAddressToWhitelist(whitelistedAddress1, { from: owner }),
'WhitelistedAddressAdded'
);
const isWhitelisted = await mock.whitelist(whitelistedAddress1);
isWhitelisted.should.be.equal(true);
});

it('should add addresses to the whitelist', async function () {
await expectEvent.inTransaction(
mock.addAddressesToWhitelist(whitelistedAddresses, { from: owner }),
'WhitelistedAddressAdded'
);
for (let addr of whitelistedAddresses) {
const isWhitelisted = await mock.whitelist(addr);
isWhitelisted.should.be.equal(true);
}
});

it('should not announce WhitelistedAddressAdded event if address is already in the whitelist', async function () {
const { logs } = await mock.addAddressToWhitelist(whitelistedAddress1, { from: owner });
logs.should.be.empty;
});

it('should remove address from the whitelist', async function () {
await expectEvent.inTransaction(
mock.removeAddressFromWhitelist(whitelistedAddress1, { from: owner }),
'WhitelistedAddressRemoved'
);
let isWhitelisted = await mock.whitelist(whitelistedAddress1);
isWhitelisted.should.be.equal(false);
});

it('should remove addresses from the the whitelist', async function () {
await expectEvent.inTransaction(
mock.removeAddressesFromWhitelist(whitelistedAddresses, { from: owner }),
'WhitelistedAddressRemoved'
);
for (let addr of whitelistedAddresses) {
const isWhitelisted = await mock.whitelist(addr);
isWhitelisted.should.be.equal(false);
}
});

it('should not announce WhitelistedAddressRemoved event if address is not in the whitelist', async function () {
const { logs } = await mock.removeAddressFromWhitelist(whitelistedAddress1, { from: owner });
logs.should.be.empty;
});

it('should allow whitelisted address to call #onlyWhitelistedCanDoThis', async () => {
await mock.addAddressToWhitelist(whitelistedAddress1, { from: owner });
await mock.onlyWhitelistedCanDoThis({ from: whitelistedAddress1 })
.should.be.fulfilled;
});
});

context('in adversarial conditions', () => {
it('should not allow "anyone" to add to the whitelist', async () => {
await expectThrow(
mock.addAddressToWhitelist(whitelistedAddress1, { from: anyone })
);
});

it('should not allow "anyone" to remove from the whitelist', async () => {
await expectThrow(
mock.removeAddressFromWhitelist(whitelistedAddress1, { from: anyone })
);
});

it('should not allow "anyone" to call #onlyWhitelistedCanDoThis', async () => {
await expectThrow(
mock.onlyWhitelistedCanDoThis({ from: anyone })
);
});
});
});