Skip to content

Commit

Permalink
Merge pull request #53 from gnosis/chore/scripts-and-documentation-up…
Browse files Browse the repository at this point in the history
…date

Chore: Tasks and documentation update
  • Loading branch information
auryn-macmillan authored Sep 12, 2021
2 parents de36e6e + eaddfd6 commit 5497649
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 95 deletions.
55 changes: 29 additions & 26 deletions docs/setup_guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,15 @@ To start the process you need to create a Safe on the Rinkeby test network (e.g.

For the hardhat tasks to work the environment needs to be properly configured. See the [sample env file](../.env.sample) for more information.

The guide will use the Rinkeby ETH Realitio contract at [`0x3D00D77ee771405628a4bA4913175EcC095538da`](https://rinkeby.etherscan.io/address/0x3D00D77ee771405628a4bA4913175EcC095538da#code). Other network addresses can be found in the truffle build folder on the [Realitio GitHub repo](https://github.com/realitio/realitio-contracts). E.g. on mainnet the ETH Realitio contract can be found at [`0x325a2e0f3cca2ddbaebb4dfc38df8d19ca165b47`](https://etherscan.io/address/0x325a2e0f3cca2ddbaebb4dfc38df8d19ca165b47#code).
The guide will use the Rinkeby ETH RealitioV3 contract at [`0xDf33060F476F8cff7511F806C72719394da1Ad64`](https://rinkeby.etherscan.io/address/0xDf33060F476F8cff7511F806C72719394da1Ad64#code). Other network addresses can be found in the truffle build folder on the [Realitio GitHub repo](https://github.com/RealityETH/monorepo/tree/main/packages/contracts/chains/deployments).

DISCLAIMER: Check the deployed Realitio contracts before using them.

## Setting up the module

The first step is to deploy the module. Every DAO will have their own module. The module is linked to a DAO (called avatar in the contract) and an oracle (e.g. Realitio). These cannot be changed after deployment.

As part of the setup you need to define or choose a template on Realitio. More information can be found in [their docs](https://github.com/realitio/realitio-dapp#structuring-and-fetching-information)

### Setup the Realitio template

As part of the setup you need to define or choose a template on Realitio. More information can be found in [their docs](https://github.com/realitio/realitio-dapp#structuring-and-fetching-information).

To define your own template a hardhat task is provided in the repository. It is possible to provide a template to that task via `--template` else the [default template](../src/tasks/defaultTemplate.json) is used.

The template should have the following format:
Expand All @@ -46,40 +43,46 @@ 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 0x3D00D77ee771405628a4bA4913175EcC095538da`
`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

Hardhat tasks can be used to deploy a reality module instance. There are two different tasks, the first one is through a normal deployment and passing arguments to the constructor (with the task `setup`), or, deploy the Module through a [Minimal Proxy Factory](https://eips.ethereum.org/EIPS/eip-1167) and save on gas costs (with the task `factorySetup`) - In rinkeby the address of the Proxy Factory is: `0xd067410a85ffC8C55f7245DE4BfE16C95329D232` and the master copy of the Reality Module: `0x4D0D4Bd6eCA52f2F931c099B6a8a8B2ae85FFD4E`.
The module has nine 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)

Now that we have a template, a hardhat task can be used to deploy a Reality module instance. These tasks requires the following parameters:

- `avatar` - the address of the avatar.
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.

This task requires the following parameters:
- `owner` - the address of the owner
- `oracle` - the address of the Realitio contract
- `template` - the template to be used with Realitio
- `avatar` - the address of the avatar.
- `target` - the address of the target.
- `oracle` - the address of the RealitioV3 contract
- `template` - the template to be used with RealitioV3
- `iserc20` (optional) - If set to true, the module `RealityERC20` is going to be deployed, otherwise `RealityETH` is deployed. By default is false
- `proxied` (optional) - Deploys the module through a proxy factory

There are also optional parameters, for more information run `yarn hardhat setup --help` or `yarn hardhat factory-setup --help`.
There are more optional parameters, for more information run `yarn hardhat setup --help`.

An example for this on Rinkeby would be:
`yarn hardhat --network rinkeby setup --owner <owner_address> --avatar <avatar_address> --oracle 0x3D00D77ee771405628a4bA4913175EcC095538da --template 0x0000000000000000000000000000000000000000000000000000000000000dad`

or

`yarn hardhat --network rinkeby factorySetup --factory <factory_address> --mastercopy <mastercopy_address> --owner <owner_address> --avatar <avatar_address> --oracle 0x3D00D77ee771405628a4bA4913175EcC095538da --template 0x0000000000000000000000000000000000000000000000000000000000000dad`

or

`yarn hardhat --network rinkeby factory-setup --factory <factory_address> --mastercopy <mastercopy_address> --dao <dao_address> --oracle 0x3D00D77ee771405628a4bA4913175EcC095538da --template 0x0000000000000000000000000000000000000000000000000000000000000dad`

This should return the address of the deployed Reality module. For this guide we assume this to be `0x4242424242424242424242424242424242424242`
`yarn hardhat --network rinkeby setup --owner <owner_address> --avatar <avatar_address> --target <target_address> --oracle 0xDf33060F476F8cff7511F806C72719394da1Ad64 --template 0x0000000000000000000000000000000000000000000000000000000000000dad`

Once the module is deployed you should verify the source code (Note: If you used the factory deployment the contract should be already verified). If you use a network that is Etherscan compatible and you configure the `ETHERSCAN_API_KEY` in your environment you can use the provided hardhat task to do this.
Once the module is deployed you should verify the source code (Note: Probably etherscan will verify it automatically, but just in case). If you use a network that is Etherscan compatible and you configure the `ETHERSCAN_API_KEY` in your environment you can use the provided hardhat task to do this.

An example for this on Rinkeby would be:
`yarn hardhat --network rinkeby verifyEtherscan --module 0x4242424242424242424242424242424242424242 --owner <owner_address> --avatar <avatar_address> --oracle 0x3D00D77ee771405628a4bA4913175EcC095538da --template 0x0000000000000000000000000000000000000000000000000000000000000dad`
`yarn hardhat --network rinkeby verifyEtherscan --module 0x4242424242424242424242424242424242424242 --owner <owner_address> --avatar <avatar_address> --target <target_address> --oracle 0xDf33060F476F8cff7511F806C72719394da1Ad64 --template 0x0000000000000000000000000000000000000000000000000000000000000dad`

### Enabling the module

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"author": "richard@gnosis.io",
"license": "MIT",
"devDependencies": {
"@gnosis.pm/zodiac": "0.0.1-prealpha2",
"@gnosis.pm/zodiac": "0.0.1-prealpha7",
"@nomiclabs/hardhat-ethers": "^2.0.0",
"@nomiclabs/hardhat-etherscan": "^2.1.0",
"@nomiclabs/hardhat-waffle": "^2.0.0",
Expand Down
137 changes: 73 additions & 64 deletions src/tasks/setup.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,78 @@
import "hardhat-deploy";
import "@nomiclabs/hardhat-ethers";
import { task, types } from "hardhat/config";
import { deployAndSetUpModule } from "@gnosis.pm/zodiac"
import defaultTemplate from "./defaultTemplate.json";
import { Contract } from "ethers";
import { AbiCoder } from "ethers/lib/utils";
import { HardhatRuntimeEnvironment } from "hardhat/types";

const FIRST_ADDRESS = "0x0000000000000000000000000000000000000001";
const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
interface RealityTaskArgs {
owner: string
avatar: string
target: string
oracle: string
timeout: string
cooldown: string
expiration: string
bond: string
template: string
proxied: boolean
iserc20: boolean
}

task("setup", "Provides the clearing price to an auction")
.addParam("owner", "Address of the owner", undefined, types.string)
.addParam("avatar", "Address of the avatar (e.g. Safe)", undefined, types.string)
.addParam("oracle", "Address of the oracle (e.g. Realitio)", undefined, types.string)
.addParam(
"template",
"Template that should be used for proposal questions (See https://github.com/realitio/realitio-dapp#structuring-and-fetching-information)",
undefined,
types.string
)
.addParam("timeout", "Timeout in seconds that should be required for the oracle", 48 * 3600, types.int, true)
.addParam("cooldown", "Cooldown in seconds that should be required after a oracle provided answer", 24 * 3600, types.int, true)
.addParam("expiration", "Time duration in seconds for which a positive answer is valid. After this time the answer is expired", 7 * 24 * 3600, types.int, true)
.addParam("bond", "Minimum bond that is required for an answer to be accepted", "0", types.string, true)
.setAction(async (taskArgs, hardhatRuntime) => {
const [caller] = await hardhatRuntime.ethers.getSigners();
console.log("Using the account:", caller.address);
const Module = await hardhatRuntime.ethers.getContractFactory("RealityModule");
const module = await Module.deploy(taskArgs.owner, taskArgs.avatar, taskArgs.oracle, taskArgs.timeout, taskArgs.cooldown, taskArgs.expiration, taskArgs.bond, taskArgs.template);
const deployRealityModule = async (taskArgs: RealityTaskArgs, hardhatRuntime: HardhatRuntimeEnvironment) => {
const [caller] = await hardhatRuntime.ethers.getSigners();
console.log("Using the account:", caller.address);

if (taskArgs.proxied) {
const chainId = await hardhatRuntime.getChainId();
const module = taskArgs.iserc20 ? "realityERC20" : "realityETH"
const { transaction } = deployAndSetUpModule(
module,
{
types: [
"address",
"address",
"address",
"address",
"uint32",
"uint32",
"uint32",
"uint256",
"uint256",
],
values: [
taskArgs.owner,
taskArgs.avatar,
taskArgs.target,
taskArgs.oracle,
taskArgs.timeout,
taskArgs.cooldown,
taskArgs.expiration,
taskArgs.bond,
taskArgs.template,
],
},
hardhatRuntime.ethers.provider,
Number(chainId),
Date.now().toString()
);
const deploymentTransaction = await caller.sendTransaction(transaction);
const receipt = await deploymentTransaction.wait();
console.log("Module deployed to:", receipt.logs[1].address)
return
}

console.log("Module deployed to:", module.address);
});
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);
await module.deployTransaction.wait()
console.log("Module deployed to:", module.address);
}

task("factorySetup", "Deploy and initialize Reality Module through a Proxy Factory")
.addParam("factory", "Address of the Proxy Factory", undefined, types.string)
.addParam("mastercopy", "Address of the Reality Module Master Copy", undefined, types.string)
task("setup", "Provides the clearing price to an auction")
.addParam("owner", "Address of the owner", undefined, types.string)
.addParam("avatar", "Address of the avatar (e.g. Safe)", undefined, types.string)
.addParam("target", "Address of the target", undefined, types.string)
.addParam("oracle", "Address of the oracle (e.g. Realitio)", undefined, types.string)
.addParam(
"template",
Expand All @@ -47,43 +84,15 @@ task("factorySetup", "Deploy and initialize Reality Module through a Proxy Facto
.addParam("cooldown", "Cooldown in seconds that should be required after a oracle provided answer", 24 * 3600, types.int, true)
.addParam("expiration", "Time duration in seconds for which a positive answer is valid. After this time the answer is expired", 7 * 24 * 3600, types.int, true)
.addParam("bond", "Minimum bond that is required for an answer to be accepted", "0", types.string, true)
.setAction(async (taskArgs, hardhatRuntime) => {
const [caller] = await hardhatRuntime.ethers.getSigners();
console.log("Using the account:", caller.address);
.addParam("proxied", "Deploys module through proxy factory", false, types.boolean, true)
.addParam("iserc20", "Defines if Reality is deployed for ETH or ERC20. By default is false", false, types.boolean, true)
.setAction(deployRealityModule);

const FactoryAbi = [
`function deployModule(
address masterCopy,
bytes memory initializer
) public returns (address proxy)`,
];

const Factory = new Contract(taskArgs.factory, FactoryAbi, caller)
const Module = await hardhatRuntime.ethers.getContractFactory("RealityModule");

const encodedParams = new AbiCoder().encode(
["address", "address", "address", "uint32", "uint32", "uint32", "uint256", "uint256"],
[
taskArgs.owner,
taskArgs.avatar,
taskArgs.oracle,
taskArgs.timeout,
taskArgs.cooldown,
taskArgs.expiration,
taskArgs.bond,
taskArgs.template
]
)

const initParams = Module.interface.encodeFunctionData('setUp', [encodedParams])

const receipt = await Factory.deployModule(taskArgs.mastercopy, initParams).then((tx: any) => tx.wait(3));
console.log("Module deployed to:", receipt.logs[1].address);
});
task("verifyEtherscan", "Verifies the contract on etherscan")
.addParam("module", "Address of the module", undefined, types.string)
.addParam("owner", "Address of the owner", undefined, types.string)
.addParam("avatar", "Address of the avatar (e.g. Safe)", undefined, types.string)
.addParam("target", "Address of the target", undefined, types.string)
.addParam("oracle", "Address of the oracle (e.g. Realitio)", undefined, types.string)
.addParam(
"template",
Expand All @@ -95,17 +104,17 @@ task("verifyEtherscan", "Verifies the contract on etherscan")
.addParam("cooldown", "Cooldown in seconds that should be required after a oracle provided answer", 24 * 3600, types.int, true)
.addParam("expiration", "Time duration in seconds for which a positive answer is valid. After this time the answer is expired", 7 * 24 * 3600, types.int, true)
.addParam("bond", "Minimum bond that is required for an answer to be accepted", "0", types.string, true)
.setAction(async (taskArgs, hardhatRuntime) => {
.setAction(async (taskArgs: RealityTaskArgs & { module: string }, hardhatRuntime) => {
await hardhatRuntime.run("verify", {
address: taskArgs.module,
constructorArgsParams: [
taskArgs.owner, taskArgs.avatar, taskArgs.oracle, `${taskArgs.timeout}`, `${taskArgs.cooldown}`, `${taskArgs.expiration}`, `${taskArgs.bond}`, taskArgs.template
taskArgs.owner, taskArgs.avatar, taskArgs.oracle, taskArgs.target, `${taskArgs.timeout}`, `${taskArgs.cooldown}`, `${taskArgs.expiration}`, `${taskArgs.bond}`, taskArgs.template
]
})
});

task("createDaoTemplate", "Creates a question template on the oracle address")
.addParam("oracle", "Address of the oracle (e.g. Realitio)", undefined, types.string)
.addParam("oracle", "Address of the oracle (e.g. RealitioV3)", undefined, types.string)
.addParam(
"template",
"Template string for question (should include placeholders for proposal id and txs hash)",
Expand All @@ -116,7 +125,7 @@ task("createDaoTemplate", "Creates a question template on the oracle address")
.setAction(async (taskArgs, hardhatRuntime) => {
const [caller] = await hardhatRuntime.ethers.getSigners();
console.log("Using the account:", caller.address);
const oracle = await hardhatRuntime.ethers.getContractAt("Realitio", taskArgs.oracle);
const oracle = await hardhatRuntime.ethers.getContractAt("RealitioV3", taskArgs.oracle);
const receipt = await oracle.createTemplate(taskArgs.template).then((tx: any) => tx.wait());
const id = receipt.logs[0].topics[1]
console.log("Template id:", id);
Expand Down
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -509,10 +509,10 @@
resolved "https://registry.yarnpkg.com/@gnosis.pm/safe-contracts/-/safe-contracts-1.3.0.tgz#316741a7690d8751a1f701538cfc9ec80866eedc"
integrity sha512-1p+1HwGvxGUVzVkFjNzglwHrLNA67U/axP0Ct85FzzH8yhGJb4t9jDjPYocVMzLorDoWAfKicGy1akPY9jXRVw==

"@gnosis.pm/zodiac@0.0.1-prealpha1":
version "0.0.1-prealpha1"
resolved "https://registry.yarnpkg.com/@gnosis.pm/zodiac/-/zodiac-0.0.1-prealpha1.tgz#02adcbd4d7c11aeffd01304bf7668e5e37fe18f4"
integrity sha512-SGi6TBCPribYH8++ooXDIPKbA/f/XY7yC3zPRXu3jNnjTGXGEj9Zv8RJUppc6GQgLL1a13Z6aALcRyMNGFbagQ==
"@gnosis.pm/zodiac@0.0.1-prealpha7":
version "0.0.1-prealpha7"
resolved "https://registry.yarnpkg.com/@gnosis.pm/zodiac/-/zodiac-0.0.1-prealpha7.tgz#0e648e45ca71cbe34fcc25e4c49332570c21d48b"
integrity sha512-BPgND+dozu3c0g0Tijm/DbYC/Xo51/EQHnCMN8yK1glogsM13BEkto8dshzTxXgwrRRyv6X46CGPLeNg7D56zQ==
dependencies:
"@gnosis.pm/mock-contract" "^4.0.0"
"@gnosis.pm/safe-contracts" "1.3.0"
Expand Down

0 comments on commit 5497649

Please sign in to comment.