Skip to content

Commit

Permalink
added Organization.globalConstraints (#33)
Browse files Browse the repository at this point in the history
* Remove all wallet functionality

* added Organization.globalConstraints

* remove migrateContracs.initialize from travis script

* add migrateContracts.fetchFromArc to travis build

* little improvement to the test

* added Organization.globalConstraints

* remove migrateContracs.initialize from travis script

* add migrateContracts.fetchFromArc to travis build

* little improvement to the test

* changes to comments

* fixed name of test
  • Loading branch information
dkent600 authored Jan 19, 2018
1 parent 9717d2a commit 49eef96
Show file tree
Hide file tree
Showing 8 changed files with 192 additions and 55 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ before_install:

install:
- npm install
- npm start migrateContracts.initialize
- nohup npm start test.ganache.run &
- npm start migrateContracts.fetchFromArc
- npm start migrateContracts

script:
Expand Down
18 changes: 18 additions & 0 deletions lib/arc.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,15 @@ declare module "daostack-arc-js" {
permissions: string;
}

/********************************
* Returned from Organization.globalConstraints
*/
export interface OrganizationGlobalConstraintInfo {
name: string;
address: string;
paramsHash: string;
}

/********************************
* Organization
*/
Expand All @@ -218,7 +227,16 @@ declare module "daostack-arc-js" {
*/
votingMachine: any;

/**
* returns schemes currently registered into this DAO, as Array<OrganizationSchemeInfo>
* @param contractName like "SchemeRegistrar"
*/
schemes(contractName?: string): Promise<Array<OrganizationSchemeInfo>>;
/**
* Returns global constraints currently registered into this DAO, as Array<OrganizationGlobalConstraintInfo>
* @param contractName like "TokenCapGC"
*/
globalConstraints(contractName?: string): Promise<Array<OrganizationGlobalConstraintInfo>>;
/**
* Returns promise of a scheme as ExtendTruffleScheme, or ? if not found
* @param contract name of scheme, like "SchemeRegistrar"
Expand Down
104 changes: 98 additions & 6 deletions lib/organization.js
Original file line number Diff line number Diff line change
Expand Up @@ -145,17 +145,15 @@ export class Organization {
}

/**
* returns
* @param name linke "SchemeRegistrar"
* returns schemes currently registered into this Organization, as Array<OrganizationSchemeInfo>
* @param name like "SchemeRegistrar"
*/
async schemes(name) {
// return the schemes registered on this controller satisfying the contract spec
// return all schems if contract is not given
// return all schemes if contract is not given
const schemes = await this._getSchemes();
if (name) {
return schemes.filter(s => {
return s.name === name;
});
return schemes.filter(s => s.name === name);
} else {
return schemes;
}
Expand Down Expand Up @@ -236,6 +234,7 @@ export class Organization {
name: arcTypesMap.get(schemeAddress)
};

// dedup
schemesMap.set(schemeAddress, schemeInfo);
}
}
Expand Down Expand Up @@ -273,4 +272,97 @@ export class Organization {
// NB: this will not work for proposals using votingMachine's that are not the default one
return this.votingMachine.vote(proposalId, choice, params);
}

/**
* Returns global constraints currently registered into this Organization, as Array<OrganizationGlobalConstraintInfo>
* @param name like "TokenCapGC"
*/
async globalConstraints(name) {
// return the global constraints registered on this controller satisfying the contract spec
// return all global constraints if name is not given
const constraints = await this._getConstraints();
if (name) {
return constraints.filter(s => s.name === name);
} else {
return constraints;
}
}

/**
* returns global constraints currently in this Organization, as OrganizationGlobalConstraintInfo
*/
async _getConstraints() {
// TODO: this is *expensive*, we need to cache the results (and perhaps poll for latest changes if necessary)
const constraintsMap = new Map(); // <string, OrganizationGlobalConstraintInfo>
const controller = this.controller;
const avatar = this.avatar;
const arcTypesMap = new Map(); // <address: string, name: string>
const contracts = await getDeployedContracts();

/**
* TODO: This should pull in all known versions of the constraints, names
* and versions in one fell swoop.
*/
for (const name in contracts.allContracts) {
const contract = contracts.allContracts[name];
arcTypesMap.set(contract.address, name);
}

const event = controller.AddGlobalConstraint(
{},
{ fromBlock: 0, toBlock: "latest" }
);

await new Promise(resolve => {
event.get((err, eventsArray) =>
this._handleConstraintEvent(
err,
eventsArray,
true,
arcTypesMap,
constraintsMap
).then(() => {
event.stopWatching();
resolve();
})
);
});

const registeredConstraints = [];

for (const gc of constraintsMap.values()) {
if (await controller.isGlobalConstraintRegister(gc.address, avatar.address)) {
registeredConstraints.push(gc);
}
}

return registeredConstraints;
}

async _handleConstraintEvent(
err,
eventsArray,
adding,
arcTypesMap,
constraintsMap // : Promise<void>
) {
if (!(eventsArray instanceof Array)) {
eventsArray = [eventsArray];
}
const count = eventsArray.length;
for (let i = 0; i < count; i++) {
const address = eventsArray[i].args._globalconstraint;
const paramsHash = eventsArray[i].args._params;

const info = {
address: address,
paramsHash: paramsHash,
// will be undefined if not a known scheme
name: arcTypesMap.get(address)
};

// dedup
constraintsMap.set(address, info);
}
}
}
6 changes: 1 addition & 5 deletions package-lock.json

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

