From bd478848e7713bc98c4bf361615b9601bd2d0a55 Mon Sep 17 00:00:00 2001 From: Oren Sokolowsky Date: Tue, 30 Apr 2019 15:39:25 +0300 Subject: [PATCH 1/2] indexed only dao with indexed avatar --- ops/mappings.json | 12 +++ src/mappings/Avatar/datasource.yaml | 2 + src/mappings/Avatar/mapping.ts | 21 ++--- src/mappings/Controller/mapping.ts | 25 +++--- src/mappings/UController/mapping.ts | 27 ++++--- test/integration/Reputation.spec.ts | 53 +++++++++++-- test/integration/Subscription.spec.ts | 42 +++++++++- test/integration/SubscriptionLoop.spec.ts | 47 +++++++++++- test/integration/UController.spec.ts | 93 +++++++++++++++-------- 9 files changed, 245 insertions(+), 77 deletions(-) diff --git a/ops/mappings.json b/ops/mappings.json index 01f9803f..7bf253d7 100644 --- a/ops/mappings.json +++ b/ops/mappings.json @@ -26,6 +26,12 @@ "dao": "test", "mapping": "DAOToken" }, + { + "name": "Avatar", + "contractName": "Avatar", + "dao": "test", + "mapping": "Avatar" + }, { "name": "Reputation", "contractName": "Reputation", @@ -44,6 +50,12 @@ "dao": "organs", "mapping": "DAOToken" }, + { + "name": "Avatar", + "contractName": "DemoAvatar", + "dao": "organs", + "mapping": "Avatar" + }, { "name": "Reputation", "contractName": "Reputation", diff --git a/src/mappings/Avatar/datasource.yaml b/src/mappings/Avatar/datasource.yaml index 5f9ac54f..cf2b4f2b 100644 --- a/src/mappings/Avatar/datasource.yaml +++ b/src/mappings/Avatar/datasource.yaml @@ -5,3 +5,5 @@ eventHandlers: handler: handleSendEth - event: ReceiveEther(address,uint256) handler: handleReceiveEth + - event: OwnershipTransferred(address,address) + handler: handleOwnershipTransferred diff --git a/src/mappings/Avatar/mapping.ts b/src/mappings/Avatar/mapping.ts index a0c15ba4..787b6959 100644 --- a/src/mappings/Avatar/mapping.ts +++ b/src/mappings/Avatar/mapping.ts @@ -2,8 +2,8 @@ import 'allocator/arena'; import { Address, BigInt, store } from '@graphprotocol/graph-ts'; -// Import event types from the Token contract ABI -import { Avatar, ReceiveEther, SendEther } from '../../types/Avatar/Avatar'; +// Import event types from the Avatar contract ABI +import { Avatar, OwnershipTransferred, ReceiveEther, SendEther } from '../../types/Avatar/Avatar'; // Import entity types generated from the GraphQL schema import { AvatarContract } from '../../types/schema'; @@ -13,17 +13,10 @@ function handleAvatarBalance( value: BigInt, received: boolean, ): void { - let avatarSC = Avatar.bind(address); let avatar = store.get('AvatarContract', address.toHex()) as AvatarContract; if (avatar == null) { - avatar = new AvatarContract(address.toHex()); - avatar.address = address; - avatar.name = avatarSC.orgName(); - avatar.nativeReputation = avatarSC.nativeReputation(); - avatar.nativeToken = avatarSC.nativeToken(); - avatar.owner = avatarSC.owner(); - avatar.balance = BigInt.fromI32(0); + return; } if (received) { @@ -41,3 +34,11 @@ export function handleSendEth(event: SendEther): void { export function handleReceiveEth(event: ReceiveEther): void { handleAvatarBalance(event.address, event.params._value, true); } +export function handleOwnershipTransferred(event: OwnershipTransferred): void { + let avatar = AvatarContract.load(event.address.toHex()); + if (avatar == null) { + avatar = new AvatarContract(event.address.toHex()); + } + avatar.owner = event.params.newOwner; + avatar.save(); +} diff --git a/src/mappings/Controller/mapping.ts b/src/mappings/Controller/mapping.ts index c22aa8e2..12a86acf 100644 --- a/src/mappings/Controller/mapping.ts +++ b/src/mappings/Controller/mapping.ts @@ -76,6 +76,7 @@ function insertOrganization( controllerAddress: Address, avatarAddress: Address, ): void { + let controller = Controller.bind(controllerAddress); let reputation = controller.nativeReputation(); @@ -100,16 +101,16 @@ function insertOrganization( ent.nativeReputation = reputation.toHex(); ent.controller = controllerAddress; - let avatarSC = Avatar.bind(avatarAddress); - let avatar = new AvatarContract(avatarAddress.toHex()); - avatar.address = avatarAddress; - avatar.name = avatarSC.orgName(); - avatar.nativeReputation = avatarSC.nativeReputation(); - avatar.nativeToken = avatarSC.nativeToken(); - avatar.owner = avatarSC.owner(); - avatar.balance = BigInt.fromI32(0); - store.set('AvatarContract', avatar.id, avatar); - + let avatar = AvatarContract.load(avatarAddress.toHex()); + if (avatar != null) { + let avatarSC = Avatar.bind(avatarAddress); + avatar.address = avatarAddress; + avatar.name = avatarSC.orgName(); + avatar.nativeReputation = avatarSC.nativeReputation(); + avatar.nativeToken = avatarSC.nativeToken(); + avatar.balance = BigInt.fromI32(0); + store.set('AvatarContract', avatar.id, avatar as AvatarContract); + } store.set('ControllerOrganization', ent.id, ent); } @@ -160,6 +161,10 @@ function deleteGlobalConstraint( export function handleRegisterScheme(event: RegisterScheme): void { let controller = Controller.bind(event.address); let avatar = controller.avatar(); + + if (AvatarContract.load(avatar.toHex()) == null) { + return; + } let token = controller.nativeToken(); let reputation = controller.nativeReputation(); domain.handleRegisterScheme(avatar, token, reputation); diff --git a/src/mappings/UController/mapping.ts b/src/mappings/UController/mapping.ts index 18d742ef..0ad3ad32 100644 --- a/src/mappings/UController/mapping.ts +++ b/src/mappings/UController/mapping.ts @@ -71,6 +71,7 @@ function insertOrganization( uControllerAddress: Address, avatarAddress: Address, ): void { + let uController = UController.bind(uControllerAddress); let org = uController.organizations(avatarAddress); @@ -87,22 +88,22 @@ function insertOrganization( tokenContract.owner = uControllerAddress; store.set('TokenContract', tokenContract.id, tokenContract); + let avatar = AvatarContract.load(avatarAddress.toHex()); + if (avatar != null) { + let avatarSC = Avatar.bind(avatarAddress); + avatar.address = avatarAddress; + avatar.name = avatarSC.orgName(); + avatar.nativeReputation = avatarSC.nativeReputation(); + avatar.nativeToken = avatarSC.nativeToken(); + avatar.balance = BigInt.fromI32(0); + store.set('AvatarContract', avatar.id, avatar as AvatarContract); + } + let ent = new UControllerOrganization(avatarAddress.toHex()); ent.avatarAddress = avatarAddress; ent.nativeToken = org.value0.toHex(); ent.nativeReputation = org.value1.toHex(); ent.controller = uControllerAddress; - - let avatarSC = Avatar.bind(avatarAddress); - let avatar = new AvatarContract(avatarAddress.toHex()); - avatar.address = avatarAddress; - avatar.name = avatarSC.orgName(); - avatar.nativeReputation = avatarSC.nativeReputation(); - avatar.nativeToken = avatarSC.nativeToken(); - avatar.owner = avatarSC.owner(); - avatar.balance = BigInt.fromI32(0); - store.set('AvatarContract', avatar.id, avatar); - store.set('UControllerOrganization', ent.id, ent); } @@ -153,6 +154,10 @@ function deleteGlobalConstraint( export function handleRegisterScheme(event: RegisterScheme): void { let uController = UController.bind(event.address); + if (AvatarContract.load(event.params._avatar.toHex()) == null) { + return; + } + let org = uController.organizations(event.params._avatar); domain.handleRegisterScheme(event.params._avatar, org.value0 , org.value1); diff --git a/test/integration/Reputation.spec.ts b/test/integration/Reputation.spec.ts index a8ca9d58..f9f2aaa1 100644 --- a/test/integration/Reputation.spec.ts +++ b/test/integration/Reputation.spec.ts @@ -2,21 +2,58 @@ import { getContractAddresses, getOptions, getWeb3, sendQuery } from './util'; const Reputation = require('@daostack/arc/build/contracts/Reputation.json'); const UController = require('@daostack/arc/build/contracts/UController.json'); +const Avatar = require('@daostack/arc/build/contracts/Avatar.json'); +const DAOToken = require('@daostack/arc/build/contracts/DAOToken.json'); describe('Reputation', () => { let web3; let addresses; let reputation; + let opts; + let uController; + let daoToken; + let accounts; beforeAll(async () => { web3 = await getWeb3(); addresses = getContractAddresses(); - const opts = await getOptions(web3); + opts = await getOptions(web3); + accounts = web3.eth.accounts.wallet; + uController = new web3.eth.Contract( + UController.abi, + addresses.UController, + opts, + ); reputation = new web3.eth.Contract( Reputation.abi, addresses.DemoReputation, opts, ); + daoToken = new web3.eth.Contract( + DAOToken.abi, + addresses.DemoDAOToken, + opts, + ); + const avatar = new web3.eth.Contract( + Avatar.abi, + addresses.DemoAvatar, + opts, + ); + + if (await avatar.methods.owner().call() === accounts[0].address) { + await avatar.methods.transferOwnership(uController.options.address).send({from: accounts[0].address}); + + } + if (await reputation.methods.owner().call() === accounts[0].address) { + await reputation.methods.transferOwnership(uController.options.address).send(); + } + if (await daoToken.methods.owner().call() === accounts[0].address) { + await daoToken.methods.transferOwnership(uController.options.address).send(); + } + let organs = await uController.methods.organizations(avatar.options.address).call(); + if (organs[0] !== daoToken.options.address) { + await uController.methods.newOrganization(avatar.options.address).send(); + } }); async function checkTotalSupply(value) { @@ -33,23 +70,23 @@ describe('Reputation', () => { } it('Sanity', async () => { - const accounts = web3.eth.accounts.wallet; let txs = []; - txs.push(await reputation.methods.mint(accounts[0].address, '100').send()); + txs.push(await uController.methods.mintReputation(100, accounts[0].address, addresses.DemoAvatar) + .send({from : accounts[0].address})); await checkTotalSupply(100); - txs.push(await reputation.methods.mint(accounts[1].address, '100').send()); + txs.push(await uController.methods.mintReputation('100' , accounts[1].address, addresses.DemoAvatar).send()); await checkTotalSupply(200); - txs.push(await reputation.methods.burn(accounts[0].address, '30').send()); + txs.push(await uController.methods.burnReputation('30', accounts[0].address, addresses.DemoAvatar).send()); await checkTotalSupply(170); - txs.push(await reputation.methods.mint(accounts[2].address, '300').send()); + txs.push(await uController.methods.mintReputation('300', accounts[2].address, addresses.DemoAvatar).send()); await checkTotalSupply(470); - txs.push(await reputation.methods.burn(accounts[1].address, '100').send()); + txs.push(await uController.methods.burnReputation('100' , accounts[1].address, addresses.DemoAvatar).send()); await checkTotalSupply(370); - txs.push(await reputation.methods.burn(accounts[2].address, '1').send()); + txs.push(await uController.methods.burnReputation( '1', accounts[2].address, addresses.DemoAvatar).send()); await checkTotalSupply(369); txs = txs.map(({ transactionHash }) => transactionHash); diff --git a/test/integration/Subscription.spec.ts b/test/integration/Subscription.spec.ts index 6a56ab8b..d66e525a 100644 --- a/test/integration/Subscription.spec.ts +++ b/test/integration/Subscription.spec.ts @@ -7,6 +7,9 @@ import { } from './util'; const Reputation = require('@daostack/arc/build/contracts/Reputation.json'); +const UController = require('@daostack/arc/build/contracts/UController.json'); +const Avatar = require('@daostack/arc/build/contracts/Avatar.json'); +const DAOToken = require('@daostack/arc/build/contracts/DAOToken.json'); const gql = require('graphql-tag'); describe('Subscriptions', () => { @@ -14,18 +17,51 @@ describe('Subscriptions', () => { let addresses; let opts; let reputation; + let uController; + let accounts; beforeAll(async () => { web3 = await getWeb3(); addresses = getContractAddresses(); opts = await getOptions(web3); + accounts = web3.eth.accounts.wallet; + + uController = new web3.eth.Contract( + UController.abi, + addresses.UController, + opts, + ); reputation = new web3.eth.Contract( Reputation.abi, addresses.DemoReputation, opts, ); + const daoToken = new web3.eth.Contract( + DAOToken.abi, + addresses.DemoDAOToken, + opts, + ); + const avatar = new web3.eth.Contract( + Avatar.abi, + addresses.DemoAvatar, + opts, + ); + + if (await avatar.methods.owner().call() === accounts[0].address) { + await avatar.methods.transferOwnership(uController.options.address).send({from: accounts[0].address}); + + } + if (await reputation.methods.owner().call() === accounts[0].address) { + await reputation.methods.transferOwnership(uController.options.address).send(); + } + if (await daoToken.methods.owner().call() === accounts[0].address) { + await daoToken.methods.transferOwnership(uController.options.address).send(); + } + let organs = await uController.methods.organizations(avatar.options.address).call(); + if (organs[0] !== daoToken.options.address) { + await uController.methods.newOrganization(avatar.options.address).send(); + } }); it('Run one subscription and test for updates', async () => { - const accounts = web3.eth.accounts.wallet; const SUBSCRIBE_QUERY = gql` subscription { reputationMints { @@ -53,8 +89,8 @@ describe('Subscriptions', () => { expect(true).toEqual(false); }, ); - - await reputation.methods.mint(accounts[4].address, '99').send(); + await uController.methods.mintReputation('99', accounts[4].address, addresses.DemoAvatar) + .send({from: accounts[0].address}); // wait until the subscription callback has been called await waitUntilTrue(() => nextWasCalled); diff --git a/test/integration/SubscriptionLoop.spec.ts b/test/integration/SubscriptionLoop.spec.ts index 0662d21d..b6999ade 100644 --- a/test/integration/SubscriptionLoop.spec.ts +++ b/test/integration/SubscriptionLoop.spec.ts @@ -7,6 +7,9 @@ import { } from './util'; const Reputation = require('@daostack/arc/build/contracts/Reputation.json'); +const UController = require('@daostack/arc/build/contracts/UController.json'); +const Avatar = require('@daostack/arc/build/contracts/Avatar.json'); +const DAOToken = require('@daostack/arc/build/contracts/DAOToken.json'); const gql = require('graphql-tag'); describe('Subscriptions Loop', () => { @@ -14,18 +17,56 @@ describe('Subscriptions Loop', () => { let addresses; let opts; let reputation; + let uController; + let accounts; beforeAll(async () => { web3 = await getWeb3(); addresses = getContractAddresses(); opts = await getOptions(web3); + accounts = web3.eth.accounts.wallet; + + reputation = new web3.eth.Contract( + Reputation.abi, + addresses.DemoReputation, + opts, + ); + uController = new web3.eth.Contract( + UController.abi, + addresses.UController, + opts, + ); reputation = new web3.eth.Contract( Reputation.abi, addresses.DemoReputation, opts, ); + const daoToken = new web3.eth.Contract( + DAOToken.abi, + addresses.DemoDAOToken, + opts, + ); + const avatar = new web3.eth.Contract( + Avatar.abi, + addresses.DemoAvatar, + opts, + ); + + if (await avatar.methods.owner().call() === accounts[0].address) { + await avatar.methods.transferOwnership(uController.options.address).send({from: accounts[0].address}); + + } + if (await reputation.methods.owner().call() === accounts[0].address) { + await reputation.methods.transferOwnership(uController.options.address).send(); + } + if (await daoToken.methods.owner().call() === accounts[0].address) { + await daoToken.methods.transferOwnership(uController.options.address).send(); + } + let organs = await uController.methods.organizations(avatar.options.address).call(); + if (organs[0] !== daoToken.options.address) { + await uController.methods.newOrganization(avatar.options.address).send(); + } }); it('Run 10 subscriptions and test for updates', async () => { - const accounts = web3.eth.accounts.wallet; const SUBSCRIBE_QUERY = gql` subscription { reputationMints { @@ -56,8 +97,8 @@ describe('Subscriptions Loop', () => { }, ); - await reputation.methods.mint(accounts[4].address, i.toString()).send(); - + await uController.methods.mintReputation(i.toString(), accounts[4].address, addresses.DemoAvatar) + .send({from: accounts[0].address}); // wait until the subscription callback has been called await waitUntilTrue(() => nextWasCalled); diff --git a/test/integration/UController.spec.ts b/test/integration/UController.spec.ts index 20819680..8c82d1cf 100644 --- a/test/integration/UController.spec.ts +++ b/test/integration/UController.spec.ts @@ -30,31 +30,25 @@ describe('UController', () => { addresses.UController, opts, ); - reputation = await new web3.eth.Contract(Reputation.abi, undefined, opts).deploy({ - data: Reputation.bytecode, - arguments: [], - }).send(); - - daoToken = await new web3.eth.Contract(DAOToken.abi, undefined, opts) - .deploy({ - data: DAOToken.bytecode, - arguments: ['TEST', 'TST', 1000000000], - }) - .send(); + reputation = new web3.eth.Contract( + Reputation.abi, + addresses.DemoReputation, + opts, + ); + daoToken = new web3.eth.Contract( + DAOToken.abi, + addresses.DemoDAOToken, + opts, + ); }); it('Sanity', async () => { const accounts = web3.eth.accounts.wallet; - const avatar = await new web3.eth.Contract(Avatar.abi, undefined, opts) - .deploy({ - data: Avatar.bytecode, - arguments: [ - 'Test', - daoToken.options.address, - reputation.options.address, - ], - }) - .send(); + const avatar = new web3.eth.Contract( + Avatar.abi, + addresses.DemoAvatar, + opts, + ); const tokenCap1 = await new web3.eth.Contract( TokenCapGC.abi, @@ -71,14 +65,27 @@ describe('UController', () => { ) .deploy({ data: TokenCapGC.bytecode, arguments: [] }) .send(); + if (await avatar.methods.owner().call() === accounts[0].address) { + await avatar.methods.transferOwnership(uController.options.address).send({from: accounts[0].address}); + + } + if (await reputation.methods.owner().call() === accounts[0].address) { + await reputation.methods.transferOwnership(uController.options.address).send(); + } + if (await daoToken.methods.owner().call() === accounts[0].address) { + await daoToken.methods.transferOwnership(uController.options.address).send(); + } - await avatar.methods.transferOwnership(uController.options.address).send(); - await reputation.methods.transferOwnership(uController.options.address).send(); - await daoToken.methods.transferOwnership(uController.options.address).send(); let txs = []; - txs.push( - await uController.methods.newOrganization(avatar.options.address).send(), - ); + let organs = await uController.methods.organizations(avatar.options.address).call(); + if (organs[0] !== daoToken.options.address) { + txs.push( + await uController.methods.newOrganization(avatar.options.address).send(), + ); + } else { + txs.push('0'); + } + txs.push( await uController.methods .registerScheme( @@ -89,6 +96,7 @@ describe('UController', () => { ) .send(), ); + txs.push( await uController.methods .addGlobalConstraint( @@ -98,6 +106,7 @@ describe('UController', () => { ) .send(), ); + txs.push( await uController.methods .registerScheme( @@ -108,6 +117,7 @@ describe('UController', () => { ) .send(), ); + txs.push( await uController.methods .addGlobalConstraint( @@ -117,11 +127,13 @@ describe('UController', () => { ) .send(), ); + txs.push( await uController.methods .unregisterScheme(accounts[3].address, avatar.options.address) .send(), ); + txs.push( await uController.methods .removeGlobalConstraint( @@ -130,6 +142,7 @@ describe('UController', () => { ) .send(), ); + txs = txs.map(({ transactionHash }) => transactionHash); const { ucontrollerRegisterSchemes } = await sendQuery(`{ @@ -142,8 +155,16 @@ describe('UController', () => { } }`); - expect(ucontrollerRegisterSchemes).toContainEqual({ - txHash: txs[0], + const getRegisterSchemes = `{ + ucontrollerRegisterSchemes { + controller, + contract, + avatarAddress, + scheme + } + }`; + + expect((await sendQuery(getRegisterSchemes)).ucontrollerRegisterSchemes).toContainEqual({ controller: uController.options.address.toLowerCase(), contract: accounts[0].address.toLowerCase(), avatarAddress: avatar.options.address.toLowerCase(), @@ -301,9 +322,15 @@ describe('UController', () => { type: 'Post', }); + let uController2 = await new web3.eth.Contract( + UController.abi, + undefined, + opts, + ).deploy({data: UController.bytecode, arguments: []}).send(); + txs.push( (await uController.methods - .upgradeController(accounts[4].address, avatar.options.address) + .upgradeController(uController2.options.address, avatar.options.address) .send()).transactionHash, ); @@ -320,7 +347,7 @@ describe('UController', () => { txHash: txs[7], controller: uController.options.address.toLowerCase(), avatarAddress: avatar.options.address.toLowerCase(), - newController: accounts[4].address.toLowerCase(), + newController: uController2.options.address.toLowerCase(), }); const { @@ -342,7 +369,9 @@ describe('UController', () => { avatarAddress: avatar.options.address.toLowerCase(), nativeToken: { address: daoToken.options.address.toLowerCase() }, nativeReputation: { address: reputation.options.address.toLowerCase() }, - controller: accounts[4].address.toLowerCase(), + controller: uController2.options.address.toLowerCase(), }); + await uController2.methods.newOrganization(avatar.options.address).send(); + await uController2.methods.upgradeController(uController.options.address, avatar.options.address).send(); }, 20000); }); From 1daf6d0ba9f9f3e319074809922ff00ff4e63a17 Mon Sep 17 00:00:00 2001 From: Oren Sokolowsky Date: Wed, 1 May 2019 10:16:51 +0300 Subject: [PATCH 2/2] test --- test/integration/UController.spec.ts | 37 ++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/test/integration/UController.spec.ts b/test/integration/UController.spec.ts index 8c82d1cf..7cc63cfb 100644 --- a/test/integration/UController.spec.ts +++ b/test/integration/UController.spec.ts @@ -371,6 +371,43 @@ describe('UController', () => { nativeReputation: { address: reputation.options.address.toLowerCase() }, controller: uController2.options.address.toLowerCase(), }); + + // verify that none indexed avatar will not create dao entity. + const testReputation = await new web3.eth.Contract(Reputation.abi, undefined, opts).deploy({ + data: Reputation.bytecode, + arguments: [], + }).send(); + + const testDaoToken = await new web3.eth.Contract(DAOToken.abi, undefined, opts) + .deploy({ + data: DAOToken.bytecode, + arguments: ['TEST', 'TST', 1000000000], + }) + .send(); + + const testAvatar = await new web3.eth.Contract(Avatar.abi, undefined, opts) + .deploy({ + data: Avatar.bytecode, + arguments: [ + 'testAvatar', + testDaoToken.options.address, + testReputation.options.address, + ], + }) + .send(); + + await testAvatar.methods.transferOwnership(uController.options.address).send(); + await testReputation.methods.transferOwnership(uController.options.address).send(); + await testDaoToken.methods.transferOwnership(uController.options.address).send(); + await uController.methods.newOrganization(testAvatar.options.address).send(); + + const { dao } = await sendQuery(`{ + dao(id: "${testAvatar.options.address.toLowerCase()}") { + id + } + }`); + + expect(dao).toBeNull(); await uController2.methods.newOrganization(avatar.options.address).send(); await uController2.methods.upgradeController(uController.options.address, avatar.options.address).send(); }, 20000);