import { GraphQLClient } from "graphql-request" ; import { gql } from "graphql-request" ; import redstone from "redstone-api" ; import prisma from "../lib/prisma" ; const endpoint = "https://arweave.net/graphql" ; const gqlclient = new GraphQLClient ( endpoint , { timeout : 600000 } ) ; const queryGetTranasctions = gql `
  query GetTransactions($minblock: Int!, $maxblock: Int!, $cursor: String) {
    transactions(
      first: 1000
      sort: HEIGHT_ASC
      block: { min: $minblock, max: $maxblock }
      after: $cursor
    ) {
      pageInfo {
        hasNextPage
      }
      edges {
        cursor
        node {
          id
          block {
            id
            timestamp
            height
          }
          fee {
            winston
            ar
          }
        }
      }
    }
  }
` ; const queryGetLastBlock = gql `
  query queryGetLastBlock {
    block {
      height
    }
  }
` ; const queryGetBlock = gql `
  query GetBlock($blockid: Int!) {
    blocks(height: { min: $blockid, max: $blockid }) {
      edges {
        node {
          id
          height
          timestamp
        }
      }
    }
  }
` ; const coin = { name : "arweave" , symbol : "AR" , } ; const today = new Date ( ) ; today . setHours ( 0 , 0 , 0 , 0 ) ; const arweaveImport = async ( ) => { 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 , 10 ) ; let retry = 0 ; if ( isNaN ( parsedId ) ) { throw new Error ( "unable to parse int." ) ; } let lastBlockId ; try { lastBlockId = await getLastBlockId ( ) ; } catch ( e ) { throw new Error ( "unable to get last block id from blockchain." ) ; } console . log ( "last block id: " + lastBlockId ) ; let previousBlockHeight ; try { previousBlockHeight = await getBlockHeight ( parsedId ) ; } catch ( e ) { throw new Error ( "unable to get block height from blockchain." ) ; } console . log ( "Last imported block: " + previousBlockHeight ) ; let variables = { minblock : parsedId , maxblock : lastBlockId , cursor : "" , } ; let cursor ; const dayData = { date : 0 , fees : 0 , blockHeight : "" , } ; let ARinUSDT = 0 ; let exit = false ; while ( ! exit ) { let data ; console . log ( JSON . stringify ( variables ) ) ; retry = 0 ; while ( retry < 10 ) { try { data = await gqlclient . request ( queryGetTranasctions , variables ) ; retry = 10 ; } catch ( e ) { retry ++ ; console . log ( "Error executing gql query GetTransactions. Retry - " + retry ) ; if ( retry == 10 ) { throw new Error ( "Error executing gql query GetTransactions." ) ; } } } for ( let index = 0 ; index < data . transactions . edges . length ; index ++ ) { const element = data . transactions . edges [ index ] ; if ( element . node . block == null ) { exit = true ; break ; } if ( dayData . date == 0 ) { const parsedUnixTimestamp = parseInt ( element . node . block . timestamp , 10 ) ; if ( isNaN ( parsedUnixTimestamp ) ) { throw new Error ( "unable to parse int." ) ; } dayData . date = getMidnightUnixTimestamp ( parsedUnixTimestamp ) ; console . log ( "Date was empty. Start parsing from date: " + dayData . date ) ; } const blockUnixTimestamp = parseInt ( element . node . block . timestamp , 10 ) ; if ( isNaN ( blockUnixTimestamp ) ) { throw new Error ( "unable to parse int." ) ; } if ( dayData . blockHeight != element . node . block . height ) { ARinUSDT = await getHistoricalData ( coin . symbol , blockUnixTimestamp ) ; console . log ( "Value: " + ARinUSDT ) ; console . log ( "Block ID: " + element . node . block . id ) ; dayData . blockHeight = element . node . block . height ; } if ( ! isSameDate ( dayData . date , blockUnixTimestamp ) ) { console . log ( "New day: store info in DB." ) ; console . log ( JSON . stringify ( dayData ) + " - " + blockUnixTimestamp ) ; await storeDBData ( dayData , project . id ) ; dayData . fees = 0 ; dayData . date = getMidnightUnixTimestamp ( blockUnixTimestamp ) ; } const transactionFee = parseFloat ( element . node . fee . ar ) ; if ( isNaN ( transactionFee ) ) { throw new Error ( "unable to parse int." ) ; } dayData . fees += transactionFee * ARinUSDT ; cursor = data . transactions . edges [ index ] . cursor ; } if ( data . transactions . pageInfo . hasNextPage && ! exit ) { variables = { minblock : parsedId , maxblock : lastBlockId , cursor : cursor , } ; } else { console . log ( "Exiting loop..." ) ; console . log ( "New day: store info in DB." ) ; console . log ( JSON . stringify ( dayData ) ) ; await storeDBData ( dayData , project . id ) ; exit = true ; continue ; } } console . log ( "exit scrape function." ) ; return ; } ; const getHistoricalData = async ( symbol , date ) => { const dt = new Date ( date * 1000 ) ; const price = await redstone . getHistoricalPrice ( symbol , { date : dt . toISOString ( ) , } ) ; return price . value ; } ; const getProject = async ( name ) => { let project = await prisma . project . findFirst ( { where : { name : name , } , } ) ; if ( project == null ) { console . log ( "Project arweave doesn't exist. Create it" ) ; await prisma . project . create ( { data : { name : name , lastImportedId : "422250" , } , } ) ; project = await prisma . project . findUnique ( { where : { name : name , } , } ) ; } return project ; } ; const getBlockHeight = async ( blockId ) => { const variables = { blockid : blockId , } ; let data ; try { data = await gqlclient . request ( queryGetBlock , variables ) ; } catch ( e ) { throw new Error ( "Error getting block height from blockchain: " + e ) ; } return data . blocks . edges [ 0 ] . node . height ; } ; const getLastBlockId = async ( ) => { let data ; try { data = await gqlclient . request ( queryGetLastBlock ) ; } catch ( e ) { throw new Error ( "Error getting last block id from blockchain: " + JSON . stringify ( e ) + JSON . stringify ( data ) ) ; } return data . block . height ; } ; const storeDBData = async ( dayData , projectId ) => { const day = await prisma . day . findFirst ( { where : { date : dayData . date , projectId : projectId , } , } ) ; if ( day != null ) { await prisma . day . update ( { where : { id : day . id , } , data : { revenue : dayData . fees + day . revenue , } , } ) ; } 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 . blockHeight . toString ( ) , } , } ) ; return ; } ; const getMidnightUnixTimestamp = ( unixTimestamp ) => { const date = new Date ( unixTimestamp * 1000 ) ; date . setUTCHours ( 0 , 0 , 0 , 0 ) ; return date . getTime ( ) / 1000 ; } ; const isSameDate = ( firstDate , secondDate ) => { return ( getMidnightUnixTimestamp ( firstDate ) == getMidnightUnixTimestamp ( secondDate ) ) ; } ; arweaveImport ( ) . then ( ( ) => { process . exit ( 0 ) ; } ) . catch ( ( err ) => { console . log ( err ) ; process . exit ( 1 ) ; } ) ;