Skip to content

Commit f8ed6dd

Browse files
authored
feat(express-relay): Add api key (#1619)
1 parent b672613 commit f8ed6dd

File tree

11 files changed

+311
-59
lines changed

11 files changed

+311
-59
lines changed

express_relay/sdk/js/package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

express_relay/sdk/js/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@pythnetwork/express-relay-evm-js",
3-
"version": "0.5.0",
3+
"version": "0.6.0",
44
"description": "Utilities for interacting with the express relay protocol",
55
"homepage": "https://github.com/pyth-network/pyth-crosschain/tree/main/express_relay/sdk/js",
66
"author": "Douro Labs",

express_relay/sdk/js/src/examples/simpleSearcher.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,14 @@ class SimpleSearcher {
1212
constructor(
1313
public endpoint: string,
1414
public chainId: string,
15-
public privateKey: string
15+
public privateKey: string,
16+
public apiKey?: string
1617
) {
1718
this.client = new Client(
18-
{ baseUrl: endpoint },
19+
{
20+
baseUrl: endpoint,
21+
apiKey,
22+
},
1923
undefined,
2024
this.opportunityHandler.bind(this),
2125
this.bidStatusHandler.bind(this)
@@ -103,6 +107,12 @@ const argv = yargs(hideBin(process.argv))
103107
type: "string",
104108
demandOption: true,
105109
})
110+
.option("api-key", {
111+
description:
112+
"The API key of the searcher to authenticate with the server for fetching and submitting bids",
113+
type: "string",
114+
demandOption: false,
115+
})
106116
.help()
107117
.alias("help", "h")
108118
.parseSync();
@@ -116,7 +126,8 @@ async function run() {
116126
const searcher = new SimpleSearcher(
117127
argv.endpoint,
118128
argv.chainId,
119-
argv.privateKey
129+
argv.privateKey,
130+
argv.apiKey
120131
);
121132
await searcher.start();
122133
}

express_relay/sdk/js/src/index.ts

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { components, paths } from "./serverTypes";
22
import createClient, {
33
ClientOptions as FetchClientOptions,
4+
HeadersOptions,
45
} from "openapi-fetch";
56
import { Address, Hex, isAddress, isHex } from "viem";
67
import { privateKeyToAccount, signTypedData } from "viem/accounts";
@@ -15,13 +16,14 @@ import {
1516
OpportunityBid,
1617
OpportunityParams,
1718
TokenAmount,
19+
BidsResponse,
1820
} from "./types";
1921

2022
export * from "./types";
2123

2224
export class ClientError extends Error {}
2325

24-
type ClientOptions = FetchClientOptions & { baseUrl: string };
26+
type ClientOptions = FetchClientOptions & { baseUrl: string; apiKey?: string };
2527

2628
export interface WsOptions {
2729
/**
@@ -75,13 +77,25 @@ export class Client {
7577
statusUpdate: BidStatusUpdate
7678
) => Promise<void>;
7779

80+
private getAuthorization() {
81+
return this.clientOptions.apiKey
82+
? {
83+
Authorization: `Bearer ${this.clientOptions.apiKey}`,
84+
}
85+
: {};
86+
}
87+
7888
constructor(
7989
clientOptions: ClientOptions,
8090
wsOptions?: WsOptions,
8191
opportunityCallback?: (opportunity: Opportunity) => Promise<void>,
8292
bidStatusCallback?: (statusUpdate: BidStatusUpdate) => Promise<void>
8393
) {
8494
this.clientOptions = clientOptions;
95+
this.clientOptions.headers = {
96+
...(this.clientOptions.headers ?? {}),
97+
...this.getAuthorization(),
98+
};
8599
this.wsOptions = { ...DEFAULT_WS_OPTIONS, ...wsOptions };
86100
this.websocketOpportunityCallback = opportunityCallback;
87101
this.websocketBidStatusCallback = bidStatusCallback;
@@ -93,7 +107,9 @@ export class Client {
93107
websocketEndpoint.protocol === "https:" ? "wss:" : "ws:";
94108
websocketEndpoint.pathname = "/v1/ws";
95109

96-
this.websocket = new WebSocket(websocketEndpoint.toString());
110+
this.websocket = new WebSocket(websocketEndpoint.toString(), {
111+
headers: this.getAuthorization(),
112+
});
97113
this.websocket.on("message", async (data: string) => {
98114
const message:
99115
| components["schemas"]["ServerResultResponse"]
@@ -443,4 +459,23 @@ export class Client {
443459
}
444460
}
445461
}
462+
463+
/**
464+
* Get bids for an api key
465+
* @param fromTime The datetime to fetch bids from. If undefined or null, fetches from the beginning of time.
466+
* @returns The paginated bids response
467+
*/
468+
async getBids(fromTime?: Date): Promise<BidsResponse> {
469+
const client = createClient<paths>(this.clientOptions);
470+
const response = await client.GET("/v1/bids", {
471+
params: { query: { from_time: fromTime?.toISOString() } },
472+
});
473+
if (response.error) {
474+
throw new ClientError(response.error.error);
475+
} else if (response.data === undefined) {
476+
throw new ClientError("No data returned");
477+
} else {
478+
return response.data;
479+
}
480+
}
446481
}

express_relay/sdk/js/src/serverTypes.d.ts

Lines changed: 110 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -5,43 +5,42 @@
55

66
export interface paths {
77
"/v1/bids": {
8+
/**
9+
* Returns at most 20 bids which were submitted after a specific time.
10+
* @description If no time is provided, the server will return the first bids.
11+
*/
12+
get: operations["get_bids_by_time"];
813
/**
914
* Bid on a specific permission key for a specific chain.
10-
* @description Bid on a specific permission key for a specific chain.
11-
*
12-
* Your bid will be simulated and verified by the server. Depending on the outcome of the auction, a transaction
15+
* @description Your bid will be simulated and verified by the server. Depending on the outcome of the auction, a transaction
1316
* containing the contract call will be sent to the blockchain expecting the bid amount to be paid after the call.
1417
*/
1518
post: operations["bid"];
1619
};
1720
"/v1/bids/{bid_id}": {
18-
/**
19-
* Query the status of a specific bid.
20-
* @description Query the status of a specific bid.
21-
*/
21+
/** Query the status of a specific bid. */
2222
get: operations["bid_status"];
2323
};
2424
"/v1/opportunities": {
25-
/**
26-
* Fetch all opportunities ready to be exectued.
27-
* @description Fetch all opportunities ready to be exectued.
28-
*/
25+
/** Fetch all opportunities ready to be exectued. */
2926
get: operations["get_opportunities"];
3027
/**
3128
* Submit an opportunity ready to be executed.
32-
* @description Submit an opportunity ready to be executed.
33-
*
34-
* The opportunity will be verified by the server. If the opportunity is valid, it will be stored in the database
29+
* @description The opportunity will be verified by the server. If the opportunity is valid, it will be stored in the database
3530
* and will be available for bidding.
3631
*/
3732
post: operations["post_opportunity"];
3833
};
3934
"/v1/opportunities/{opportunity_id}/bids": {
35+
/** Bid on opportunity */
36+
post: operations["opportunity_bid"];
37+
};
38+
"/v1/profiles/access_tokens": {
4039
/**
41-
* Bid on opportunity
42-
* @description Bid on opportunity
40+
* Revoke the authenticated profile access token.
41+
* @description Returns empty response.
4342
*/
44-
post: operations["opportunity_bid"];
43+
delete: operations["delete_profile_access_token"];
4544
};
4645
}
4746

@@ -295,6 +294,54 @@ export interface components {
295294
/** @enum {string} */
296295
type: "bid_status_update";
297296
};
297+
/** BidResponse */
298+
SimulatedBid: {
299+
/**
300+
* @description Amount of bid in wei.
301+
* @example 10
302+
*/
303+
bid_amount: string;
304+
/**
305+
* @description The chain id for bid.
306+
* @example op_sepolia
307+
*/
308+
chain_id: string;
309+
/**
310+
* @description The unique id for bid.
311+
* @example obo3ee3e-58cc-4372-a567-0e02b2c3d479
312+
*/
313+
id: string;
314+
/**
315+
* @description The time server received the bid formatted in rfc3339.
316+
* @example 2024-05-23T21:26:57.329954Z
317+
*/
318+
initiation_time: string;
319+
/**
320+
* @description The permission key for bid.
321+
* @example 0xdeadbeef
322+
*/
323+
permission_key: string;
324+
/**
325+
* @description The profile id for the bid owner.
326+
* @example
327+
*/
328+
profile_id: string;
329+
status: components["schemas"]["BidStatus"];
330+
/**
331+
* @description Calldata for the contract call.
332+
* @example 0xdeadbeef
333+
*/
334+
target_calldata: string;
335+
/**
336+
* @description The contract address to call.
337+
* @example 0xcA11bde05977b3631167028862bE2a173976CA11
338+
*/
339+
target_contract: string;
340+
};
341+
/** BidsResponse */
342+
SimulatedBids: {
343+
items: components["schemas"]["SimulatedBid"][];
344+
};
298345
TokenAmount: {
299346
/**
300347
* @description Token amount
@@ -350,6 +397,13 @@ export interface components {
350397
};
351398
};
352399
};
400+
SimulatedBids: {
401+
content: {
402+
"application/json": {
403+
items: components["schemas"]["SimulatedBid"][];
404+
};
405+
};
406+
};
353407
};
354408
parameters: never;
355409
requestBodies: never;
@@ -362,11 +416,30 @@ export type $defs = Record<string, never>;
362416
export type external = Record<string, never>;
363417

364418
export interface operations {
419+
/**
420+
* Returns at most 20 bids which were submitted after a specific time.
421+
* @description If no time is provided, the server will return the first bids.
422+
*/
423+
get_bids_by_time: {
424+
parameters: {
425+
query?: {
426+
/** @example 2024-05-23T21:26:57.329954Z */
427+
from_time?: string | null;
428+
};
429+
};
430+
responses: {
431+
/** @description Paginated list of bids for the specified query */
432+
200: {
433+
content: {
434+
"application/json": components["schemas"]["SimulatedBids"];
435+
};
436+
};
437+
400: components["responses"]["ErrorBodyResponse"];
438+
};
439+
};
365440
/**
366441
* Bid on a specific permission key for a specific chain.
367-
* @description Bid on a specific permission key for a specific chain.
368-
*
369-
* Your bid will be simulated and verified by the server. Depending on the outcome of the auction, a transaction
442+
* @description Your bid will be simulated and verified by the server. Depending on the outcome of the auction, a transaction
370443
* containing the contract call will be sent to the blockchain expecting the bid amount to be paid after the call.
371444
*/
372445
bid: {
@@ -391,10 +464,7 @@ export interface operations {
391464
};
392465
};
393466
};
394-
/**
395-
* Query the status of a specific bid.
396-
* @description Query the status of a specific bid.
397-
*/
467+
/** Query the status of a specific bid. */
398468
bid_status: {
399469
parameters: {
400470
path: {
@@ -418,10 +488,7 @@ export interface operations {
418488
};
419489
};
420490
};
421-
/**
422-
* Fetch all opportunities ready to be exectued.
423-
* @description Fetch all opportunities ready to be exectued.
424-
*/
491+
/** Fetch all opportunities ready to be exectued. */
425492
get_opportunities: {
426493
parameters: {
427494
query?: {
@@ -447,9 +514,7 @@ export interface operations {
447514
};
448515
/**
449516
* Submit an opportunity ready to be executed.
450-
* @description Submit an opportunity ready to be executed.
451-
*
452-
* The opportunity will be verified by the server. If the opportunity is valid, it will be stored in the database
517+
* @description The opportunity will be verified by the server. If the opportunity is valid, it will be stored in the database
453518
* and will be available for bidding.
454519
*/
455520
post_opportunity: {
@@ -474,10 +539,7 @@ export interface operations {
474539
};
475540
};
476541
};
477-
/**
478-
* Bid on opportunity
479-
* @description Bid on opportunity
480-
*/
542+
/** Bid on opportunity */
481543
opportunity_bid: {
482544
parameters: {
483545
path: {
@@ -506,4 +568,17 @@ export interface operations {
506568
};
507569
};
508570
};
571+
/**
572+
* Revoke the authenticated profile access token.
573+
* @description Returns empty response.
574+
*/
575+
delete_profile_access_token: {
576+
responses: {
577+
/** @description The token successfully revoked */
578+
200: {
579+
content: never;
580+
};
581+
400: components["responses"]["ErrorBodyResponse"];
582+
};
583+
};
509584
}

express_relay/sdk/js/src/types.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,3 +150,8 @@ export type Bid = {
150150
export type BidStatusUpdate = {
151151
id: BidId;
152152
} & components["schemas"]["BidStatus"];
153+
154+
export type BidResponse = components["schemas"]["SimulatedBid"];
155+
export type BidsResponse = {
156+
items: BidResponse[];
157+
};

0 commit comments

Comments
 (0)