@@ -16,11 +16,24 @@ import { logger } from "./logging";
16
16
import { PromClient } from "./promClient" ;
17
17
import { retry } from "ts-retry-promise" ;
18
18
import { 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" ;
19
27
20
28
const MORGAN_LOG_FORMAT =
21
29
':remote-addr - :remote-user ":method :url HTTP/:http-version"' +
22
30
' :status :res[content-length] :response-time ms ":referrer" ":user-agent"' ;
23
31
32
+ // GET argument string to represent the options for target_chain
33
+ export const targetChainArgString = `target_chain=<${ validTargetChains . join (
34
+ "|"
35
+ ) } >`;
36
+
24
37
export class RestException extends Error {
25
38
statusCode : number ;
26
39
message : string ;
@@ -144,7 +157,7 @@ export class RestAPI {
144
157
priceInfoToJson (
145
158
priceInfo : PriceInfo ,
146
159
verbose : boolean ,
147
- binary : boolean
160
+ targetChain : TargetChain | undefined
148
161
) : object {
149
162
return {
150
163
...priceInfo . priceFeed . toJson ( ) ,
@@ -156,8 +169,8 @@ export class RestAPI {
156
169
price_service_receive_time : priceInfo . priceServiceReceiveTime ,
157
170
} ,
158
171
} ) ,
159
- ...( binary && {
160
- vaa : priceInfo . vaa . toString ( "base64" ) ,
172
+ ...( targetChain !== undefined && {
173
+ vaa : encodeVaaForChain ( priceInfo . vaa , targetChain ) ,
161
174
} ) ,
162
175
} ;
163
176
}
@@ -182,13 +195,20 @@ export class RestAPI {
182
195
ids : Joi . array ( )
183
196
. items ( Joi . string ( ) . regex ( / ^ ( 0 x ) ? [ a - f 0 - 9 ] { 64 } $ / ) )
184
197
. required ( ) ,
198
+ target_chain : Joi . string ( )
199
+ . valid ( ...validTargetChains )
200
+ . optional ( ) ,
185
201
} ) . required ( ) ,
186
202
} ;
187
203
app . get (
188
204
"/api/latest_vaas" ,
189
205
validate ( latestVaasInputSchema ) ,
190
206
( req : Request , res : Response ) => {
191
207
const priceIds = ( req . query . ids as string [ ] ) . map ( removeLeading0x ) ;
208
+ const targetChain = getOrElse (
209
+ req . query . target_chain as TargetChain | undefined ,
210
+ defaultTargetChain
211
+ ) ;
192
212
193
213
// Multiple price ids might share same vaa, we use sequence number as
194
214
// key of a vaa and deduplicate using a map of seqnum to vaa bytes.
@@ -212,14 +232,14 @@ export class RestAPI {
212
232
}
213
233
214
234
const jsonResponse = Array . from ( vaaMap . values ( ) , ( vaa ) =>
215
- vaa . toString ( "base64" )
235
+ encodeVaaForChain ( vaa , targetChain )
216
236
) ;
217
237
218
238
res . json ( jsonResponse ) ;
219
239
}
220
240
) ;
221
241
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 } `
223
243
) ;
224
244
225
245
const getVaaInputSchema : schema = {
@@ -228,6 +248,9 @@ export class RestAPI {
228
248
. regex ( / ^ ( 0 x ) ? [ a - f 0 - 9 ] { 64 } $ / )
229
249
. required ( ) ,
230
250
publish_time : Joi . number ( ) . required ( ) ,
251
+ target_chain : Joi . string ( )
252
+ . valid ( ...validTargetChains )
253
+ . optional ( ) ,
231
254
} ) . required ( ) ,
232
255
} ;
233
256
@@ -237,25 +260,32 @@ export class RestAPI {
237
260
asyncWrapper ( async ( req : Request , res : Response ) => {
238
261
const priceFeedId = removeLeading0x ( req . query . id as string ) ;
239
262
const publishTime = Number ( req . query . publish_time as string ) ;
263
+ const targetChain = getOrElse (
264
+ req . query . target_chain as TargetChain | undefined ,
265
+ defaultTargetChain
266
+ ) ;
240
267
241
268
if (
242
269
this . priceFeedVaaInfo . getLatestPriceInfo ( priceFeedId ) === undefined
243
270
) {
244
271
throw RestException . PriceFeedIdNotFound ( [ priceFeedId ] ) ;
245
272
}
246
273
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 ) {
250
279
throw RestException . VaaNotFound ( ) ;
251
280
} else {
252
- res . json ( vaa ) ;
281
+ vaaConfig . vaa = encodeVaaForChain ( vaaConfig . vaa , targetChain ) ;
282
+ res . json ( vaaConfig ) ;
253
283
}
254
284
} )
255
285
) ;
256
286
257
287
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 } `
259
289
) ;
260
290
261
291
const getVaaCcipInputSchema : schema = {
@@ -317,6 +347,9 @@ export class RestAPI {
317
347
. required ( ) ,
318
348
verbose : Joi . boolean ( ) ,
319
349
binary : Joi . boolean ( ) ,
350
+ target_chain : Joi . string ( )
351
+ . valid ( ...validTargetChains )
352
+ . optional ( ) ,
320
353
} ) . required ( ) ,
321
354
} ;
322
355
app . get (
@@ -326,8 +359,12 @@ export class RestAPI {
326
359
const priceIds = ( req . query . ids as string [ ] ) . map ( removeLeading0x ) ;
327
360
// verbose is optional, default to false
328
361
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
+ }
331
368
332
369
const responseJson = [ ] ;
333
370
@@ -342,7 +379,7 @@ export class RestAPI {
342
379
}
343
380
344
381
responseJson . push (
345
- this . priceInfoToJson ( latestPriceInfo , verbose , binary )
382
+ this . priceInfoToJson ( latestPriceInfo , verbose , targetChain )
346
383
) ;
347
384
}
348
385
@@ -362,6 +399,9 @@ export class RestAPI {
362
399
endpoints . push (
363
400
"api/latest_price_feeds?ids[]=<price_feed_id>&ids[]=<price_feed_id_2>&..&verbose=true&binary=true"
364
401
) ;
402
+ endpoints . push (
403
+ `api/latest_price_feeds?ids[]=<price_feed_id>&ids[]=<price_feed_id_2>&..&verbose=true&${ targetChainArgString } `
404
+ ) ;
365
405
366
406
const getPriceFeedInputSchema : schema = {
367
407
query : Joi . object ( {
@@ -371,6 +411,9 @@ export class RestAPI {
371
411
publish_time : Joi . number ( ) . required ( ) ,
372
412
verbose : Joi . boolean ( ) ,
373
413
binary : Joi . boolean ( ) ,
414
+ target_chain : Joi . string ( )
415
+ . valid ( ...validTargetChains )
416
+ . optional ( ) ,
374
417
} ) . required ( ) ,
375
418
} ;
376
419
@@ -382,8 +425,12 @@ export class RestAPI {
382
425
const publishTime = Number ( req . query . publish_time as string ) ;
383
426
// verbose is optional, default to false
384
427
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
+ }
387
434
388
435
if (
389
436
this . priceFeedVaaInfo . getLatestPriceInfo ( priceFeedId ) === undefined
@@ -404,7 +451,7 @@ export class RestAPI {
404
451
if ( priceInfo === undefined ) {
405
452
throw RestException . VaaNotFound ( ) ;
406
453
} else {
407
- res . json ( this . priceInfoToJson ( priceInfo , verbose , binary ) ) ;
454
+ res . json ( this . priceInfoToJson ( priceInfo , verbose , targetChain ) ) ;
408
455
}
409
456
} )
410
457
) ;
0 commit comments