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
120 changes: 120 additions & 0 deletions contracts/schemes/SignalScheme.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
pragma solidity ^0.5.4;

import "@daostack/infra/contracts/votingMachines/IntVoteInterface.sol";
import "@daostack/infra/contracts/votingMachines/VotingMachineCallbacksInterface.sol";
import "../votingMachines/VotingMachineCallbacks.sol";
import "../controller/Avatar.sol";


/**
* @title A scheme for proposing a signal on behalkf of the daoCreator
*/

contract SignalScheme is VotingMachineCallbacks, ProposalExecuteInterface {

event NewSignalProposal(
address indexed _avatar,
bytes32 indexed _proposalId,
uint256 indexed _signalType,
string _descriptionHash
);

event Signal(
address indexed _avatar,
bytes32 indexed _proposalId,
uint256 indexed _signalType,
string _descriptionHash
);

struct Proposal {
string descriptionHash;
bool executed;
}

struct Parameters {
bytes32 voteApproveParams;
IntVoteInterface intVote;
uint256 signalType;
Avatar avatar;
}

mapping(bytes32 => Proposal) public proposals;

Parameters public params;

/**
* @dev initialize
* @param _avatar the scheme avatar
* @param _signalType - signal types
* @param _voteApproveParams voting machine params
* @param _intVote voting machine address
*/
function initialize(Avatar _avatar,
uint256 _signalType,
bytes32 _voteApproveParams,
IntVoteInterface _intVote)
external {
require(params.avatar == Avatar(0), "can be called only one time");
require(_avatar != Avatar(0), "avatar cannot be zero");
params = Parameters({
voteApproveParams: _voteApproveParams,
signalType: _signalType,
intVote: _intVote,
avatar: _avatar
});
}

/**
* @dev Submit a proposal for a dao signal
* @param _descriptionHash A hash of the proposal's description
*/
function proposeSignal(
string calldata _descriptionHash
)
external
returns(bytes32)
{
require(ControllerInterface(params.avatar.owner()).isSchemeRegistered(address(this), address(params.avatar)),
"scheme is not registered");

bytes32 proposalId = params.intVote.propose(
2,
params.voteApproveParams,
msg.sender,
address(params.avatar)
);

proposals[proposalId].descriptionHash = _descriptionHash;

emit NewSignalProposal(
address(params.avatar),
proposalId,
params.signalType,
_descriptionHash
);

proposalsInfo[address(params.intVote)][proposalId] = ProposalInfo({
blockNumber:block.number,
avatar:params.avatar
});
return proposalId;
}

/**
* @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.
*/
function executeProposal(bytes32 _proposalId, int256 _param) external onlyVotingMachine(_proposalId) returns(bool) {
require(!proposals[_proposalId].executed);
proposals[_proposalId].executed = true;
// Check if vote was successful:
if (_param == 1) {
emit Signal(address(params.avatar),
_proposalId,
params.signalType,
proposals[_proposalId].descriptionHash);
}
return true;
}
}
126 changes: 126 additions & 0 deletions test/signalscheme.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import * as helpers from './helpers';
const constants = require('./constants');
const SignalScheme = artifacts.require("./SignalScheme.sol");
const DaoCreator = artifacts.require("./DaoCreator.sol");
const ControllerCreator = artifacts.require("./ControllerCreator.sol");

export class SignalSchemeParams {
constructor() {
}
}


const setupSignalSchemeParam = async function(
signalScheme,
accounts,
genesisProtocol,
avatar
) {
var signalSchemeParams = new SignalSchemeParams();
if (genesisProtocol === true) {
signalSchemeParams.votingMachine = await helpers.setupGenesisProtocol(accounts,token,avatar,helpers.NULL_ADDRESS);
await signalScheme.initialize( avatar.address,
1234,
setupSignalSchemeParam.votingMachine.params,
setupSignalSchemeParam.votingMachine.genesisProtocol.address);
} else {
signalSchemeParams.votingMachine = await helpers.setupAbsoluteVote(helpers.NULL_ADDRESS,50,signalScheme.address);
await signalScheme.initialize( avatar.address,
1234,
signalSchemeParams.votingMachine.params,
signalSchemeParams.votingMachine.absoluteVote.address);
}
return signalSchemeParams;
};

