Skip to content

Commit

Permalink
feat(express-relay): Add api key (#1619)
Browse files Browse the repository at this point in the history
  • Loading branch information
danimhr committed May 28, 2024
1 parent b672613 commit f8ed6dd
Show file tree
Hide file tree
Showing 11 changed files with 311 additions and 59 deletions.
2 changes: 1 addition & 1 deletion express_relay/sdk/js/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion express_relay/sdk/js/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@pythnetwork/express-relay-evm-js",
"version": "0.5.0",
"version": "0.6.0",
"description": "Utilities for interacting with the express relay protocol",
"homepage": "https://github.com/pyth-network/pyth-crosschain/tree/main/express_relay/sdk/js",
"author": "Douro Labs",
Expand Down
17 changes: 14 additions & 3 deletions express_relay/sdk/js/src/examples/simpleSearcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,14 @@ class SimpleSearcher {
constructor(
public endpoint: string,
public chainId: string,
public privateKey: string
public privateKey: string,
public apiKey?: string
) {
this.client = new Client(
{ baseUrl: endpoint },
{
baseUrl: endpoint,
apiKey,
},
undefined,
this.opportunityHandler.bind(this),
this.bidStatusHandler.bind(this)
Expand Down Expand Up @@ -103,6 +107,12 @@ const argv = yargs(hideBin(process.argv))
type: "string",
demandOption: true,
})
.option("api-key", {
description:
"The API key of the searcher to authenticate with the server for fetching and submitting bids",
type: "string",
demandOption: false,
})
.help()
.alias("help", "h")
.parseSync();
Expand All @@ -116,7 +126,8 @@ async function run() {
const searcher = new SimpleSearcher(
argv.endpoint,
argv.chainId,
argv.privateKey
argv.privateKey,
argv.apiKey
);
await searcher.start();
}
Expand Down
39 changes: 37 additions & 2 deletions express_relay/sdk/js/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { components, paths } from "./serverTypes";
import createClient, {
ClientOptions as FetchClientOptions,
HeadersOptions,

Check warning on line 4 in express_relay/sdk/js/src/index.ts

View workflow job for this annotation

GitHub Actions / Publish Javascript Packages to NPM

'HeadersOptions' is defined but never used
} from "openapi-fetch";
import { Address, Hex, isAddress, isHex } from "viem";
import { privateKeyToAccount, signTypedData } from "viem/accounts";
Expand All @@ -15,13 +16,14 @@ import {
OpportunityBid,
OpportunityParams,
TokenAmount,
BidsResponse,
} from "./types";

export * from "./types";

export class ClientError extends Error {}

type ClientOptions = FetchClientOptions & { baseUrl: string };
type ClientOptions = FetchClientOptions & { baseUrl: string; apiKey?: string };

export interface WsOptions {
/**
Expand Down Expand Up @@ -75,13 +77,25 @@ export class Client {
statusUpdate: BidStatusUpdate
) => Promise<void>;

private getAuthorization() {
return this.clientOptions.apiKey
? {
Authorization: `Bearer ${this.clientOptions.apiKey}`,
}
: {};
}

constructor(
clientOptions: ClientOptions,
wsOptions?: WsOptions,
opportunityCallback?: (opportunity: Opportunity) => Promise<void>,
bidStatusCallback?: (statusUpdate: BidStatusUpdate) => Promise<void>
) {
this.clientOptions = clientOptions;
this.clientOptions.headers = {
...(this.clientOptions.headers ?? {}),
...this.getAuthorization(),
};
this.wsOptions = { ...DEFAULT_WS_OPTIONS, ...wsOptions };
this.websocketOpportunityCallback = opportunityCallback;
this.websocketBidStatusCallback = bidStatusCallback;
Expand All @@ -93,7 +107,9 @@ export class Client {
websocketEndpoint.protocol === "https:" ? "wss:" : "ws:";
websocketEndpoint.pathname = "/v1/ws";

this.websocket = new WebSocket(websocketEndpoint.toString());
this.websocket = new WebSocket(websocketEndpoint.toString(), {
headers: this.getAuthorization(),
});
this.websocket.on("message", async (data: string) => {
const message:
| components["schemas"]["ServerResultResponse"]
Expand Down Expand Up @@ -443,4 +459,23 @@ export class Client {
}
}
}

/**
* Get bids for an api key
* @param fromTime The datetime to fetch bids from. If undefined or null, fetches from the beginning of time.
* @returns The paginated bids response
*/
async getBids(fromTime?: Date): Promise<BidsResponse> {
const client = createClient<paths>(this.clientOptions);
const response = await client.GET("/v1/bids", {
params: { query: { from_time: fromTime?.toISOString() } },
});
if (response.error) {
throw new ClientError(response.error.error);
} else if (response.data === undefined) {
throw new ClientError("No data returned");
} else {
return response.data;
}
}
}
145 changes: 110 additions & 35 deletions express_relay/sdk/js/src/serverTypes.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,43 +5,42 @@

export interface paths {
"/v1/bids": {
/**
* Returns at most 20 bids which were submitted after a specific time.
* @description If no time is provided, the server will return the first bids.
*/
get: operations["get_bids_by_time"];
/**
* Bid on a specific permission key for a specific chain.
* @description Bid on a specific permission key for a specific chain.
*
* Your bid will be simulated and verified by the server. Depending on the outcome of the auction, a transaction
* @description Your bid will be simulated and verified by the server. Depending on the outcome of the auction, a transaction
* containing the contract call will be sent to the blockchain expecting the bid amount to be paid after the call.
*/
post: operations["bid"];
};
"/v1/bids/{bid_id}": {
/**
* Query the status of a specific bid.
* @description Query the status of a specific bid.
*/
/** Query the status of a specific bid. */
get: operations["bid_status"];
};
"/v1/opportunities": {
/**
* Fetch all opportunities ready to be exectued.
* @description Fetch all opportunities ready to be exectued.
*/
/** Fetch all opportunities ready to be exectued. */
get: operations["get_opportunities"];
/**
* Submit an opportunity ready to be executed.
* @description Submit an opportunity ready to be executed.
*
* The opportunity will be verified by the server. If the opportunity is valid, it will be stored in the database
* @description The opportunity will be verified by the server. If the opportunity is valid, it will be stored in the database
* and will be available for bidding.
*/
post: operations["post_opportunity"];
};
"/v1/opportunities/{opportunity_id}/bids": {
/** Bid on opportunity */
post: operations["opportunity_bid"];
};
"/v1/profiles/access_tokens": {
/**
* Bid on opportunity
* @description Bid on opportunity
* Revoke the authenticated profile access token.
* @description Returns empty response.
*/
post: operations["opportunity_bid"];
delete: operations["delete_profile_access_token"];
};
}

Expand Down Expand Up @@ -295,6 +294,54 @@ export interface components {
/** @enum {string} */
type: "bid_status_update";
};
/** BidResponse */
SimulatedBid: {
/**
* @description Amount of bid in wei.
* @example 10
*/
bid_amount: string;
/**
* @description The chain id for bid.
* @example op_sepolia
*/
chain_id: string;
/**
* @description The unique id for bid.
* @example obo3ee3e-58cc-4372-a567-0e02b2c3d479
*/
id: string;
/**
* @description The time server received the bid formatted in rfc3339.
* @example 2024-05-23T21:26:57.329954Z
*/
initiation_time: string;
/**
* @description The permission key for bid.
* @example 0xdeadbeef
*/
permission_key: string;
/**
* @description The profile id for the bid owner.
* @example
*/
profile_id: string;
status: components["schemas"]["BidStatus"];
/**
* @description Calldata for the contract call.
* @example 0xdeadbeef
*/
target_calldata: string;
/**
* @description The contract address to call.
* @example 0xcA11bde05977b3631167028862bE2a173976CA11
*/
target_contract: string;
};
/** BidsResponse */
SimulatedBids: {
items: components["schemas"]["SimulatedBid"][];
};
TokenAmount: {
/**
* @description Token amount
Expand Down Expand Up @@ -350,6 +397,13 @@ export interface components {
};
};
};
SimulatedBids: {
content: {
"application/json": {
items: components["schemas"]["SimulatedBid"][];
};
};
};
};
parameters: never;
requestBodies: never;
Expand All @@ -362,11 +416,30 @@ export type $defs = Record<string, never>;
export type external = Record<string, never>;

export interface operations {
/**
* Returns at most 20 bids which were submitted after a specific time.
* @description If no time is provided, the server will return the first bids.
*/
get_bids_by_time: {
parameters: {
query?: {
/** @example 2024-05-23T21:26:57.329954Z */
from_time?: string | null;
};
};
responses: {
/** @description Paginated list of bids for the specified query */
200: {
content: {
"application/json": components["schemas"]["SimulatedBids"];
};
};
400: components["responses"]["ErrorBodyResponse"];
};
};
/**
* Bid on a specific permission key for a specific chain.
* @description Bid on a specific permission key for a specific chain.
*
* Your bid will be simulated and verified by the server. Depending on the outcome of the auction, a transaction
* @description Your bid will be simulated and verified by the server. Depending on the outcome of the auction, a transaction
* containing the contract call will be sent to the blockchain expecting the bid amount to be paid after the call.
*/
bid: {
Expand All @@ -391,10 +464,7 @@ export interface operations {
};
};
};
/**
* Query the status of a specific bid.
* @description Query the status of a specific bid.
*/
/** Query the status of a specific bid. */
bid_status: {
parameters: {
path: {
Expand All @@ -418,10 +488,7 @@ export interface operations {
};
};
};
/**
* Fetch all opportunities ready to be exectued.
* @description Fetch all opportunities ready to be exectued.
*/
/** Fetch all opportunities ready to be exectued. */
get_opportunities: {
parameters: {
query?: {
Expand All @@ -447,9 +514,7 @@ export interface operations {
};
/**
* Submit an opportunity ready to be executed.
* @description Submit an opportunity ready to be executed.
*
* The opportunity will be verified by the server. If the opportunity is valid, it will be stored in the database
* @description The opportunity will be verified by the server. If the opportunity is valid, it will be stored in the database
* and will be available for bidding.
*/
post_opportunity: {
Expand All @@ -474,10 +539,7 @@ export interface operations {
};
};
};
/**
* Bid on opportunity
* @description Bid on opportunity
*/
/** Bid on opportunity */
opportunity_bid: {
parameters: {
path: {
Expand Down Expand Up @@ -506,4 +568,17 @@ export interface operations {
};
};
};
/**
* Revoke the authenticated profile access token.
* @description Returns empty response.
*/
delete_profile_access_token: {
responses: {
/** @description The token successfully revoked */
200: {
content: never;
};
400: components["responses"]["ErrorBodyResponse"];
};
};
}
5 changes: 5 additions & 0 deletions express_relay/sdk/js/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,3 +150,8 @@ export type Bid = {
export type BidStatusUpdate = {
id: BidId;
} & components["schemas"]["BidStatus"];

export type BidResponse = components["schemas"]["SimulatedBid"];
export type BidsResponse = {
items: BidResponse[];
};
Loading

0 comments on commit f8ed6dd

Please sign in to comment.