@@ -16,11 +16,24 @@ import { logger } from "./logging";
1616import { PromClient } from "./promClient" ;
1717import { retry } from "ts-retry-promise" ;
1818import { parseVaa } from "@certusone/wormhole-sdk" ;
19+ import { getOrElse } from "./helpers" ;
20+ import {
21+ TargetChain ,
22+ validTargetChains ,
23+ defaultTargetChain ,
24+ VaaEncoding ,
25+ encodeVaaForChain ,
26+ } from "./encoding" ;
1927
2028const MORGAN_LOG_FORMAT =
2129 ':remote-addr - :remote-user ":method :url HTTP/:http-version"' +
2230 ' :status :res[content-length] :response-time ms ":referrer" ":user-agent"' ;
2331
32+ // GET argument string to represent the options for target_chain
33+ export const targetChainArgString = `target_chain=<${ validTargetChains . join (
34+ "|"
35+ ) } >`;
36+
2437export class RestException extends Error {
2538 statusCode : number ;
2639 message : string ;
@@ -144,7 +157,7 @@ export class RestAPI {
144157 priceInfoToJson (
145158 priceInfo : PriceInfo ,
146159 verbose : boolean ,
147- binary : boolean
160+ targetChain : TargetChain | undefined
148161 ) : object {
149162 return {
150163 ...priceInfo . priceFeed . toJson ( ) ,
@@ -156,8 +169,8 @@ export class RestAPI {
156169 price_service_receive_time : priceInfo . priceServiceReceiveTime ,
157170 } ,
158171 } ) ,
159- ...( binary && {
160- vaa : priceInfo . vaa . toString ( "base64" ) ,
172+ ...( targetChain !== undefined && {
173+ vaa : encodeVaaForChain ( priceInfo . vaa , targetChain ) ,
161174 } ) ,
162175 } ;
163176 }
@@ -182,13 +195,20 @@ export class RestAPI {
182195 ids : Joi . array ( )
183196 . items ( Joi . string ( ) . regex ( / ^ ( 0 x ) ? [ a - f 0 - 9 ] { 64 } $ / ) )
184197 . required ( ) ,
198+ target_chain : Joi . string ( )
199+ . valid ( ...validTargetChains )
200+ . optional ( ) ,
185201 } ) . required ( ) ,
186202 } ;
187203 app . get (
188204 "/api/latest_vaas" ,
189205 validate ( latestVaasInputSchema ) ,
190206 ( req : Request , res : Response ) => {
191207 const priceIds = ( req . query . ids as string [ ] ) . map ( removeLeading0x ) ;
208+ const targetChain = getOrElse (
209+ req . query . target_chain as TargetChain | undefined ,
210+ defaultTargetChain
211+ ) ;
192212
193213 // Multiple price ids might share same vaa, we use sequence number as
194214 // key of a vaa and deduplicate using a map of seqnum to vaa bytes.
@@ -212,14 +232,14 @@ export class RestAPI {
212232 }
213233
214234 const jsonResponse = Array . from ( vaaMap . values ( ) , ( vaa ) =>
215- vaa . toString ( "base64" )
235+ encodeVaaForChain ( vaa , targetChain )
216236 ) ;
217237
218238 res . json ( jsonResponse ) ;
219239 }
220240 ) ;
221241 endpoints . push (
222- " api/latest_vaas?ids[]=<price_feed_id>&ids[]=<price_feed_id_2>&.."
242+ ` api/latest_vaas?ids[]=<price_feed_id>&ids[]=<price_feed_id_2>&..& ${ targetChainArgString } `
223243 ) ;
224244
225245 const getVaaInputSchema : schema = {
@@ -228,6 +248,9 @@ export class RestAPI {
228248 . regex ( / ^ ( 0 x ) ? [ a - f 0 - 9 ] { 64 } $ / )
229249 . required ( ) ,
230250 publish_time : Joi . number ( ) . required ( ) ,
251+ target_chain : Joi . string ( )
252+ . valid ( ...validTargetChains )
253+ . optional ( ) ,
231254 } ) . required ( ) ,
232255 } ;
233256
@@ -237,25 +260,32 @@ export class RestAPI {
237260 asyncWrapper ( async ( req : Request , res : Response ) => {
238261 const priceFeedId = removeLeading0x ( req . query . id as string ) ;
239262 const publishTime = Number ( req . query . publish_time as string ) ;
263+ const targetChain = getOrElse (
264+ req . query . target_chain as TargetChain | undefined ,
265+ defaultTargetChain
266+ ) ;
240267
241268 if (
242269 this . priceFeedVaaInfo . getLatestPriceInfo ( priceFeedId ) === undefined
243270 ) {
244271 throw RestException . PriceFeedIdNotFound ( [ priceFeedId ] ) ;
245272 }
246273
247- const vaa = await this . getVaaWithDbLookup ( priceFeedId , publishTime ) ;
248-
249- if ( vaa === undefined ) {
274+ const vaaConfig = await this . getVaaWithDbLookup (
275+ priceFeedId ,
276+ publishTime
277+ ) ;
278+ if ( vaaConfig === undefined ) {
250279 throw RestException . VaaNotFound ( ) ;
251280 } else {
252- res . json ( vaa ) ;
281+ vaaConfig . vaa = encodeVaaForChain ( vaaConfig . vaa , targetChain ) ;
282+ res . json ( vaaConfig ) ;
253283 }
254284 } )
255285 ) ;
256286
257287 endpoints . push (
258- " api/get_vaa?id=<price_feed_id>&publish_time=<publish_time_in_unix_timestamp>"
288+ ` api/get_vaa?id=<price_feed_id>&publish_time=<publish_time_in_unix_timestamp>& ${ targetChainArgString } `
259289 ) ;
260290
261291 const getVaaCcipInputSchema : schema = {
@@ -317,6 +347,9 @@ export class RestAPI {
317347 . required ( ) ,
318348 verbose : Joi . boolean ( ) ,
319349 binary : Joi . boolean ( ) ,
350+ target_chain : Joi . string ( )
351+ . valid ( ...validTargetChains )
352+ . optional ( ) ,
320353 } ) . required ( ) ,
321354 } ;
322355 app . get (
@@ -326,8 +359,12 @@ export class RestAPI {
326359 const priceIds = ( req . query . ids as string [ ] ) . map ( removeLeading0x ) ;
327360 // verbose is optional, default to false
328361 const verbose = req . query . verbose === "true" ;
329- // binary is optional, default to false
330- const binary = req . query . binary === "true" ;
362+ // The binary and target_chain are somewhat redundant. Binary still exists for backward compatibility reasons.
363+ // No VAA will be returned if both arguments are omitted. binary=true is the same as target_chain=default
364+ let targetChain = req . query . target_chain as TargetChain | undefined ;
365+ if ( targetChain === undefined && req . query . binary === "true" ) {
366+ targetChain = defaultTargetChain ;
367+ }
331368
332369 const responseJson = [ ] ;
333370
@@ -342,7 +379,7 @@ export class RestAPI {
342379 }
343380
344381 responseJson . push (
345- this . priceInfoToJson ( latestPriceInfo , verbose , binary )
382+ this . priceInfoToJson ( latestPriceInfo , verbose , targetChain )
346383 ) ;
347384 }
348385
@@ -362,6 +399,9 @@ export class RestAPI {
362399 endpoints . push (
363400 "api/latest_price_feeds?ids[]=<price_feed_id>&ids[]=<price_feed_id_2>&..&verbose=true&binary=true"
364401 ) ;
402+ endpoints . push (
403+ `api/latest_price_feeds?ids[]=<price_feed_id>&ids[]=<price_feed_id_2>&..&verbose=true&${ targetChainArgString } `
404+ ) ;
365405
366406 const getPriceFeedInputSchema : schema = {
367407 query : Joi . object ( {
@@ -371,6 +411,9 @@ export class RestAPI {
371411 publish_time : Joi . number ( ) . required ( ) ,
372412 verbose : Joi . boolean ( ) ,
373413 binary : Joi . boolean ( ) ,
414+ target_chain : Joi . string ( )
415+ . valid ( ...validTargetChains )
416+ . optional ( ) ,
374417 } ) . required ( ) ,
375418 } ;
376419
@@ -382,8 +425,12 @@ export class RestAPI {
382425 const publishTime = Number ( req . query . publish_time as string ) ;
383426 // verbose is optional, default to false
384427 const verbose = req . query . verbose === "true" ;
385- // binary is optional, default to false
386- const binary = req . query . binary === "true" ;
428+ // The binary and target_chain are somewhat redundant. Binary still exists for backward compatibility reasons.
429+ // No VAA will be returned if both arguments are omitted. binary=true is the same as target_chain=default
430+ let targetChain = req . query . target_chain as TargetChain | undefined ;
431+ if ( targetChain === undefined && req . query . binary === "true" ) {
432+ targetChain = defaultTargetChain ;
433+ }
387434
388435 if (
389436 this . priceFeedVaaInfo . getLatestPriceInfo ( priceFeedId ) === undefined
@@ -404,7 +451,7 @@ export class RestAPI {
404451 if ( priceInfo === undefined ) {
405452 throw RestException . VaaNotFound ( ) ;
406453 } else {
407- res . json ( this . priceInfoToJson ( priceInfo , verbose , binary ) ) ;
454+ res . json ( this . priceInfoToJson ( priceInfo , verbose , targetChain ) ) ;
408455 }
409456 } )
410457 ) ;
0 commit comments