2019-01-21 17:48:40 +01:00
|
|
|
import AquariusProvider from "../aquarius/AquariusProvider"
|
2019-02-12 15:07:10 +01:00
|
|
|
import { SearchQuery } from "../aquarius/query/SearchQuery"
|
2019-01-21 17:48:40 +01:00
|
|
|
import BrizoProvider from "../brizo/BrizoProvider"
|
2019-02-04 11:46:24 +01:00
|
|
|
import { Condition } from "../ddo/Condition"
|
|
|
|
import { DDO } from "../ddo/DDO"
|
|
|
|
import { MetaData } from "../ddo/MetaData"
|
2019-02-07 14:21:16 +01:00
|
|
|
import { Service, ServiceAuthorization } from "../ddo/Service"
|
2019-01-21 17:48:40 +01:00
|
|
|
import ContractEvent from "../keeper/Event"
|
|
|
|
import EventListener from "../keeper/EventListener"
|
|
|
|
import Keeper from "../keeper/Keeper"
|
|
|
|
import SecretStoreProvider from "../secretstore/SecretStoreProvider"
|
|
|
|
import Account from "./Account"
|
|
|
|
import DID from "./DID"
|
|
|
|
import IdGenerator from "./IdGenerator"
|
|
|
|
import ServiceAgreement from "./ServiceAgreements/ServiceAgreement"
|
|
|
|
import ServiceAgreementTemplate from "./ServiceAgreements/ServiceAgreementTemplate"
|
|
|
|
import Access from "./ServiceAgreements/Templates/Access"
|
2019-02-15 23:40:55 +01:00
|
|
|
import ConfigProvider from "../ConfigProvider"
|
2019-01-21 17:48:40 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Assets submodule of Ocean Protocol.
|
|
|
|
*/
|
|
|
|
export default class OceanAssets {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the instance of OceanAssets.
|
|
|
|
* @return {Promise<OceanAssets>}
|
|
|
|
*/
|
|
|
|
public static async getInstance(): Promise<OceanAssets> {
|
|
|
|
if (!OceanAssets.instance) {
|
|
|
|
OceanAssets.instance = new OceanAssets()
|
|
|
|
}
|
|
|
|
|
|
|
|
return OceanAssets.instance
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* OceanAssets instance.
|
|
|
|
* @type {OceanAssets}
|
|
|
|
*/
|
|
|
|
private static instance: OceanAssets = null
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns a DDO by DID.
|
|
|
|
* @param {string} did Decentralized ID.
|
|
|
|
* @return {Promise<DDO>}
|
|
|
|
*/
|
|
|
|
public async resolve(did: string): Promise<DDO> {
|
|
|
|
const d: DID = DID.parse(did)
|
|
|
|
return AquariusProvider.getAquarius().retrieveDDO(d)
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Creates a new DDO.
|
|
|
|
* @param {MetaData} metadata DDO metadata.
|
|
|
|
* @param {Account} publisher Publicher account.
|
|
|
|
* @return {Promise<DDO>}
|
|
|
|
*/
|
2019-02-07 11:32:50 +01:00
|
|
|
public async create(metadata: MetaData, publisher: Account, services: Service[] = []): Promise<DDO> {
|
2019-02-15 23:40:55 +01:00
|
|
|
const {secretStoreUri} = ConfigProvider.getConfig()
|
2019-01-21 17:48:40 +01:00
|
|
|
const {didRegistry} = await Keeper.getInstance()
|
|
|
|
const aquarius = AquariusProvider.getAquarius()
|
|
|
|
const brizo = BrizoProvider.getBrizo()
|
|
|
|
|
|
|
|
const did: DID = DID.generate()
|
|
|
|
|
2019-02-07 14:21:16 +01:00
|
|
|
const authorizationService = (services.find(({type}) => type === "Authorization") || {}) as ServiceAuthorization
|
|
|
|
const secretStoreUrl = authorizationService.service === "SecretStore" && authorizationService.serviceEndpoint
|
2019-02-15 23:40:55 +01:00
|
|
|
const secretStoreConfig = {
|
|
|
|
secretStoreUri: secretStoreUrl,
|
|
|
|
}
|
2019-02-07 14:21:16 +01:00
|
|
|
|
2019-02-15 23:40:55 +01:00
|
|
|
const encryptedFiles = await SecretStoreProvider.getSecretStore(secretStoreConfig).encryptDocument(did.getId(), metadata.base.files)
|
2019-01-21 17:48:40 +01:00
|
|
|
|
|
|
|
const template = new Access()
|
|
|
|
const serviceAgreementTemplate = new ServiceAgreementTemplate(template)
|
|
|
|
|
|
|
|
const conditions: Condition[] = await serviceAgreementTemplate.getConditions(metadata, did.getId())
|
|
|
|
|
|
|
|
const serviceEndpoint = aquarius.getServiceEndpoint(did)
|
|
|
|
|
2019-02-07 11:29:55 +01:00
|
|
|
let serviceDefinitionIdCount = 0
|
2019-01-21 17:48:40 +01:00
|
|
|
// create ddo itself
|
|
|
|
const ddo: DDO = new DDO({
|
|
|
|
authentication: [{
|
|
|
|
type: "RsaSignatureAuthentication2018",
|
|
|
|
publicKey: did.getDid() + "#keys-1",
|
2019-02-04 11:46:24 +01:00
|
|
|
}],
|
2019-01-21 17:48:40 +01:00
|
|
|
id: did.getDid(),
|
|
|
|
publicKey: [
|
|
|
|
{
|
|
|
|
id: did.getDid() + "#keys-1",
|
|
|
|
type: "Ed25519VerificationKey2018",
|
|
|
|
owner: did.getDid(),
|
|
|
|
publicKeyBase58: await publisher.getPublicKey(),
|
2019-02-04 11:46:24 +01:00
|
|
|
},
|
2019-01-21 17:48:40 +01:00
|
|
|
],
|
2019-02-07 14:21:16 +01:00
|
|
|
service: [
|
2019-01-21 17:48:40 +01:00
|
|
|
{
|
|
|
|
type: template.templateName,
|
|
|
|
purchaseEndpoint: brizo.getPurchaseEndpoint(),
|
|
|
|
serviceEndpoint: brizo.getConsumeEndpoint(),
|
|
|
|
// the id of the service agreement?
|
2019-02-07 11:29:55 +01:00
|
|
|
serviceDefinitionId: String(serviceDefinitionIdCount++),
|
2019-01-21 17:48:40 +01:00
|
|
|
// the id of the service agreement template
|
|
|
|
templateId: serviceAgreementTemplate.getId(),
|
|
|
|
serviceAgreementContract: {
|
2019-01-30 15:35:31 +01:00
|
|
|
contractName: "ServiceExecutionAgreement",
|
2019-01-21 17:48:40 +01:00
|
|
|
fulfillmentOperator: template.fulfillmentOperator,
|
|
|
|
events: [
|
|
|
|
{
|
2019-01-30 15:35:31 +01:00
|
|
|
name: "AgreementInitialized",
|
2019-01-21 17:48:40 +01:00
|
|
|
actorType: "consumer",
|
|
|
|
handler: {
|
|
|
|
moduleName: "payment",
|
|
|
|
functionName: "lockPayment",
|
|
|
|
version: "0.1",
|
2019-02-04 11:46:24 +01:00
|
|
|
},
|
|
|
|
},
|
2019-01-21 17:48:40 +01:00
|
|
|
],
|
2019-02-04 11:46:24 +01:00
|
|
|
},
|
2019-01-21 17:48:40 +01:00
|
|
|
conditions,
|
2019-02-04 11:46:24 +01:00
|
|
|
},
|
2019-01-21 17:48:40 +01:00
|
|
|
{
|
|
|
|
type: "Compute",
|
2019-02-07 11:29:55 +01:00
|
|
|
serviceEndpoint: brizo.getComputeEndpoint(publisher.getId(), String(serviceDefinitionIdCount), "xxx", "xxx"),
|
|
|
|
serviceDefinitionId: String(serviceDefinitionIdCount++),
|
2019-02-04 11:46:24 +01:00
|
|
|
},
|
2019-02-15 23:40:55 +01:00
|
|
|
{
|
|
|
|
type: "Authorization",
|
|
|
|
services: 'SecretStore',
|
|
|
|
serviceEndpoint: secretStoreUri,
|
|
|
|
serviceDefinitionId: String(serviceDefinitionIdCount++),
|
|
|
|
},
|
2019-01-21 17:48:40 +01:00
|
|
|
{
|
|
|
|
type: "Metadata",
|
|
|
|
serviceEndpoint,
|
2019-02-07 11:29:55 +01:00
|
|
|
serviceDefinitionId: String(serviceDefinitionIdCount++),
|
2019-02-04 17:45:49 +01:00
|
|
|
metadata: {
|
|
|
|
// Default values
|
|
|
|
curation: {
|
|
|
|
rating: 0,
|
|
|
|
numVotes: 0,
|
|
|
|
},
|
|
|
|
additionalInformation: {
|
|
|
|
updateFrecuency: "yearly",
|
|
|
|
structuredMarkup: [],
|
|
|
|
},
|
|
|
|
// Overwrites defaults
|
|
|
|
...metadata,
|
2019-02-06 13:10:24 +01:00
|
|
|
// Cleaning not needed information
|
|
|
|
base: {
|
|
|
|
...metadata.base,
|
2019-02-07 14:21:16 +01:00
|
|
|
contentUrls: [],
|
|
|
|
encryptedFiles,
|
2019-02-06 13:10:24 +01:00
|
|
|
files: undefined,
|
2019-02-06 13:37:31 +01:00
|
|
|
} as any,
|
2019-02-04 17:45:49 +01:00
|
|
|
},
|
2019-02-04 11:46:24 +01:00
|
|
|
},
|
2019-02-07 14:21:16 +01:00
|
|
|
...services
|
|
|
|
.map((_) => ({..._, serviceDefinitionId: String(serviceDefinitionIdCount++)})),
|
2019-02-15 23:40:55 +01:00
|
|
|
]
|
|
|
|
// Remove duplications
|
|
|
|
.reverse()
|
|
|
|
.filter(({type}, i, list) => list.findIndex(({type: t}) => t === type) === i)
|
|
|
|
.reverse() as Service[],
|
2019-01-21 17:48:40 +01:00
|
|
|
})
|
|
|
|
|
2019-02-04 17:45:49 +01:00
|
|
|
ddo.addChecksum()
|
|
|
|
await ddo.addProof(publisher.getId(), publisher.getPassword())
|
|
|
|
|
2019-01-21 17:48:40 +01:00
|
|
|
const storedDdo = await aquarius.storeDDO(ddo)
|
|
|
|
|
|
|
|
await didRegistry.registerAttribute(
|
|
|
|
did.getId(),
|
2019-02-06 12:54:06 +01:00
|
|
|
ddo.getChecksum(),
|
2019-01-21 17:48:40 +01:00
|
|
|
serviceEndpoint,
|
2019-02-06 13:10:24 +01:00
|
|
|
publisher.getId(),
|
|
|
|
)
|
2019-01-21 17:48:40 +01:00
|
|
|
|
|
|
|
return storedDdo
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Purchases a service agreement by DID.
|
|
|
|
* @param {string} did Decentralized ID.
|
|
|
|
* @param {string} serviceDefinitionId Service definition ID.
|
|
|
|
* @param {Account} consumer Consumer account.
|
2019-02-13 13:05:08 +01:00
|
|
|
* @return {Promise<string>} Returns Agreement ID
|
2019-01-21 17:48:40 +01:00
|
|
|
*/
|
|
|
|
public async order(
|
|
|
|
did: string,
|
|
|
|
serviceDefinitionId: string,
|
|
|
|
consumer: Account,
|
2019-02-13 13:05:08 +01:00
|
|
|
): Promise<string> {
|
2019-01-21 17:48:40 +01:00
|
|
|
|
|
|
|
const d: DID = DID.parse(did as string)
|
|
|
|
const ddo = await AquariusProvider.getAquarius().retrieveDDO(d)
|
|
|
|
const serviceAgreementId: string = IdGenerator.generateId()
|
|
|
|
|
|
|
|
try {
|
2019-02-13 13:05:08 +01:00
|
|
|
await ServiceAgreement.signServiceAgreement(
|
2019-01-21 17:48:40 +01:00
|
|
|
ddo, serviceDefinitionId, serviceAgreementId, consumer)
|
|
|
|
|
2019-02-07 12:10:25 +01:00
|
|
|
const accessService = ddo.findServiceByType("Access")
|
|
|
|
const metadataService = ddo.findServiceByType("Metadata")
|
2019-01-21 17:48:40 +01:00
|
|
|
|
|
|
|
const price = metadataService.metadata.base.price
|
|
|
|
const balance = await consumer.getOceanBalance()
|
|
|
|
if (balance < price) {
|
|
|
|
throw new Error(`Not enough ocean tokens! Should have ${price} but has ${balance}`)
|
|
|
|
}
|
|
|
|
|
|
|
|
const event: ContractEvent = EventListener.subscribe(
|
|
|
|
accessService.serviceAgreementContract.contractName,
|
|
|
|
accessService.serviceAgreementContract.events[0].name, {
|
|
|
|
serviceAgreementId,
|
|
|
|
})
|
|
|
|
|
|
|
|
event.listenOnce(async (data) => {
|
2019-02-11 14:56:48 +01:00
|
|
|
const sa: ServiceAgreement = new ServiceAgreement(data.returnValues.agreementId)
|
2019-01-21 17:48:40 +01:00
|
|
|
await sa.payAsset(
|
|
|
|
d.getId(),
|
|
|
|
metadataService.metadata.base.price,
|
|
|
|
consumer,
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
2019-02-13 13:05:08 +01:00
|
|
|
return serviceAgreementId
|
2019-01-21 17:48:40 +01:00
|
|
|
|
|
|
|
} catch (err) {
|
2019-02-13 13:05:08 +01:00
|
|
|
throw new Error("Signing ServiceAgreement failed: " + err)
|
2019-01-21 17:48:40 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Search over the assets using a query.
|
|
|
|
* @param {SearchQuery} query Query to filter the assets.
|
|
|
|
* @return {Promise<DDO[]>}
|
|
|
|
*/
|
|
|
|
public async query(query: SearchQuery): Promise<DDO[]> {
|
2019-02-12 15:07:10 +01:00
|
|
|
return AquariusProvider.getAquarius().queryMetadataByText(query)
|
2019-01-21 17:48:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Search over the assets using a keyword.
|
|
|
|
* @param {SearchQuery} text Text to filter the assets.
|
|
|
|
* @return {Promise<DDO[]>}
|
|
|
|
*/
|
|
|
|
public async search(text: string): Promise<DDO[]> {
|
|
|
|
return AquariusProvider.getAquarius().queryMetadataByText({
|
|
|
|
text,
|
|
|
|
page: 0,
|
|
|
|
offset: 100,
|
|
|
|
query: {
|
|
|
|
value: 1,
|
|
|
|
},
|
|
|
|
sort: {
|
|
|
|
value: 1,
|
|
|
|
},
|
|
|
|
} as SearchQuery)
|
|
|
|
}
|
|
|
|
}
|