Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Votable schemes #761

Draft
wants to merge 1 commit into
base: arc-factory
Choose a base branch
from
Draft
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
1 change: 1 addition & 0 deletions buidler.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ usePlugin("@nomiclabs/buidler-truffle5");
usePlugin("@nomiclabs/buidler-solhint");
usePlugin("solidity-coverage");
usePlugin("@nomiclabs/buidler-web3");
usePlugin("buidler-gas-reporter");

// This is a sample Buidler task. To learn how to create your own go to
// https://buidler.dev/guides/create-task.html
Expand Down
2 changes: 1 addition & 1 deletion contracts/schemes/Competition.sol
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ contract Competition is Initializable, Rewarder {
bytes32 proposalId = suggestions[_suggestionId].proposalId;
require(proposalId != bytes32(0), "suggestion does not exist");
setSnapshotBlock(proposalId);
Avatar avatar = ArcScheme(contributionRewardExt).avatar();
Avatar avatar = VotableScheme(contributionRewardExt).avatar();
uint256 reputation = avatar.nativeReputation().balanceOfAt(msg.sender, proposals[proposalId].snapshotBlock);
require(reputation > 0, "voter had no reputation when snapshot was taken");
Proposal storage proposal = proposals[proposalId];
Expand Down
59 changes: 22 additions & 37 deletions contracts/schemes/ContributionReward.sol
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
pragma solidity ^0.5.17;

import "../votingMachines/VotingMachineCallbacks.sol";
import "./VotableScheme.sol";
import "@openzeppelin/contracts-ethereum-package/contracts/math/SafeMath.sol";

/**
* @title A scheme for proposing and rewarding contributions to an organization
* @dev An agent can ask an organization to recognize a contribution and reward
* him with token, reputation, ether or any combination.
*/
contract ContributionReward is
VotingMachineCallbacks,
ProposalExecuteInterface {
contract ContributionReward is VotableScheme, ProposalExecuteInterface {
using SafeMath for uint;

event NewContributionProposal(
address indexed _avatar,
bytes32 indexed _proposalId,
address indexed _intVoteInterface,
string _descriptionHash,
int256 _reputationChange,
uint[5] _rewards,
Expand Down Expand Up @@ -63,48 +61,36 @@ contract ContributionReward is
mapping(bytes32=>ContributionProposal) public organizationProposals;

/**
* @dev initialize
* @param _avatar the avatar this scheme referring to.
* @param _votingParams genesisProtocol parameters
* @param _voteOnBehalf parameter
* @param _daoFactory DAOFactory instance to instance a votingMachine.
* @param _stakingToken (for GenesisProtocol)
* @param _packageVersion packageVersion to instance the votingMachine from.
* @param _votingMachineName the votingMachine contract name.
*/
* @dev initialize
* @param _avatar the scheme avatar
* @param _stakingToken (for GenesisProtocol)
* @param _votingParams genesisProtocol parameters - valid only if _voteParamsHash is zero
* @param _voteOnBehalf parameter
* @param _authorizedToPropose only this address allow to propose (unless it is zero)
*/
function initialize(
Avatar _avatar,
uint256[11] calldata _votingParams,
IERC20 _stakingToken,
uint[11] calldata _votingParams,
address _voteOnBehalf,
DAOFactory _daoFactory,
address _stakingToken,
uint64[3] calldata _packageVersion,
string calldata _votingMachineName
)
external
initializer
{
super._initializeGovernance(
address _authorizedToPropose
) external {
VotableScheme._initializeVoting(
_avatar,
_stakingToken,
_votingParams,
_voteOnBehalf,
_daoFactory,
_stakingToken,
address(this),
address(this),
_packageVersion,
_votingMachineName);
_authorizedToPropose
);
}

/**
* @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 _decision a parameter of the voting result, 1 yes and 2 is no.
*/
function executeProposal(bytes32 _proposalId, int256 _decision)
external
onlyVotingMachine(_proposalId)
returns(bool) {
// TODO: Maybe should be internal or public?
function executeProposal(bytes32 _proposalId, int256 _decision) external onlySelf returns(bool) {
require(organizationProposals[_proposalId].executionTime == 0);
require(organizationProposals[_proposalId].beneficiary != address(0));
// Check if vote was successful:
Expand Down Expand Up @@ -140,7 +126,7 @@ contract ContributionReward is
returns(bytes32)
{
validateProposalParams(_reputationChange, _rewards);
bytes32 proposalId = votingMachine.propose(2, msg.sender);
bytes32 proposalId = GenesisProtocolLogic.propose(2, msg.sender);
address payable beneficiary = _beneficiary;
if (beneficiary == address(0)) {
beneficiary = msg.sender;
Expand All @@ -163,7 +149,6 @@ contract ContributionReward is
emit NewContributionProposal(
address(avatar),
proposalId,
address(votingMachine),
_descriptionHash,
_reputationChange,
_rewards,
Expand Down Expand Up @@ -296,7 +281,7 @@ contract ContributionReward is
* whatToRedeem[3] - ExternalToken
* @return result boolean array for each redeem type.
*/
function redeem(bytes32 _proposalId, bool[4] memory _whatToRedeem)
function redeemContributionReward(bytes32 _proposalId, bool[4] memory _whatToRedeem)
public
returns(int256 reputationReward, uint256 nativeTokenReward, uint256 etherReward, uint256 externalTokenReward)
{
Expand Down
58 changes: 26 additions & 32 deletions contracts/schemes/ContributionRewardExt.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
pragma solidity 0.5.17;

import "../votingMachines/VotingMachineCallbacks.sol";
import "./VotableScheme.sol";
import "../utils/DAOFactory.sol";
import "@openzeppelin/contracts-ethereum-package/contracts/math/SafeMath.sol";


interface Rewarder {
Expand All @@ -17,14 +18,13 @@ interface Rewarder {
* It enable to assign a rewarder, which, after the contributionreward has been accepted,
* can then later distribute the assets as it would like.
*/
contract ContributionRewardExt is VotingMachineCallbacks, ProposalExecuteInterface {
contract ContributionRewardExt is VotableScheme, ProposalExecuteInterface {
using SafeMath for uint;
using SafeERC20 for IERC20;

event NewContributionProposal(
address indexed _avatar,
bytes32 indexed _proposalId,
address indexed _intVoteInterface,
string _descriptionHash,
int256 _reputationChange,
uint[3] _rewards,
Expand Down Expand Up @@ -81,46 +81,41 @@ contract ContributionRewardExt is VotingMachineCallbacks, ProposalExecuteInterfa
address public rewarder;
Vault public vault;

/**
* @dev initialize
* @param _avatar the avatar this scheme referring to.
* @param _votingParams genesisProtocol parameters
* @param _voteOnBehalf parameter
* @param _daoFactory DAOFactory instance to instance a votingMachine.
* @param _stakingToken (for GenesisProtocol)
* @param _packageVersion packageVersion to instance the votingMachine from.
* @param _votingMachineName the votingMachine contract name.
* @param _rewarderName the rewarder contract name.
*/
/**
* @dev initialize
* @param _avatar the scheme avatar
* @param _stakingToken (for GenesisProtocol)
* @param _votingParams genesisProtocol parameters - valid only if _voteParamsHash is zero
* @param _voteOnBehalf parameter
* @param _authorizedToPropose only this address allow to propose (unless it is zero)
* @param _daoFactory DAOFactory instance to instance a votingMachine.
* @param _packageVersion packageVersion to instance the votingMachine from.
* @param _rewarderName the rewarder contract name.
*/
function initialize(
Avatar _avatar,
uint256[11] calldata _votingParams,
IERC20 _stakingToken,
uint[11] calldata _votingParams,
address _voteOnBehalf,
address _authorizedToPropose,
DAOFactory _daoFactory,
address _stakingToken,
uint64[3] calldata _packageVersion,
string calldata _votingMachineName,
string calldata _rewarderName
)
external
{
super._initializeGovernance(
) external {
VotableScheme._initializeVoting(
_avatar,
_stakingToken,
_votingParams,
_voteOnBehalf,
_daoFactory,
_stakingToken,
address(this),
address(this),
_packageVersion,
_votingMachineName);
_authorizedToPropose
);
vault = new Vault();
vault.initialize(address(this));
if (bytes(_rewarderName).length != 0) {
rewarder = address(_daoFactory.createInstance(
_packageVersion,
_rewarderName,
address(avatar),
address(_avatar),
abi.encodeWithSignature("initialize(address)", address(this))));
}
}
Expand All @@ -132,7 +127,7 @@ contract ContributionRewardExt is VotingMachineCallbacks, ProposalExecuteInterfa
*/
function executeProposal(bytes32 _proposalId, int256 _decision)
external
onlyVotingMachine(_proposalId)
onlySelf
returns(bool) {
require(organizationProposals[_proposalId].acceptedByVotingMachine == false);
require(organizationProposals[_proposalId].beneficiary != address(0));
Expand Down Expand Up @@ -170,7 +165,7 @@ contract ContributionRewardExt is VotingMachineCallbacks, ProposalExecuteInterfa
if (proposer == address(0)) {
proposer = msg.sender;
}
proposalId = votingMachine.propose(2, proposer);
proposalId = GenesisProtocolLogic.propose(2, proposer);
address payable beneficiary = _beneficiary;
if (beneficiary == address(0)) {
beneficiary = msg.sender;
Expand All @@ -197,7 +192,6 @@ contract ContributionRewardExt is VotingMachineCallbacks, ProposalExecuteInterfa
emit NewContributionProposal(
address(avatar),
proposalId,
address(votingMachine),
_descriptionHash,
_reputationChange,
_rewards,
Expand Down Expand Up @@ -432,7 +426,7 @@ contract ContributionRewardExt is VotingMachineCallbacks, ProposalExecuteInterfa
* whatToRedeem[3] - ExternalToken
* @return result boolean array for each redeem type.
*/
function redeem(bytes32 _proposalId, bool[4] memory _whatToRedeem)
function redeemContributionRewardExt(bytes32 _proposalId, bool[4] memory _whatToRedeem)
public
returns(int256 reputationReward, uint256 nativeTokenReward, uint256 etherReward, uint256 externalTokenReward)
{
Expand Down
79 changes: 79 additions & 0 deletions contracts/schemes/VotableScheme.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
pragma solidity ^0.5.17;

import "../controller/Avatar.sol";
import "../controller/Controller.sol";
import "@daostack/infra-experimental/contracts/votingMachines/GenesisProtocol.sol";
import "@daostack/infra-experimental/contracts/votingMachines/VotingMachineCallbacksInterface.sol";
import "@daostack/infra-experimental/contracts/votingMachines/ProposalExecuteInterface.sol";

contract VotableScheme is VotingMachineCallbacksInterface, GenesisProtocol {
Avatar public avatar;

modifier onlySelf() {
require(msg.sender == address(this), "Only the scheme can call this method");
_;
}

/**
* @dev _initialize
* @param _avatar the scheme avatar
* @param _stakingToken (for GenesisProtocol)
* @param _votingParams genesisProtocol parameters - valid only if _voteParamsHash is zero
* @param _voteOnBehalf parameter
* @param _authorizedToPropose only this address allow to propose (unless it is zero)
*/
function _initializeVoting(
Avatar _avatar,
IERC20 _stakingToken,
uint[11] memory _votingParams,
address _voteOnBehalf,
address _authorizedToPropose
) internal {
require(address(_avatar) != address(0), "Scheme must have avatar");
avatar = _avatar;
GenesisProtocolLogic.initialize(
_stakingToken,
_votingParams,
_voteOnBehalf,
address(_avatar),
address(this),
_authorizedToPropose
);
}

// proposalId -> blockNumber
mapping(bytes32 => uint256) public proposalsBlockNumber;

// TODO: Remove _proposalId from the interface
function mintReputation(uint256 _amount, address _beneficiary, bytes32 _proposalId) public onlySelf returns(bool) {
return Controller(avatar.owner()).mintReputation(_amount, _beneficiary);
}

// TODO: Remove _proposalId from the interface
function burnReputation(uint256 _amount, address _beneficiary, bytes32 _proposalId) public onlySelf returns(bool) {
return Controller(avatar.owner()).burnReputation(_amount, _beneficiary);
}

// TODO: Remove _proposalId from the interface
function stakingTokenTransfer(
IERC20 _stakingToken,
address _beneficiary,
uint256 _amount,
bytes32 _proposalId
) public onlySelf returns(bool) {
return Controller(avatar.owner()).externalTokenTransfer(_stakingToken, _beneficiary, _amount);
}

// TODO: Remove _proposalId from the interface
function balanceOfStakingToken(IERC20 _stakingToken, bytes32 _proposalId) public view returns(uint256) {
return _stakingToken.balanceOf(address(avatar));
}

function getTotalReputationSupply(bytes32 _proposalId) public view returns(uint256) {
return avatar.nativeReputation().totalSupplyAt(proposalsBlockNumber[_proposalId]);
}

function reputationOf(address _owner, bytes32 _proposalId) public view returns(uint256) {
return avatar.nativeReputation().balanceOfAt(_owner, proposalsBlockNumber[_proposalId]);
}
}
Loading