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

Final refactor to dxdao gov 1.5 contracts #216

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
4e8acf7
refactor(contracts): finally remove daostack contracts
AugustoL Sep 19, 2022
fc9170d
refactor(contracts): remove not needed DxToken
AugustoL Sep 19, 2022
7feaecc
refactor(contracts): move dxvote utils to utils folder
AugustoL Sep 19, 2022
15e7a6b
refactor(contracts): remove unnecesary DaoCreator and upgrade RealMat…
AugustoL Sep 19, 2022
557dc16
refactor(contracts): refactor and reorder of Gov 1.5 contracts
AugustoL Sep 19, 2022
0942d3f
fix(scripts): small change in deploy scripts just to compile for tests
AugustoL Sep 19, 2022
e7503ef
refactor(tests): refactor helpers to woek with new dao contracts
AugustoL Sep 19, 2022
dcfe01b
refactor(contracts/dxdao): rename Dx contracts to DAO contracts
AugustoL Sep 20, 2022
16512f8
refactor(contracts/dao): contracts renamed form dxdao to dao and plac…
AugustoL Sep 22, 2022
3e15a7d
test(dao): tests renamed and placed in folders matching contracts
AugustoL Sep 22, 2022
f44b23e
chore(package.json): some dependencies updated
AugustoL Sep 22, 2022
9ada690
refactor(contracts): use solc 0.8.17, removed not needed contracts, c…
AugustoL Sep 22, 2022
c33d195
test(all): remove deleted contracts, do some changes to get most of t…
AugustoL Sep 22, 2022
7e10cb6
refactor(contracts/dao/schemes): refactor WalletScheme into Scheme, W…
AugustoL Sep 22, 2022
9eb873a
test(walletschemes): remove doAvatarGenericCalls parameter from Walle…
AugustoL Sep 22, 2022
c627996
fix deployment script
MiltonTulli Sep 22, 2022
0826077
fix: fixed WalletScheme test - proposal to change max proposal time
dcrescimbeni Sep 23, 2022
e9aa693
fix: fixed test MasterWalletScheme - proposal to change max proposal …
dcrescimbeni Sep 23, 2022
fc19269
feat(contracts/dao): dAOController now keeps track of active/inactive…
AugustoL Sep 23, 2022
b10d5f4
test(dao): check active/inactive proposals in DAOController
AugustoL Sep 23, 2022
4fa9a75
feat: ownership of REP is now transferred to controller instead of av…
dcrescimbeni Sep 23, 2022
bc5a489
Merge branch 'gov-1-5-contracts' of github.com:AugustoL/dxdao-contrac…
AugustoL Sep 23, 2022
28a3edb
refactor(contracts/dao): rename daoreputation in DAOController and ad…
AugustoL Sep 23, 2022
5f4e803
fix(contracts/dao): walletScheme option 2 is rejected and dont execut…
AugustoL Sep 23, 2022
127c3de
test: fixed tests
dcrescimbeni Sep 23, 2022
1cd82ac
fix: switched checks for executionTimeout and winningOption being the…
dcrescimbeni Sep 23, 2022
037dad4
fix(contracts/dao): remove check of permissions allowed for registeri…
AugustoL Sep 23, 2022
98893ba
fix(contracts/dao): remove not necessary _avatar parameter for unregi…
AugustoL Sep 23, 2022
ca13065
refactor(contracts/dao): take in count all proposed calls for option 1
AugustoL Sep 23, 2022
e6fb365
test(dao): update name of main variables used for dao tests and fixed…
AugustoL Sep 23, 2022
749a9d4
refactor(contracts/dao): final refactor to Schemes contracts
AugustoL Sep 25, 2022
6027872
feat(hardhat): add viaIR compiler setting to improve compile optimiza…
AugustoL Sep 25, 2022
12142f8
refactor(contracts/dao): remove staking token callbacks and let votin…
AugustoL Sep 25, 2022
786da34
test(test/all): change test helpers and test cases to work with new c…
AugustoL Sep 26, 2022
b774b1e
Merge branch 'gov-1-5-contracts' of github.com:AugustoL/dxdao-contrac…
AugustoL Sep 26, 2022
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
11 changes: 6 additions & 5 deletions contracts/dxdao/DxAvatar.sol → contracts/dao/DAOAvatar.sol
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.8;
pragma solidity ^0.8.17;

import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";

/**
@title DXAvatar
@author github:miltontulli
@dev An Avatar holds tokens, reputation and ether for a controller
@title DAO Avatar
@dev The avatar, representing the DAO, owned by the DAO, controls the reputation and funds of the DAO.
*/

