Skip to content

DAOTracker Support #380

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

Merged
merged 40 commits into from
Nov 12, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
1518830
init
dOrgJelli Oct 29, 2019
4324736
testing next
dOrgJelli Nov 1, 2019
3ab8fbe
tests
dOrgJelli Nov 1, 2019
6f8a3ca
remove brainstorming doc
dOrgJelli Nov 1, 2019
c1f2855
fix
dOrgJelli Nov 1, 2019
0748136
fix
dOrgJelli Nov 1, 2019
26bb9e5
fix
dOrgJelli Nov 1, 2019
01c335b
fixes
dOrgJelli Nov 1, 2019
b27bde5
fix
dOrgJelli Nov 1, 2019
1a14687
:face_palm:
dOrgJelli Nov 1, 2019
c655571
fix
dOrgJelli Nov 1, 2019
a3635e1
fix
dOrgJelli Nov 1, 2019
7dc18a2
timeout
dOrgJelli Nov 1, 2019
1da76e8
found it
dOrgJelli Nov 1, 2019
7703a4a
fix
dOrgJelli Nov 1, 2019
a3acb0b
checking correct things
dOrgJelli Nov 1, 2019
8771ada
see if dao tracker is even a thing
dOrgJelli Nov 1, 2019
35c62d8
fix datasource.yaml
dOrgJelli Nov 1, 2019
730907b
.toLowerCase()
dOrgJelli Nov 1, 2019
0b826d5
fix
dOrgJelli Nov 1, 2019
21c7d3b
fix
dOrgJelli Nov 1, 2019
ab7135a
wait longer?
dOrgJelli Nov 1, 2019
9bed19a
feedback changes
dOrgJelli Nov 4, 2019
1fc11a8
updates based on feedback
dOrgJelli Nov 4, 2019
7614966
fixes
dOrgJelli Nov 4, 2019
2e8621a
change to 31 so tests pass
dOrgJelli Nov 4, 2019
b2d371b
fixed
dOrgJelli Nov 4, 2019
4e05317
fix lint
dOrgJelli Nov 4, 2019
85656bb
Merge branch 'master' into new-dao-indexing
dOrgJelli Nov 4, 2019
590c9d3
merge master
dOrgJelli Nov 11, 2019
3350d4c
new DAOtracker
dOrgJelli Nov 12, 2019
336a558
revert
dOrgJelli Nov 12, 2019
918ad72
fix?
dOrgJelli Nov 12, 2019
25cbf81
fix
dOrgJelli Nov 12, 2019
b43c982
ci pls work
dOrgJelli Nov 12, 2019
ea63c15
maybe this?
dOrgJelli Nov 12, 2019
98a82f9
DaoCreator only
dOrgJelli Nov 12, 2019
8599ecc
Hardcoded Blacklist
dOrgJelli Nov 12, 2019
5cb7cdf
revert
dOrgJelli Nov 12, 2019
6ef7316
fix lint
dOrgJelli Nov 12, 2019
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
32 changes: 31 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ In order to add support for a new contract follow these steps:
list of entities that are written by the the mapping.
3. [`eventHandlers`](https://github.com/graphprotocol/graph-node/blob/master/docs/subgraph-manifest.md#1522-eventhandler) -
map of solidity event signatures to event handlers in mapping code.
4. [`templates`]([https://](https://github.com/graphprotocol/graph-node/blob/master/docs/subgraph-manifest.md#17-dynamicdatasource)) - list of datasource mappings that are created by the mapping.
4. `test/integration/<contract name>.spec.ts`

3. Add your contract to `ops/mappings.json`. Under the JSON object for the network your contract is located at, under the `"mappings"` JSON array, add the following.
Expand Down Expand Up @@ -107,6 +106,24 @@ In order to add support for a new contract follow these steps:

To index a DAO please follow the instructions here: [https://github.com/daostack/subgraph/blob/master/documentations/Deployment.md#indexing-a-new-dao](https://github.com/daostack/subgraph/blob/master/documentations/Deployment.md#indexing-a-new-dao)

## Add a new datasource template

Datasource templates allow you to index blockchain data from addresses the subgraph finds out about at runtime. This is used to dynamically index newly deployed DAOs. To add a new contract ABI that can be used as a template within your mappings, modify the `ops/templates.json` file like so:

```json
{
"templates": [
...,
{
"name": "<contract name as appears in `abis/arcVersion` folder>",
"mapping": "<name of the `src/mappings/...` folder to be used with this contract>",
"start_arcVersion": "<contract arc version under which the abi is located in the `abis` folder>",
"end_arcVersion": "(optional) <contract arc version under which the abi is located in the `abis` folder> if not given, all future versions of this `name`'s contract ABI will be added as a template for this mapping"
}
]
}
```

## Deploy Subgraph

To deploy the subgraph, please follow the instructions below:
Expand Down Expand Up @@ -148,3 +165,16 @@ The docker images are available as:

`daostack/subgraph-postgres:${network}-${migration-version}-${subgraph-version}`
`daostack/subgraph-ipfs:${network}-${migration-version}-${subgraph-version}`

## Blacklist a malicious DAO
Add the DAO's Avatar address to the `ops/blacklist.json` file in the proper network array. For example, blacklisting `0xF7074b67B4B7830694a6f58Df06375F00365d2c2` on mainnet would look like:
```json
{
"private": [],
"kovan": [],
"rinkeby": [],
"mainnet": [
"0xF7074b67B4B7830694a6f58Df06375F00365d2c2"
]
}
```
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ services:
ipfs: 'ipfs:5001'
ethereum: 'private:http://ganache:8545'
GRAPH_IPFS_TIMEOUT: '2'
GRAPH_MAX_IPFS_FILE_BYTES: '120000'
GRAPH_MAX_IPFS_FILE_BYTES: '200000'
GRAPH_GRAPHQL_MAX_FIRST: '1000'
ipfs:
build: docker/ipfs
Expand Down
6 changes: 6 additions & 0 deletions ops/blacklist.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"private": [],
"kovan": [],
"rinkeby": [],
"mainnet": []
}
3 changes: 1 addition & 2 deletions ops/generate-abis.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
const fs = require("fs-extra");
const path = require("path");

/**
* Fetch all abis from @daostack/migration into the `abis` folder.
*/
async function generateAbis() {
fs.copy("node_modules/@daostack/migration/abis", "abis");
fs.copySync("node_modules/@daostack/migration/abis", `${__dirname}/../abis`);
}

if (require.main === module) {
Expand Down
28 changes: 24 additions & 4 deletions ops/generate-contractsinfo.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
const fs = require("fs");
const yaml = require("js-yaml");
const { migrationFileLocation: defaultMigrationFileLocation, network } = require("./settings");
const { forEachTemplate } = require("./utils");
const path = require("path");
const currentDir = path.resolve(`${__dirname}`)
const currentDir = path.resolve(`${__dirname}`);

/**
* Generate a `src/contractinfo.js` file from `migration.json`
Expand All @@ -20,8 +20,8 @@ async function generateContractInfo(opts={}) {
const migration = JSON.parse(fs.readFileSync(require.resolve(opts.migrationFile), "utf-8"));

let versions = migration[network].base
let buffer = "import { setContractInfo } from './utils';\n";
buffer += "// this code was generated automatically . please not edit it -:)\n";
let buffer = "import {\n setBlacklistedDAO,\n setContractInfo,\n setTemplateInfo,\n} from './utils';\n";
buffer += "\n// this code was generated automatically . please not edit it -:)\n";
buffer += "/* tslint:disable:max-line-length */\n";

buffer += "export function setContractsInfo(): void {\n";
Expand Down Expand Up @@ -53,6 +53,26 @@ async function generateContractInfo(opts={}) {
});
buffer += "}\n";

buffer += "\nexport function setTemplatesInfo(): void {\n";

forEachTemplate((name, mapping, arcVersion) => {
const templateName = arcVersion.replace(/\.|-/g, '_');
buffer += ` setTemplateInfo('${name}', '${arcVersion}', '${name}_${templateName}');\n`;
});

buffer += "}\n";

const blacklist = require("./blacklist.json")[network];

buffer += "\nexport function setBlacklistedDAOs(): void {\n";

blacklist.forEach(function(avatar) {
buffer += ` setBlacklistedDAO('${avatar.toLowerCase()}');\n`;
});

buffer += " return;\n";
buffer += "}\n";

fs.writeFileSync(
`${currentDir}/../src/contractsInfo.ts`,
buffer,
Expand Down
58 changes: 38 additions & 20 deletions ops/generate-subgraph.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const path = require("path")
const yaml = require("js-yaml");
const { migrationFileLocation: defaultMigrationFileLocation,
network ,startBlock} = require("./settings");
const { versionToNum, forEachTemplate } = require("./utils");
const mappings = require("./mappings.json")[network].mappings;
const { subgraphLocation: defaultSubgraphLocation } = require('./graph-cli')

Expand Down Expand Up @@ -38,10 +39,13 @@ async function generateSubgraph(opts={}) {
throw Error(`The following contracts are missing addresses: ${missing.toString()}`);
}

const templates = buildTemplates();

const subgraph = {
specVersion: "0.0.1",
schema: { file: "./schema.graphql" },
dataSources
dataSources,
templates
};

fs.writeFileSync(
Expand All @@ -55,19 +59,17 @@ function combineFragments(fragments, isTemplate, addresses, missingAddresses) {
let ids = [];
return fragments.map(mapping => {
const contract = mapping.name;
const version = mapping.arcVersion;
const fragment = `${__dirname}/../src/mappings/${mapping.mapping}/datasource.yaml`;
var abis, entities, eventHandlers, templates, file, yamlLoad, abi;
var abis, entities, eventHandlers, file, yamlLoad, abi;

if (fs.existsSync(fragment)) {
yamlLoad = yaml.safeLoad(fs.readFileSync(fragment, "utf-8"));
file = `${__dirname}/../src/mappings/${mapping.mapping}/mapping.ts`;
eventHandlers = yamlLoad.eventHandlers;
entities = yamlLoad.entities;
templates = yamlLoad.templates;
abis = (yamlLoad.abis || [contract]).map(contractName => {
const version = mapping.arcVersion;
const strlen = version.length
const versionNum = Number(version.slice(strlen - 2, strlen));
const versionNum = versionToNum(version);

if ((versionNum < 24) && (contractName === "UGenericScheme")) {
return {
Expand Down Expand Up @@ -95,17 +97,17 @@ function combineFragments(fragments, isTemplate, addresses, missingAddresses) {
if (mapping.dao === 'address') {
contractAddress = mapping.address;
} else if (mapping.dao === 'organs') {
contractAddress = addresses[network].test[mapping.arcVersion][mapping.dao][mapping.contractName];
contractAddress = addresses[network].test[version][mapping.dao][mapping.contractName];
} else {
contractAddress = addresses[network][mapping.dao][mapping.arcVersion][mapping.contractName];
contractAddress = addresses[network][mapping.dao][version][mapping.contractName];
}

// If the contract isn't predeployed
if (!contractAddress) {
// Keep track of contracts that're missing addresses.
// These contracts should have addresses because they're not
// templated contracts aren't used as templates
const daoContract = `${network}-${mapping.arcVersion}-${mapping.contractName}-${mapping.dao}`;
const daoContract = `${network}-${version}-${mapping.contractName}-${mapping.dao}`;
if (missingAddresses[daoContract] === undefined) {
missingAddresses[daoContract] = true;
}
Expand All @@ -131,6 +133,12 @@ function combineFragments(fragments, isTemplate, addresses, missingAddresses) {
return;
}

if (isTemplate) {
// convert name to be version specific
const classVersion = version.replace(/\.|-/g, '_');
name = `${name}_${classVersion}`
}

var result = {
kind: 'ethereum/contract',
name: `${name}`,
Expand All @@ -147,21 +155,31 @@ function combineFragments(fragments, isTemplate, addresses, missingAddresses) {
}
};

if (templates && templates.length) {
result.templates = combineFragments(
templates.map(template => ({
name: template,
mapping: template,
arcVersion: mapping.arcVersion
})),
true, addresses, missingAddresses
);
}

return result;
});
}

function buildTemplates() {
let results = [];

forEachTemplate((name, mapping, arcVersion) => {
results.push(
...combineFragments(
[{
name,
mapping,
arcVersion
}],
true,
undefined,
undefined
)
);
});

return results;
}

if (require.main === module) {
generateSubgraph().catch(err => {
console.log(err);
Expand Down
21 changes: 21 additions & 0 deletions ops/mappings.json
Original file line number Diff line number Diff line change
Expand Up @@ -610,6 +610,13 @@
"dao": "base",
"mapping": "Redeemer",
"arcVersion": "0.0.1-rc.32"
},
{
"name": "DAOTracker",
"contractName": "DAOTracker",
"dao": "base",
"mapping": "DAOTracker",
"arcVersion": "0.0.1-rc.32"
}
]
},
Expand Down Expand Up @@ -824,6 +831,13 @@
"dao": "base",
"mapping": "GenesisProtocol",
"arcVersion": "0.0.1-rc.24"
},
{
"name": "DAOTracker",
"contractName": "DAOTracker",
"dao": "base",
"mapping": "DAOTracker",
"arcVersion": "0.0.1-rc.32"
}
]
},
Expand Down Expand Up @@ -969,6 +983,13 @@
"dao": "base",
"mapping": "DAORegistry",
"arcVersion": "0.0.1-rc.30"
},
{
"name": "DAOTracker",
"contractName": "DAOTracker",
"dao": "base",
"mapping": "DAOTracker",
"arcVersion": "0.0.1-rc.32"
}
]
}
Expand Down
24 changes: 24 additions & 0 deletions ops/templates.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"templates": [
{
"name": "Avatar",
"mapping": "Avatar",
"start_arcVersion": "0.0.1-rc.16"
},
{
"name": "Controller",
"mapping": "Controller",
"start_arcVersion": "0.0.1-rc.16"
},
{
"name": "DAOToken",
"mapping": "DAOToken",
"start_arcVersion": "0.0.1-rc.16"
},
{
"name": "Reputation",
"mapping": "Reputation",
"start_arcVersion": "0.0.1-rc.16"
}
]
}
34 changes: 34 additions & 0 deletions ops/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
const fs = require("fs");

function versionToNum(version) {
const strlen = version.length;
return Number(version.slice(strlen - 2, strlen));
}

function forEachTemplate(callback) {
const templates = require("./templates.json").templates;
const abiDirectories = fs.readdirSync(`${__dirname}/../abis`, { withFileTypes: true })
.filter(dirent => dirent.isDirectory())
.map(dirent => dirent.name);

for (var template of templates) {
const { name, mapping, start_arcVersion, end_arcVersion } = template;
const startNum = versionToNum(start_arcVersion);
const endNum = end_arcVersion ? versionToNum(end_arcVersion) : undefined;

// for each ABI directory, if it falls within start & end
for (var abiDirectory of abiDirectories) {
const arcVersion = abiDirectory;
const arcNum = versionToNum(arcVersion);

if (arcNum >= startNum && (endNum === undefined || arcNum <= endNum)) {
callback(name, mapping, arcVersion);
}
}
}
}

module.exports = {
versionToNum,
forEachTemplate
}
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion src/domain/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Address, BigDecimal, BigInt, ByteArray, Bytes, crypto, Entity, store, Value} from '@graphprotocol/graph-ts';
import { setContractsInfo } from '../contractsInfo';
import { setContractsInfo, setTemplatesInfo } from '../contractsInfo';
import {
NewContributionProposal,
ProposalExecuted,
Expand Down Expand Up @@ -208,6 +208,7 @@ export function handleRegisterScheme(avatar: Address,
);
if (isFirstRegister == null) {
setContractsInfo();
setTemplatesInfo();
let dao = daoModule.insertNewDAO(avatar, nativeTokenAddress , nativeReputationAddress);
insertToken(hexToAddress(dao.nativeToken), avatar.toHex());
insertReputation(
Expand Down
5 changes: 5 additions & 0 deletions src/domain/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,11 @@ type ContractInfo @entity {
address: Bytes!
}

type TemplateInfo @entity {
id: ID!
templateName: String!
}

type Event @entity {
id: ID!
type: EventType!
Expand Down
8 changes: 8 additions & 0 deletions src/mappings/DAOTracker/datasource.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
abis:
- DAOTracker
entities:
- DAOTrackerContract
- BlacklistedDAO
eventHandlers:
- event: TrackDAO(indexed address,address,address,address,address,string)
handler: handleTrackDAO
Loading