UNPKG

@minespider/core-bundles

Version:

A high-level SDK for Minespider Core. It abstract the low-level features from the core SDK for a more high-level usage such as DAPPs. Some of the features are 1:1 with the SDK some others abstract some low-level interactions or multiple actions

756 lines (652 loc) 19.8 kB
import * as ethers from "ethers"; import { CertificateDTO, CertificateEnvelope, CertificateFile, EntityType, CertificateHistoryResponseEntryInterface, Minespider, FileMetadata, MaterialMassBalanceCertification, EntityDTO, } from "@minespider/core-sdk"; import { AllowanceEntry } from "@minespider/core-sdk/dist/types/domain/queries/getMaterialAllowancesQuery"; import { JSONInterface, BaseMetadataInterface, } from "@minespider/core-sdk/dist/types/service/metadata-service"; import { CertificateCacheServiceAdapterInterface, CertificateCacheServiceAdapter } from "../../Communication/Adapter/CertificateCacheServiceAdapter"; const ERROR_NO_PRIVATE_METADATA = "No private metadata found for certificate"; const ERROR_NO_PUBLIC_METADATA = "No public metadata found for certificate"; const ERROR_PATH_NOT_EXIST = "Path doesn't exist"; export interface ParsedCertificate extends CertificateDTO { metadataFiles: { public: FileMetadata[]; private: FileMetadata[]; }; } const certificateEnvelopesMap = new Map<string, CertificateEnvelope>(); const certificates = new Map<string, ParsedCertificate>(); const entities = new Map<string, EntityDTO>(); export class MinespiderModel { private cacheAdapter: CertificateCacheServiceAdapterInterface; private wallet: ethers.Wallet; constructor( private minespider: Minespider, mnemonic: string, certificateCacheServiceEndpoint: string ) { this.cacheAdapter = new CertificateCacheServiceAdapter(certificateCacheServiceEndpoint) this.wallet = ethers.Wallet.fromMnemonic(mnemonic) } /** * Retreive a single Certificate Data Envelope * * @param id */ public async getCertificateById(id: string): Promise<any> { if (!certificates.has(id.toLowerCase())) { try { const certificate = await this.cacheAdapter.getCertificate( id.toLowerCase(), this.wallet.privateKey ); certificates.set(id.toLowerCase(), certificate); } catch (error) { throw error; } } return Object.assign({}, certificates.get(id.toLowerCase())); } public async getCertificateHistoryByCertificate( certificateUuid: string, parentsDepth: number = 10, childrenDepth: number = 10 ): Promise<CertificateHistoryResponseEntryInterface[]> { return this.cacheAdapter.getCertificateHistoryByCertificate( certificateUuid, parentsDepth, childrenDepth ); } public async getCertificateHistoryByOwner( entityId: string ): Promise<CertificateHistoryResponseEntryInterface[]> { return this.cacheAdapter.getCertificateHistoryByOwner(entityId); } /** * Get all certificates for the authenticated account and store them on the runtime * using global constants (@TODO change this behaviour) */ public async getCertificates(): Promise<any> { try { const ownerUuid = await this.minespider.getCurrentAccountAddress(); const entries = await this.cacheAdapter.getCertificates(ownerUuid, this.wallet.privateKey) await this.refreshEntitiesCache(); const certificateEnvelopes = await this.minespider.getMyCertificateEnvelopes(); certificateEnvelopes.map((certificateEnvelope) => { certificateEnvelopesMap.set( certificateEnvelope.manifest.uuid.toLowerCase(), certificateEnvelope ); }); return Promise.all( entries.map(async (certificateDTO: CertificateDTO) => { const certificateEnvelope = certificateEnvelopesMap.get( certificateDTO.uuid.toLowerCase() ); certificates.set(certificateDTO.uuid.toLowerCase(), { ...certificateDTO, metadataFiles: { public: certificateEnvelope.publicMetadataFiles, private: certificateEnvelope.privateMetadataFiles, }, }); const certificate = certificates.get(certificateDTO.uuid.toLowerCase()); return Object.assign({}, certificate); }) ); } catch (error) { throw error; } } public async getCertificatesFromCertificateEnvelopes(): Promise<any> { try { const entries = []; const certificateEnvelopes = await this.minespider.getMyCertificateEnvelopes(); await Promise.all(certificateEnvelopes.map(async (certificateEnvelope) => { certificateEnvelopesMap.set( certificateEnvelope.manifest.uuid.toLowerCase(), certificateEnvelope ); const certificate = await this.cacheAdapter.getCertificate( certificateEnvelope.manifest.uuid, this.wallet.privateKey ) entries.push(certificate) })); return entries; } catch (error) { throw error; } } private async refreshEntitiesCache() { (await this.minespider.getEntities()).map((entityDTO) => { entities.set(entityDTO.id.toLowerCase(), entityDTO); }); } /** * General method for creation of different entities (should not be used directly, use the aliases instead) * * @param name * @param latitude * @param longitude * @param location * @param meta * @param entityType */ public async createEntity( name: string, latitude: string, longitude: string, location: string, meta: object, entityType: number, materialMassBalanceCertifications?: MaterialMassBalanceCertification[] ) { try { const account = await this.minespider.registerEntity( entityType, name, latitude, longitude, location, materialMassBalanceCertifications ); await this.cacheAdapter.registerClient({ uuid: account.address.toString(), type: entityType, mnemonic: account.mnemonic.toString(), publicKey: account.keyPair.publicKey.toString(), }); await this.refreshEntitiesCache(); return account; } catch (error) { throw error; } } /** * Alias for creation of the entity type Certifier * * @param name * @param latitude * @param longitude * @param location * @param meta */ public async createCertifier( name: string, latitude: string, longitude: string, location: string, meta = {} ) { return this.createEntity( name, latitude, longitude, location, meta, EntityType.Certifier ); } /** * Alias for creation of the entity type Certifier * * @param name * @param latitude * @param longitude * @param location * @param meta */ public async createProducer( name: string, latitude: string, longitude: string, location: string, meta = {} ) { return this.createEntity( name, latitude, longitude, location, meta, EntityType.Producer ); } /** * Modify Producer entity allowance to produce materialTaxonomyUuid (this is the TOTAL allowance) * * @param producerId * @param materialTaxonomyUuid * @param amount */ public async modifyMassBalanceCertification( producerId: string, materialTaxonomyUuid: string, measurementUnitUuid: string, amount: number ): Promise<any> { let result = await this.minespider.modifyMassBalanceCertification( producerId, materialTaxonomyUuid, measurementUnitUuid, amount ); return result; } /** * Modify Producer entity allowance to produce materialTaxonomyUuid (this is the TOTAL allowance) * * @param producerId * @param materialTaxonomyUuid * @param amount */ public async modifyMassBalanceCertificationForMultipleMaterials( producerId: string, materialMassBalanceCertifications: MaterialMassBalanceCertification[] ): Promise<any> { let result = await this.minespider.modifyMassBalanceCertificationForMultipleMaterials( producerId, materialMassBalanceCertifications ); return result; } public async getEntityDetails(entityId: string) { try { return await this.minespider.getEntityDetails(entityId); } catch (error) { throw error; } } public async getEntitiesByName(entityName: string): Promise<EntityDTO[]> { try { const entities = await this.getEntities(); return entities.filter(entity => entity.name.toLowerCase().indexOf(entityName.toLowerCase()) > -1); } catch (error) { throw error; } } public async getEntities(): Promise<EntityDTO[]> { if (entities.size == 0) { await this.refreshEntitiesCache(); } return Array.from(entities.values()); } /** * @TODO * @param producerId */ public async getProducerMBCertification( producerId: string, materialTaxonomyUuid: string, measurementUnitUuid: string ): Promise<any> { try { return await this.minespider.getProducerMBCertification( producerId, materialTaxonomyUuid, measurementUnitUuid ); } catch (error) { throw error; } } public async downloadCertificateEnvelope( address: string ): Promise<CertificateEnvelope> { return this.minespider.downloadCertificateEnvelope(address); } /** * Create a Certified Data Package (Certificate) with Minespider Protocol into the Blockchain * * @param certificate */ public async createCertificate(certificate: any): Promise<string> { try { const response = await this.minespider.createCertificate( certificate.certificateAmount, certificate.certificateRawAmount, certificate.certificateGrade, certificate.certificateUnit, certificate.certificateProducer, certificate.materialTaxonomyUuid, certificate.materialTypeUuid, certificate.publicFiles, certificate.privateFiles, certificate.meta ); await this.getCertificates(); return response; } catch (error) { throw error; } } /** * Sell a Certified Data Package (Certificate) with Minespider Protocol and assign it to a given address * * @param packetId * @param cmw * @param newOwner * @param publicFilesList * @param privateFilesList */ public async sellCertificate( certificateUuid: string, amount: number, newOwnerAddress: string, publicFilesList: CertificateFile[], privateFilesList: CertificateFile[], newCertificateType?: number, meta?: BaseMetadataInterface ): Promise<any> { try { if ( certificates.size <= 0 || !certificates.has(certificateUuid.toLowerCase()) ) { await this.getCertificates(); } //@TODO this is a workaround remove for getting the certificate envelope directly instead const certificateEnvelope = certificateEnvelopesMap.get( certificateUuid.toLowerCase() ); const sellCertificateResponse = await this.minespider.sellCertificate( certificateEnvelopesMap.get(certificateUuid.toLowerCase()), amount, newOwnerAddress, publicFilesList, privateFilesList, newCertificateType, meta ); const certificateDTO = await this.cacheAdapter.getCertificate( certificateEnvelope.manifest.uuid.toLowerCase(), this.wallet.privateKey ); certificates.set(certificateEnvelope.manifest.uuid.toLowerCase(), { ...certificateDTO, metadataFiles: { public: certificateEnvelope.publicMetadataFiles, private: certificateEnvelope.privateMetadataFiles, }, }); return sellCertificateResponse; } catch (error) { throw error; } } /** * Retrieve the list of all public files for a given Certificate Id and returns it's data * * @param certificateUuid */ public async getCertificatePublicFiles( certificateUuid: string ): Promise<any> { if ( certificates.size <= 0 || !certificates.has(certificateUuid.toLowerCase()) ) { await this.getCertificates(); } //@TODO this is a workaround remove for getting the certificate envelope directly instead const dataPacketEnvelope = certificateEnvelopesMap.get( certificateUuid.toLowerCase() ); return dataPacketEnvelope.publicMetadataFiles; } /** * Retrieve the list of all private files for a given CertificateUuid and returns it's data * * @param certificateUuid */ public async getCertificatePrivateFiles( certificateUuid: string ): Promise<any> { if ( certificates.size <= 0 || !certificates.has(certificateUuid.toLowerCase()) ) { await this.getCertificates(); } //@TODO this is a workaround remove for getting the certificate envelope directly instead const dataPacketEnvelope = certificateEnvelopesMap.get( certificateUuid.toLowerCase() ); return dataPacketEnvelope.privateMetadataFiles; } public async downloadCertificatePublicFile( certificateUuid: string, fileAddress: string ) { const dataPacketEnvelope = certificateEnvelopesMap.get( certificateUuid.toLowerCase() ); const fileMetadata = dataPacketEnvelope.publicMetadataFiles.find((file) => { return file.target === fileAddress; }); if (!fileMetadata) { throw new Error(`No file metadata found for the address ${fileAddress}`); } return this.minespider.downloadFile( dataPacketEnvelope.publicFilesKey, fileMetadata ); } public async downloadCertificatePrivateFile( certificateUuid: string, fileAddress: string ) { const dataPacketEnvelope = certificateEnvelopesMap.get( certificateUuid.toLowerCase() ); const fileMetadata = dataPacketEnvelope.privateMetadataFiles.find( (file) => { return file.target === fileAddress; } ); if (!fileMetadata) { throw new Error(`No file metadata found for the address ${fileAddress}`); } return this.minespider.downloadFile( dataPacketEnvelope.privateFilesKey, fileMetadata ); } public async getCurrentAccountAddress() { return await this.minespider.getCurrentAccountAddress(); } public async getCertificateManifest(certificateUuid: string) { const dataPacketEnvelope = certificateEnvelopesMap.get( certificateUuid.toLowerCase() ); return dataPacketEnvelope.manifest; } public async readCertificateFileList( fileList: FileList ): Promise<CertificateFile[]> { var certificateFiles: CertificateFile[] = []; for (let i = 0; i < fileList.length; i++) { var fileContent = await new Promise<Buffer>((resolve, reject) => { var reader = new FileReader(); reader.onload = function (event: any) { resolve(Buffer.from(event.target.result)); }; reader.readAsArrayBuffer(fileList[i]); }); certificateFiles.push( new CertificateFile(fileContent, fileList[i].name, { type: fileList[i].type, }) ); } return certificateFiles; } public async getMaterialAllowances( balanceHolderUuid: string, materialTypeUuid: string, measurementUnitUuid: string ): Promise<AllowanceEntry[]> { return this.minespider.getMaterialAllowances( balanceHolderUuid, materialTypeUuid, measurementUnitUuid ); } public async getMaterialTaxonomies() { return this.minespider.getMaterialTaxonomies(); } public async getMaterialTypes() { return this.minespider.getMaterialTypes(); } public async getMeasurementUnits() { return this.minespider.getMeasurementUnits(); } public async getMeasurementUnitTypes() { return this.minespider.getMeasurementUnitTypes(); } /** * Get private metadata information * @param certificateUuid * @param path, ex: 'header.sdkVersion' */ public async getPrivateMetadata( certificateUuid: string, path?: string ): Promise<unknown> { const dataPacketEnvelope = certificateEnvelopesMap.get( certificateUuid.toLowerCase() ); const fileMetadata = dataPacketEnvelope.privateMetadataFiles .filter((file) => { return file.filename === "minespider.json"; }) .pop(); if (!fileMetadata) { throw new Error(`${ERROR_NO_PRIVATE_METADATA} ${certificateUuid}`); } const file = await this.minespider.downloadFile( dataPacketEnvelope.privateFilesKey, fileMetadata ); try { const metadata = JSON.parse(file.buffer.toString()); return this.getObjectPath(metadata, path); } catch (e) { throw e; } } /** * Get public metadata information * @param certificateUuid * @param path, ex: 'header.sdkVersion' */ public async getPublicMetadata( certificateUuid: string, path?: string ): Promise<unknown> { const dataPacketEnvelope = certificateEnvelopesMap.get( certificateUuid.toLowerCase() ); const fileMetadata = dataPacketEnvelope.publicMetadataFiles .filter((file) => { return file.filename === "minespider.json"; }) .pop(); if (!fileMetadata) { throw new Error(`${ERROR_NO_PUBLIC_METADATA} ${certificateUuid}`); } const file = await this.minespider.downloadFile( dataPacketEnvelope.publicFilesKey, fileMetadata ); try { const metadata: JSONInterface = JSON.parse(file.buffer.toString()); return this.getObjectPath(metadata, path); } catch (e) { throw e; } } private getObjectPath(obj: JSONInterface, path: string): unknown { if (!path) { return obj; } return path.split(".").reduce((acc, key) => { if (!acc[key]) { throw new Error(ERROR_PATH_NOT_EXIST); } acc = acc[key]; return acc; }, obj); } public async getCertificateOwner(certificateId: string): Promise<EntityDTO> { if ( certificates.size <= 0 || !certificates.has(certificateId.toLowerCase()) ) { await this.getCertificates(); } const certificate = await this.cacheAdapter.getCertificate( certificateId.toLowerCase(), this.wallet.privateKey ) if (!certificate) { return; } if (entities.has(certificate.owner.uuid.toLowerCase())) { const entity = entities.get(certificate.owner.uuid.toLowerCase()) return entity; } const entity = { ...(await this.minespider.getEntityDetails(certificate.owner.uuid.toLowerCase())), entityType: certificate.owner.type } if (!entity.id) { return; } entities.set(entity.id.toLowerCase(), entity); return entity; } public async getCertificateParentOwner( certificateId: string ): Promise<EntityDTO> { if ( certificates.size <= 0 || !certificates.has(certificateId.toLowerCase()) ) { await this.getCertificates(); } const certificate = certificates.get(certificateId.toLowerCase()) const parentCertificate = await this.cacheAdapter.getCertificate( certificate.details.parent.toLowerCase(), this.wallet.privateKey ) if (!parentCertificate) { return; } if (entities.has(parentCertificate.owner.uuid.toLowerCase())) { return entities.get(parentCertificate.owner.uuid.toLowerCase()); } const entity = { ...(await this.minespider.getEntityDetails(parentCertificate.owner.uuid.toLowerCase())), entityType: parentCertificate.owner.type } entities.set(entity.id.toLowerCase(), entity); return entity; } public async getBalanceHolderUuid() { return this.minespider.getBalanceHolderUuid(); } public async acceptCertificate(certificateUuid: string): Promise<void> { return this.minespider.acceptCertificate(certificateUuid); } }