contract DXAvatar is OwnableUpgradeable {
contract DAOAvatar is OwnableUpgradeable {
event CallExecuted(address indexed _to, bytes _data, uint256 _value, bool _success);

receive() external payable {}

function initialize(address _owner) public initializer {
__Ownable_init();
transferOwnership(_owner);
Expand Down
241 changes: 241 additions & 0 deletions contracts/dao/DAOController.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.17;

import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/utils/math/SafeMathUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/structs/EnumerableSetUpgradeable.sol";
import "./DAOAvatar.sol";
import "./DAOReputation.sol";

/**
* @title DAO Controller
* @dev A controller controls and connect the organizations schemes, reputation and avatar.
* The schemes execute proposals through the controller to the avatar.
* Each scheme has it own parameters and operation permissions.
*/
contract DAOController is Initializable {
using SafeMathUpgradeable for uint256;
using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet;
using EnumerableSetUpgradeable for EnumerableSetUpgradeable.Bytes32Set;

EnumerableSetUpgradeable.Bytes32Set private activeProposals;
EnumerableSetUpgradeable.Bytes32Set private inactiveProposals;
mapping(bytes32 => address) public schemeOfProposal;

struct ProposalAndScheme {
bytes32 proposalId;
address scheme;
}

DAOReputation public reputationToken;

struct Scheme {
bytes32 paramsHash; // a hash voting parameters of the scheme
bool isRegistered;
bool canManageSchemes;
bool canMakeAvatarCalls;
}

address[] public schemesAddresses;
mapping(address => Scheme) public schemes;
uint256 public schemesWithManageSchemesPermission;

event RegisterScheme(address indexed _sender, address indexed _scheme);
event UnregisterScheme(address indexed _sender, address indexed _scheme);

function initialize(address _scheme, address _reputationToken) public initializer {
schemes[_scheme] = Scheme({
paramsHash: bytes32(0),
isRegistered: true,
canManageSchemes: true,
canMakeAvatarCalls: true
});
schemesWithManageSchemesPermission = 1;
reputationToken = DAOReputation(_reputationToken);
}

modifier onlyRegisteredScheme() {
require(schemes[msg.sender].isRegistered, "DAOController: Sender is not a registered scheme");
_;
}

modifier onlyRegisteringSchemes() {
require(schemes[msg.sender].canManageSchemes, "DAOController: Sender cannot manage schemes");
_;
}

modifier onlyAvatarCallScheme() {
require(schemes[msg.sender].canMakeAvatarCalls, "DAOController: Sender cannot perform avatar calls");
_;
}

/**
* @dev register a scheme
* @param _scheme the address of the scheme
* @param _paramsHash a hashed configuration of the usage of the scheme
* @param _canManageSchemes whether the scheme is able to manage schemes
* @param _canMakeAvatarCalls whether the scheme is able to make avatar calls
* @return bool success of the operation
*/
function registerScheme(
address _scheme,
bytes32 _paramsHash,
bool _canManageSchemes,
bool _canMakeAvatarCalls
) external onlyRegisteredScheme onlyRegisteringSchemes returns (bool) {
Scheme memory scheme = schemes[_scheme];

// Add or change the scheme:
if ((!scheme.isRegistered || !scheme.canManageSchemes) && _canManageSchemes) {
schemesWithManageSchemesPermission = schemesWithManageSchemesPermission.add(1);
}

schemes[_scheme] = Scheme({
paramsHash: _paramsHash,
isRegistered: true,
canManageSchemes: _canManageSchemes,
canMakeAvatarCalls: _canMakeAvatarCalls
});

emit RegisterScheme(msg.sender, _scheme);

return true;
}

/**
* @dev unregister a scheme
* @param _scheme the address of the scheme
* @return bool success of the operation
*/
function unregisterScheme(address _scheme) external onlyRegisteredScheme onlyRegisteringSchemes returns (bool) {
Scheme memory scheme = schemes[_scheme];

//check if the scheme is registered
if (_isSchemeRegistered(_scheme) == false) {
return false;
}

if (scheme.isRegistered && scheme.canManageSchemes) {
require(
schemesWithManageSchemesPermission > 1,
"DAOController: Cannot unregister last scheme with manage schemes permission"
);
schemesWithManageSchemesPermission = schemesWithManageSchemesPermission.sub(1);
}

emit UnregisterScheme(msg.sender, _scheme);

schemes[_scheme] = Scheme({
paramsHash: bytes32(0),
isRegistered: false,
canManageSchemes: false,
canMakeAvatarCalls: false
});
return true;
}

/**
* @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.
* @param _avatar the controller's avatar address
* @param _value value (ETH) to transfer with the transaction
* @return bool -success
* bytes - the return value of the called _contract's function.
*/
function avatarCall(
address _contract,
bytes calldata _data,
DAOAvatar _avatar,
uint256 _value
) external onlyRegisteredScheme onlyAvatarCallScheme returns (bool, bytes memory) {
return _avatar.executeCall(_contract, _data, _value);
}

/**
* @dev Adds a proposal to the active proposals list
* @param _proposalId the proposalId
*/
function startProposal(bytes32 _proposalId) external onlyRegisteredScheme {
activeProposals.add(_proposalId);
schemeOfProposal[_proposalId] = msg.sender;
}

/**
* @dev Moves a proposal from the active proposals list to the inactive list
* @param _proposalId the proposalId
*/
function endProposal(bytes32 _proposalId) external {
require(
schemes[msg.sender].isRegistered ||
(!schemes[schemeOfProposal[_proposalId]].isRegistered && activeProposals.contains(_proposalId)),
"DAOController: Sender is not a registered scheme or proposal is not active"
);
activeProposals.remove(_proposalId);
inactiveProposals.add(_proposalId);
}

/**
* @dev Burns dao reputation
* @param _amount the amount of reputation to burn
* @param _account the account to burn reputation from
*/
function burnReputation(uint256 _amount, address _account) external onlyRegisteredScheme returns (bool) {
return reputationToken.burn(_account, _amount);
}

/**
* @dev Mints dao reputation
* @param _amount the amount of reputation to mint
* @param _account the account to mint reputation from
*/
function mintReputation(uint256 _amount, address _account) external onlyRegisteredScheme returns (bool) {
return reputationToken.mint(_account, _amount);
}

function isSchemeRegistered(address _scheme) external view returns (bool) {
return _isSchemeRegistered(_scheme);
}

function getSchemeParameters(address _scheme) external view returns (bytes32) {
return schemes[_scheme].paramsHash;
}

function getSchemeCanManageSchemes(address _scheme) external view returns (bool) {
return schemes[_scheme].canManageSchemes;
}

function getSchemeCanMakeAvatarCalls(address _scheme) external view returns (bool) {
return schemes[_scheme].canMakeAvatarCalls;
}

function getSchemesCountWithManageSchemesPermissions() external view returns (uint256) {
return schemesWithManageSchemesPermission;
}

function _isSchemeRegistered(address _scheme) private view returns (bool) {
return (schemes[_scheme].isRegistered);
}

function getActiveProposals() external view returns (ProposalAndScheme[] memory activeProposalsArray) {
activeProposalsArray = new ProposalAndScheme[](activeProposals.length());
for (uint256 i = 0; i < activeProposals.length(); i++) {
activeProposalsArray[i].proposalId = activeProposals.at(i);
activeProposalsArray[i].scheme = schemeOfProposal[activeProposals.at(i)];
}
return activeProposalsArray;
}

function getInactiveProposals() external view returns (ProposalAndScheme[] memory inactiveProposalsArray) {
inactiveProposalsArray = new ProposalAndScheme[](inactiveProposals.length());
for (uint256 i = 0; i < inactiveProposals.length(); i++) {
inactiveProposalsArray[i].proposalId = inactiveProposals.at(i);
inactiveProposalsArray[i].scheme = schemeOfProposal[inactiveProposals.at(i)];
}
return inactiveProposalsArray;
}

function getDaoReputation() external view returns (DAOReputation) {
return reputationToken;
}
}
77 changes: 77 additions & 0 deletions contracts/dao/DAOReputation.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// SPDX-License-Identifier: AGPL-3.0
pragma solidity 0.8.17;

import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20SnapshotUpgradeable.sol";

/**
* @title DAO Reputation
* @dev An ERC20 token that is non-transferable, owned and controlled by the DAO.
* Used by the DAO to vote on proposals.
* It uses a snapshot mechanism to keep track of the reputation at the moment of each proposal creation.
*/
contract DAOReputation is OwnableUpgradeable, ERC20SnapshotUpgradeable {
event Mint(address indexed _to, uint256 _amount);
event Burn(address indexed _from, uint256 _amount);

function initialize(string memory name, string memory symbol) external initializer {
__ERC20_init(name, symbol);
__Ownable_init();
}

// @dev Not allow the transfer of tokens
function _transfer(
address sender,
address recipient,
uint256 amount
) internal virtual override {
revert("DAOReputation: Reputation tokens are non-transferable");
}

// @notice Generates `_amount` reputation that are assigned to `_account`
// @param _account The address that will be assigned the new reputation
// @param _amount The quantity of reputation generated
// @return True if the reputation are generated correctly
function mint(address _account, uint256 _amount) external onlyOwner returns (bool) {
_mint(_account, _amount);
_snapshot();
emit Mint(_account, _amount);
return true;
}

function mintMultiple(address[] memory _accounts, uint256[] memory _amount) external onlyOwner returns (bool) {
for (uint256 i = 0; i < _accounts.length; i++) {
_mint(_accounts[i], _amount[i]);
_snapshot();
emit Mint(_accounts[i], _amount[i]);
}
return true;
}

// @notice Burns `_amount` reputation from `_account`
// @param _account The address that will lose the reputation
// @param _amount The quantity of reputation to burn
// @return True if the reputation are burned correctly
function burn(address _account, uint256 _amount) external onlyOwner returns (bool) {
_burn(_account, _amount);
_snapshot();
emit Burn(_account, _amount);
return true;
}

function burnMultiple(address[] memory _accounts, uint256 _amount) external onlyOwner returns (bool) {
for (uint256 i = 0; i < _accounts.length; i++) {
_burn(_accounts[i], _amount);
_snapshot();
emit Burn(_accounts[i], _amount);
}
return true;
}

/**
* @dev Get the current snapshotId
*/
function getCurrentSnapshotId() public view returns (uint256) {
return _getCurrentSnapshotId();
}
}
Loading