import { generateId } from '../utils/GeneratorHelpers' import Account from './Account' import DID from './DID' import { zeroX, didPrefixed } from '../utils' import { Instantiable, InstantiableConfig } from '../Instantiable.abstract' import { AgreementConditionsStatus } from '../keeper/contracts/templates/AgreementTemplateBase' import { ConditionState } from '../keeper/contracts/conditions/Condition.abstract' import { OceanAgreementsConditions } from './OceanAgreementsConditions' export interface AgreementPrepareResult { agreementId: string signature: string } /** * Agreements submodule of Ocean Protocol. */ export class OceanAgreements extends Instantiable { /** * Returns the instance of OceanAgreements. * @return {Promise} */ public static async getInstance( config: InstantiableConfig ): Promise { const instance = new OceanAgreements() instance.setInstanceConfig(config) instance.conditions = await OceanAgreementsConditions.getInstance(config) return instance } /** * Agreements Conditions submodule. * @type {OceanAgreementsConditions} */ public conditions: OceanAgreementsConditions /** * Creates a consumer signature for the specified asset service. * @param {string} did Decentralized ID. * @param {number} index Service index. * @param {Account} consumer Consumer account. * @return {Promise} Agreement ID and signaturee. */ public async prepare( did: string, index: number, consumer: Account ): Promise { const d: DID = DID.parse(did as string) const ddo = await this.ocean.aquarius.retrieveDDO(d) const agreementId: string = zeroX(generateId()) const templateName = ddo.findServiceByType('access').attributes .serviceAgreementTemplate.contractName const agreementConditionsIds = await this.ocean.keeper .getTemplateByName(templateName) .getConditionIdsFromDDO(agreementId, ddo, consumer.getId(), consumer.getId()) const signature = await this.ocean.utils.agreements.signServiceAgreement( ddo, index, agreementId, agreementConditionsIds, consumer ) return { agreementId, signature } } /** * Submit a service agreement to the publisher to create the agreement on-chain. * @param {string} did Decentralized ID. * @param {number} index Service index. * @param {Account} consumer Consumer account. * @return {Promise} */ public async send( did: string, agreementId: string, index: number, signature: string, consumer: Account ): Promise { const result = await this.ocean.brizo.initializeServiceAgreement( didPrefixed(did), zeroX(agreementId), index, zeroX(signature), consumer.getId() ) if (!result.ok) { throw new Error('Error on initialize agreement: ' + (await result.text())) } } /** * Create a service agreement on-chain. This should be called by the publisher of the asset. * Consumer signature will be verified on-chain, but it is recommended to verify the signature * in this method before submitting on-chain. * @param {string} did Decentralized ID. * @param {string} agreementId Service agreement ID. * @param {number} index Service index. * @param {string} signature Service agreement signature. * @param {Account} consumer Consumer account. * @param {string} provider ethereum address of service provider * @param {Account} from account of party creating the agreement (usually the consumer). * @return {Promise} */ public async create( did: string, agreementId: string, index: number, signature: string, consumer: Account, provider: string, from: Account ) { const d: DID = DID.parse(did) const ddo = await this.ocean.aquarius.retrieveDDO(d) const service = ddo.findServiceById(index) const templateName = service.attributes.serviceAgreementTemplate.contractName return this.ocean.keeper .getTemplateByName(templateName) .createAgreementFromDDO( agreementId, ddo, service.type, consumer.getId(), provider, from.getId() ) } /** * Get the status of a service agreement. * @param {string} agreementId Service agreement ID. * @param {boolean} extended Returns a complete status with dependencies. * @return {Promise} */ public async status( agreementId: string, extended?: false ): Promise<{ [condition: string]: ConditionState }> public async status( agreementId: string, extended: true ): Promise public async status(agreementId: string, extended: boolean = false) { const { templateId } = await this.ocean.keeper.agreementStoreManager.getAgreement( agreementId ) if (templateId === `0x${'0'.repeat(64)}`) { this.logger.error( `agreement ${agreementId} is not found, templateId is ${templateId}` ) return } const fullStatus = await this.ocean.keeper .getTemplateById(templateId) .getAgreementStatus(agreementId, this.ocean.keeper.conditionStoreManager) if (!fullStatus) { return } if (extended) { return fullStatus } const simpleStatus = {} Object.entries(fullStatus).forEach(([condition, { state }]) => { simpleStatus[condition] = state }) return simpleStatus as any } }