Ver Fonte

Adding new Superuser contract with test (#952)

* Adding new Superuser contract + tests
Patricio Mosse há 7 anos atrás
pai
commit
a0c03ee61c
2 ficheiros alterados com 124 adições e 0 exclusões
  1. 62 0
      contracts/ownership/Superuser.sol
  2. 62 0
      test/ownership/Superuser.test.js

+ 62 - 0
contracts/ownership/Superuser.sol

@@ -0,0 +1,62 @@
+pragma solidity ^0.4.23;
+
+
+import "./Ownable.sol";
+import "./rbac/RBAC.sol";
+
+
+/**
+ * @title Superuser
+ * @dev The Superuser contract defines a single superuser who can transfer the ownership 
+ * @dev of a contract to a new address, even if he is not the owner. 
+ * @dev A superuser can transfer his role to a new address. 
+ */
+contract Superuser is Ownable, RBAC {
+  string public constant ROLE_SUPERUSER = "superuser";
+
+  constructor () public {
+    addRole(msg.sender, ROLE_SUPERUSER);
+  }
+
+  /**
+   * @dev Throws if called by any account that's not a superuser.
+   */
+  modifier onlySuperuser() {
+    checkRole(msg.sender, ROLE_SUPERUSER);
+    _;
+  }
+
+  /**
+   * @dev getter to determine if address has superuser role
+   */
+  function isSuperuser(address _addr)
+    public
+    view
+    returns (bool)
+  {
+    return hasRole(_addr, ROLE_SUPERUSER);
+  }
+
+  /**
+   * @dev Allows the current superuser to transfer his role to a newSuperuser.
+   * @param _newSuperuser The address to transfer ownership to.
+   */
+  function transferSuperuser(address _newSuperuser) 
+    onlySuperuser
+    public
+  {
+    require(_newSuperuser != address(0));
+    removeRole(msg.sender, ROLE_SUPERUSER);
+    addRole(_newSuperuser, ROLE_SUPERUSER);
+  }
+
+  /**
+   * @dev Allows the current superuser to transfer control of the contract to a newOwner.
+   * @param _newOwner The address to transfer ownership to.
+   */
+  function transferOwnership(address _newOwner) public onlySuperuser {
+    require(_newOwner != address(0));
+    owner = _newOwner;
+    emit OwnershipTransferred(owner, _newOwner);
+  }
+}

+ 62 - 0
test/ownership/Superuser.test.js

@@ -0,0 +1,62 @@
+import expectThrow from '../helpers/expectThrow';
+import expectEvent from '../helpers/expectEvent';
+
+const Superuser = artifacts.require('Superuser');
+
+require('chai')
+  .use(require('chai-as-promised'))
+  .should();
+
+contract('Superuser', function (accounts) {
+  const [
+    firstOwner,
+    newSuperuser,
+    newOwner,
+    anyone,
+  ] = accounts;
+
+  before(async function () {
+    this.superuser = await Superuser.new();
+  });
+
+  context('in normal conditions', () => {
+    it('should set the owner as the default superuser', async function () {
+      const ownerIsSuperuser = await this.superuser.isSuperuser(firstOwner);
+      ownerIsSuperuser.should.be.equal(true);
+    });
+
+    it('should change superuser after transferring', async function () {
+      await this.superuser.transferSuperuser(newSuperuser, { from: firstOwner });
+      
+      const ownerIsSuperuser = await this.superuser.isSuperuser(firstOwner);
+      ownerIsSuperuser.should.be.equal(false);
+
+      const address1IsSuperuser = await this.superuser.isSuperuser(newSuperuser);
+      address1IsSuperuser.should.be.equal(true);
+    });
+
+    it('should change owner after transferring', async function () {
+      await expectEvent.inTransaction(
+        this.superuser.transferOwnership(newOwner, { from: newSuperuser }),
+        'OwnershipTransferred'
+      );
+
+      const currentOwner = await this.superuser.owner();
+      currentOwner.should.be.equal(newOwner);
+    });
+  });
+
+  context('in adversarial conditions', () => {
+    it('should prevent non-superusers from transfering the superuser role', async function () {
+      await expectThrow(
+        this.superuser.transferSuperuser(newOwner, { from: anyone })
+      );
+    });
+
+    it('should prevent non-superusers from setting a new owner', async function () {
+      await expectThrow(
+        this.superuser.transferOwnership(newOwner, { from: anyone })
+      );
+    });
+  });
+});