UNPKG

@foreverrbum/ethsign

Version:

This package will allow you to electronically sign documents within your application

798 lines (729 loc) 32.3 kB
import bs58 from 'bs58'; import { store } from 'react-notifications-component'; import { isFileWithPassword } from './download'; import Fortmatic from 'fortmatic'; import Torus from '@toruslabs/torus-embed'; import Ethsign from '../artifacts/EthSign.json'; import jsPDF from "jspdf"; import "jspdf-autotable"; import logo from '../assets/logo.png'; import moment from 'moment'; import request from 'request'; // New imports import { ethers } from 'ethers'; import { v4 } from 'uuid'; import _ from 'lodash'; import { getTimestampOfFutureBlock } from './block'; import { getChain, getFortmaticChainOptions, getTorusChainOptions, isTestnet } from './chains'; import { Biconomy } from '@biconomy/mexa' import MetaMaskLogo from '../assets/metamask.svg'; import FortmaticLogo from '../assets/fortmatic.svg'; import TorusLogo from '../assets/torus.svg'; import imTokenLogo from '../assets/imtoken.svg'; // const fromAscii = ethers.utils.formatBytes32String; const toAscii = ethers.utils.parseBytes32String; const fortmatic_key = 'pk_live_6D2FFF6E41301BF0'; const fortmatic_test_key = 'pk_test_F4BDDED1F885923E'; export const getLoggedOutWeb3Credentials = async (networkId) => { let provider = new ethers.providers.JsonRpcProvider(getChain(networkId).rpc[0]); const deployedNetwork = Ethsign.networks[networkId]; let contract = new ethers.Contract(deployedNetwork.address, Ethsign.abi, provider); return { networkId: networkId, provider: provider, contract: contract, } } export const getWeb3Credentials = async (web3Case, preferredNetwork, location, history, _provider) => { let fm = null; let biconomy = null; let torus = null; let innerNetwork = preferredNetwork; // Detect case if none provided if(web3Case == null) { innerNetwork = location.state?.networkId; if(location.state !== undefined && location.state.fortmatic && location.state?.networkId) { web3Case = 1; } else if(location.state !== undefined && location.state.torus && location.state?.networkId) { web3Case = 4; } else if(window.ethereum) { web3Case = 2; } else { window.alert('No wallet detected!'); history.goBack(); return; } } // Init biconomy/provider/other instance variables if (web3Case == 1) { if(innerNetwork == 1) { fm = new Fortmatic(fortmatic_key); } else { fm = new Fortmatic(isTestnet(innerNetwork) ? fortmatic_test_key : fortmatic_key, getFortmaticChainOptions(innerNetwork)) } if(getChain(innerNetwork).biconomySupport) { let originalProvider = new ethers.providers.Web3Provider(fm.getProvider()); biconomy = new Biconomy(originalProvider, { apiKey: getChain(innerNetwork).biconomyKey, strictMode: false }); _provider = new ethers.providers.Web3Provider(biconomy); } else { _provider = new ethers.providers.Web3Provider(fm.getProvider()); } } else if(web3Case == 4) { torus = new Torus(); await torus.init(getTorusChainOptions(innerNetwork)); await torus.ethereum.enable(); torus.ethereum.isStatus = true; if(getChain(innerNetwork).biconomySupport) { let originalProvider = new ethers.providers.Web3Provider(torus.ethereum); biconomy = new Biconomy(originalProvider, { apiKey: getChain(innerNetwork).biconomyKey, strictMode: false }); _provider = new ethers.providers.Web3Provider(biconomy); } else { _provider = new ethers.providers.Web3Provider(torus.ethereum); } } else if (web3Case == 2) { if(getChain(await window.ethereum.request({ method: 'eth_chainId' })).biconomySupport) { let originalProvider = new ethers.providers.Web3Provider(window.ethereum); biconomy = new Biconomy(originalProvider, { apiKey: getChain(await window.ethereum.request({ method: 'eth_chainId' })).biconomyKey, strictMode: false }); _provider = new ethers.providers.Web3Provider(biconomy); } else { _provider = new ethers.providers.Web3Provider(window.ethereum); } } const signer = await _provider.getSigner(); // signer == current logged in user const account = await signer.getAddress(); const networkId = (await _provider.getNetwork()).chainId; const deployedNetwork = Ethsign.networks[networkId]; let contract = null; if (biconomy == null) { contract = new ethers.Contract(deployedNetwork.address, Ethsign.abi, _provider); console.log("EthSign: Initialized normally.") } else { await new Promise((resolve, reject) => { biconomy.onEvent(biconomy.READY, async () => { contract = new ethers.Contract( deployedNetwork.address, Ethsign.abi, biconomy.getSignerByAddress(account) ); console.log("EthSign: Initialized with Mexa.") resolve(); }).onEvent(biconomy.ERROR, (error, message) => { console.log("EthSign: Failed to initialize with Mexa.") console.log(message); console.log(error); reject(); }); }); } return ({ web3: _provider, fm: fm, torus: torus, ethAccount: account?.toLowerCase(), networkId: networkId, contract: contract, web3Case: web3Case }) } export const timer = ms => new Promise(res => setTimeout(res, ms)); export const getSignInWalletLogo = (walletName) => { switch(walletName) { case 'Metamask': return MetaMaskLogo; case 'Fortmatic': return FortmaticLogo; case 'Torus': return TorusLogo; case 'imToken': return imTokenLogo; default: return null; } } const getPastEvents = async (provider, contract, filter, fromBlock) => { const latest = await provider.getBlockNumber(); const networkId = (await provider.getNetwork()).chainId; let contractBirth; if (fromBlock != null) contractBirth = fromBlock; else { const contractBirthTxHash = Ethsign.networks[networkId].transactionHash; contractBirth = (await provider.getTransaction(contractBirthTxHash)).blockNumber; } let events = []; if (networkId == 56 || networkId == 1) { let i_increment; if (networkId == "56") i_increment = 4999; else if (networkId == "1") i_increment = 511; for (let i = contractBirth; i < latest; i += i_increment) { let toBlock; if (i + i_increment > latest) { toBlock = latest; } else { toBlock = i + i_increment; } const slicedEvents = await contract.queryFilter(filter, i, toBlock); events.push.apply(events, slicedEvents); } } else { events = await contract.queryFilter(filter, contractBirth, latest); } console.log(events); return events; } export function getIpfsHashFromBytes32(bytes32Hex) { if ( bytes32Hex == null || bytes32Hex === '' || bytes32Hex === '0x0000000000000000000000000000000000000000000000000000000000000000' ) return ""; // Add our default ipfs values for first 2 bytes: // function:0x12=sha2, size:0x20=256 bits // and cut off leading "0x" const hashHex = '1220' + bytes32Hex.slice(2); const hashBytes = Buffer.from(hashHex, 'hex'); const hashStr = bs58.encode(hashBytes); return hashStr; } export const getDocumentDetails = async (documentKey, documentBasicInfo, contract, provider) => { const signer = provider.getSigner(); const signerAddress = (await signer.getAddress())?.toLowerCase(); const instance = await contract.connect(signer); const { name, birth, expiration, numOfSigners, initiator } = documentBasicInfo; const created_at = await provider.getBlock(birth); const currentBlock = await getCurrentBlockNumber(provider); let expire_at = null, expiration_block = expiration; if (expiration !== 0) { const estimateDate = await getTimestampOfFutureBlock(expiration, currentBlock, provider) expire_at = estimateDate ? moment(estimateDate).unix() : null } else { expiration_block = 'Never' } // Check document current status const { docStorageProvider, docStorage_id0, docStorage_id1 } = await instance.getDocumentDocStorageInfo(documentKey); // const saltedAddressMappingKey = await instance.hashSaltedAddressMappingKey(documentKey, signerAddress); const { metaStorageProvider, metaStorage_id0, metaStorage_id1 } = await instance.getDocumentMetaStorageInfo(documentKey); let docHash = getIpfsHashFromBytes32(docStorage_id0) + getIpfsHashFromBytes32(docStorage_id1); let metaHash = getIpfsHashFromBytes32(metaStorage_id0) + getIpfsHashFromBytes32(metaStorage_id1); let commentDataRaw = await instance.aggregateGetAllCommentsOfAllSigners(documentKey); let commentData=[] commentDataRaw.map((data)=>{ const {signer, commentStorageInfo} = data const {storage_id0, storage_id1, provider} = commentStorageInfo; const commentHash = getIpfsHashFromBytes32(storage_id0) + getIpfsHashFromBytes32(storage_id1); if (commentHash != ""){ commentData.push({ address: signer.toLowerCase(), provider: safeToAscii(provider), commentHash: commentHash }) } }) /* * Statuses: * 0: 'PDF Not Uploaded' * 1: 'More Signers Needed' * 2: 'Pending Signatures' * 3: 'All Signed' * 4: 'Waiting For Others' * 5: 'Need More Signers' */ let voteStatus = 2; if (docStorageProvider == 0) { // console.log("Document suspended: PDF needs to be uploaded"); voteStatus = 0; } const signatureDataRaw = await instance.aggregateGetIsSignedForAllSignatureFields(documentKey); let signatureData = [] let numAllSignersTotalSigned = 0; let numAllSignersTotalFields = 0; let signers = [] signatureDataRaw.map((data)=>{ var {signer, fieldSigned} = data const signed = fieldSigned.filter(field => field == true); const numSignedFields = signed.length; const numTotalFields = fieldSigned.length; if(signer == signerAddress && numSignedFields == numTotalFields){ voteStatus = 4; // user signed all his fields } numAllSignersTotalSigned = numAllSignersTotalSigned + numSignedFields; numAllSignersTotalFields = numAllSignersTotalFields + numTotalFields; signatureData.push({ signer: signer.toLowerCase(), signed: signed.length, notSigned: fieldSigned.length-signed.length, fieldSigned: fieldSigned }) signers.push({ address: signer.toLowerCase(), avatar: null, alias: null, fullySigned: numSignedFields == numTotalFields }) }) if ( numAllSignersTotalSigned == numAllSignersTotalFields ){ voteStatus = 3; } let withPassword = await isFileWithPassword(docHash); const enrolledNumOfSigners = await instance.getNumberOfSignersForDocument(documentKey); // Total number of signers enrolled (needs to match totalNumOfSigners to proceed at all) if (enrolledNumOfSigners != numOfSigners) { voteStatus = 5 } // TODO: voteStatus for need more signers state // with the assumption that all files (doc, meta, comments) are stored at the same storageprovider const storageProvider = safeToAscii(docStorageProvider) return ({ documentKey: documentKey, initiator: initiator, name: name, creation: { block: birth, date: created_at.timestamp }, expiration: { block: expiration_block, date: expire_at ? expire_at : null }, status: voteStatus, ipfsHash: docHash, metaHash: metaHash, storageProvider: storageProvider, commentData: commentData, withPassword: withPassword, signers: signers, signatureData: signatureData, }); } export const getDocument = async (documentKey, contract, provider, formatMessage) => { const instance = await contract.connect(provider.getSigner()); let document = {} try { const documentBasicInfo = await instance.getDocumentBasicInfo(documentKey); document.birth = documentBasicInfo.birth.toNumber(); document.expiration = documentBasicInfo.expiration.toNumber(); document.name = safeToAscii(documentBasicInfo.name).replace(/\0.*$/g, ''); document.numOfSigners = documentBasicInfo.numOfSigners.toNumber(); document.initiator = documentBasicInfo.initiator?.toLowerCase(); } catch (err) { console.log(err) storeNotif(formatMessage({id: "ERROR_FETCHING_DATA"}), formatMessage({id: "DATA_NOT_FETCHED_PLEASE_RELOAD"}), 'danger') } return document; } export const getData = async (filter, contract, provider) => { const instance = await contract.connect(provider.getSigner()); // This gives a JsonRpcSigner, aka read & write // Commented code below is for testing // const docName = fromAscii('Name_PLACEHOLDER2.pdf'); // const docPW = fromAscii('Password PLACEHOLDER'); // const expiration = 0; // PLACEHOLDER // const numOfSigners = 1; // PLACEHOLDER // const docKey = await instance.hashDocumentKey(docName, docPW); // await handleNewBasicDocument(instance, docKey, docName, expiration, numOfSigners); // await handleAddSigners(instance, docKey, ['0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266']); let documents = []; if (filter == 'original') { const numOfDocumentsCreatedByMe = (await instance.getNumOfDocumentsCreatedByMe()).toNumber(); // console.log("numOfDocumentsCreatedByMe,", numOfDocumentsCreatedByMe); for (let i = 0; i < numOfDocumentsCreatedByMe; ++i) { let document = {}; const documentKey = await instance.getDocumentCreatedByMeAtIndex(i); const documentBasicInfo = await instance.getDocumentBasicInfo(documentKey); // console.log(documentBasicInfo); document.birth = documentBasicInfo.birth.toNumber(); document.expiration = documentBasicInfo.expiration.toNumber(); document.name = safeToAscii(documentBasicInfo.name).replace(/\0.*$/g, ''); document.numOfSigners = documentBasicInfo.numOfSigners.toNumber(); document.initiator = documentBasicInfo.initiator.toLowerCase(); // console.log(i); document = await getDocumentDetails(documentKey, document, contract, provider) document.type = 'CreatedByMe'; if (document.status != 5){ documents.push(document); } // console.log("findSignersForDocument():", await findSignersForDocument(contract, documentKey)); // await loadHistory(contract, provider, documentBasicInfo, documentKey); } } else if (filter == 'shared') { const numOfDocumentsSharedWithMe = (await instance.getNumOfDocumentsSharedWithMe()).toNumber(); // console.log("numOfDocumentsSharedWithMe,", numOfDocumentsSharedWithMe); for (let i = 0; i < numOfDocumentsSharedWithMe; ++i) { let document = {}; const documentKey = await instance.getDocumentSharedWithMeAtIndex(i); const documentBasicInfo = await instance.getDocumentBasicInfo(documentKey); document.birth = documentBasicInfo.birth.toNumber(); document.expiration = documentBasicInfo.expiration.toNumber(); document.name = safeToAscii(documentBasicInfo.name).replace(/\0.*$/g, ''); document.numOfSigners = documentBasicInfo.numOfSigners.toNumber(); document.initiator = documentBasicInfo.initiator.toLowerCase(); document = await getDocumentDetails(documentKey, document, contract, provider) document.type = 'SharedWithMe'; if (document.status != 5){ documents.push(document); } // console.log("getDocumentDetails():", await getDocumentDetails(documentKey, documentBasicInfo, contract, provider)); // console.log("findSignersForDocument():", await findSignersForDocument(contract, documentKey)); } } else if(filter=='archived') { const numOfDocumentsArchived = (await instance.getNumOfDocumentsArchived()).toNumber(); // console.log("numOfDocumentsCreatedByMe,", numOfDocumentsCreatedByMe); for (let i = 0; i < numOfDocumentsArchived; ++i) { let document = {}; const documentKey = await instance.getDocumentArchivedAtIndex(i); const documentBasicInfo = await instance.getDocumentBasicInfo(documentKey); // console.log(documentBasicInfo); document.birth = documentBasicInfo.birth.toNumber(); document.expiration = documentBasicInfo.expiration.toNumber(); document.name = safeToAscii(documentBasicInfo.name).replace(/\0.*$/g, ''); document.numOfSigners = documentBasicInfo.numOfSigners.toNumber(); document.initiator = documentBasicInfo.initiator.toLowerCase(); // console.log(i); document = await getDocumentDetails(documentKey, document, contract, provider); document.type = 'Archived'; if (document.status != 5){ documents.push(document); } // console.log("findSignersForDocument():", await findSignersForDocument(contract, documentKey)); // await loadHistory(contract, provider, documentBasicInfo, documentKey); } } // let table_data = []; // for (const event of events) { // // Get basic document info // const documentKey = event.args.documentKey; // const document = await getDocumentDetails(documentKey, contract, ethAccount, provider); // if (document !== 0) { // table_data.unshift(document); // } // } return documents; } export const archiveDocuments = async (provider, contract, documentKeys, handleArchivedWaiting, formatMessage) => { try { const signer = await provider.getSigner(); // signer == current logged in user const instance = await contract.connect(signer); let tx = await instance.archiveDocuments(documentKeys, { gasLimit: 250000 }); handleArchivedWaiting(true); const networkId = (await provider.getNetwork()).chainId; await tx.wait(networkId == 1287 ? 2 : 1).then((receipt) => { // console.log(receipt) }) return true; } catch(err) { storeNotif(formatMessage({id: "TRANSACTION_ERROR"}), formatMessage({id: "ERROR_ARCHIVING_DOCUMENT"}), 'danger'); console.log(err); return false; } } export const getCurrentBlockNumber = async (provider) => { const currentBlock = await provider.getBlockNumber(); return currentBlock; } export const findCreator = async (provider, contract, datasource) => { const LogNewDocumentFilter = contract.filters.LogNewDocument(null, datasource.documentKey); const newDocEvent = await getPastEvents(provider, contract, LogNewDocumentFilter); return newDocEvent[0].args.sender; } // This replaces findTrustedParties export const findSignersForDocument = async (contract, documentKey) => { let signers = []; const numOfSigners = (await contract.getNumberOfSignersForDocument(documentKey)).toNumber(); for (let i = 0; i < numOfSigners; ++i) { const signer = await contract.getDocumentSignerAtIndex(documentKey, i); signers.push(signer.toLowerCase()); } return signers; } export const findTrustedParties = async (contract, datasource, creator) => { let trustedParties = []; const LogClearedProposalFilter = contract.filters.LogClearedProposal(null, datasource.documentKey, null, null, 1); const addedTrustedPartyEvents = await getPastEvents(provider, contract, LogClearedProposalFilter); for (const event of addedTrustedPartyEvents) { const returnValues = event.args; if ( returnValues.proposedAuthorizedParty !== '0x0000000000000000000000000000000000000000' ) { if (returnValues.passed) { // this is an add party event trustedParties.push(returnValues.proposedAuthorizedParty); } else { // this is a remove party event // Don't think this is possible trustedParties = trustedParties.filter( (item) => item !== returnValues.proposedAuthorizedParty ); } } } // adds creator to trustedParties if there are other trustedparties if (trustedParties.length > 0 && creator) { trustedParties.push(creator); } return trustedParties; } export const validateExpiration = (documentExpiration, currentBlock) => { if (documentExpiration <= currentBlock && documentExpiration != 0) { store.addNotification({ title: 'Error', message: `The expiration block (${documentExpiration}) must be larger than the current block (${currentBlock}).`, type: 'danger', insert: 'top', container: 'bottom-right', animationIn: ['animated', 'fadeIn'], animationOut: ['animated', 'fadeOut'], dismiss: { duration: 10000, onScreen: true, }, }); return false; } else { return true; } } export const getNewDocumentKey = async (contract) => { let documentKey; let boolDocumentExists = true; while (boolDocumentExists==true) { try { documentKey = await contract.hashDocumentKey(v4()); document = await contract.getDocumentBasicInfo(documentKey); } catch (error) { boolDocumentExists = false; } } return documentKey; } export const safeToAscii = (value) => { let parsed; try { parsed = toAscii(value); } catch (err) { parsed = ""; } return parsed; } export const loadHistory = async (contract, provider, doc, documentKey) => { const selfAddress = await provider.getSigner().getAddress(); const birth = doc.creation.block; const LogNewDocumentFilter = contract.filters.LogNewDocument(null, documentKey); const newDocumentEvent = await getPastEvents(provider, contract, LogNewDocumentFilter, birth); const LogChangedStorageFilter = contract.filters.LogChangedDocumentStorage(documentKey); const changedStorageEvents = await getPastEvents(provider, contract, LogChangedStorageFilter, birth); const LogChangedMetadataFilter = contract.filters.LogChangedMetadataStorage(documentKey); const changedMetadataEvents = await getPastEvents(provider, contract, LogChangedMetadataFilter, birth); const LogAddedNewSignerForDocumentFilter = contract.filters.LogAddedNewSignerForDocument(null, documentKey); const newSignerEvents = await getPastEvents(provider, contract, LogAddedNewSignerForDocumentFilter, birth); const LogSetNumberOfSignatureFieldsFilter = contract.filters.LogSetNumberOfSignatureFields(documentKey); const setNumberOfSignatureFieldsEvents = await getPastEvents(provider, contract, LogSetNumberOfSignatureFieldsFilter, birth); const LogLeftNewCommentOnDocumentFilter = contract.filters.LogLeftNewCommentOnDocument(null, documentKey); const leftNewCommentOnDocumentEvents = await getPastEvents(provider, contract, LogLeftNewCommentOnDocumentFilter, birth); const LogEditedCommentOnDocumentFilter = contract.filters.LogEditedCommentOnDocument(null, documentKey); const editedCommentOnDocumentEvents = await getPastEvents(provider, contract, LogEditedCommentOnDocumentFilter, birth); let combined = [].concat.apply( [], [ newDocumentEvent, changedStorageEvents, changedMetadataEvents, newSignerEvents, setNumberOfSignatureFieldsEvents, leftNewCommentOnDocumentEvents, editedCommentOnDocumentEvents, ] ); combined.sort((a, b) => a.blockNumber > b.blockNumber ? 1 : a.blockNumber === b.blockNumber ? a.event === 'LogNewDocument' ? 1 : a.event !== 'LogNewDocument' ? a.event === 'LogAddedNewSignerForDocument' ? 1 : -1 : -1 : -1 ); const toAscii = ethers.utils.parseBytes32String; let combinedViewModel = []; // TODO: Change history table columns to: // Event type, comment (not the comment in 2.0, but any extra information), raw event name (e.g. LogChangedDocumentStorage) for (const event of combined) { let eventType = '-'; let comment = ''; const storage_provider = safeToAscii(event.args.provider) const id0 = safeToAscii(event.args.storage_id0); const id1 = safeToAscii(event.args.storage_id1); switch (event.event) { case 'LogNewDocument': eventType = 'Document created'; comment = "Initiator: " + event.args.sender; break; case 'LogChangedDocumentStorage': eventType = 'Document updated'; comment = storage_provider + ": " + id0 + id1 // Maybe need to convert to IPFS hash if provider is IPFS or Fleek? break; case 'LogAddedNewSignerForDocument': eventType = 'New signer added'; comment = "New signer: " + event.args.party; break; case 'LogChangedMetadataStorage': eventType = 'Document annotations updated'; comment = storage_provider + ": " + id0 + id1 break; case 'LogSetNumberOfSignatureFields': eventType = 'Number of signature fields set'; comment = event.args.number + " signature fields for " + event.args.signer; break; case 'LogLeftNewCommentOnDocument': eventType = 'New comment'; comment = event.args.author + " left a new comment"; break; case 'LogEditedCommentOnDocument': eventType = 'Edited comment'; comment = event.args.author + " edited a comment"; break; default: eventType = event.event; } // This would be nice to have still, might need to run a check in every case (or pre-process it?) // if (sender === selfAddress) sender += ' (Me)'; // if (newParty === selfAddress) newParty += ' (Me)'; // if (newHash !== '-') newHash = getIpfsHashFromBytes32(newHash); const block = await provider.getBlock(event.blockNumber); // combinedViewModel.push({ // block: event.blockNumber, // created_at: block.timestamp, // eventType: eventType, // sender: sender, // newHash: newHash, // newParty: newParty, // comment: comment, // }); } return combinedViewModel; } export const exportHistory = (doc, history) => { const unit = "pt"; const size = "A4"; // Use A1, A2, A3 or A4 const orientation = "portrait"; // portrait or landscape const marginLeft = 40; const pdf = new jsPDF(orientation, unit, size); // Total page size is 595.28 x 841.89 pdf.setFontSize(15); const title = `Contract History of ${doc.name}`; const headers = [["Created At", "Event Type", "Comment", "Sender", "New Hash", "New Party"]]; var img = new Image() img.src = logo; pdf.addImage(img, 'png', 40, 40, 114, 57, undefined, 'FAST'); const data = history.map(record => [ `Block #${record.block} - ${moment.unix(record.created_at).format('lll')}`, record.eventType, record.comment, record.sender, record.newHash, record.newParty ]); let content = { startY: 120, head: headers, body: data, columnStyles: { 0: { cellWidth: 60 }, 1: { cellWidth: 60 }, 2: { cellWidth: 60 }, 3: { cellWidth: 111.76 }, 4: { cellWidth: 111.76 }, 5: { cellWidth: 111.76 }, } }; pdf.text(title, marginLeft, 110); pdf.autoTable(content); pdf.save(`history_${doc.name}.pdf`) } export const manipulateFileName = (file_name, handleFileName) => { const fileExt = file_name.substring(file_name.lastIndexOf('.')); handleFileName({ name: file_name, ext: fileExt }); } export const handleShowLabel = (value, handleLabel) => { if (value != '') { handleLabel(true) } else { handleLabel(false) } } export const isEmptyFile = (ipfsHash, handleEmptyFile) => { const url = `https://ipfs.infura.io:5001/api/v0/block/stat?arg=${ipfsHash}` request({ url: url }, (error, response, body) => { body = JSON.parse(body); const size = body.Size if (size !== 72) { handleEmptyFile(false); } }) } export const getDocumentFormattedStatus = (status, formatMessage) => { /* * Statuses: * -2: 'Search Results' * -1: 'All Status' * 0: 'PDF Not Uploaded' * 1: 'More Signers Needed' * 2: 'Pending Signatures' * 3: 'All Signed' * 4: 'Waiting For Others' */ switch(status) { case -2: return formatMessage({id: 'SEARCH_RESULTS'}); case -1: return formatMessage({id: 'ALL_STATUS'}); case 0: return formatMessage({id: 'PDF_NOT_UPLOADED'}); case 1: return formatMessage({id: 'MORE_SIGNERS_NEEDED'}); case 2: return formatMessage({id: 'PENDING_SIGNATURES'}); case 3: return formatMessage({id: 'ALL_SIGNED'}); case 4: return formatMessage({id: 'WAITING_FOR_OTHERS'}); default: return ''; } } export const getDocumentComment = async (contract, provider, documentKey) => { const signer = provider.getSigner(); const instance = await contract.connect(signer); const ethAccount = await signer.getAddress(); const comment = await instance.getDocumentCommentsForSigner(ethAccount, documentKey); // See smart contract for return values return comment; } export const storeNotif = (subject, message, type) => { store.addNotification({ title: subject, message: message? message:" ", type: type.toString(), insert: 'top', container: 'bottom-right', animationIn: ['animated', 'fadeIn'], animationOut: ['animated', 'fadeOut'], dismiss: { duration: 10000, onScreen: true, showIcon: true, click: false, touch: false }, }); } export const truncate = (fullStr, frontChars, backChars, separator) => { frontChars = frontChars || 5; backChars = backChars || 3; separator = separator || '...'; if (fullStr.length <= frontChars+backChars ) return fullStr; return fullStr.substr(0, frontChars) + separator + fullStr.substr(fullStr.length - backChars); }; export default { getDocumentDetails, getDocument, getWeb3Credentials, getData, getCurrentBlockNumber, findCreator, findTrustedParties, validateExpiration, getNewDocumentKey, manipulateFileName, handleShowLabel, loadHistory, exportHistory, isEmptyFile, storeNotif, truncate }