Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 22 additions & 12 deletions contracts/Multiownable.sol
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,27 @@ contract Multiownable {
modifier onlyManyOwners {
if (insideOnlyManyOwners == msg.sender) {
_;
return;
} else if (checkOnlyManyOwners()) {
insideOnlyManyOwners = msg.sender;
_;
insideOnlyManyOwners = address(0);
}
}

// CONSTRUCTOR

function Multiownable() public {
owners.push(msg.sender);
ownersIndices[msg.sender] = 1;
howManyOwnersDecide = 1;
}

// INTERNAL METHODS

/**
* @dev onlyManyOwners modifier helper
*/
function checkOnlyManyOwners() internal constant returns(bool) {
require(isOwner(msg.sender));

uint ownerIndex = ownersIndices[msg.sender] - 1;
Expand All @@ -70,18 +89,9 @@ contract Multiownable {
// If all owners confirm same operation
if (votesCountByOperation[operation] == howManyOwnersDecide) {
deleteOperation(operation);
insideOnlyManyOwners = msg.sender;
_;
insideOnlyManyOwners = address(0);
return true;
}
}

// CONSTRUCTOR

function Multiownable() public {
owners.push(msg.sender);
ownersIndices[msg.sender] = 1;
howManyOwnersDecide = 1;
return false;
}

// INTERNAL METHODS
Expand Down
32 changes: 32 additions & 0 deletions contracts/MultiownableOverOwnable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
pragma solidity ^0.4.11;

import 'zeppelin-solidity/contracts/ownership/Ownable.sol';
import './Multiownable.sol';


contract MultiownableOverOwnable is Ownable, Multiownable {

/**
* @dev Allows to override Ownable onlyOwner modifier to onlyAnyOwner
*/
modifier onlyOwner_overrideForAnyOwner {
require(isOwner(msg.sender));
owner = msg.sender;
_;
}

/**
* @dev Allows to override Ownable onlyOwner modifier to onlyManyOwners
*/
modifier onlyOwner_overrideForManyOwners {
if (insideOnlyManyOwners == msg.sender) {
_;
} else if (checkOnlyManyOwners()) {
insideOnlyManyOwners = msg.sender;
owner = msg.sender;
_;
insideOnlyManyOwners = address(0);
}
}

}
35 changes: 35 additions & 0 deletions test/Multiownable.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import EVMThrow from './helpers/EVMThrow';

const Multiownable = artifacts.require('Multiownable.sol');
const MultiownableImpl = artifacts.require('./impl/MultiownableImpl.sol');
const MultisigMintableToken = artifacts.require('./impl/MultisigMintableToken.sol');

contract('Multiownable', function ([_, wallet1, wallet2, wallet3, wallet4, wallet5]) {

Expand Down Expand Up @@ -386,6 +387,16 @@ contract('Multiownable', function ([_, wallet1, wallet2, wallet3, wallet4, walle
(await obj.value.call()).should.be.bignumber.equal(100);
})

it('should works for nested methods with onlyOwner_overrideForManyOwners modifier', async function() {
const obj = await MultisigMintableToken.new();
await obj.transferOwnership([wallet1, wallet2]);

await obj.nestedFirst(100, {from: wallet1});
await obj.nestedFirst(100, {from: wallet2});

(await obj.value.call()).should.be.bignumber.equal(100);
})

it('should not allow to transfer ownership to several equal users', async function() {
const obj = await Multiownable.new();
await obj.transferOwnership([wallet1, wallet1]).should.be.rejectedWith(EVMThrow);
Expand Down Expand Up @@ -415,4 +426,28 @@ contract('Multiownable', function ([_, wallet1, wallet2, wallet3, wallet4, walle
]).should.be.rejectedWith(EVMThrow);
})

it('should override onlyOwner_overrideForAnyOwner', async function() {
const token = await MultisigMintableToken.new();
await token.transferOwnership([wallet1, wallet2]);

await token.mint(_, 100).should.be.rejectedWith(EVMThrow);

(await token.totalSupply.call()).should.be.bignumber.equal(0);
await token.mint(_, 100, {from: wallet1});
(await token.totalSupply.call()).should.be.bignumber.equal(0);
await token.mint(_, 100, {from: wallet2});
(await token.totalSupply.call()).should.be.bignumber.equal(100);
})

it('should override onlyOwner_overrideForManyOwners', async function() {
const token = await MultisigMintableToken.new();
await token.transferOwnership([wallet1, wallet2]);

await token.finishMinting().should.be.rejectedWith(EVMThrow);

(await token.mintingFinished.call()).should.be.false;
await token.finishMinting({from: wallet2});
(await token.mintingFinished.call()).should.be.true;
})

})
42 changes: 42 additions & 0 deletions test/impl/MultisigMintableToken.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
pragma solidity ^0.4.11;

import "zeppelin-solidity/contracts/token/MintableToken.sol";
import "../../contracts/MultiownableOverOwnable.sol";


contract MintableTokenExt is MintableToken {

uint public value = 0;

function nestedFirst(uint _value) public onlyOwner {
nestedSecond(_value);
}

function nestedSecond(uint _value) public onlyOwner {
value = _value;
}

}


contract MultisigMintableToken is MintableTokenExt, MultiownableOverOwnable {

// Only all owners can mint
function mint(address _to, uint256 _amount) onlyOwner_overrideForManyOwners canMint public returns (bool) {
return super.mint(_to, _amount);
}

// Any of the owners can finish
function finishMinting() onlyOwner_overrideForAnyOwner public returns (bool) {
return super.finishMinting();
}

function nestedFirst(uint _value) public onlyOwner_overrideForManyOwners {
super.nestedFirst(_value);
}

function nestedSecond(uint _value) public onlyOwner_overrideForManyOwners {
super.nestedSecond(_value);
}

}