import prisma from "../lib/prisma" ; const axios = require ( "axios" ) ; const priceEndpoint = "http://ec2-35-177-209-25.eu-west-2.compute.amazonaws.com/prices/pokt" ; const poktNetworkDataEndpoint = "https://poktscan.com/api/pokt-network/summary" ; const relayToPOKTRatio = 0.01 * 0.89 ; const coin = { name : "pocket" , symbol : "POKT" , } ; const pocketImport = async ( ) => { let revenue = 0 ; let successfulRelays = 0 ; const project = await getProject ( coin . name ) ; const deleteProject = project . delete ; if ( deleteProject ) { await prisma . project . update ( { where : { name : coin . name , } , data : { delete : false , lastImportedId : "0" , } , } ) ; } const lastId = project . lastImportedId ; const parsedId = parseInt ( lastId ) ; if ( isNaN ( parsedId ) ) { throw new Error ( "Unable to parse int." ) ; } const fromDate = new Date ( parsedId * 1000 ) ; const toDate = new Date ( ) ; const days = dateRangeToList ( fromDate , toDate ) ; const dateDiff = dateDiffInDays ( fromDate , toDate ) ; const pocketPrices = await getPOKTDayPrices ( formatDate ( fromDate ) , formatDate ( toDate ) ) ; let timeUnitMsg = "on day" ; for ( const day of days ) { const dayISO = formatDate ( day ) ; const dateUnixTimestamp = day . getTime ( ) / 1000 ; const { totalAppStakes , totalPOKTsupply , totalRelays1d , totalRelays1hr } = await getPOKTNetworkData ( day ) ; if ( dateDiff >= 1 ) { successfulRelays = totalRelays1d ; } else { successfulRelays = totalRelays1hr ; timeUnitMsg = "in the last hour of day" ; } console . log ( `Successful relays ${ timeUnitMsg } ${ dayISO }: ${ numberWithCommas ( successfulRelays ) }.` ) ; const { price : currentDayPrice } = pocketPrices . find ( ( x ) => x . date === dayISO ) ; if ( successfulRelays > 0 && currentDayPrice > 0 ) { revenue = ( totalAppStakes / totalPOKTsupply ) * ( successfulRelays * relayToPOKTRatio * currentDayPrice ) ; } console . log ( `${ project . name } estimated revenue on ${ dayISO }: ${ revenue . toLocaleString ( "en-US" , { style : "currency" , currency : "USD" , } ) } USD.` ) ; const fee = { date : dateUnixTimestamp , fees : revenue , } ; await storeDBData ( fee , project . id ) ; } console . log ( "Finished updating pocket revenue..." ) ; return ; } ; const getProject = async ( name ) => { let project = await prisma . project . findFirst ( { where : { name : name , } , } ) ; if ( project == null ) { console . log ( `Project ${ name } doesn't exist. Create it` ) ; await prisma . project . create ( { data : { name : name , lastImportedId : "1625112000" , } , } ) ; project = await prisma . project . findUnique ( { where : { name : name , } , } ) ; } return project ; } ; const storeDBData = async ( dayData , projectId ) => { const day = await prisma . day . findFirst ( { where : { date : dayData . date , projectId : projectId , } , } ) ; if ( day != null ) { const accruedRevenue = day . revenue + dayData . fees ; await prisma . day . update ( { where : { id : day . id , } , data : { revenue : accruedRevenue , } , } ) ; } else { await prisma . day . create ( { data : { date : dayData . date , revenue : dayData . fees , projectId : projectId , } , } ) ; } await prisma . project . updateMany ( { where : { name : coin . name , } , data : { lastImportedId : dayData . date . toString ( ) , } , } ) ; return ; } ; const getPOKTDayPrices = async ( dateFrom , dateTo ) => { const dayPrices = [ ] ; try { const { data : response } = await axios . get ( `${ priceEndpoint }?date_from=${ dateFrom }&date_to=${ dateTo }` ) ; if ( ! response ) { throw new Error ( "No data returned by the price API." ) ; } for ( const entry of response . data ) { const price = parseFloat ( entry . price ) ; const date = String ( entry . created_date ) ; dayPrices . push ( { price , date } as DayPrice ) ; } return dayPrices ; } catch ( e ) { throw new Error ( e ) ; } } ; const getPOKTNetworkData = async ( date ) => { const dateFrom = date ; const ISODateFrom = formatDate ( dateFrom ) ; const dateTo = new Date ( dateFrom . setUTCDate ( dateFrom . getUTCDate ( ) + 1 ) ) ; const ISODateTo = formatDate ( dateTo ) ; const payload = { from : ISODateFrom , to : ISODateTo , debug : true } ; try { const { data : response } = await axios . post ( poktNetworkDataEndpoint , payload ) ; if ( ! response ) { throw new Error ( "No data returned by the poktscan API." ) ; } const [ data ] = response ; const blocks = data . blocks as BlockData [ ] ; const latestBlock = filterLastBlock ( blocks ) ; const lastFourBlocks = filterLastFourBlocks ( blocks ) ; const totalRelays1d = data . total_relays_completed ; const totalRelays1hr = lastFourBlocks . reduce ( ( sum , block ) => sum + block . total_relays_completed , 0 ) ; return { totalAppStakes : latestBlock . apps_staked_tokens , totalPOKTsupply : latestBlock . total_supply , totalRelays1d , totalRelays1hr , } ; } catch ( e ) { throw new Error ( e ) ; } } ; const filterLastBlock = ( blocksData ) => { let maxid = 0 ; let maxObj ; blocksData . forEach ( function ( obj ) { if ( obj . height > maxid ) { maxObj = obj ; maxid = maxObj . height ; } } ) ; return maxObj as BlockData ; } ; const filterLastFourBlocks = ( blocksData ) => { let blockNumbers = [ ] ; const latestBlocks = [ ] ; blocksData . forEach ( function ( obj ) { blockNumbers . push ( obj . height ) ; } ) ; blockNumbers = blockNumbers . sort ( ( a , b ) => ( a < b ? 1 : a > b ? - 1 : 0 ) ) . slice ( 0 , 4 ) ; blocksData . forEach ( function ( obj ) { if ( blockNumbers . includes ( obj . height ) ) { latestBlocks . push ( obj ) ; } } ) ; return latestBlocks ; } ; const dateDiffInDays = ( fromDate , toDate ) : number => { const _MS_PER_DAY = 1000 * 60 * 60 * 24 ; const utc1 = Date . UTC ( fromDate . getUTCFullYear ( ) , fromDate . getUTCMonth ( ) , fromDate . getUTCDate ( ) ) ; const utc2 = Date . UTC ( toDate . getUTCFullYear ( ) , toDate . getUTCMonth ( ) , toDate . getUTCDate ( ) ) ; return Math . floor ( ( utc2 - utc1 ) / _MS_PER_DAY ) ; } ; const dateRangeToList = ( fromDate , toDate ) : Date [ ] => { const dayList = [ ] ; for ( let dt = new Date ( fromDate ) ; dt <= toDate ; dt . setDate ( dt . getDate ( ) + 1 ) ) { dayList . push ( new Date ( dt ) ) ; } return dayList ; } ; const formatDate = ( date ) => { return date . toISOString ( ) . slice ( 0 , 10 ) ; } ; function numberWithCommas ( x ) { return x . toString ( ) . replace ( /\B(?=(\d{3})+(?!\d))/g , "," ) ; } type DayPrice = { date : string ; price : number ; } ; type BlockData = { time : string ; height : number ; total_supply : number ; apps_staked_tokens : number ; total_relays_completed : number ; } ; pocketImport ( ) . then ( ( ) => { process . exit ( 0 ) ; } ) . catch ( ( err ) => { console . log ( err ) ; process . exit ( 1 ) ; } ) ;