From d0820511b45640fcdea551cc68775e403eaa46d8 Mon Sep 17 00:00:00 2001 From: S3bb1 Date: Tue, 25 Sep 2018 10:30:54 +0200 Subject: [PATCH 1/9] add remove consumer feature --- docs/contracts/base-contract.rst | 58 +++++++++++++++++++ .../base-contract/base-contract.spec.ts | 53 +++++++++++++++++ src/contracts/base-contract/base-contract.ts | 33 +++++++++++ 3 files changed, 144 insertions(+) diff --git a/docs/contracts/base-contract.rst b/docs/contracts/base-contract.rst index 5d769c74..d3144009 100644 --- a/docs/contracts/base-contract.rst +++ b/docs/contracts/base-contract.rst @@ -192,6 +192,64 @@ To check if an account is a member of a contract, the contract function ``isMemb // true +-------------------------------------------------------------------------------- + +.. _base-contract_removeFromContract: + +removeFromContract +================================================================================ + +.. code-block:: javascript + + baseContract.removeFromContract(businessCenterDomain, contract, accountId, idToBeRemoved); + +Remove user from contract. +To deny previously invited accounts to work with contract resources, they have to be removed as members from the contract. This function does exactly that. + + +---------- +Parameters +---------- + +#. ``businessCenterDomain`` - ``string`` : ENS domain name of the business center the contract was created in; use null when working without business center +#. ``contract`` - ``string`` : Ethereum id of the contract +#. ``accountId`` - ``string`` : account id of executing user +#. ``idToBeRemoved`` - ``string`` : account id which should be removed + +------- +Returns +------- + +``Promise`` returns ``void``: resolved when done + +------- +Example +------- + +.. code-block:: javascript + + const contractOwner = '0x0000000000000000000000000000000000000001'; + const idToBeRemoved = '0x0000000000000000000000000000000000000002'; + const businessCenterDomain = 'testbc.evan'; + const contract = loader.loadContract('BaseContractInterface', contractId); + await baseContract.removeFromContract( + businessCenterDomain, + contractId, + contractOwner, + idToBeRemoved, + ); + + +To check if an account is a member of a contract, the contract function ``isMember`` can be used: + +.. code-block:: typescript + + const isMember = await executor.executeContractCall(contract, 'isConsumer', idToBeRemoved); + console.log(isMember); + // Output: + // false + + -------------------------------------------------------------------------------- .. _base-contract_changeConsumerState: diff --git a/src/contracts/base-contract/base-contract.spec.ts b/src/contracts/base-contract/base-contract.spec.ts index 06f5bc0a..b092464e 100644 --- a/src/contracts/base-contract/base-contract.spec.ts +++ b/src/contracts/base-contract/base-contract.spec.ts @@ -126,6 +126,32 @@ describe('BaseContract', function() { expect(isMember).to.be.true; }); + it.only('can remove invited members to it by the owner', async () => { + const contractId = await baseContract.createUninitialized( + 'testdatacontract', + accounts[0], + businessCenterDomain); + const contract = loader.loadContract('BaseContractInterface', contractId); + let isMember = await executor.executeContractCall(contract, 'isConsumer', accounts[1]); + expect(isMember).to.be.false; + await baseContract.inviteToContract( + businessCenterDomain, + contractId, + accounts[0], + accounts[1], + ); + isMember = await executor.executeContractCall(contract, 'isConsumer', accounts[1]); + expect(isMember).to.be.true; + await baseContract.removeFromContract( + businessCenterDomain, + contractId, + accounts[0], + accounts[1], + ); + isMember = await executor.executeContractCall(contract, 'isConsumer', accounts[1]); + expect(isMember).to.be.false; + }); + it('cannot have new members invited to it by members that are not the owner ', async () => { const contractId = await baseContract.createUninitialized( 'testdatacontract', @@ -163,6 +189,7 @@ describe('BaseContract', function() { await expect(promise).to.be.rejected; }); + // intendend skip, tested but currently not activated it.skip('cannot have members invited, when the invitee doesn\'t know / ignores inviter', async () => { const contractId = await baseContract.createUninitialized( 'testdatacontract', @@ -253,6 +280,32 @@ describe('BaseContract', function() { expect(isMember).to.be.true; }); + it('can remove invited members to it by the owner', async () => { + const contractId = await baseContract.createUninitialized( + 'testdatacontract', + accounts[0], + null); + const contract = loader.loadContract('BaseContractInterface', contractId); + let isMember = await executor.executeContractCall(contract, 'isConsumer', accounts[1]); + expect(isMember).to.be.false; + await baseContract.inviteToContract( + null, + contractId, + accounts[0], + accounts[1], + ); + isMember = await executor.executeContractCall(contract, 'isConsumer', accounts[1]); + expect(isMember).to.be.true; + await baseContract.removeFromContract( + null, + contractId, + accounts[0], + accounts[1], + ); + isMember = await executor.executeContractCall(contract, 'isConsumer', accounts[1]); + expect(isMember).to.be.false; + }); + it('triggers contract events from on its own instead of letting the bc do this', async () => { return new Promise(async (resolve, reject) => { try { diff --git a/src/contracts/base-contract/base-contract.ts b/src/contracts/base-contract/base-contract.ts index 0f25305f..8b5c18df 100644 --- a/src/contracts/base-contract/base-contract.ts +++ b/src/contracts/base-contract/base-contract.ts @@ -211,4 +211,37 @@ export class BaseContract extends Logger { state, ); } + + /** + * remove user from contract + * + * @param {string} businessCenterDomain ENS domain name of the business center the + * contract was created in; use null when + * working without business center + * @param {string} contract Ethereum id of the contract + * @param {string} accountId account id of executing user + * @param {string} idToBeRemoved account id which should be removed + * @return {Promise} resolved when done + */ + public async removeFromContract( + businessCenterDomain: string, + contract: string, + accountId: string, + idToBeRemoved: string): Promise { + const baseContractInterface = (typeof contract === 'object') ? + contract : this.options.loader.loadContract('BaseContractInterface', contract); + let businessCenterAddress; + if (businessCenterDomain) { + businessCenterAddress = await this.options.nameResolver.getAddress(businessCenterDomain); + } else { + businessCenterAddress = '0x0000000000000000000000000000000000000000'; + } + await this.options.executor.executeContractTransaction( + baseContractInterface, + 'removeConsumer', + { from: accountId, autoGas: 1.1, }, + idToBeRemoved, + businessCenterAddress + ); + } } From 3f7b4be78a6c34844aa450b19b16fdb1ccd57b79 Mon Sep 17 00:00:00 2001 From: wulfraem Date: Mon, 1 Oct 2018 09:50:51 +0200 Subject: [PATCH 2/9] code cleanup --- src/contracts/base-contract/base-contract.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/contracts/base-contract/base-contract.ts b/src/contracts/base-contract/base-contract.ts index 0f25305f..a1cfc07b 100644 --- a/src/contracts/base-contract/base-contract.ts +++ b/src/contracts/base-contract/base-contract.ts @@ -164,7 +164,7 @@ export class BaseContract extends Logger { 'inviteConsumer', { from: inviterId, autoGas: 1.1, }, inviteeId, - businessCenterAddress + businessCenterAddress, ); } From 34f788b1af420308c1e5f6b3b0c43de430567fec Mon Sep 17 00:00:00 2001 From: wulfraem Date: Tue, 2 Oct 2018 14:13:58 +0200 Subject: [PATCH 3/9] fix `ipld` deleting issue, that occurred when deleting linked nodes in linked subtrees --- VERSIONS.md | 3 + src/dfs/ipld.spec.ts | 193 ++++++++++++++++++++++++++++++++++++++++++- src/dfs/ipld.ts | 14 +++- 3 files changed, 206 insertions(+), 4 deletions(-) diff --git a/VERSIONS.md b/VERSIONS.md index c22d5d4b..8b30a049 100644 --- a/VERSIONS.md +++ b/VERSIONS.md @@ -3,8 +3,11 @@ ## Next Version ### Features ### Fixes +- fix `ipld` deleting issue, that occurred when deleting linked nodes in linked subtrees + ### Deprecations + ## Version 1.2.2 ### Fixes - move require(`@evan.network/smart-contracts-core`) within `createDefaultRuntime` to capsuled scope, to be able to require it only in backend scope diff --git a/src/dfs/ipld.spec.ts b/src/dfs/ipld.spec.ts index 2095d971..44acc73b 100644 --- a/src/dfs/ipld.spec.ts +++ b/src/dfs/ipld.spec.ts @@ -477,7 +477,6 @@ describe('IPLD handler', function() { await createSampleGraph(); }); - it('can delete plain object properties in a simple tree', async () => { const expectedGraph = { gods: { @@ -586,6 +585,196 @@ describe('IPLD handler', function() { expect(loaded).not.to.be.undefined; Ipld.purgeCryptoInfo(loaded); expect(loaded).to.deep.eq(expectedGraph); - }) + }); + + it('can delete different properties inside subtrees', async () => { + const deletion = 'gods/eris/details/origin'; + const expectedGraph = { + gods: { + eris: { + '/': { + name: 'eris', + latinName: 'discordia', + details: { + '/': { + occupation: 'goddess of chaos', + }, + }, + }, + }, + }, + humans: { + helena: { + origin: 'troja', + }, + }, + titans: { + '/': {}, + }, + }; + let stored; + let loaded; + let updated; + + const sampleGraph = await createSampleGraph(); + updated = await ipld.remove(sampleGraph, deletion); + stored = await ipld.store(Object.assign({}, updated)); + loaded = await ipld.getResolvedGraph(stored, ''); + + // add lv2 + let plusSub = await ipld.set(sampleGraph, 'titans', {}); + plusSub = await ipld.set(sampleGraph, 'titans/prometeus', { origin: 'none' }); + const loadedSub = await ipld.getLinkedGraph(plusSub, ''); + updated = await ipld.remove(loadedSub, 'titans/prometeus'); + + stored = await ipld.store(Object.assign({}, updated)); + loaded = await ipld.getResolvedGraph(stored, ''); + Ipld.purgeCryptoInfo(loaded); + expect(loaded).to.deep.eq(expectedGraph); + }); + + it('can delete different properties inside subtrees', async () => { + const deletion = 'gods/eris/details/origin'; + const expectedGraph = { + gods: { + eris: { + '/': { + name: 'eris', + latinName: 'discordia', + details: { + '/': { + occupation: 'goddess of chaos', + }, + }, + }, + }, + }, + humans: { + helena: { + origin: 'troja', + }, + }, + titans: { + '/': { + prometeus: { + '/': {}, + }, + }, + }, + }; + let stored; + let loaded; + let updated; + + const sampleGraph = await createSampleGraph(); + updated = await ipld.remove(sampleGraph, deletion); + stored = await ipld.store(Object.assign({}, updated)); + loaded = await ipld.getResolvedGraph(stored, ''); + + // add lv3 + let plusSub = await ipld.set(sampleGraph, 'titans', {}); + plusSub = await ipld.set(sampleGraph, 'titans/prometeus', { }); + plusSub = await ipld.set(sampleGraph, 'titans/prometeus/punishment', { animal: 'raven' }); + const loadedSub = await ipld.getLinkedGraph(plusSub, ''); + updated = await ipld.remove(loadedSub, 'titans/prometeus/punishment'); + + stored = await ipld.store(Object.assign({}, updated)); + loaded = await ipld.getResolvedGraph(stored, ''); + Ipld.purgeCryptoInfo(loaded); + expect(loaded).to.deep.eq(expectedGraph); + }); + + it('can delete different properties inside subtrees', async () => { + const deletion = 'gods/eris/details/origin'; + const expectedGraph = { + gods: { + eris: { + '/': { + name: 'eris', + latinName: 'discordia', + details: { + '/': { + occupation: 'goddess of chaos', + }, + }, + }, + }, + }, + humans: { + helena: { + origin: 'troja', + }, + }, + titans: { + prometeus: { + '/': {}, + }, + }, + }; + let stored; + let loaded; + let updated; + + const sampleGraph = await createSampleGraph(); + updated = await ipld.remove(sampleGraph, deletion); + stored = await ipld.store(Object.assign({}, updated)); + loaded = await ipld.getResolvedGraph(stored, ''); + + // add lv3 + let plusSub = await ipld.set(sampleGraph, 'titans/prometeus', { punishment: { animal: 'raven' } }); + const loadedSub = await ipld.getLinkedGraph(plusSub, ''); + updated = await ipld.remove(loadedSub, 'titans/prometeus/punishment'); + + stored = await ipld.store(Object.assign({}, updated)); + loaded = await ipld.getResolvedGraph(stored, ''); + Ipld.purgeCryptoInfo(loaded); + expect(loaded).to.deep.eq(expectedGraph); + }); + + it('can delete different properties inside subtrees', async () => { + const deletion = 'gods/eris/details/origin'; + const expectedGraph = { + gods: { + eris: { + '/': { + name: 'eris', + latinName: 'discordia', + }, + }, + }, + humans: { + helena: { + origin: 'troja', + }, + }, + titans: { + prometeus: { + '/': { + 'punishment': { + animal: 'raven', + }, + }, + }, + }, + }; + let stored; + let loaded; + let updated; + + const sampleGraph = await createSampleGraph(); + updated = await ipld.remove(sampleGraph, deletion); + stored = await ipld.store(Object.assign({}, updated)); + loaded = await ipld.getResolvedGraph(stored, ''); + + // add lv3 + let plusSub = await ipld.set(sampleGraph, 'titans/prometeus', { punishment: { animal: 'raven' } }); + const loadedSub = await ipld.getLinkedGraph(plusSub, ''); + updated = await ipld.remove(loadedSub, 'gods/eris/details'); + + stored = await ipld.store(Object.assign({}, updated)); + loaded = await ipld.getResolvedGraph(stored, ''); + Ipld.purgeCryptoInfo(loaded); + expect(loaded).to.deep.eq(expectedGraph); + }); }); }); diff --git a/src/dfs/ipld.ts b/src/dfs/ipld.ts index b0a752d1..ac3d9584 100644 --- a/src/dfs/ipld.ts +++ b/src/dfs/ipld.ts @@ -303,7 +303,11 @@ export class Ipld extends Logger { while (currentNode = toTraverse.pop()) { currentTree = await this.getLinkedGraph(tree, toTraverse.join('/')); if (currentTree[currentNode]['/']) { - linkedParent = await this.getLinkedGraph(tree, `${toTraverse.join('/')}/${currentNode}`); + if (toTraverse.length) { + linkedParent = await this.getLinkedGraph(tree, `${toTraverse.join('/')}/${currentNode}`); + } else { + linkedParent = await this.getLinkedGraph(tree, currentNode); + } break; } } @@ -316,7 +320,13 @@ export class Ipld extends Logger { splitPathInParent = pathInParent.split('/').slice(1, -1); // skip parent prop, skip last } else { pathInParent = path; - splitPathInParent = path.split('/').slice(0, -1); // skip last + if (linkedParent === tree) { + // entire graph is plain object, current linkedParent is entire tree + splitPathInParent = path.split('/').slice(0, -1); // skip last + } else { + // linkedParent points to found node, node name is still in path + splitPathInParent = path.split('/').slice(1, -1); // skip parent prop, skip last + } } let nodeInParentPath = linkedParent; let nodeNameInParentPath; From 7b9135727cd765427711f1a1dfc66b99dd739f0e Mon Sep 17 00:00:00 2001 From: wulfraem Date: Tue, 2 Oct 2018 15:29:26 +0200 Subject: [PATCH 4/9] add `getKeyHistory` and `bumpSharings` to `sharings` - add `getKeyHistory` to `sharings` to retrieve all keys for an account and a section - add `bumpSharings` to `sharings`, that adds a new key for all given accounts for given section --- VERSIONS.md | 3 ++ docs/contracts/sharing.rst | 90 +++++++++++++++++++++++++++++++++++ src/contracts/sharing.spec.ts | 48 ++++++++++++++++++- src/contracts/sharing.ts | 82 +++++++++++++++++++++++++++++++ 4 files changed, 222 insertions(+), 1 deletion(-) diff --git a/VERSIONS.md b/VERSIONS.md index 8b30a049..67601ee8 100644 --- a/VERSIONS.md +++ b/VERSIONS.md @@ -2,6 +2,9 @@ ## Next Version ### Features +- add `getKeyHistory` to `sharings` to retrieve all keys for an account and a section +- add `bumpSharings` to `sharings`, that adds a new key for all given accounts for given section + ### Fixes - fix `ipld` deleting issue, that occurred when deleting linked nodes in linked subtrees diff --git a/docs/contracts/sharing.rst b/docs/contracts/sharing.rst index 81b5fccd..c6ac1edd 100644 --- a/docs/contracts/sharing.rst +++ b/docs/contracts/sharing.rst @@ -222,6 +222,55 @@ Example +-------------------------------------------------------------------------------- + +.. _sharing_bumpSharings: + +bumpSharings +================================================================================ + +.. code-block:: typescript + + sharing.bumpSharings(address, originator, partners, section, block, sharingKey); + +Bump keys for given accounts by adding given key to their sharings. This is basically a shorthand +version for adding the new key for every account in the ``partners`` array in a single transaction. + +``context``, ``hashKeys`` and ``sharingId`` are currently not supported. + +---------- +Parameters +---------- + +#. ``address`` - ``string``: contract address or ENS address +#. ``originator`` - ``string``: Ethereum account id of the sharing user +#. ``partner`` - ``string``: Ethereum account id for which key shall be added +#. ``section`` - ``string``: data section the key is intended for or '*' +#. ``block`` - ``number|string``: starting with this block, the key is valid +#. ``sharingKey`` - ``string``: key to share + +------- +Returns +------- + +``Promise`` returns ``void``: resolved when done + +------- +Example +------- + +.. code-block:: typescript + + // two sample users, user1 wants to bump keys for user2 and user3 + const user1 = '0x0000000000000000000000000000000000000001'; + const user2 = '0x0000000000000000000000000000000000000002'; + const user3 = '0x0000000000000000000000000000000000000003'; + // assume we have a contract with sharings for those accounts + const contractId = '0x00000000000000000000000000000000c027rac7'; + await sharing.bumpSharings(contractId, user1, [ user2, user3 ], '*', 0, 'i am a bump key'); + + + -------------------------------------------------------------------------------- .. _sharing_extendSharing: @@ -308,6 +357,47 @@ Example +-------------------------------------------------------------------------------- + +.. _sharing_getKeyHistory: + +getKeyHistory +================================================================================ + +.. code-block:: typescript + + sharing.getKeyHistory(address, partner, section[, sharingId]); + +Get history of keys for an account and a section. + +---------- +Parameters +---------- + +#. ``address`` - ``string``: contract address or ENS address +#. ``partner`` - ``string``: Ethereum account id for which key shall be retrieved +#. ``section`` - ``string``: data section the key is intended for or '*' +#. ``sharingId`` - ``string`` (optional): id of a sharing (when multi-sharings is used), defaults to ``null`` + +------- +Returns +------- + +``Promise`` returns ``any``: object with key: blockNr, value: key + +------- +Example +------- + +.. code-block:: typescript + + // a sample user + const user2 = '0x0000000000000000000000000000000000000002'; + // user2 wants to retrieve all keys for '*' + const keyHistory = await sharing.getKeyHistory(contract.options.address, user2, '*'); + + + -------------------------------------------------------------------------------- .. _sharing_ensureHashKey: diff --git a/src/contracts/sharing.spec.ts b/src/contracts/sharing.spec.ts index 94fe65c7..e560d084 100644 --- a/src/contracts/sharing.spec.ts +++ b/src/contracts/sharing.spec.ts @@ -313,6 +313,23 @@ describe('Sharing handler', function() { expect(hashKeyRetrieved).to.eq(hashKey); }); + it('should be able to retrieve a history of keys for an account and a section', async () => { + const randomSecret = [ + `super secret; ${Math.random()}`, + `super secret; ${Math.random()}`, + ]; + const target = { + 100: randomSecret[0], + 200: randomSecret[1], + }; + const contract = await executor.createContract(contractName, [], { from: accounts[0], gas: 500000, }); + await sharing.addSharing(contract.options.address, accounts[0], accounts[1], 'sectionOne', 100, randomSecret[0], null, false, sharingId); + await sharing.addSharing(contract.options.address, accounts[0], accounts[1], 'sectionOne', 200, randomSecret[1], null, false, sharingId); + const history = await sharing.getKeyHistory(contract.options.address, accounts[1], 'sectionOne', sharingId); + + expect(history).to.deep.eq(target); + }); + describe('when adding preloaded sharing hashes', () => { it('should be able to work with correct added to the hash cache', async () => { const randomSecret = `super secret; ${Math.random()}`; @@ -343,12 +360,41 @@ describe('Sharing handler', function() { const key = await newSharing.getKey(contract.options.address, accounts[1], '*', 0, sharingId); expect(key).to.eq(randomSecret); }); - }); } describe('for contracts that inherit from "Shared"', function() { runContractTests(false); + + it('should be able to bump keys (add a new key for given section to all given accounts', async () => { + const randomSecret = [ + `super secret; ${Math.random()}`, + `super secret; ${Math.random()}`, + ]; + const target = { + 100: randomSecret[0], + 200: randomSecret[1], + }; + const contract = await executor.createContract('Shared', [], { from: accounts[0], gas: 500000, }); + await sharing.addSharing(contract.options.address, accounts[0], accounts[1], 'sectionOne', 100, randomSecret[0], null, false); + await sharing.addSharing(contract.options.address, accounts[0], accounts[1], 'sectionOne', 200, randomSecret[1], null, false); + const history = await sharing.getKeyHistory(contract.options.address, accounts[1], 'sectionOne'); + + const bumpKey = `bump bump bump ${Math.random()}`; + let block = await web3.eth.getBlockNumber(); + await sharing.bumpSharings( + contract.options.address, + accounts[0], + [ accounts[1] ], + 'sectionOne', + block, + bumpKey, + ); + sharing.clearCache(); + block = await web3.eth.getBlockNumber(); + const key = await sharing.getKey(contract.options.address, accounts[1], 'sectionOne', block); + expect(key).to.eq(bumpKey); + }); }); describe('for contracts that inherit from "MultiShared"', function() { diff --git a/src/contracts/sharing.ts b/src/contracts/sharing.ts index d7e42606..f3613187 100644 --- a/src/contracts/sharing.ts +++ b/src/contracts/sharing.ts @@ -174,6 +174,68 @@ export class Sharing extends Logger { this.hashCache[address][sharingId] = sharings; } + /** + * Bump keys for given accounts by adding given key to their sharings. This is basically a + * shorthand version for adding the new key for every account in the `partners` array in a single + * transaction. Sharing context and sharingIds are currently not supported. + * + * @param {string} address contract address + * @param {string} originator executing users account id + * @param {string} partners account ids of a contract participant + * @param {string} section data section the key is intended for or '*' + * @param {number} block starting with this block, the key is valid + * @param {string} sharingKey new key to share + * @return {Promise} resolved when done + */ + public async bumpSharings( + address: string, + originator: string, + partners: string[], + section: string, + block: number, + sharingKey: string, + ): Promise { + let sharings; + let contract; + let description; + + // load + if (address.startsWith('0x')) { + // encrypted sharings from contract + contract = this.options.contractLoader.loadContract('Shared', address); + sharings = await this.getSharingsFromContract(contract); + } else { + description = await this.options.description.getDescriptionFromEns(address); + // ensure sharings + if (description && description.public && description.public.sharings) { + sharings = description.public.sharings; + } else { + sharings = {}; + } + // ensure description + if (!description) { + description = {}; + } + if (!description.public) { + description.public = {}; + } + } + + // add new keys + for (let partner of partners) { + sharings = await this.extendSharings(sharings, originator, partner, section, block, sharingKey); + } + + // save updated sharings + if (address.startsWith('0x')) { + await this.saveSharingsToContract(address, sharings, originator); + } else { + // save to ens + description.public.sharings = sharings; + await this.options.description.setDescriptionToEns(address, description, originator); + } + } + /** * clear caches and fetch new hashes and sharing on next request * @@ -396,6 +458,26 @@ export class Sharing extends Logger { } } + /** + * get history of keys for an account and a section + * + * @param {string} address contract address or ENS address + * @param {string} partner Ethereum account id for which key shall be retrieved + * @param {string} section data section the key is intended for or '*' + * @param {string} sharingId id of a sharing (when multi-sharings is used) + * @return {Promise} object with key: blockNr, value: key + */ + public async getKeyHistory(address: string, partner: string, section: string, sharingId: string = null): Promise { + const sharings = await this.getSharings(address, partner, section, null, sharingId); + const partnetHash = this.options.nameResolver.soliditySha3(partner); + const sectiontHash = this.options.nameResolver.soliditySha3(section); + if (sharings && sharings[partnetHash] && sharings[partnetHash][sectiontHash]) { + return sharings[partnetHash][sectiontHash]; + } else { + return null; + } + } + /** * remove a sharing key from a contract with sharing info * From 1bdbc7b73f8a8bcbdea76322f5eceee8e665a564 Mon Sep 17 00:00:00 2001 From: Tobias Winkler Date: Thu, 4 Oct 2018 17:34:40 +0200 Subject: [PATCH 5/9] add removeBcContract to profile to remove profile entries that were writte using addBcContract --- VERSIONS.md | 1 + docs/profile/profile.rst | 41 +++++++++++++++++++++++++++++++++++++++- src/profile/profile.ts | 15 +++++++++++++++ 3 files changed, 56 insertions(+), 1 deletion(-) diff --git a/VERSIONS.md b/VERSIONS.md index 67601ee8..cccd308b 100644 --- a/VERSIONS.md +++ b/VERSIONS.md @@ -4,6 +4,7 @@ ### Features - add `getKeyHistory` to `sharings` to retrieve all keys for an account and a section - add `bumpSharings` to `sharings`, that adds a new key for all given accounts for given section +- add `removeBcContract` to `profile` to remove profile entries that were writte using `addBcContract` ### Fixes - fix `ipld` deleting issue, that occurred when deleting linked nodes in linked subtrees diff --git a/docs/profile/profile.rst b/docs/profile/profile.rst index 5c49bf18..a92c0095 100644 --- a/docs/profile/profile.rst +++ b/docs/profile/profile.rst @@ -873,7 +873,7 @@ addContract .. code-block:: typescript - profile.addContract(address, data); + profile.addContract(bc, address, data); Add a contract to the current profile. @@ -881,6 +881,7 @@ Add a contract to the current profile. Parameters ---------- +#. ``bc`` - ``string``: business center ens address or contract address #. ``address`` - ``string``: contact address #. ``data`` - ``any``: bookmark metadata @@ -900,6 +901,44 @@ Example +------------------------------------------------------------------------------ + + + +.. _profile_removeContract: + +removeContract +================================================================================ + +.. code-block:: typescript + + profile.removeContract(address, data); + +removes a contract (task contract etc. ) from a business center scope of the current profile + +---------- +Parameters +---------- + +#. ``bc`` - ``string``: business center ens address or contract address +#. ``address`` - ``any``: contact address + +------- +Returns +------- + +``Promise`` returns ``void``: resolved when done + +------- +Example +------- + +.. code-block:: typescript + + await profile.removeBcContract('testbc.evan', '0x'); + + + ------------------------------------------------------------------------------ diff --git a/src/profile/profile.ts b/src/profile/profile.ts index 6798bbf1..892525dc 100644 --- a/src/profile/profile.ts +++ b/src/profile/profile.ts @@ -117,6 +117,21 @@ export class Profile extends Logger { await this.ipld.set(this.trees['contracts'], `${bc}/${address}`, data, false); } + /** + * removes a contract (task contract etc. ) from a business center scope of the current profile + * + * @param {string} bc business center ens address or contract address + * @param {string} address contact address + * @return {Promise} resolved when done + */ + async removeBcContract(bc: string, address: string): Promise { + this.ensureTree('contracts'); + const bcSet = await this.ipld.getLinkedGraph(this.trees['contracts'], bc); + if (bcSet) { + await this.ipld.remove(this.trees['contracts'], `${bc}/${address}`); + } + } + /** * add a key for a contact to bookmarks * From ee807f6f123543ebcce84cc84e039adbaa1efa64 Mon Sep 17 00:00:00 2001 From: S3bb1 Date: Fri, 5 Oct 2018 16:07:17 +0200 Subject: [PATCH 6/9] add get contracts for user from bc --- src/profile/business-center-profile.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/profile/business-center-profile.ts b/src/profile/business-center-profile.ts index 06258742..d83be0a9 100644 --- a/src/profile/business-center-profile.ts +++ b/src/profile/business-center-profile.ts @@ -202,4 +202,21 @@ export class BusinessCenterProfile extends Logger { await this.loadFromIpld(hash); } } + + /** + * gets all registered contracts for a specific contract type on a businesscenter + * + * @param {string} businessCenterDomain The business center domain + * @param {string} contractType The contract type + * @param {string} account current accountId + * @return {Array} Array with all registered bc contracts + */ + async getMyBusinessCenterContracts(businessCenterDomain: string, contractType: string, account: string): Promise { + const address = await this.nameResolver.getAddress(businessCenterDomain); + const contract = this.nameResolver.contractLoader.loadContract('BusinessCenterInterface', address); + const bcIndex = await this.nameResolver.executor.executeContractCall(contract, 'getMyIndex', {from: account}); + const indexContract = this.nameResolver.contractLoader.loadContract('DataStoreIndexInterface', bcIndex); + const contracts = await this.nameResolver.getArrayFromIndexContract(indexContract, this.nameResolver.soliditySha3(contractType)); + return contracts; + } } From 3d0e876de0906619c1ff27f17da1507795836d95 Mon Sep 17 00:00:00 2001 From: Tobias Winkler Date: Fri, 5 Oct 2018 17:11:19 +0200 Subject: [PATCH 7/9] export crypto library, DBCP Vaildator, DBCP Envelop --- VERSIONS.md | 1 + package.json | 2 +- src/bundles/bcc/bcc.ts | 5 ++++- src/bundles/bcc/dbcp.json | 4 ++-- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/VERSIONS.md b/VERSIONS.md index cccd308b..5ecb85ce 100644 --- a/VERSIONS.md +++ b/VERSIONS.md @@ -5,6 +5,7 @@ - add `getKeyHistory` to `sharings` to retrieve all keys for an account and a section - add `bumpSharings` to `sharings`, that adds a new key for all given accounts for given section - add `removeBcContract` to `profile` to remove profile entries that were writte using `addBcContract` +- export `crypto` library, `DBCP Vaildator`, `DBCP Envelop` ### Fixes - fix `ipld` deleting issue, that occurred when deleting linked nodes in linked subtrees diff --git a/package.json b/package.json index d7562b60..5f7fadff 100644 --- a/package.json +++ b/package.json @@ -98,4 +98,4 @@ }, "types": "./dist/index.d.ts", "version": "1.2.2" -} \ No newline at end of file +} diff --git a/src/bundles/bcc/bcc.ts b/src/bundles/bcc/bcc.ts index 43859982..530a721f 100644 --- a/src/bundles/bcc/bcc.ts +++ b/src/bundles/bcc/bcc.ts @@ -33,6 +33,7 @@ import keystore = require('eth-lightwallet/lib/keystore'); import Mnemonic = require('bitcore-mnemonic'); import Web3 = require('web3'); import prottle = require('prottle'); +import crypto = require('crypto'); // used for building bundle import { @@ -655,10 +656,12 @@ export { createBC, createCore, createDefaultRuntime, + crypto, CryptoProvider, DataContract, Description, DfsInterface, + Envelope, EventHub, Executor, ExecutorAgent, @@ -686,6 +689,6 @@ export { SignerExternal, SignerInternal, Unencrypted, + Validator, Web3, - }; diff --git a/src/bundles/bcc/dbcp.json b/src/bundles/bcc/dbcp.json index 56302ade..856ad2f7 100644 --- a/src/bundles/bcc/dbcp.json +++ b/src/bundles/bcc/dbcp.json @@ -9,7 +9,7 @@ "files": [ "bcc.js" ], - "origin": "QmS7s1dwp9pXnkQbmKQADrZXtrib1PAu3NnhaA71PskNfs", + "origin": "Qmf2BxUD3BotTisDbedeMCCeiDsctoVgCaRnMfUQVya1ug", "type": "library" }, "description": "Contractus for loading ens entries and it's data...", @@ -28,7 +28,7 @@ "1.0.2": "QmdC3NTNRPCs2VTrEQx1RNL6LoaDzhQLpa4nsAMA61sM7i", "1.1.0": "QmeXw3ytsm7WWH71R1LEG1ocLbrVnGMzVLk4Wfx7FqQr6v", "1.2.0": "QmSqC4ZP3yAncMKB31KBx6UqBzcxUg1wK4vT6Ku6dsQcBH", - "1.2.1": "QmdVyU3a4tnZtWibggZcUEDZyvBQ39HfxJhuSejheNKsAk" + "1.2.1": "QmWVFRDQvxJYGxYtBwkZZq7eG6A3XGYBvJp8s1YF8eiXWw" }, "dbcpVersion": 1 } From a4d42fe474a372b76bf4862607cf925870b162e6 Mon Sep 17 00:00:00 2001 From: Tobias Winkler Date: Mon, 15 Oct 2018 14:28:09 +0200 Subject: [PATCH 8/9] export 'createDefaultRuntime' within the 'bcc frontend bundle' + adjust it for frontend smartcontracts usage --- VERSIONS.md | 1 + src/runtime.ts | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/VERSIONS.md b/VERSIONS.md index 5ecb85ce..ffad1f66 100644 --- a/VERSIONS.md +++ b/VERSIONS.md @@ -6,6 +6,7 @@ - add `bumpSharings` to `sharings`, that adds a new key for all given accounts for given section - add `removeBcContract` to `profile` to remove profile entries that were writte using `addBcContract` - export `crypto` library, `DBCP Vaildator`, `DBCP Envelop` +- export `createDefaultRuntime` within the `bcc frontend bundle` + adjust it for frontend smartcontracts usage ### Fixes - fix `ipld` deleting issue, that occurred when deleting linked nodes in linked subtrees diff --git a/src/runtime.ts b/src/runtime.ts index b16aeb6a..9f548655 100644 --- a/src/runtime.ts +++ b/src/runtime.ts @@ -119,7 +119,14 @@ export async function createDefaultRuntime(web3: any, dfs: DfsInterface, runtime // if this lib is used within the browser using browserify, smart-contracts-core needs to be // defined externaly (normally defined by @evan.network/ui-dapp-browser) to return the abis // directly as json - contracts = require('@evan.network/smart-contracts-core'); + const originalContracts = require('@evan.network/smart-contracts-core'); + contracts = { }; + + // map the contracts value object correctly + Object.keys(originalContracts).forEach((key) => { + const contractKey = (key.indexOf(':') !== -1) ? key.split(':')[1] : key; + contracts[contractKey] = originalContracts[key]; + }); } // web3 contract interfaces From c9eca463eed32d8cf57883b2e6ed174352b47d2a Mon Sep 17 00:00:00 2001 From: Tobias Winkler Date: Thu, 18 Oct 2018 09:58:55 +0200 Subject: [PATCH 9/9] release preparations --- VERSIONS.md | 8 +++++--- package.json | 8 ++++---- src/bundles/bcc/dbcp.json | 9 +++++---- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/VERSIONS.md b/VERSIONS.md index ffad1f66..28a37467 100644 --- a/VERSIONS.md +++ b/VERSIONS.md @@ -2,6 +2,11 @@ ## Next Version ### Features +### Fixes +### Deprecations + +## Version 1.3.0 +### Features - add `getKeyHistory` to `sharings` to retrieve all keys for an account and a section - add `bumpSharings` to `sharings`, that adds a new key for all given accounts for given section - add `removeBcContract` to `profile` to remove profile entries that were writte using `addBcContract` @@ -11,9 +16,6 @@ ### Fixes - fix `ipld` deleting issue, that occurred when deleting linked nodes in linked subtrees -### Deprecations - - ## Version 1.2.2 ### Fixes - move require(`@evan.network/smart-contracts-core`) within `createDefaultRuntime` to capsuled scope, to be able to require it only in backend scope diff --git a/package.json b/package.json index 5f7fadff..f89a23ae 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { "author": "evan GmbH", "dependencies": { - "@evan.network/dbcp": "1.3.0", - "@evan.network/smart-contracts-core": "1.1.1", + "@evan.network/dbcp": "^1.3.1", + "@evan.network/smart-contracts-core": "^1.1.2", "@types/node": "8.0.53", "ajv": "^5.5.1", "babel-plugin-transform-es3-property-literals": "^6.22.0", @@ -97,5 +97,5 @@ "testunitbrk": "env-cmd ./.env.local npm run build && mocha --inspect-brk -r ts-node/register $*" }, "types": "./dist/index.d.ts", - "version": "1.2.2" -} + "version": "1.3.0" +} \ No newline at end of file diff --git a/src/bundles/bcc/dbcp.json b/src/bundles/bcc/dbcp.json index 856ad2f7..cac8825e 100644 --- a/src/bundles/bcc/dbcp.json +++ b/src/bundles/bcc/dbcp.json @@ -3,13 +3,13 @@ "author": "evan GmbH", "dapp": { "dependencies": { - "smartcontracts": "^1.0.3" + "smartcontracts": "^1.1.2" }, "entrypoint": "bcc.js", "files": [ "bcc.js" ], - "origin": "Qmf2BxUD3BotTisDbedeMCCeiDsctoVgCaRnMfUQVya1ug", + "origin": "QmNPBSyAggFpLJDVj3snwRVr1Qarqrgv5uL6BusCyJpYgL", "type": "library" }, "description": "Contractus for loading ens entries and it's data...", @@ -19,7 +19,7 @@ "contractus", "library" ], - "version": "1.2.1", + "version": "1.3.0", "versions": { "0.1.0": "QmTsY7ASbvxATLnEemHZQ8oQha64ujYe9VXbDCouDk7Xtp", "0.9.0": "Qmbw3yX82TVN9WhsRyeaRpd89M9XXL1pds9GgqJL29ohar", @@ -28,7 +28,8 @@ "1.0.2": "QmdC3NTNRPCs2VTrEQx1RNL6LoaDzhQLpa4nsAMA61sM7i", "1.1.0": "QmeXw3ytsm7WWH71R1LEG1ocLbrVnGMzVLk4Wfx7FqQr6v", "1.2.0": "QmSqC4ZP3yAncMKB31KBx6UqBzcxUg1wK4vT6Ku6dsQcBH", - "1.2.1": "QmWVFRDQvxJYGxYtBwkZZq7eG6A3XGYBvJp8s1YF8eiXWw" + "1.2.1": "QmWVFRDQvxJYGxYtBwkZZq7eG6A3XGYBvJp8s1YF8eiXWw", + "1.3.0": "Qmby7yc72ZyXJVnL4ijqEGpSokz5RFvThwR9qmn2zAnNWG" }, "dbcpVersion": 1 }