client.ts
1 import { Environment, CompilationInputs, FunctionHashes } from './types'; 2 import { Client as MythXClient } from 'mythxjs'; 3 4 export interface Data { 5 contractName: string; 6 bytecode: string; 7 sourceMap: any; 8 deployedBytecode: string; 9 deployedSourceMap: any; 10 sourceList: string[]; 11 analysisMode: string; 12 toolName: string; 13 noCacheLookup: boolean; 14 sources: Sources | CompilationInputs; 15 mainSource: string; 16 functionHashes?: FunctionHashes; 17 } 18 19 interface Sources { 20 [key: string]: { 21 ast: any; 22 source: string; 23 }; 24 } 25 26 export default class Client { 27 private mythXClient: MythXClient; 28 constructor(env: Environment) { 29 const { apiUrl, username, password, apiKey } = env; 30 this.mythXClient = new MythXClient( 31 username, 32 password, 33 undefined, 34 apiUrl, 35 apiKey 36 ); 37 } 38 39 public failAnalysis(reason: string, status: string) { 40 throw new Error( 41 reason + 42 ' ' + 43 'The analysis job state is ' + 44 status.toLowerCase() + 45 ' and the result may become available later.' 46 ); 47 } 48 49 public async awaitAnalysisFinish( 50 uuid: string, 51 initialDelay: number, 52 timeout: number 53 ) { 54 const statuses = ['Error', 'Finished']; 55 56 let state = await this.mythXClient.getAnalysisStatus(uuid); 57 58 if (statuses.includes(state.status)) { 59 return state; 60 } 61 62 const timer = (interval: number) => 63 new Promise(resolve => setTimeout(resolve, interval)); 64 65 const maxRequests = 10; 66 const start = Date.now(); 67 const remaining = Math.max(timeout - initialDelay, 0); 68 const inverted = Math.sqrt(remaining) / Math.sqrt(285); 69 70 for (let r = 0; r < maxRequests; r++) { 71 const idle = Math.min( 72 r === 0 ? initialDelay : (inverted * r) ** 2, 73 start + timeout - Date.now() 74 ); 75 76 // eslint-disable-next-line no-await-in-loop 77 await timer(idle); 78 79 if (Date.now() - start >= timeout) { 80 this.failAnalysis( 81 `User or default timeout reached after ${timeout / 1000} sec(s).`, 82 state.status 83 ); 84 } 85 86 // eslint-disable-next-line no-await-in-loop 87 state = await this.mythXClient.getAnalysisStatus(uuid); 88 89 if (statuses.includes(state.status)) { 90 return state; 91 } 92 } 93 94 this.failAnalysis( 95 `Allowed number (${maxRequests}) of requests was reached.`, 96 state.status 97 ); 98 } 99 100 public async authenticate() { 101 return this.mythXClient.login(); 102 } 103 104 public async submitDataForAnalysis(data: Data) { 105 return this.mythXClient.analyze(data); 106 } 107 108 public async getReport(uuid: string) { 109 return this.mythXClient.getDetectedIssues(uuid); 110 } 111 112 public async getApiVersion() { 113 return this.mythXClient.getVersion(); 114 } 115 116 public async getAnalysesList() { 117 return this.mythXClient.getAnalysesList(); 118 } 119 120 public async getAnalysisStatus(uuid: string) { 121 return this.mythXClient.getAnalysisStatus(uuid); 122 } 123 }