29 changes: 9 additions & 20 deletions package-scripts.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,10 @@ module.exports = {
),
clean: rimraf(pathDaostackArcGanacheDb),
zip: `node ./package-scripts/archiveGanacheDb.js ${pathDaostackArcGanacheDbZip} ${pathDaostackArcGanacheDb}`,
unzip: `node ./package-scripts/unArchiveGanacheDb.js ${pathDaostackArcGanacheDbZip} ${pathArcJsRoot}`,
unzip: series(
"nps test.ganacheDb.clean",
`node ./package-scripts/unArchiveGanacheDb.js ${pathDaostackArcGanacheDbZip} ${pathArcJsRoot}`
),
restoreFromZip: series(
"nps test.ganacheDb.clean",
"nps test.ganacheDb.unzip"
Expand All @@ -114,11 +117,7 @@ module.exports = {
*
* Typical workflow for migrating to ganache (Ganache):
*
* You only need to ever call this once:
*
* npm start migrateContracts.initialize
*
* Then fire up ganache (Ganache) in a separate window.
* Fire up ganache (Ganache) in a separate window.
*
* npm start test.ganache.runAsync
*
Expand All @@ -145,23 +144,12 @@ module.exports = {
* (see "Arc Configuration" in the root readme.md)
*/
migrateContracts: {
/**
* If you want to do migrations, run migrateContracts.initialize first.
* Same goes for applications that are depending on this.
* You only need to call it once. Thereafter you can run
* migrateContracts all you want without calling migrateContracts.initialize again.
*/
initialize: series(
"npm install daostack-arc --save-dev", // only needed for applications, and only to pull in its contract json files
"nps migrateContracts.clean",
"nps migrateContracts.fetchFromArc"
),
/**
* Migrate contracts.
*
* Assumes you have at some previous time run migrationContracts.initialize.
*
* Truffle will merge this migration with whatever previous ones are already present in the contract json files.
*
* Run migrateContracts.fetchFromArc first if you want to start with fresh unmigrated contracts from daostack-arc.
*/
default: `${truffleCommand} migrate --contracts_build_directory ${pathArcJsContracts} --without-compile ${network ? `--network ${network}` : "ganache"}`,
/**
Expand All @@ -177,7 +165,8 @@ module.exports = {
andMigrate: series("nps migrateContracts.clean", "nps migrateContracts.fetchFromArc", "nps migrateContracts")
},
/**
* fetch the unmigrated contract json files from DAOstack-Arc
* Fetch the unmigrated contract json files from DAOstack-Arc.
* Run this only when we want to start with fresh unmigrated contracts from daostack-arc.
*/
fetchFromArc: copy(`${joinPath(pathDaostackArcRepo, "build", "contracts", "*")} ${pathArcJsContracts}`)
}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "daostack-arc-js",
"version": "0.0.0-alpha.11",
"version": "0.0.0-alpha.13",
"description": "A JavaScript library for interacting with daostack-arc ethereum smart contracts",
"main": "dist/arc.js",
"types": "lib/arc.d.ts",
Expand Down
22 changes: 0 additions & 22 deletions test/globalconstraintregistrar.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,29 +38,8 @@ describe("GlobalConstraintRegistrar", () => {
globalConstraintParametersHash: globalConstraintParametersHash,
votingMachineHash: votingMachineHash
});

// const proposalId = getValueFromLogs(tx, '_proposalId');

// console.log(`****** proposal ID ${proposalId} ******`);
});

// it("proposeToRemoveGlobalConstraint javascript wrapper should not crash", async function() {
// const organization = await helpers.forgeOrganization();

// let tokenCapGC = await organization.scheme('TokenCapGC');

// let globalConstraintRegistrar = await organization.scheme('GlobalConstraintRegistrar');

// await globalConstraintRegistrar.proposeToRemoveGlobalConstraint({
// avatar: organization.avatar.address,
// globalConstraint: tokenCapGC.address
// });

// // const proposalId = getValueFromLogs(tx, '_proposalId');

// // console.log(`****** proposal ID ${proposalId} ******`);
// });

it("should register and enforce a global constraint", async () => {
const organization = await helpers.forgeOrganization();

Expand Down Expand Up @@ -93,7 +72,6 @@ describe("GlobalConstraintRegistrar", () => {

const proposalId = getValueFromLogs(tx, "_proposalId");

// console.log(`****** proposal ID ${proposalId} ******`);

// serveral users now cast their vote
await organization.vote(proposalId, 1, { from: web3.eth.accounts[0] });
Expand Down
64 changes: 64 additions & 0 deletions test/organization.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Organization } from "../lib/organization.js";
import * as helpers from "./helpers";
import { proposeContributionReward } from "./contributionreward.js";
import { getValueFromLogs } from "../lib/utils.js";

describe("Organization", () => {
let organization;
Expand Down Expand Up @@ -76,4 +77,67 @@ describe("Organization", () => {

assert.equal((await organization.schemes()).length, 4);
});

it("has a working globalConstraints() function to access its constraints", async () => {
const org = await helpers.forgeOrganization();

assert.equal((await org.globalConstraints()).length, 0);
assert.equal((await org.controller.globalConstraintsCount(org.avatar.address)).toNumber(), 0);

const tokenCapGC = await org.scheme("TokenCapGC");

const globalConstraintParametersHash = await tokenCapGC.getParametersHash(
org.token.address,
3141
);
await tokenCapGC.setParameters(org.token.address, 3141);

const votingMachineHash = await org.votingMachine.getParametersHash(
org.reputation.address,
50,
true
);

await org.votingMachine.setParameters(
org.reputation.address,
50,
true
);

const globalConstraintRegistrar = await org.scheme("GlobalConstraintRegistrar");

let tx = await globalConstraintRegistrar.proposeToAddModifyGlobalConstraint({
avatar: org.avatar.address,
globalConstraint: tokenCapGC.address,
globalConstraintParametersHash: globalConstraintParametersHash,
votingMachineHash: votingMachineHash
}
);

let proposalId = getValueFromLogs(tx, "_proposalId");
// several users now cast their vote
await org.vote(proposalId, 1, { from: web3.eth.accounts[0] });
// next is decisive vote: the proposal will be executed
await org.vote(proposalId, 1, { from: web3.eth.accounts[2] });

const gcs = await org.globalConstraints();
assert.equal(gcs.length, 1);
assert.equal(gcs[0].address, tokenCapGC.address);
assert.equal((await org.controller.globalConstraintsCount(org.avatar.address)).toNumber(), 1);

tx = await globalConstraintRegistrar.proposeToRemoveGlobalConstraint({
avatar: org.avatar.address,
globalConstraint: tokenCapGC.address
}
);

proposalId = getValueFromLogs(tx, "_proposalId");
// several users now cast their vote
await org.vote(proposalId, 1, { from: web3.eth.accounts[0] });
// next is decisive vote: the proposal will be executed
await org.vote(proposalId, 1, { from: web3.eth.accounts[2] });

assert.equal((await org.globalConstraints()).length, 0);
assert.equal((await org.controller.globalConstraintsCount(org.avatar.address)).toNumber(), 0);
});
});

0 comments on commit 49eef96

Please sign in to comment.