Skip to content

Commit

Permalink
Merge branch 'develop' into feature/dao-erc165-tests
Browse files Browse the repository at this point in the history
  • Loading branch information
heueristik committed May 25, 2023
2 parents 1c976cd + 43a5f39 commit 2d49112
Show file tree
Hide file tree
Showing 19 changed files with 828 additions and 365 deletions.
1 change: 1 addition & 0 deletions DEPLOYMENT_CHECKLIST.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ This checklist is seen as a guide to deploy the stack to a new chain.

## Pre-Deployment

- [ ] Bump the OSx protocol version in the `ProtocolVersion.sol` file.
- [ ] Choose an ENS domain for DAOs
- [ ] Choose an ENS domain for plugins
- [ ] Check if there is an official ENS deployment for the chosen chain and if yes:
Expand Down
2 changes: 2 additions & 0 deletions packages/contracts/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- Inherit `ProtocolVersion` and `ERC165` in `DAOFactory`.
- Inherit `ProtocolVersion` in `DAO`.
- Added a `nonReentrant` modifier to the `execute` function in the `DAO` contract.
- Added `allowFailureMap` to `IDAO.Executed` event.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import {DeployFunction} from 'hardhat-deploy/types';
import {HardhatRuntimeEnvironment} from 'hardhat/types';
import {DAO__factory} from '../../../typechain';
import {Operation} from '../../../utils/types';
import {getContractAddress} from '../../helpers';
import {DAO__factory} from '../../../typechain';

import daoFactoryArtifact from '../../../artifacts/src/framework/dao/DAOFactory.sol/DAOFactory.json';

const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
console.log('Updating DAOFactory');
Expand All @@ -23,6 +25,7 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
console.log(`Using PreviousDAOFactory ${previousDAOFactoryAddress}`);