const setup = async function (accounts,genesisProtocol = false) {
var testSetup = new helpers.TestSetup();
testSetup.signalScheme = await SignalScheme.new();
var controllerCreator = await ControllerCreator.new({gas: constants.ARC_GAS_LIMIT});
testSetup.daoCreator = await DaoCreator.new(controllerCreator.address,{gas:constants.ARC_GAS_LIMIT});
if (genesisProtocol) {
testSetup.reputationArray = [1000,100,0];
} else {
testSetup.reputationArray = [2000,4000,7000];
}
testSetup.org = await helpers.setupOrganizationWithArrays(testSetup.daoCreator,[accounts[0],accounts[1],accounts[2]],[1000,0,0],testSetup.reputationArray);
testSetup.signalSchemeParams= await setupSignalSchemeParam(
testSetup.signalScheme,
accounts,
genesisProtocol,
testSetup.org.avatar);
var permissions = "0x00000000";
await testSetup.daoCreator.setSchemes(testSetup.org.avatar.address,
[testSetup.signalScheme.address],
[helpers.NULL_HASH],[permissions],"metaData");
return testSetup;
};
contract('SignalScheme', accounts => {

it("proposeSignal log", async function() {
var testSetup = await setup(accounts);
var parameters = await testSetup.signalScheme.params();
assert.equal(parameters.avatar,testSetup.org.avatar.address);
assert.equal(parameters.signalType,1234);
assert.equal(parameters.voteApproveParams,testSetup.signalSchemeParams.votingMachine.params);
assert.equal(parameters.intVote,testSetup.signalSchemeParams.votingMachine.absoluteVote.address);
var tx = await testSetup.signalScheme.proposeSignal("description-hash");
assert.equal(tx.logs.length, 1);
assert.equal(tx.logs[0].event, "NewSignalProposal");
assert.equal(await helpers.getValueFromLogs(tx, '_avatar',0), testSetup.org.avatar.address, "Wrong log: _avatar");
assert.equal(await helpers.getValueFromLogs(tx, '_descriptionHash',15), "description-hash", "Wrong log: _contributionDescription");
assert.equal(await helpers.getValueFromLogs(tx, '_signalType',0), 1234, "Wrong log: _signalType");
});


it("execute signalScheme yes ", async function() {
var testSetup = await setup(accounts);
var tx = await testSetup.signalScheme.proposeSignal(web3.utils.asciiToHex("description"));
//Vote with reputation to trigger execution
var proposalId = await helpers.getValueFromLogs(tx, '_proposalId',1);
tx = await testSetup.signalSchemeParams.votingMachine.absoluteVote.vote(proposalId,1,0,helpers.NULL_ADDRESS,{from:accounts[2]});
await testSetup.signalScheme.getPastEvents('Signal', {
fromBlock: tx.blockNumber,
toBlock: 'latest'
})
.then(function(events){
assert.equal(events[0].event,"Signal");
assert.equal(events[0].args._avatar, testSetup.org.avatar.address);
assert.equal(events[0].args._proposalId, proposalId);
assert.equal(events[0].args._signalType, 1234);
assert.equal(events[0].args._descriptionHash, web3.utils.asciiToHex("description"));
});
var proposal = await testSetup.signalScheme.proposals(proposalId);
assert.equal(proposal.executed,true);
});

it("execute signalScheme no ", async function() {
var testSetup = await setup(accounts);
var tx = await testSetup.signalScheme.proposeSignal(web3.utils.asciiToHex("description"));
//Vote with reputation to trigger execution
var proposalId = await helpers.getValueFromLogs(tx, '_proposalId',1);
tx = await testSetup.signalSchemeParams.votingMachine.absoluteVote.vote(proposalId,2,0,helpers.NULL_ADDRESS,{from:accounts[2]});
await testSetup.signalScheme.getPastEvents('Signal', {
fromBlock: tx.blockNumber,
toBlock: 'latest'
})
.then(function(events){
assert.equal(events.length , 0);
});
var proposal = await testSetup.signalScheme.proposals(proposalId);
assert.equal(proposal.executed,true);
});

it("cannot initialize twice", async () => {
let testSetup = await setup(accounts);
try {
await testSetup.signalScheme.initialize(testSetup.org.avatar.address,
1234,
testSetup.signalSchemeParams.votingMachine.params,
testSetup.signalSchemeParams.votingMachine.absoluteVote.address);
assert(false, "cannot initialize twice");
} catch(error) {
helpers.assertVMException(error);
}
});
});