diff --git a/.travis.yml b/.travis.yml index f035cfb..4da682b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,7 +23,7 @@ before_script: - ganache-cli --port 18545 > ganache-cli.log & - git clone https://github.com/oceanprotocol/barge - cd barge - - export AQUARIUS_VERSION=v1.0.7 + - export AQUARIUS_VERSION=unstable - export BRIZO_VERSION=v0.9.3 - export KEEPER_VERSION=v0.13.2 - export EVENTS_HANDLER_VERSION=v0.4.5 diff --git a/src/aquarius/Aquarius.ts b/src/aquarius/Aquarius.ts index cd52a2f..e082394 100644 --- a/src/aquarius/Aquarius.ts +++ b/src/aquarius/Aquarius.ts @@ -215,6 +215,51 @@ export class Aquarius { return this.retrieveDDO(undefined, metadataServiceEndpoint) } + /** + * Transfer ownership of a DDO + * @param {DID | string} did DID of the asset to update. + * @param {String} newOwner New owner of the DDO + * @param {String} updated Updated field of the DDO + * @param {String} signature Signature using updated field to verify that the consumer has rights + * @return {Promise} Result. + */ + public async transferOwnership( + did: DID | string, + newOwner: string, + updated: string, + signature: string + ): Promise { + did = did && DID.parse(did) + const fullUrl = `${this.url}${apiPath}/owner/update/${did.getDid()}` + const result = await this.fetch + .put( + fullUrl, + JSON.stringify({ + signature: signature, + updated: updated, + newOwner: newOwner + }) + ) + .then((response: any) => { + if (response.ok) { + return response.text + } + this.logger.log( + 'transferownership failed:', + response.status, + response.statusText + ) + return null + }) + + .catch(error => { + this.logger.error('Error transfering ownership metadata: ', error) + return null + }) + + return result + } + public getServiceEndpoint(did: DID) { return `${this.url}/api/v1/aquarius/assets/ddo/did:op:${did.getId()}` } diff --git a/src/ddo/DDO.ts b/src/ddo/DDO.ts index 4692294..8f56cb7 100644 --- a/src/ddo/DDO.ts +++ b/src/ddo/DDO.ts @@ -40,6 +40,8 @@ export class DDO { public created: string + public updated: string + public publicKey: PublicKey[] = [] public authentication: Authentication[] = [] diff --git a/src/ocean/OceanAssets.ts b/src/ocean/OceanAssets.ts index 2515855..d3cd89a 100644 --- a/src/ocean/OceanAssets.ts +++ b/src/ocean/OceanAssets.ts @@ -311,6 +311,16 @@ export class OceanAssets extends Instantiable { * @return {Promise} Returns Account ID */ public async owner(did: string): Promise { + const owner = await this.ocean.keeper.didRegistry.getDIDOwner(did) + return owner + } + + /** + * Returns the creator of a asset. + * @param {string} did Decentralized ID. + * @return {Promise} Returns eth address + */ + public async creator(did: string): Promise { const ddo = await this.resolve(did) const checksum = ddo.getChecksum() const { creator, signatureValue } = ddo.proof @@ -341,14 +351,37 @@ export class OceanAssets extends Instantiable { * Transfer ownership of an asset. * @param {string} did Asset DID. * @param {string} newOwner Ethereum address of the new owner of the DID. + * @param {Account} account Ethereum account of original/old owner to sign and prove the ownership. * @return {Promise} Returns Web3 transaction receipt. */ public async transferOwnership( did: string, - newOwner: string + newOwner: string, + account: Account ): Promise { - const owner = await this.ocean.assets.owner(did) - return this.ocean.keeper.didRegistry.transferDIDOwnership(did, newOwner, owner) + const oldOwner = await this.ocean.assets.owner(did) + const oldDdo = await this.ocean.aquarius.retrieveDDO(did) + + // update owner on-chain + const txReceipt = this.ocean.keeper.didRegistry.transferDIDOwnership( + did, + newOwner, + oldOwner + ) + // get a signature + const signature = await this.ocean.utils.signature.signForAquarius( + oldDdo.updated, + account + ) + if (signature != null) + await this.ocean.aquarius.transferOwnership( + did, + newOwner, + oldDdo.updated, + signature + ) + + return txReceipt } /** diff --git a/src/ocean/utils/SignatureUtils.ts b/src/ocean/utils/SignatureUtils.ts index 9da6072..2f269ae 100644 --- a/src/ocean/utils/SignatureUtils.ts +++ b/src/ocean/utils/SignatureUtils.ts @@ -1,5 +1,6 @@ import Web3 from 'web3' import { Logger } from '../../utils' +import { Account } from '../../squid' export class SignatureUtils { private web3: Web3 @@ -40,4 +41,35 @@ export class SignatureUtils { public async verifyText(text: string, signature: string): Promise { return this.web3.eth.personal.ecRecover(text, signature) } + + public async getHash(message: string): Promise { + let hex = '' + for (let i = 0; i < message.length; i++) { + hex += '' + message.charCodeAt(i).toString(16) + } + const hexMessage = '0x' + hex + return hexMessage as string + } + + public async signForAquarius(message: string, account: Account): Promise { + const hash = await this.getHash(message) + const isMetaMask = + this.web3 && + this.web3.currentProvider && + (this.web3.currentProvider as any).isMetaMask + try { + return this.web3.eth.personal.sign( + hash, + account.getId(), + account.getPassword() + ) + } catch (e) { + if (isMetaMask) { + throw e + } + this.logger.warn('Error on personal sign.') + this.logger.warn(e) + return null + } + } } diff --git a/test/integration/ocean/AssetOwners.test.ts b/test/integration/ocean/AssetOwners.test.ts index 215c197..5df02a8 100644 --- a/test/integration/ocean/AssetOwners.test.ts +++ b/test/integration/ocean/AssetOwners.test.ts @@ -81,7 +81,6 @@ describe('Asset Owners', () => { ) const ddo = await ocean.assets.create(metadata as any, account1) - const { length: finalLength1 } = await ocean.assets.consumerAssets( account2.getId() ) @@ -98,10 +97,8 @@ describe('Asset Owners', () => { ) ) } catch {} - await ocean.assets.order(ddo.id, account2) // Access granted - const { length: finalLength2 } = await ocean.assets.consumerAssets( account2.getId() ) @@ -110,12 +107,13 @@ describe('Asset Owners', () => { it('should be able to transfer ownership', async () => { const { id } = await ocean.assets.create(metadata as any, account1) - // transfer - await ocean.assets.transferOwnership(id, account2.getId()) + await ocean.assets.transferOwnership(id, account2.getId(), account1) const newOwner = await ocean.keeper.didRegistry.getDIDOwner(id) - assert.equal(newOwner, account2.getId()) + // check aquarius + const aquariusOwner = await ocean.assets.owner(id) + assert.equal(aquariusOwner, account2.getId()) }) it('should add and remove correctly an address to/from FreeWhiteList on an asset', async () => {