const deployResult = await deploy('DAOFactory', {
contract: daoFactoryArtifact,
from: deployer.address,
args: [daoRegistryAddress, pluginSetupProcessorAddress],
log: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,21 @@ import {HardhatRuntimeEnvironment} from 'hardhat/types';
import {PluginRepo__factory} from '../../../typechain';
import {getContractAddress, uploadToIPFS} from '../../helpers';

import multisigSetupArtifact from '../../../artifacts/src/plugins/governance/multisig/MultisigSetup.sol/MultisigSetup.json';

import multisigReleaseMetadata from '../../../src/plugins/governance/multisig/release-metadata.json';
import multisigBuildMetadata from '../../../src/plugins/governance/multisig/build-metadata.json';

const TARGET_RELEASE = 1;

const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
console.log('\nUpdate Multisig Plugin');
const {deployments, ethers, network} = hre;
const {deploy} = deployments;
const [deployer] = await ethers.getSigners();

const deployResult = await deploy('MultisigSetup', {
contract: multisigSetupArtifact,
from: deployer.address,
args: [],
log: true,
Expand Down Expand Up @@ -44,7 +49,7 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
const tx = await multisigRepo
.connect(deployer)
.createVersion(
1,
TARGET_RELEASE,
deployResult.address,
ethers.utils.toUtf8Bytes(`ipfs://${multisigBuildCIDPath}`),
ethers.utils.toUtf8Bytes(`ipfs://${multisigReleaseCIDPath}`)
Expand All @@ -57,7 +62,7 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
const tx = await multisigRepo
.connect(deployer)
.populateTransaction.createVersion(
1,
TARGET_RELEASE,
deployResult.address,
ethers.utils.toUtf8Bytes(`ipfs://${multisigBuildCIDPath}`),
ethers.utils.toUtf8Bytes(`ipfs://${multisigReleaseCIDPath}`)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import {DeployFunction} from 'hardhat-deploy/types';
import {HardhatRuntimeEnvironment} from 'hardhat/types';
import {PluginRepo__factory} from '../../../typechain';
import {getContractAddress, uploadToIPFS} from '../../helpers';

import tokenVotingSetupArtifact from '../../../artifacts/src/plugins/governance/majority-voting/token/TokenVotingSetup.sol/TokenVotingSetup.json';
import tokenVotingReleaseMetadata from '../../../src/plugins/governance/majority-voting/token/release-metadata.json';
import tokenVotingBuildMetadata from '../../../src/plugins/governance/majority-voting/token/build-metadata.json';

const TARGET_RELEASE = 1;

const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
console.log('\nUpdate TokenVoting Plugin');
const {deployments, ethers, network} = hre;
const {deploy} = deployments;
const [deployer] = await ethers.getSigners();

const deployResult = await deploy('TokenVotingSetup', {
contract: tokenVotingSetupArtifact,
from: deployer.address,
args: [],
log: true,
});

const tokenVotingReleaseCIDPath = await uploadToIPFS(
JSON.stringify(tokenVotingReleaseMetadata),
network.name
);
const tokenVotingBuildCIDPath = await uploadToIPFS(
JSON.stringify(tokenVotingBuildMetadata),
network.name
);

const tokenVotingRepoAddress = await getContractAddress(
'token-voting-repo',
hre
);
const tokenVotingRepo = PluginRepo__factory.connect(
tokenVotingRepoAddress,
ethers.provider
);
if (
await tokenVotingRepo.callStatic.isGranted(
tokenVotingRepoAddress,
deployer.address,
await tokenVotingRepo.MAINTAINER_PERMISSION_ID(),
'0x00'
)
) {
console.log(`Deployer has permission to install new TokenVoting version`);
const tx = await tokenVotingRepo
.connect(deployer)
.createVersion(
TARGET_RELEASE,
deployResult.address,
ethers.utils.toUtf8Bytes(`ipfs://${tokenVotingBuildCIDPath}`),
ethers.utils.toUtf8Bytes(`ipfs://${tokenVotingReleaseCIDPath}`)
);
console.log(`Creating new TokenVoting build version with ${tx.hash}`);
await tx.wait();
return;
}

const tx = await tokenVotingRepo
.connect(deployer)
.populateTransaction.createVersion(
TARGET_RELEASE,
deployResult.address,
ethers.utils.toUtf8Bytes(`ipfs://${tokenVotingBuildCIDPath}`),
ethers.utils.toUtf8Bytes(`ipfs://${tokenVotingReleaseCIDPath}`)
);

if (!tx.to || !tx.data) {
throw new Error(
`Failed to populate TokenVoting Repo createVersion transaction`
);
}

console.log(
`Deployer has no permission to create a new version. Adding managingDAO action`
);
hre.managingDAOActions.push({
to: tx.to,
data: tx.data,
value: 0,
description: `Creates a new build for release 1 in the TokenVotingRepo (${tokenVotingRepoAddress}) with TokenVotingSetup (${deployResult.address})`,
});
};
export default func;
func.tags = ['Update', 'TokenVotingPlugin'];
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import {DeployFunction} from 'hardhat-deploy/types';
import {HardhatRuntimeEnvironment} from 'hardhat/types';
const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
console.log('\nConcluding TokenVoting Plugin Update');

hre.aragonToVerifyContracts.push(
await hre.deployments.get('TokenVotingSetup')
);
};
export default func;
func.tags = ['TokenVotingPlugin', 'Verify'];
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import {DeployFunction} from 'hardhat-deploy/types';
import {HardhatRuntimeEnvironment} from 'hardhat/types';
import {PluginRepo__factory} from '../../../typechain';
import {getContractAddress, uploadToIPFS} from '../../helpers';

import addresslistVotingSetupArtifact from '../../../artifacts/src/plugins/governance/majority-voting/addresslist/AddresslistVotingSetup.sol/AddresslistVotingSetup.json';
import addresslistVotingReleaseMetadata from '../../../src/plugins/governance/majority-voting/addresslist/release-metadata.json';
import addresslistVotingBuildMetadata from '../../../src/plugins/governance/majority-voting/addresslist/build-metadata.json';

const TARGET_RELEASE = 1;

const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
console.log('\nUpdate AddresslistVoting Plugin');
const {deployments, ethers, network} = hre;
const {deploy} = deployments;
const [deployer] = await ethers.getSigners();

const deployResult = await deploy('AddresslistVotingSetup', {
contract: addresslistVotingSetupArtifact,
from: deployer.address,
args: [],
log: true,
});

const addresslistVotingReleaseCIDPath = await uploadToIPFS(
JSON.stringify(addresslistVotingReleaseMetadata),
network.name
);
const addresslistVotingBuildCIDPath = await uploadToIPFS(
JSON.stringify(addresslistVotingBuildMetadata),
network.name
);

const addresslistVotingRepoAddress = await getContractAddress(
'address-list-voting-repo',
hre
);
const addresslistVotingRepo = PluginRepo__factory.connect(
addresslistVotingRepoAddress,
ethers.provider
);
if (
await addresslistVotingRepo.callStatic.isGranted(
addresslistVotingRepoAddress,
deployer.address,
await addresslistVotingRepo.MAINTAINER_PERMISSION_ID(),
'0x00'
)
) {
console.log(
`Deployer has permission to install new AddresslistVoting version`
);
const tx = await addresslistVotingRepo
.connect(deployer)
.createVersion(
TARGET_RELEASE,
deployResult.address,
ethers.utils.toUtf8Bytes(`ipfs://${addresslistVotingBuildCIDPath}`),
ethers.utils.toUtf8Bytes(`ipfs://${addresslistVotingReleaseCIDPath}`)
);
console.log(`Creating new AddresslistVoting build version with ${tx.hash}`);
await tx.wait();
return;
}

const tx = await addresslistVotingRepo
.connect(deployer)
.populateTransaction.createVersion(
TARGET_RELEASE,
deployResult.address,
ethers.utils.toUtf8Bytes(`ipfs://${addresslistVotingBuildCIDPath}`),
ethers.utils.toUtf8Bytes(`ipfs://${addresslistVotingReleaseCIDPath}`)
);

if (!tx.to || !tx.data) {
throw new Error(
`Failed to populate AddresslistVoting Repo createVersion transaction`
);
}

console.log(
`Deployer has no permission to create a new version. Adding managingDAO action`
);
hre.managingDAOActions.push({
to: tx.to,
data: tx.data,
value: 0,
description: `Creates a new build for release 1 in the AddresslistVotingRepo (${addresslistVotingRepoAddress}) with AddresslistVotingSetup (${deployResult.address})`,
});
};
export default func;
func.tags = ['Update', 'AddresslistVotingPlugin'];
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import {DeployFunction} from 'hardhat-deploy/types';
import {HardhatRuntimeEnvironment} from 'hardhat/types';
const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
console.log('\nConcluding AddresslistVoting Plugin Update');

hre.aragonToVerifyContracts.push(
await hre.deployments.get('AddresslistVotingSetup')
);
};
export default func;
func.tags = ['AddresslistVotingPlugin', 'Verify'];
6 changes: 6 additions & 0 deletions packages/contracts/src/core/dao/DAO.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import "@openzeppelin/contracts-upgradeable/token/ERC1155/IERC1155ReceiverUpgrad
import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
import "@openzeppelin/contracts/interfaces/IERC1271.sol";

import {IProtocolVersion} from "../../utils/protocol/IProtocolVersion.sol";
import {ProtocolVersion} from "../../utils/protocol/ProtocolVersion.sol";
import {PermissionManager} from "../permission/PermissionManager.sol";
import {CallbackHandler} from "../utils/CallbackHandler.sol";
import {hasBit, flipBit} from "../utils/BitMap.sol";
Expand All @@ -30,6 +32,7 @@ contract DAO is
ERC165StorageUpgradeable,
IDAO,
UUPSUpgradeable,
ProtocolVersion,
PermissionManager,
CallbackHandler
{
Expand Down Expand Up @@ -149,6 +152,7 @@ contract DAO is
_registerInterface(type(IDAO).interfaceId);
_registerInterface(type(IERC1271).interfaceId);
_registerInterface(type(IEIP4824).interfaceId);
_registerInterface(type(IProtocolVersion).interfaceId); // added in v1.3.0
_registerTokenInterfaces();

_setMetadata(_metadata);
Expand All @@ -172,8 +176,10 @@ contract DAO is
}

// Initialize `_reentrancyStatus` that was added in v1.3.0.
// Register Interface `ProtocolVersion` that was added in v1.3.0.
if (_previousProtocolVersion[1] <= 2) {
_reentrancyStatus = _NOT_ENTERED;
_registerInterface(type(IProtocolVersion).interfaceId);
}
}

Expand Down
15 changes: 14 additions & 1 deletion packages/contracts/src/framework/dao/DAOFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

pragma solidity 0.8.17;

import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol";

import {IProtocolVersion} from "../../utils/protocol/IProtocolVersion.sol";
import {ProtocolVersion} from "../../utils/protocol/ProtocolVersion.sol";
import {DAO} from "../../core/dao/DAO.sol";
import {PermissionLib} from "../../core/permission/PermissionLib.sol";
import {createERC1967Proxy} from "../../utils/Proxy.sol";
Expand All @@ -14,7 +18,7 @@ import {DAORegistry} from "./DAORegistry.sol";
/// @title DAOFactory
/// @author Aragon Association - 2022-2023
/// @notice This contract is used to create a DAO.
contract DAOFactory {
contract DAOFactory is ERC165, ProtocolVersion {
/// @notice The DAO base contract, to be used for creating new `DAO`s via `createERC1967Proxy` function.
address public immutable daoBase;

Expand Down Expand Up @@ -57,6 +61,15 @@ contract DAOFactory {
daoBase = address(new DAO());
}

/// @notice Checks if this or the parent contract supports an interface by its ID.
/// @param _interfaceId The ID of the interface.
/// @return Returns `true` if the interface is supported.
function supportsInterface(bytes4 _interfaceId) public view virtual override returns (bool) {
return
_interfaceId == type(IProtocolVersion).interfaceId ||
super.supportsInterface(_interfaceId);
}

/// @notice Creates a new DAO, registers it on the DAO registry, and installs a list of plugins via the plugin setup processor.
/// @param _daoSettings The DAO settings to be set during the DAO initialization.
/// @param _pluginSettings The array containing references to plugins and their settings to be installed after the DAO has been created.
Expand Down
12 changes: 12 additions & 0 deletions packages/contracts/src/utils/protocol/IProtocolVersion.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// SPDX-License-Identifier: AGPL-3.0-or-later

pragma solidity ^0.8.8;

/// @title IProtocolVersion
/// @author Aragon Association - 2022-2023
/// @notice An interface defining the semantic OSx protocol version.
interface IProtocolVersion {
/// @notice Returns the protocol version at which the current contract was built. Use it to check for future upgrades that might be applicable.
/// @return _version Returns the semantic OSx protocol version.
function protocolVersion() external view returns (uint8[3] memory _version);
}
18 changes: 18 additions & 0 deletions packages/contracts/src/utils/protocol/ProtocolVersion.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// SPDX-License-Identifier: AGPL-3.0-or-later

pragma solidity 0.8.17;

import {IProtocolVersion} from "./IProtocolVersion.sol";

/// @title ProtocolVersion
/// @author Aragon Association - 2023
/// @notice An abstract, stateless, non-upgradeable contract serves as a base for other contracts requiring awareness of the OSx protocol version.
/// @dev Do not add any new variables to this contract that would shift down storage in the inheritance chain.
abstract contract ProtocolVersion is IProtocolVersion {
// IMPORTANT: Do not add any storage variable, see the above notice.

/// @inheritdoc IProtocolVersion
function protocolVersion() public pure returns (uint8[3] memory) {
return [1, 3, 0];
}
}
Loading

0 comments on commit 2d49112

Please sign in to comment.