UNPKG

@ixily/activ

Version:

Alpha Capture Trade Idea Verification. Blockchain ownership proven trade ideas and strategies.

373 lines (341 loc) 10 kB
import { ILitAction, LIT_ACTIONS, LitModule, generateUUID, LogModule as log, loop, retryFunctionHelper, CONTRACT_INTERFACES, } from '../..' import { ParallelChunksModule } from './parallel-chunks.module' import { IG_PRE_AUTHENTICATE } from '../../constants/lit-actions' const CROUPIER_URL = 'https://croupier.ixily.io' // 'https://api.ixily.io/v1/activ/croupier' const state = { useProxyUntrusted: false as boolean, } const config = (params: { useProxyUntrusted?: boolean }): void => { if (params.useProxyUntrusted !== undefined) { state.useProxyUntrusted = params.useProxyUntrusted } } export const extractPricingKeysArrayFromPriceLogs = ( logs: string[], ): [string, string][] => { const keysArray: [string, string][] = [] for (const logi of logs) { const loga = logi.split('\n') // console.log('loga') // console.log(loga) const logo = loga[loga.length - 2] // console.log('logo') // console.log(logo) const logp = logo.split(':') // console.log('logp') // console.log(logp) if (logp[1] !== 'myidpass') { throw new Error('Error Decoding Node Key for a node, for pricing') } const nodeId = logp[2] // console.log('nodeId') // console.log(nodeId) const nodeKey = logp[3] // console.log('nodeKey') // console.log(nodeKey) keysArray.push([nodeId, nodeKey]) } // sort key arrays alphabetically by first entry of the double array keysArray.sort((a, b) => { if (a[0] < b[0]) { return -1 } else if (a[0] > b[0]) { return 1 } else { return 0 } }) return keysArray } export const getValidPriceFromSigLogPrice = (litResult: { signatures: any response: CONTRACT_INTERFACES.IPrice logs: string[] }): CONTRACT_INTERFACES.IValidPrice => { const keys = extractPricingKeysArrayFromPriceLogs(litResult.logs) return { response: litResult.response as unknown as string[], signature: litResult.signatures.priceSignature, keys, } } export const getSigLogPriceResponseFromLitResult = ( litResult: any, ): { signatures: any response: CONTRACT_INTERFACES.IPrice logs: string[] } => { // console.log('litResult') // console.log(litResult) const sigLogResponse = { signatures: litResult.signatures, response: litResult.response as CONTRACT_INTERFACES.IPrice, logs: litResult.debug.allNodeLogs as string[], } return sigLogResponse } export const getValidPriceFromLitPriceResult = ( litResult: any, ): CONTRACT_INTERFACES.IValidPrice => { const sigLogResponse = getSigLogPriceResponseFromLitResult(litResult) const validPrice = getValidPriceFromSigLogPrice(sigLogResponse) return validPrice } const LIT_PRICING_LIT_JS_TASK = 'litpri' const LIT_PRICING_LIT_JS_TASK_CHUNKS = 5 ParallelChunksModule.defineTaskChunks( LIT_PRICING_LIT_JS_TASK, LIT_PRICING_LIT_JS_TASK_CHUNKS, ) const getPriceDetails = async ( params: CONTRACT_INTERFACES.IProviderRequest, mockPricing: boolean = false, customSettings?: { tracker?: string attempts?: number | undefined croupierUrl?: string }, ): Promise<CONTRACT_INTERFACES.IValidPrice> => { // only for debug/testing if (mockPricing) { const price = await testPricingAsset(params) return { response: [JSON.stringify(price)], signature: null, keys: [], } } // pricing code // let litAction: ILitActionV2 let litAction: ILitAction if (params.provider === 'Binance') { log.dev('set to ask binance') litAction = LIT_ACTIONS.GET_PRICE_BINANCE_V2 } else if (params.provider === 'IEX') { log.dev('set to ask iex') litAction = LIT_ACTIONS.GET_PRICE_IEX_V2 } else if (params.provider === 'IG Group') { log.dev('set to ask IG') litAction = LIT_ACTIONS.GET_PRICE_IG_V2 const trueCreds = await IG_PRE_AUTHENTICATE( params.auth!.key, params.auth!.secret!, params.auth!.secret2!, ) params.auth!.key = trueCreds.key params.auth!.secret = trueCreds.secret params.auth!.secret2 = trueCreds.secret2 } else if (params.provider === 'Alpaca') { log.dev('set to ask alpaca') litAction = LIT_ACTIONS.GET_PRICE_ALPACA_V2 } else if (params.provider === 'Tradestation') { log.dev('set to ask tradestation') litAction = LIT_ACTIONS.GET_PRICE_TRADESTATION_V2 } else if (params.provider === 'CoinMarketCap') { log.dev('set to ask coinmarketcap') litAction = LIT_ACTIONS.GET_PRICE_COINMARKETCAP_V2 } else if (params.provider === 'CryptoCompare') { log.dev('set to ask cryptocompare') if (params.params.symbol.indexOf('=') === -1) { throw new Error( 'Pricing Error: For CryptoCompare, please separate the assets with "=". For instance: "BTC=USD"', ) } litAction = LIT_ACTIONS.GET_PRICE_CRYPTOCOMPARE_V2 } else { // throw new Error( // 'PricingModule: getPriceDetails: Price Provider not supported: ' + // params.provider, // ) throw new Error('Unsupported provider') } // trying the first time to load this and force await loop( async () => { log.dev( `The ipfs content to this id "${litAction.ipfsId}" was loaded successfully.`, ) log.dev(`GET https://ipfs.io/ipfs/${litAction.ipfsId}`) }, async () => { let isPassed = false try { log.dev( `Calling the ipfs content to "${params.provider} lit action" with id "${litAction.ipfsId}". loading...`, ) const result = await fetch( `https://ipfs.io/ipfs/${litAction.ipfsId}`, ) if (result.status === 200) { isPassed = true } } catch (er: any) { log.dev('er:', er) isPassed = false } return isPassed }, { loopTimeInMs: 10000, limitTimeSecond: 300, }, async (err: any) => { log.dev('err', err) }, ) // note: define one interface for this (LitModule.runJS<...>) // let dt: any = null // This is no the best place for a retry function as such. // try { // dt = await retryFunctionHelper({ // maxRetries: 3, // retryCallback: async () => { // console.log( // 'ACTIV: PricingModule: getPriceDetails: tracker: ', // customSettings?.tracker, // ) const litActionParams = { symbol: params.params.symbol, apiKey: params.auth?.key || '', apiSecret: params.auth?.secret || '', apiSecret2: params.auth?.secret2 || '', ipfsId: litAction.ipfsId, uniqueExecutionId: generateUUID(), croupierUrl: customSettings?.croupierUrl || CROUPIER_URL, tracker: customSettings?.tracker, attempts: customSettings?.attempts, useProxy: state.useProxyUntrusted === true ? true : false, } // console.log('[pricing.module] getPriceDetails (litActionParams)', litActionParams) const dt = await ParallelChunksModule.run( LIT_PRICING_LIT_JS_TASK, async (): Promise<any> => { return LitModule.runJS( // litAction.fetcher.ipfsId, litAction.ipfsId, // litAction.fetcher.publicKey, litAction.publicKey, litActionParams, ) }, ) // }, // notificationCallback: async (errMsg: string, retryInx: number) => { // log.dev( // `[${params.provider}] getPriceDetails LitModule.runJS (retry #${retryInx})`, // errMsg, // ) // }, // rejectOnMaxRetries: true, // }) // } catch (err: any) { // We do prefer to show error for sure and we do prefer the uggly; // cause the uggly is actually pretty and says everythin we want to know. // the pretty is a code that tells us nothing. /* let errorCode = err.message let prettyError = null as any const showCode = false if (showCode) { switch (errorCode) { case 'There was an error getting the signing shares from the nodes': errorCode = 'LA-001' break case 'There was a timeout error executing the Javascript for this action': errorCode = 'LA-002' break case 'LitNodeClient is not ready. Please call await litNodeClient.connect() first.': errorCode = 'LA-003' break // we need catch and define the case for this error default: errorCode = 'LA-000' break } prettyError = `Request failed (${errorCode})` } throw new Error(prettyError || errorCode) */ // We do prefer to show error for sure and we do prefer the uggly; // cause the uggly is actually pretty and says everythin we want to know. // the pretty is a code that tells us nothing. // throw err // } // console.log('dt') // console.log(dt) return getValidPriceFromLitPriceResult(dt) } const testPricingAsset = async ( request: CONTRACT_INTERFACES.IProviderRequest, ): Promise<CONTRACT_INTERFACES.IPrice> => { try { switch (request.provider) { case 'Binance': const binanceParams = { symbol: request.params.symbol, key: request.auth?.key, secret: request.auth?.secret, useProxy: undefined as boolean | undefined, } if (state.useProxyUntrusted === true) { binanceParams.useProxy = true } return LIT_ACTIONS.GET_PRICE_BINANCE_V2.testPricing( binanceParams, ) case 'IEX': return LIT_ACTIONS.GET_PRICE_IEX_V2.testPricing({ symbol: request.params.symbol, key: request.auth?.key, }) case 'IG Group': return LIT_ACTIONS.GET_PRICE_IG_V2.testPricing({ key: request.auth?.key, secret: request.auth?.secret, secret2: request.auth?.secret2, symbol: request.params.symbol, }) case 'CoinMarketCap': return LIT_ACTIONS.GET_PRICE_COINMARKETCAP_V2.testPricing({ symbol: request.params.symbol, key: request.auth?.key, }) case 'CryptoCompare': return LIT_ACTIONS.GET_PRICE_CRYPTOCOMPARE_V2.testPricing({ symbol: request.params.symbol, key: request.auth?.key, }) case 'Alpaca': return LIT_ACTIONS.GET_PRICE_ALPACA_V2.testPricing({ symbol: request.params.symbol, key: request.auth?.key, secret: request.auth?.secret, }) case 'Tradestation': return LIT_ACTIONS.GET_PRICE_TRADESTATION_V2.testPricing({ symbol: request.params.symbol, key: request.auth?.key, }) default: throw new Error('Provider not supported') } } catch (err) { ;(err as any).message = 'PRICING MODULE ERROR: ' + (err as any).message throw err } } export const PricingModule = { config, getPriceDetails, testPricingAsset, }