Skip to content
Merged
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
18 changes: 10 additions & 8 deletions contracts/controller/Avatar.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ contract Avatar is Ownable {
DAOToken public nativeToken;
Reputation public nativeReputation;

event GenericCall(address indexed _contract, bytes _params);
event GenericCall(address indexed _contract, bytes _params, bool _success);
event SendEther(uint256 _amountInWei, address indexed _to);
event ExternalTokenTransfer(address indexed _externalToken, address indexed _to, uint256 _value);
event ExternalTokenTransferFrom(address indexed _externalToken, address _from, address _to, uint256 _value);
Expand Down Expand Up @@ -45,14 +45,16 @@ contract Avatar is Ownable {
* @dev perform a generic call to an arbitrary contract
* @param _contract the contract's address to call
* @param _data ABI-encoded contract call to call `_contract` address.
* @return the return bytes of the called contract's function.
* @return bool success or fail
* bytes - the return bytes of the called contract's function.
*/
function genericCall(address _contract, bytes memory _data) public onlyOwner returns(bytes memory) {
emit GenericCall(_contract, _data);
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returnValue) = _contract.call(_data);
require(success);
return returnValue;
function genericCall(address _contract, bytes memory _data)
public
onlyOwner
returns(bool success, bytes memory returnValue) {
// solhint-disable-next-line avoid-low-level-calls
(success, returnValue) = _contract.call(_data);
emit GenericCall(_contract, _data, success);
}

/**
Expand Down
5 changes: 3 additions & 2 deletions contracts/controller/Controller.sol
Original file line number Diff line number Diff line change
Expand Up @@ -373,14 +373,15 @@ contract Controller is ControllerInterface {
* @param _contract the contract's address to call
* @param _data ABI-encoded contract call to call `_contract` address.
* @param _avatar the controller's avatar address
* @return bytes32 - the return value of the called _contract's function.
* @return bool -success
* bytes - the return value of the called _contract's function.
*/
function genericCall(address _contract, bytes calldata _data, Avatar _avatar)
external
onlyGenericCallScheme
onlySubjectToConstraint("genericCall")
isAvatarValid(address(_avatar))
returns (bytes memory returnValue)
returns (bool, bytes memory)
{
return avatar.genericCall(_contract, _data);
}
Expand Down
5 changes: 3 additions & 2 deletions contracts/controller/ControllerInterface.sol
Original file line number Diff line number Diff line change
Expand Up @@ -105,11 +105,12 @@ interface ControllerInterface {
* @param _contract the contract's address to call
* @param _data ABI-encoded contract call to call `_contract` address.
* @param _avatar the controller's avatar address
* @return bytes32 - the return value of the called _contract's function.
* @return bool -success
* bytes - the return value of the called _contract's function.
*/
function genericCall(address _contract, bytes calldata _data, Avatar _avatar)
external
returns(bytes memory);
returns(bool, bytes memory);

/**
* @dev send some ether
Expand Down
5 changes: 3 additions & 2 deletions contracts/controller/UController.sol
Original file line number Diff line number Diff line change
Expand Up @@ -366,13 +366,14 @@ contract UController is ControllerInterface {
* @dev perform a generic call to an arbitrary contract
* @param _contract the contract's address to call
* @param _data ABI-encoded contract call to call `_contract` address.
* @return bytes32 - the return value of the called _contract's function.
* @return bool -success
* bytes - the return value of the called _contract's function.
*/
function genericCall(address _contract, bytes calldata _data, Avatar _avatar)
external
onlyGenericCallScheme(address(_avatar))
onlySubjectToConstraint("genericCall", address(_avatar))
returns (bytes memory returnValue)
returns (bool, bytes memory)
{
return _avatar.genericCall(_contract, _data);
}
Expand Down
11 changes: 11 additions & 0 deletions contracts/test/ActionMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ contract ActionMock {

event WithoutReturnValue(address _addr);

uint public activationTime;

function test(uint256 _a, address _b, bytes32 _c) public view returns(uint256) {
require(_a == 7);
require(_b == address(this));
Expand All @@ -24,4 +26,13 @@ contract ActionMock {
emit WithoutReturnValue(_addr);
}

function setActivationTime(uint _activationTime) public {
activationTime = _activationTime;
}

function test3() public view {
// solhint-disable-next-line not-rely-on-time
require(now > activationTime, "now should be greater than the activation time");
}

}
4 changes: 2 additions & 2 deletions contracts/test/UniversalSchemeMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import "../controller/ControllerInterface.sol";
contract UniversalSchemeMock is UniversalScheme {

function genericCall(Avatar _avatar, address _contract, uint256 _a, address _b, bytes32 _c)
public returns(bytes memory)
public returns(bool, bytes memory)
{

address controller = _avatar.owner();
Expand All @@ -16,7 +16,7 @@ contract UniversalSchemeMock is UniversalScheme {
}

function genericCallDirect(Avatar _avatar, address _contract, uint256 _a, address _b, bytes32 _c)
public returns(bytes memory)
public returns(bool, bytes memory)
{
return _avatar.genericCall(_contract, abi.encodeWithSignature("test(uint256,address,bytes32)", _a, _b, _c));
}
Expand Down
72 changes: 54 additions & 18 deletions contracts/universalSchemes/GenericScheme.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,29 @@ contract GenericScheme is UniversalScheme, VotingMachineCallbacks, ProposalExecu
event NewCallProposal(
address indexed _avatar,
bytes32 indexed _proposalId,
bytes callData
bytes _callData,
bytes32 _descriptionHash
);

event ProposalExecuted(
address indexed _avatar,
bytes32 indexed _proposalId,
int256 _param,
bytes _genericCallReturnValue
);

event ProposalExecutedByVotingMachine(
address indexed _avatar,
bytes32 indexed _proposalId,
int256 _param
);

event ProposalDeleted(address indexed _avatar, bytes32 indexed _proposalId);

// Details of a voting proposal:
struct CallProposal {
bytes callData;
bool exist;
bool passed;
}

// A mapping from the organization (Avatar) address to the saved data of the organization:
Expand All @@ -48,25 +55,52 @@ contract GenericScheme is UniversalScheme, VotingMachineCallbacks, ProposalExecu
/**
* @dev execution of proposals, can only be called by the voting machine in which the vote is held.
* @param _proposalId the ID of the voting in the voting machine
* @param _param a parameter of the voting result, 1 yes and 2 is no.
* @param _decision a parameter of the voting result, 1 yes and 2 is no.
* @return bool success
*/
function executeProposal(bytes32 _proposalId, int256 _param) external onlyVotingMachine(_proposalId) returns(bool) {
function executeProposal(bytes32 _proposalId, int256 _decision)
external
onlyVotingMachine(_proposalId)
returns(bool) {
Avatar avatar = proposalsInfo[_proposalId].avatar;
CallProposal storage proposal = organizationsProposals[address(avatar)][_proposalId];
require(proposal.exist, "must be a live proposal");
require(proposal.passed == false, "cannot execute twice");

if (_decision == 1) {
proposal.passed = true;
execute(_proposalId);
} else {
delete organizationsProposals[address(avatar)][_proposalId];
emit ProposalDeleted(address(avatar), _proposalId);
}

emit ProposalExecutedByVotingMachine(address(avatar), _proposalId, _decision);
return true;
}

/**
* @dev execution of proposals after it has been decided by the voting machine
* @param _proposalId the ID of the voting in the voting machine
*/
function execute(bytes32 _proposalId) public {
Avatar avatar = proposalsInfo[_proposalId].avatar;
Parameters memory params = parameters[getParametersFromController(avatar)];
// Save proposal to memory and delete from storage:
CallProposal memory proposal = organizationsProposals[address(avatar)][_proposalId];
CallProposal storage proposal = organizationsProposals[address(avatar)][_proposalId];
require(proposal.exist, "must be a live proposal");
delete organizationsProposals[address(avatar)][_proposalId];
emit ProposalDeleted(address(avatar), _proposalId);
require(proposal.passed, "proposal must passed by voting machine");
proposal.exist = false;
bytes memory genericCallReturnValue;
// Check decision:
if (_param == 1) {
// Define controller and get the params:
ControllerInterface controller = ControllerInterface(Avatar(avatar).owner());
genericCallReturnValue = controller.genericCall(params.contractToCall, proposal.callData, avatar);
bool success;
ControllerInterface controller = ControllerInterface(Avatar(avatar).owner());
(success, genericCallReturnValue) = controller.genericCall(params.contractToCall, proposal.callData, avatar);
if (success) {
delete organizationsProposals[address(avatar)][_proposalId];
emit ProposalDeleted(address(avatar), _proposalId);
emit ProposalExecuted(address(avatar), _proposalId, genericCallReturnValue);
} else {
proposal.exist = true;
}
emit ProposalExecuted(address(avatar), _proposalId, _param, genericCallReturnValue);
return true;
}

/**
Expand Down Expand Up @@ -108,9 +142,10 @@ contract GenericScheme is UniversalScheme, VotingMachineCallbacks, ProposalExecu
* The function trigger NewCallProposal event
* @param _callData - The abi encode data for the call
* @param _avatar avatar of the organization
* @param _descriptionHash proposal description hash
* @return an id which represents the proposal
*/
function proposeCall(Avatar _avatar, bytes memory _callData)
function proposeCall(Avatar _avatar, bytes memory _callData, bytes32 _descriptionHash)
public
returns(bytes32)
{
Expand All @@ -121,14 +156,15 @@ contract GenericScheme is UniversalScheme, VotingMachineCallbacks, ProposalExecu

organizationsProposals[address(_avatar)][proposalId] = CallProposal({
callData: _callData,
exist: true
exist: true,
passed: false
});
proposalsInfo[proposalId] = ProposalInfo({
blockNumber:block.number,
avatar:_avatar,
votingMachine:address(params.intVote)
});
emit NewCallProposal(address(_avatar), proposalId, _callData);
emit NewCallProposal(address(_avatar), proposalId, _callData, _descriptionHash);
return proposalId;
}

Expand Down
22 changes: 16 additions & 6 deletions contracts/universalSchemes/GlobalConstraintRegistrar.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,16 @@ contract GlobalConstraintRegistrar is UniversalScheme, VotingMachineCallbacks, P
address indexed _intVoteInterface,
address _gc,
bytes32 _params,
bytes32 _voteToRemoveParams
bytes32 _voteToRemoveParams,
bytes32 _descriptionHash
);

event RemoveGlobalConstraintsProposal(
address indexed _avatar,
bytes32 indexed _proposalId,
address indexed _intVoteInterface,
address _gc
address _gc,
bytes32 _descriptionHash
);

event ProposalExecuted(address indexed _avatar, bytes32 indexed _proposalId, int256 _param);
Expand Down Expand Up @@ -124,10 +126,16 @@ contract GlobalConstraintRegistrar is UniversalScheme, VotingMachineCallbacks, P
* @param _gc the address of the global constraint that is being proposed
* @param _params the parameters for the global constraint
* @param _voteToRemoveParams the conditions (on the voting machine) for removing this global constraint
* @param _descriptionHash proposal's description hash
* @return bytes32 -the proposal id
*/
// TODO: do some checks on _voteToRemoveParams - it is very easy to make a mistake and not be able to remove the GC
function proposeGlobalConstraint(Avatar _avatar, address _gc, bytes32 _params, bytes32 _voteToRemoveParams)
function proposeGlobalConstraint(
Avatar _avatar,
address _gc,
bytes32 _params,
bytes32 _voteToRemoveParams,
bytes32 _descriptionHash)
public
returns(bytes32)
{
Expand All @@ -150,7 +158,8 @@ contract GlobalConstraintRegistrar is UniversalScheme, VotingMachineCallbacks, P
address(intVote),
_gc,
_params,
_voteToRemoveParams
_voteToRemoveParams,
_descriptionHash
);
proposalsInfo[proposalId] = ProposalInfo({
blockNumber:block.number,
Expand All @@ -164,9 +173,10 @@ contract GlobalConstraintRegistrar is UniversalScheme, VotingMachineCallbacks, P
* @dev propose to remove a global constraint:
* @param _avatar the avatar of the organization that the constraint is proposed for
* @param _gc the address of the global constraint that is being proposed
* @param _descriptionHash proposal's description hash
* @return bytes32 -the proposal id
*/
function proposeToRemoveGC(Avatar _avatar, address _gc) public returns(bytes32) {
function proposeToRemoveGC(Avatar _avatar, address _gc, bytes32 _descriptionHash) public returns(bytes32) {
Controller controller = Controller(_avatar.owner());
require(controller.isGlobalConstraintRegistered(_gc, address(_avatar)));
Parameters memory params = parameters[getParametersFromController(_avatar)];
Expand All @@ -186,7 +196,7 @@ contract GlobalConstraintRegistrar is UniversalScheme, VotingMachineCallbacks, P
});

organizationsProposals[address(_avatar)][proposalId] = proposal;
emit RemoveGlobalConstraintsProposal(address(_avatar), proposalId, address(intVote), _gc);
emit RemoveGlobalConstraintsProposal(address(_avatar), proposalId, address(intVote), _gc, _descriptionHash);
proposalsInfo[proposalId] = ProposalInfo({
blockNumber:block.number,
avatar:_avatar,
Expand Down
19 changes: 12 additions & 7 deletions contracts/universalSchemes/SchemeRegistrar.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@ contract SchemeRegistrar is UniversalScheme, VotingMachineCallbacks, ProposalExe
address indexed _intVoteInterface,
address _scheme,
bytes32 _parametersHash,
bytes4 _permissions
bytes4 _permissions,
bytes32 _descriptionHash
);

event RemoveSchemeProposal(address indexed _avatar,
bytes32 indexed _proposalId,
address indexed _intVoteInterface,
address _scheme
address _scheme,
bytes32 _descriptionHash
);

event ProposalExecuted(address indexed _avatar, bytes32 indexed _proposalId, int256 _param);
Expand Down Expand Up @@ -115,14 +117,16 @@ contract SchemeRegistrar is UniversalScheme, VotingMachineCallbacks, ProposalExe
* @param _scheme the address of the scheme to be registered
* @param _parametersHash a hash of the configuration of the _scheme
* @param _permissions the permission of the scheme to be registered
* @param _descriptionHash proposal's description hash
* @return a proposal Id
* @dev NB: not only proposes the vote, but also votes for it
*/
function proposeScheme(
Avatar _avatar,
address _scheme,
bytes32 _parametersHash,
bytes4 _permissions
bytes4 _permissions,
bytes32 _descriptionHash
)
public
returns(bytes32)
Expand All @@ -149,7 +153,8 @@ contract SchemeRegistrar is UniversalScheme, VotingMachineCallbacks, ProposalExe
proposalId,
address(controllerParams.intVote),
_scheme, _parametersHash,
_permissions
_permissions,
_descriptionHash
);
organizationsProposals[address(_avatar)][proposalId] = proposal;
proposalsInfo[proposalId] = ProposalInfo({
Expand All @@ -164,10 +169,10 @@ contract SchemeRegistrar is UniversalScheme, VotingMachineCallbacks, ProposalExe
* @dev propose to remove a scheme for a controller
* @param _avatar the address of the controller from which we want to remove a scheme
* @param _scheme the address of the scheme we want to remove
*
* @param _descriptionHash proposal description hash
* NB: not only registers the proposal, but also votes for it
*/
function proposeToRemoveScheme(Avatar _avatar, address _scheme)
function proposeToRemoveScheme(Avatar _avatar, address _scheme, bytes32 _descriptionHash)
public
returns(bytes32)
{
Expand All @@ -179,7 +184,7 @@ contract SchemeRegistrar is UniversalScheme, VotingMachineCallbacks, ProposalExe

organizationsProposals[address(_avatar)][proposalId].proposalType = 2;
organizationsProposals[address(_avatar)][proposalId].scheme = _scheme;
emit RemoveSchemeProposal(address(_avatar), proposalId, address(intVote), _scheme);
emit RemoveSchemeProposal(address(_avatar), proposalId, address(intVote), _scheme, _descriptionHash);
proposalsInfo[proposalId] = ProposalInfo({
blockNumber:block.number,
avatar:_avatar,
Expand Down
Loading