11import { BaseApiController } from './BaseApiController' ;
22import express from 'express' ;
33import { dbApiService } from '../../apiServices' ;
4- import { Brackets , EntityManager } from 'typeorm' ;
4+ import { Brackets , EntityManager , SelectQueryBuilder } from 'typeorm' ;
55import { Asset } from '../../db/entities/Asset' ;
66import { AssetResource } from '../resources/AssetResource' ;
77import { LiquidityPoolState } from '../../db/entities/LiquidityPoolState' ;
88import { LiquidityPoolResource } from '../resources/LiquidityPoolResource' ;
99import { LiquidityPool } from '../../db/entities/LiquidityPool' ;
10+ import { TickInterval } from '../../constants' ;
11+ import { LiquidityPoolTick } from '../../db/entities/LiquidityPoolTick' ;
12+ import { LiquidityPoolTickResource } from '../resources/LiquidityPoolTickResource' ;
1013
1114const MAX_PER_PAGE : number = 100 ;
1215
@@ -16,6 +19,7 @@ export class AssetController extends BaseApiController {
1619 this . router . get ( `${ this . basePath } ` , this . assets ) ;
1720 this . router . post ( `${ this . basePath } ` , this . assets ) ;
1821 this . router . get ( `${ this . basePath } /search` , this . search ) ;
22+ this . router . post ( `${ this . basePath } /ticks` , this . ticks ) ;
1923 this . router . get ( `${ this . basePath } /:lpToken/pool` , this . lpTokenPool ) ;
2024 this . router . get ( `${ this . basePath } /:asset` , this . asset ) ;
2125 this . router . get ( `${ this . basePath } /:asset/price` , this . assetPrice ) ;
@@ -217,4 +221,74 @@ export class AssetController extends BaseApiController {
217221 } ) . catch ( ( ) => response . send ( super . failResponse ( 'Unable to retrieve asset price' ) ) ) ;
218222 }
219223
224+ private ticks ( request : express . Request , response : express . Response ) {
225+ const {
226+ forAssets,
227+ } = request . body ;
228+ const {
229+ resolution,
230+ fromTime,
231+ toTime,
232+ orderBy,
233+ } = request . query ;
234+
235+ if ( forAssets && ! ( forAssets instanceof Array ) ) {
236+ return response . send ( super . failResponse ( 'Assets must be an array' ) ) ;
237+ }
238+ if ( ! ( Object . values ( TickInterval ) as string [ ] ) . includes ( resolution as string ) ) {
239+ return response . send ( super . failResponse ( `Must supply 'resolution' as ${ Object . values ( TickInterval ) . join ( ',' ) } ` ) ) ;
240+ }
241+ if ( orderBy && ! [ 'ASC' , 'DESC' ] . includes ( orderBy as string ) ) {
242+ return response . send ( super . failResponse ( "orderBy must be 'ASC' or 'DESC'" ) ) ;
243+ }
244+
245+ const assets : Asset [ ] = ( ( forAssets ?? [ ] ) as string [ ] ) . map ( ( identifier : string ) => Asset . fromId ( identifier ) ) ;
246+ const policyIds : string [ ] = assets . map ( ( asset : Asset ) => asset . policyId ) ;
247+ const nameHexs : string [ ] = assets . map ( ( asset : Asset ) => asset . nameHex ) ;
248+
249+ const fetchTicks : any = ( manager : EntityManager ) => {
250+ return manager . createQueryBuilder ( LiquidityPoolTick , 'ticks' )
251+ . leftJoinAndSelect ( 'ticks.liquidityPool' , 'liquidityPool' )
252+ . leftJoinAndMapOne (
253+ 'liquidityPool.latestState' ,
254+ LiquidityPoolState ,
255+ 'states' ,
256+ 'states.liquidityPoolId = liquidityPool.id AND states.id = (SELECT MAX(id) FROM liquidity_pool_states WHERE liquidity_pool_states.slot + 1596491091 - 4924800 <= ticks.time AND liquidity_pool_states.liquidityPoolId = liquidityPool.id)'
257+ )
258+ . leftJoinAndSelect ( 'liquidityPool.tokenB' , 'tokenB' )
259+ . andWhere ( 'liquidityPool.tokenA IS NULL' )
260+ . andWhere (
261+ new Brackets ( ( query ) => {
262+ query . andWhere ( 'tokenB.policyId IN(:policyIds) AND tokenB.nameHex IN(:nameHexs)' , {
263+ policyIds,
264+ nameHexs,
265+ } ) ;
266+
267+ if ( fromTime && ! isNaN ( parseInt ( fromTime as string ) ) ) {
268+ query . andWhere ( 'ticks.time >= :fromTime' , {
269+ fromTime : parseInt ( fromTime as string ) ,
270+ } ) ;
271+ }
272+
273+ if ( toTime && ! isNaN ( parseInt ( toTime as string ) ) ) {
274+ query . andWhere ( 'ticks.time < :toTime' , {
275+ toTime : parseInt ( toTime as string ) ,
276+ } ) ;
277+ }
278+
279+ return query ;
280+ } ) ,
281+ )
282+ . orderBy ( 'time' , orderBy ? ( orderBy as 'ASC' | 'DESC' ) : 'ASC' )
283+ . getMany ( ) ;
284+ } ;
285+
286+ return dbApiService . transaction ( fetchTicks )
287+ . then ( ( ticks : LiquidityPoolTick [ ] ) => {
288+ const resource : LiquidityPoolTickResource = new LiquidityPoolTickResource ( ) ;
289+
290+ response . send ( resource . manyToJson ( ticks ) ) ;
291+ } ) . catch ( ( e ) => response . send ( super . failResponse ( e ) ) ) ;
292+ }
293+
220294}
0 commit comments