Skip to content

Commit

Permalink
Roles can now be transfered. (#1235)
Browse files Browse the repository at this point in the history
* Roles can now be transfered.

* Now explicitly checking support for the null address.

* Now rejecting transfer to a role-haver.

* Added renounce, roles can no longer be transfered to 0.

* Fixed linter errors.

* Fixed a Roles test.
  • Loading branch information
nventuro committed Aug 28, 2018
1 parent ed04195 commit 5b7ec56
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 14 deletions.
30 changes: 17 additions & 13 deletions contracts/access/rbac/Roles.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,14 @@ library Roles {
/**
* @dev give an account access to this role
*/
function add(Role storage _role, address _account)
internal
{
function add(Role storage _role, address _account) internal {
_role.bearer[_account] = true;
}

/**
* @dev give multiple accounts access to this role
*/
function addMany(Role storage _role, address[] _accounts)
internal
{
function addMany(Role storage _role, address[] _accounts) internal {
for (uint256 i = 0; i < _accounts.length; ++i) {
add(_role, _accounts[i]);
}
Expand All @@ -35,20 +31,28 @@ library Roles {
/**
* @dev remove an account's access to this role
*/
function remove(Role storage _role, address _account)
internal
{
function remove(Role storage _role, address _account) internal {
_role.bearer[_account] = false;
}

function transfer(Role storage _role, address _account) internal {
require(_account != address(0));
require(!has(_role, _account));
require(has(_role, msg.sender));

remove(_role, msg.sender);
add(_role, _account);
}

function renounce(Role storage _role) internal {
remove(_role, msg.sender);
}

/**
* @dev check if an account has this role
* // reverts
*/
function check(Role storage _role, address _account)
internal
view
{
function check(Role storage _role, address _account) internal view {
require(has(_role, _account));
}

Expand Down
8 changes: 8 additions & 0 deletions contracts/mocks/RolesMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@ contract RolesMock {
dummyRole.remove(_account);
}

function renounce() public {
dummyRole.renounce();
}

function transfer(address _account) public {
dummyRole.transfer(_account);
}

function check(address _account) public view {
dummyRole.check(_account);
}
Expand Down
51 changes: 50 additions & 1 deletion test/access/rbac/Roles.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ require('chai')
.should();

contract('Roles', function ([_, authorized, otherAuthorized, anyone]) {
const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';

beforeEach(async function () {
this.roles = await RolesMock.new();
this.testRole = async (account, expected) => {
Expand Down Expand Up @@ -49,6 +51,10 @@ contract('Roles', function ([_, authorized, otherAuthorized, anyone]) {
await this.roles.addMany([authorized, authorized]);
await this.testRole(authorized, true);
});

it('doesn\'t revert when adding roles to the null account', async function () {
await this.roles.add(ZERO_ADDRESS);
});
});
});

Expand All @@ -64,9 +70,52 @@ contract('Roles', function ([_, authorized, otherAuthorized, anyone]) {
await this.testRole(otherAuthorized, true);
});

it('removes unassigned roles', async function () {
it('doesn\'t revert when removing unassigned roles', async function () {
await this.roles.remove(anyone);
});

it('doesn\'t revert when removing roles from the null account', async function () {
await this.roles.remove(ZERO_ADDRESS);
});
});

describe('transfering roles', function () {
context('from account with role', function () {
const from = authorized;

it('transfers to other account with no role', async function () {
await this.roles.transfer(anyone, { from });
await this.testRole(anyone, true);
await this.testRole(authorized, false);
});

it('reverts when transfering to an account with role', async function () {
await assertRevert(this.roles.transfer(otherAuthorized, { from }));
});

it('reverts when transfering to the null account', async function () {
await assertRevert(this.roles.transfer(ZERO_ADDRESS, { from }));
});
});

context('from account without role', function () {
const from = anyone;

it('reverts', async function () {
await assertRevert(this.roles.transfer(anyone, { from }));
});
});
});

describe('renouncing roles', function () {
it('renounces an assigned role', async function () {
await this.roles.renounce({ from: authorized });
await this.testRole(authorized, false);
});

it('doesn\'t revert when renouncing unassigned role', async function () {
await this.roles.renounce({ from: anyone });
});
});
});
});

0 comments on commit 5b7ec56

Please sign in to comment.