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

refactor: add arbitrator address to constructor #58

Merged
merged 1 commit into from
Sep 28, 2021
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
15 changes: 10 additions & 5 deletions contracts/RealityModule.sol
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ abstract contract RealityModule is Module {
/// @param expiration Duration that a positive answer of the oracle is valid in seconds (or 0 if valid forever)
/// @param bond Minimum bond that is required for an answer to be accepted
/// @param templateId ID of the template that should be used for proposal questions (see https://github.com/realitio/realitio-dapp#structuring-and-fetching-information)
/// @param arbitrator Address of the arbitrator that will secure the oracle resolution
/// @notice There need to be at least 60 seconds between end of cooldown and expiration
constructor(
address _owner,
Expand All @@ -65,7 +66,8 @@ abstract contract RealityModule is Module {
uint32 cooldown,
uint32 expiration,
uint256 bond,
uint256 templateId
uint256 templateId,
address arbitrator
) {
bytes memory initParams = abi.encode(
_owner,
Expand All @@ -76,7 +78,8 @@ abstract contract RealityModule is Module {
cooldown,
expiration,
bond,
templateId
templateId,
arbitrator
);
setUp(initParams);
}
Expand All @@ -91,7 +94,8 @@ abstract contract RealityModule is Module {
uint32 cooldown,
uint32 expiration,
uint256 bond,
uint256 templateId
uint256 templateId,
address arbitrator
) = abi.decode(
initParams,
(
Expand All @@ -103,7 +107,8 @@ abstract contract RealityModule is Module {
uint32,
uint32,
uint256,
uint256
uint256,
address
)
);
__Ownable_init();
Expand All @@ -120,7 +125,7 @@ abstract contract RealityModule is Module {
answerExpiration = expiration;
questionTimeout = timeout;
questionCooldown = cooldown;
questionArbitrator = address(oracle);
questionArbitrator = arbitrator;
minimumBond = bond;
template = templateId;

Expand Down
7 changes: 5 additions & 2 deletions contracts/RealityModuleERC20.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ contract RealityModuleERC20 is RealityModule {
/// @param expiration Duration that a positive answer of the oracle is valid in seconds (or 0 if valid forever)
/// @param bond Minimum bond that is required for an answer to be accepted
/// @param templateId ID of the template that should be used for proposal questions (see https://github.com/realitio/realitio-dapp#structuring-and-fetching-information)
/// @param arbitrator Address of the arbitrator that will secure the oracle resolution
/// @notice There need to be at least 60 seconds between end of cooldown and expiration
constructor(
address _owner,
Expand All @@ -24,7 +25,8 @@ contract RealityModuleERC20 is RealityModule {
uint32 cooldown,
uint32 expiration,
uint256 bond,
uint256 templateId
uint256 templateId,
address arbitrator
)
RealityModule(
_owner,
Expand All @@ -35,7 +37,8 @@ contract RealityModuleERC20 is RealityModule {
cooldown,
expiration,
bond,
templateId
templateId,
arbitrator
)
{}

Expand Down
7 changes: 5 additions & 2 deletions contracts/RealityModuleETH.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ contract RealityModuleETH is RealityModule {
/// @param expiration Duration that a positive answer of the oracle is valid in seconds (or 0 if valid forever)
/// @param bond Minimum bond that is required for an answer to be accepted
/// @param templateId ID of the template that should be used for proposal questions (see https://github.com/realitio/realitio-dapp#structuring-and-fetching-information)
/// @param arbitrator Address of the arbitrator that will secure the oracle resolution
/// @notice There need to be at least 60 seconds between end of cooldown and expiration
constructor(
address _owner,
Expand All @@ -24,7 +25,8 @@ contract RealityModuleETH is RealityModule {
uint32 cooldown,
uint32 expiration,
uint256 bond,
uint256 templateId
uint256 templateId,
address arbitrator
)
RealityModule(
_owner,
Expand All @@ -35,7 +37,8 @@ contract RealityModuleETH is RealityModule {
cooldown,
expiration,
bond,
templateId
templateId,
arbitrator
)
{}

Expand Down
21 changes: 11 additions & 10 deletions docs/setup_guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,24 +43,25 @@ The template should have the following format:
Using this template you can run the task by using `yarn hardhat --network <network> createDaoTemplate --oracle <oracle address> --template <your template json>` and this should provide you with a template id.

An example for this on Rinkeby would be (using the default template):
`yarn hardhat --network rinkeby createDaoTemplate ---oracle 0xDf33060F476F8cff7511F806C72719394da1Ad64`
`yarn hardhat --network rinkeby createDaoTemplate --oracle 0xDf33060F476F8cff7511F806C72719394da1Ad64`

For this guide we will assume that the returned template id is `0x0000000000000000000000000000000000000000000000000000000000000dad`

You can also create your template from this (UI)[https://reality.eth.link/app/template-generator/]

### Deploying the module

The module has nine attributes which are:
- Owner: address that can call setter functions
- Avatar: address of the DAO (e.g Safe)
The module has ten attributes which are:
- Owner: address that can call setter functions.
- Avatar: address of the DAO (e.g Safe).
- Target: address that the module will call `execModuleTransaction()` on.
- Oracle: address of the oracle (e.g RealitioV3)
- Timeout: Timeout in seconds that should be required for the oracle
- Cooldown: Amount in seconds of cooldown required before the transaction can be executed
- Expiration: Duration that a transaction is valid in seconds (or 0 if valid forever) after the cooldown
- Bond: Minimum bond that is required for an answer to be accepted
- Template ID: ID of the template that should be used for proposal questions (see https://github.com/realitio/realitio-dapp#structuring-and-fetching-information)
- Oracle: address of the oracle (e.g RealitioV3).
- Timeout: Timeout in seconds that should be required for the oracle.
- Cooldown: Amount in seconds of cooldown required before the transaction can be executed.
- Expiration: Duration that a transaction is valid in seconds (or 0 if valid forever) after the cooldown.
- Bond: Minimum bond that is required for an answer to be accepted.
- Template ID: ID of the template that should be used for proposal questions (see https://github.com/realitio/realitio-dapp#structuring-and-fetching-information).
- Arbitrator: the oracle's arbitrator (e.g. see Realitio's arbitrator [requirements](https://realitio.github.io/docs/html/arbitrators.html) and its arbitrators [list](https://github.com/realitio/realitio-contracts/blob/master/config/arbitrators.json)).


Hardhat tasks can be used to deploy a Reality Module instance. There are two different ways to deploy the module, the first one is through a normal deployment and passing arguments to the constructor (without the `proxied` flag), or, deploy the module through a [Minimal Proxy Factory](https://eips.ethereum.org/EIPS/eip-1167) and save on gas costs (with the `proxied` flag) - The master copy and factory address can be found in the [zodiac repository](https://github.com/gnosis/zodiac/blob/master/src/factory/constants.ts) and these are the addresses that are going to be used when deploying the module through factory.
Expand Down
2 changes: 1 addition & 1 deletion src/deploy/deploy_modules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const deploy: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
const { deployments, getNamedAccounts } = hre;
const { deployer } = await getNamedAccounts();
const { deploy } = deployments;
const args = [FIRST_ADDRESS, FIRST_ADDRESS, FIRST_ADDRESS, FIRST_ADDRESS, 1, 0, 60, 0, 0];
const args = [FIRST_ADDRESS, FIRST_ADDRESS, FIRST_ADDRESS, FIRST_ADDRESS, 1, 0, 60, 0, 0, FIRST_ADDRESS];

await deploy("RealityModuleERC20", {
from: deployer,
Expand Down
6 changes: 4 additions & 2 deletions src/tasks/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ const deployRealityModule = async (taskArgs: RealityTaskArgs, hardhatRuntime: Ha
"uint32",
"uint256",
"uint256",
"address",
],
values: [
taskArgs.owner,
Expand All @@ -50,6 +51,7 @@ const deployRealityModule = async (taskArgs: RealityTaskArgs, hardhatRuntime: Ha
taskArgs.expiration,
taskArgs.bond,
taskArgs.template,
taskArgs.oracle,
],
},
hardhatRuntime.ethers.provider,
Expand All @@ -64,7 +66,7 @@ const deployRealityModule = async (taskArgs: RealityTaskArgs, hardhatRuntime: Ha

const ModuleName = taskArgs.iserc20 ? "RealityModuleERC20" : "RealityModuleETH"
const Module = await hardhatRuntime.ethers.getContractFactory(ModuleName);
const module = await Module.deploy(taskArgs.owner, taskArgs.avatar, taskArgs.target, taskArgs.oracle, taskArgs.timeout, taskArgs.cooldown, taskArgs.expiration, taskArgs.bond, taskArgs.template);
const module = await Module.deploy(taskArgs.owner, taskArgs.avatar, taskArgs.target, taskArgs.oracle, taskArgs.timeout, taskArgs.cooldown, taskArgs.expiration, taskArgs.bond, taskArgs.template, taskArgs.oracle);
await module.deployTransaction.wait()
console.log("Module deployed to:", module.address);
}
Expand Down Expand Up @@ -108,7 +110,7 @@ task("verifyEtherscan", "Verifies the contract on etherscan")
await hardhatRuntime.run("verify", {
address: taskArgs.module,
constructorArgsParams: [
taskArgs.owner, taskArgs.avatar, taskArgs.oracle, taskArgs.target, `${taskArgs.timeout}`, `${taskArgs.cooldown}`, `${taskArgs.expiration}`, `${taskArgs.bond}`, taskArgs.template
taskArgs.owner, taskArgs.avatar, taskArgs.target, taskArgs.oracle, `${taskArgs.timeout}`, `${taskArgs.cooldown}`, `${taskArgs.expiration}`, `${taskArgs.bond}`, taskArgs.template, taskArgs.oracle
]
})
});
Expand Down
18 changes: 9 additions & 9 deletions test/DaoModuleERC20.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,14 @@ describe("RealityModuleERC20", async () => {
const setupTestWithTestAvatar = deployments.createFixture(async () => {
const base = await baseSetup();
const Module = await hre.ethers.getContractFactory("RealityModuleERC20");
const module = await Module.deploy(base.avatar.address, base.avatar.address, base.avatar.address, base.mock.address, 42, 23, 0, 0, 1337);
const module = await Module.deploy(base.avatar.address, base.avatar.address, base.avatar.address, base.mock.address, 42, 23, 0, 0, 1337, base.mock.address);
return { ...base, Module, module };
})

const setupTestWithMockAvatar = deployments.createFixture(async () => {
const base = await baseSetup();
const Module = await hre.ethers.getContractFactory("RealityModuleERC20");
const module = await Module.deploy(base.mock.address, base.mock.address, base.mock.address, base.mock.address, 42, 23, 0, 0, 1337);
const module = await Module.deploy(base.mock.address, base.mock.address, base.mock.address, base.mock.address, 42, 23, 0, 0, 1337, base.mock.address);
return { ...base, Module, module };
})
const [user1] = waffle.provider.getWallets();
Expand All @@ -64,7 +64,7 @@ describe("RealityModuleERC20", async () => {
it("throws if is already initialized", async () => {
const { mock } = await baseSetup()
const Module = await hre.ethers.getContractFactory("RealityModuleERC20")
const module = await Module.deploy(user1.address, user1.address, user1.address, user1.address, 42, 23, 0, 0, 1337)
const module = await Module.deploy(user1.address, user1.address, user1.address, user1.address, 42, 23, 0, 0, 1337, user1.address)
await expect(
module.setUp(buildMockInitializerParams(mock))
).to.be.revertedWith("Initializable: contract is already initialized")
Expand All @@ -73,40 +73,40 @@ describe("RealityModuleERC20", async () => {
it("throws if avatar is zero address", async () => {
const Module = await hre.ethers.getContractFactory("RealityModuleETH")
await expect(
Module.deploy(user1.address, ZERO_ADDRESS, user1.address, user1.address, 42, 23, 0, 0, 1337)
Module.deploy(user1.address, ZERO_ADDRESS, user1.address, user1.address, 42, 23, 0, 0, 1337, user1.address)
).to.be.revertedWith("Avatar can not be zero address")
})

it("throws if avatar is zero address", async () => {
const Module = await hre.ethers.getContractFactory("RealityModuleETH")
await expect(
Module.deploy(user1.address, user1.address, ZERO_ADDRESS, user1.address, 42, 23, 0, 0, 1337)
Module.deploy(user1.address, user1.address, ZERO_ADDRESS, user1.address, 42, 23, 0, 0, 1337, user1.address)
).to.be.revertedWith("Target can not be zero address")
})

it("throws if timeout is 0", async () => {
const Module = await hre.ethers.getContractFactory("RealityModuleERC20")
await expect(
Module.deploy(user1.address, user1.address, user1.address, user1.address, 0, 0, 0, 0, 0)
Module.deploy(user1.address, user1.address, user1.address, user1.address, 0, 0, 0, 0, 0, user1.address)
).to.be.revertedWith("Timeout has to be greater 0")
})

it("throws if not enough time between cooldown and expiration", async () => {
const Module = await hre.ethers.getContractFactory("RealityModuleERC20")
await expect(
Module.deploy(user1.address, user1.address, user1.address, user1.address, 1, 0, 59, 0, 0)
Module.deploy(user1.address, user1.address, user1.address, user1.address, 1, 0, 59, 0, 0, user1.address)
).to.be.revertedWith("There need to be at least 60s between end of cooldown and expiration")
})

it("answer expiration can be 0", async () => {
const Module = await hre.ethers.getContractFactory("RealityModuleERC20")
await Module.deploy(user1.address, user1.address, user1.address, user1.address, 1, 10, 0, 0, 0)
await Module.deploy(user1.address, user1.address, user1.address, user1.address, 1, 10, 0, 0, 0, user1.address)
})

it("should emit event because of successful set up", async () => {
const Module = await hre.ethers.getContractFactory("RealityModuleERC20")
const module = await Module.deploy(
user1.address, user1.address, user1.address, user1.address, 1, 10, 0, 0, 0
user1.address, user1.address, user1.address, user1.address, 1, 10, 0, 0, 0, user1.address
)
await module.deployed()
await expect(module.deployTransaction)
Expand Down
18 changes: 9 additions & 9 deletions test/DaoModuleETH.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,14 @@ describe("RealityModuleETH", async () => {
const setupTestWithTestAvatar = deployments.createFixture(async () => {
const base = await baseSetup();
const Module = await hre.ethers.getContractFactory("RealityModuleETH");
const module = await Module.deploy(base.avatar.address, base.avatar.address, base.avatar.address, base.mock.address, 42, 23, 0, 0, 1337);
const module = await Module.deploy(base.avatar.address, base.avatar.address, base.avatar.address, base.mock.address, 42, 23, 0, 0, 1337, base.mock.address);
return { ...base, Module, module };
})

const setupTestWithMockAvatar = deployments.createFixture(async () => {
const base = await baseSetup();
const Module = await hre.ethers.getContractFactory("RealityModuleETH");
const module = await Module.deploy(base.mock.address, base.mock.address, base.mock.address, base.mock.address, 42, 23, 0, 0, 1337);
const module = await Module.deploy(base.mock.address, base.mock.address, base.mock.address, base.mock.address, 42, 23, 0, 0, 1337, base.mock.address);
return { ...base, Module, module };
})
const [user1] = waffle.provider.getWallets();
Expand All @@ -65,7 +65,7 @@ describe("RealityModuleETH", async () => {
it("throws if is already initialized", async () => {
const { mock } = await baseSetup()
const Module = await hre.ethers.getContractFactory("RealityModuleETH")
const module = await Module.deploy(user1.address, user1.address, user1.address, user1.address, 42, 23, 0, 0, 1337)
const module = await Module.deploy(user1.address, user1.address, user1.address, user1.address, 42, 23, 0, 0, 1337, user1.address)
await expect(
module.setUp(buildMockInitializerParams(mock))
).to.be.revertedWith("Initializable: contract is already initialized")
Expand All @@ -74,40 +74,40 @@ describe("RealityModuleETH", async () => {
it("throws if avatar is zero address", async () => {
const Module = await hre.ethers.getContractFactory("RealityModuleETH")
await expect(
Module.deploy(user1.address, ZERO_ADDRESS, user1.address, user1.address, 42, 23, 0, 0, 1337)
Module.deploy(user1.address, ZERO_ADDRESS, user1.address, user1.address, 42, 23, 0, 0, 1337, user1.address)
).to.be.revertedWith("Avatar can not be zero address")
})

it("throws if target is zero address", async () => {
const Module = await hre.ethers.getContractFactory("RealityModuleETH")
await expect(
Module.deploy(user1.address, user1.address, ZERO_ADDRESS, user1.address, 42, 23, 0, 0, 1337)
Module.deploy(user1.address, user1.address, ZERO_ADDRESS, user1.address, 42, 23, 0, 0, 1337, user1.address)
).to.be.revertedWith("Target can not be zero address")
})

it("throws if timeout is 0", async () => {
const Module = await hre.ethers.getContractFactory("RealityModuleETH")
await expect(
Module.deploy(user1.address, user1.address, user1.address, user1.address, 0, 10, 100, 100, 1)
Module.deploy(user1.address, user1.address, user1.address, user1.address, 0, 10, 100, 100, 1, user1.address)
).to.be.revertedWith("Timeout has to be greater 0")
})

it("throws if not enough time between cooldown and expiration", async () => {
const Module = await hre.ethers.getContractFactory("RealityModuleETH")
await expect(
Module.deploy(user1.address, user1.address, user1.address, user1.address, 1, 0, 59, 0, 0)
Module.deploy(user1.address, user1.address, user1.address, user1.address, 1, 0, 59, 0, 0, user1.address)
).to.be.revertedWith("There need to be at least 60s between end of cooldown and expiration")
})

it("answer expiration can be 0", async () => {
const Module = await hre.ethers.getContractFactory("RealityModuleETH")
await Module.deploy(user1.address, user1.address, user1.address, user1.address, 1, 10, 0, 0, 0)
await Module.deploy(user1.address, user1.address, user1.address, user1.address, 1, 10, 0, 0, 0, user1.address)
})

it("should emit event because of successful set up", async () => {
const Module = await hre.ethers.getContractFactory("RealityModuleETH")
const module = await Module.deploy(
user1.address, user1.address, user1.address, user1.address, 1, 10, 0, 0, 0
user1.address, user1.address, user1.address, user1.address, 1, 10, 0, 0, 0, user1.address
)
await module.deployed()
await expect(module.deployTransaction)
Expand Down
Loading