Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@pythnetwork/express-relay-evm-js

Package Overview
Dependencies
Maintainers
4
Versions
12
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@pythnetwork/express-relay-evm-js - npm Package Compare versions

Comparing version 0.1.0 to 0.1.1

48

lib/examples/SimpleSearcher.js

@@ -11,5 +11,2 @@ "use strict";

const viem_1 = require("viem");
function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
const argv = (0, yargs_1.default)((0, helpers_1.hideBin)(process.argv))

@@ -24,2 +21,3 @@ .option("endpoint", {

type: "string",
demandOption: true,
})

@@ -49,26 +47,28 @@ .option("bid", {

const DAY_IN_SECONDS = 60 * 60 * 24;
// eslint-disable-next-line no-constant-condition
while (true) {
const opportunities = await client.getOpportunities(argv.chainId);
console.log(`Fetched ${opportunities.length} opportunities`);
for (const opportunity of opportunities) {
const bid = BigInt(argv.bid);
// Bid info should be generated by evaluating the opportunity
// here for simplicity we are using a constant bid and 24 hours of validity
const bidInfo = {
amount: bid,
validUntil: BigInt(Math.round(Date.now() / 1000 + DAY_IN_SECONDS)),
};
const opportunityBid = await client.signOpportunityBid(opportunity, bidInfo, argv.privateKey);
try {
await client.submitOpportunityBid(opportunityBid);
console.log(`Successful bid ${bid} on opportunity ${opportunity.opportunityId}`);
}
catch (error) {
console.error(`Failed to bid on opportunity ${opportunity.opportunityId}: ${error}`);
}
client.setOpportunityHandler(async (opportunity) => {
const bid = BigInt(argv.bid);
// Bid info should be generated by evaluating the opportunity
// here for simplicity we are using a constant bid and 24 hours of validity
const bidInfo = {
amount: bid,
validUntil: BigInt(Math.round(Date.now() / 1000 + DAY_IN_SECONDS)),
};
const opportunityBid = await client.signOpportunityBid(opportunity, bidInfo, (0, index_1.checkHex)(argv.privateKey));
try {
await client.submitOpportunityBid(opportunityBid);
console.log(`Successful bid ${bid} on opportunity ${opportunity.opportunityId}`);
}
await sleep(5000);
catch (error) {
console.error(`Failed to bid on opportunity ${opportunity.opportunityId}: ${error}`);
}
});
try {
await client.subscribeChains([argv.chainId]);
console.log(`Subscribed to chain ${argv.chainId}. Waiting for opportunities...`);
}
catch (error) {
console.error(error);
client.websocket?.close();
}
}
run();

@@ -1,3 +0,6 @@

import { ClientOptions } from "openapi-fetch";
/// <reference types="ws" />
import type { components } from "./types";
import { ClientOptions as FetchClientOptions } from "openapi-fetch";
import { Address, Hex } from "viem";
import WebSocket from "isomorphic-ws";
/**

@@ -84,6 +87,44 @@ * ERC20 token with contract address and amount

export declare function checkAddress(address: string): Address;
type ClientOptions = FetchClientOptions & {
baseUrl: string;
};
export interface WsOptions {
/**
* Max time to wait for a response from the server in milliseconds
*/
response_timeout: number;
}
export declare class Client {
private clientOptions?;
constructor(clientOptions?: ClientOptions);
clientOptions: ClientOptions;
wsOptions: WsOptions;
websocket?: WebSocket;
idCounter: number;
callbackRouter: Record<string, (response: components["schemas"]["ServerResultMessage"]) => void>;
private websocketOpportunityCallback?;
constructor(clientOptions: ClientOptions, wsOptions?: WsOptions);
private connectWebsocket;
/**
* Converts an opportunity from the server to the client format
* Returns undefined if the opportunity version is not supported
* @param opportunity
*/
private convertOpportunity;
setOpportunityHandler(callback: (opportunity: Opportunity) => Promise<void>): void;
/**
* Subscribes to the specified chains
*
* The opportunity handler will be called for opportunities on the specified chains
* If the opportunity handler is not set, an error will be thrown
* @param chains
*/
subscribeChains(chains: string[]): Promise<void>;
/**
* Unsubscribes from the specified chains
*
* The opportunity handler will no longer be called for opportunities on the specified chains
* @param chains
*/
unsubscribeChains(chains: string[]): Promise<void>;
sendWebsocketMessage(msg: components["schemas"]["ClientMessage"]): Promise<void>;
/**
* Fetches liquidation opportunities

@@ -111,2 +152,3 @@ * @param chainId Chain id to fetch opportunities for. e.g: sepolia

}
export {};
//# sourceMappingURL=index.d.ts.map

@@ -10,2 +10,3 @@ "use strict";

const accounts_1 = require("viem/accounts");
const isomorphic_ws_1 = __importDefault(require("isomorphic-ws"));
function checkHex(hex) {

@@ -31,8 +32,138 @@ if ((0, viem_1.isHex)(hex)) {

}
const DEFAULT_WS_OPTIONS = {
response_timeout: 5000,
};
class Client {
clientOptions;
constructor(clientOptions) {
wsOptions;
websocket;
idCounter = 0;
callbackRouter = {};
websocketOpportunityCallback;
constructor(clientOptions, wsOptions) {
this.clientOptions = clientOptions;
this.wsOptions = { ...DEFAULT_WS_OPTIONS, ...wsOptions };
}
connectWebsocket() {
const websocketEndpoint = new URL(this.clientOptions.baseUrl);
websocketEndpoint.protocol =
websocketEndpoint.protocol === "https:" ? "wss:" : "ws:";
websocketEndpoint.pathname = "/v1/ws";
this.websocket = new isomorphic_ws_1.default(websocketEndpoint.toString());
this.websocket.on("message", async (data) => {
const message = JSON.parse(data.toString());
if ("id" in message && message.id) {
const callback = this.callbackRouter[message.id];
if (callback !== undefined) {
callback(message);
delete this.callbackRouter[message.id];
}
}
else if ("type" in message && message.type === "new_opportunity") {
if (this.websocketOpportunityCallback !== undefined) {
const convertedOpportunity = this.convertOpportunity(message.opportunity);
if (convertedOpportunity !== undefined) {
await this.websocketOpportunityCallback(convertedOpportunity);
}
}
}
else if ("error" in message) {
// Can not route error messages to the callback router as they don't have an id
console.error(message.error);
}
});
}
/**
* Converts an opportunity from the server to the client format
* Returns undefined if the opportunity version is not supported
* @param opportunity
*/
convertOpportunity(opportunity) {
if (opportunity.version != "v1") {
console.warn(`Can not handle opportunity version: ${opportunity.version}. Please upgrade your client.`);
return undefined;
}
return {
chainId: opportunity.chain_id,
opportunityId: opportunity.opportunity_id,
permissionKey: checkHex(opportunity.permission_key),
contract: checkAddress(opportunity.contract),
calldata: checkHex(opportunity.calldata),
value: BigInt(opportunity.value),
repayTokens: opportunity.repay_tokens.map(checkTokenQty),
receiptTokens: opportunity.receipt_tokens.map(checkTokenQty),
};
}
setOpportunityHandler(callback) {
this.websocketOpportunityCallback = callback;
}
/**
* Subscribes to the specified chains
*
* The opportunity handler will be called for opportunities on the specified chains
* If the opportunity handler is not set, an error will be thrown
* @param chains
*/
async subscribeChains(chains) {
if (this.websocketOpportunityCallback === undefined) {
throw new Error("Opportunity handler not set");
}
return this.sendWebsocketMessage({
method: "subscribe",
params: {
chain_ids: chains,
},
});
}
/**
* Unsubscribes from the specified chains
*
* The opportunity handler will no longer be called for opportunities on the specified chains
* @param chains
*/
async unsubscribeChains(chains) {
return this.sendWebsocketMessage({
method: "unsubscribe",
params: {
chain_ids: chains,
},
});
}
async sendWebsocketMessage(msg) {
const msg_with_id = {
...msg,
id: (this.idCounter++).toString(),
};
return new Promise((resolve, reject) => {
this.callbackRouter[msg_with_id.id] = (response) => {
if (response.status === "success") {
resolve();
}
else {
reject(response.result);
}
};
if (this.websocket === undefined) {
this.connectWebsocket();
}
if (this.websocket !== undefined) {
if (this.websocket.readyState === isomorphic_ws_1.default.CONNECTING) {
this.websocket.on("open", () => {
this.websocket?.send(JSON.stringify(msg_with_id));
});
}
else if (this.websocket.readyState === isomorphic_ws_1.default.OPEN) {
this.websocket.send(JSON.stringify(msg_with_id));
}
else {
reject("Websocket connection closing or already closed");
}
}
setTimeout(() => {
delete this.callbackRouter[msg_with_id.id];
reject("Websocket response timeout");
}, this.wsOptions.response_timeout);
});
}
/**
* Fetches liquidation opportunities

@@ -50,16 +181,7 @@ * @param chainId Chain id to fetch opportunities for. e.g: sepolia

return opportunities.data.flatMap((opportunity) => {
if (opportunity.version != "v1") {
console.warn(`Can not handle opportunity version: ${opportunity.version}. Please upgrade your client.`);
const convertedOpportunity = this.convertOpportunity(opportunity);
if (convertedOpportunity === undefined) {
return [];
}
return {
chainId: opportunity.chain_id,
opportunityId: opportunity.opportunity_id,
permissionKey: checkHex(opportunity.permission_key),
contract: checkAddress(opportunity.contract),
calldata: checkHex(opportunity.calldata),
value: BigInt(opportunity.value),
repayTokens: opportunity.repay_tokens.map(checkTokenQty),
receiptTokens: opportunity.receipt_tokens.map(checkTokenQty),
};
return convertedOpportunity;
});

@@ -136,2 +258,3 @@ }

{ name: "bid", type: "uint256" },
{ name: "validUntil", type: "uint256" },
], [

@@ -144,4 +267,5 @@ opportunity.repayTokens.map(convertTokenQty),

bidInfo.amount,
bidInfo.validUntil,
]);
const msgHash = (0, viem_1.keccak256)((0, viem_1.encodePacked)(["bytes", "uint256"], [payload, bidInfo.validUntil]));
const msgHash = (0, viem_1.keccak256)(payload);
const hash = (0, accounts_1.signatureToHex)(await (0, accounts_1.sign)({ hash: msgHash, privateKey }));

@@ -148,0 +272,0 @@ return {

{
"name": "@pythnetwork/express-relay-evm-js",
"version": "0.1.0",
"version": "0.1.1",
"description": "Utilities for interacting with the express relay protocol",

@@ -39,5 +39,7 @@ "homepage": "https://pyth.network",

"dependencies": {
"isomorphic-ws": "^5.0.0",
"openapi-client-axios": "^7.5.4",
"openapi-fetch": "^0.8.2",
"viem": "^2.7.6"
"viem": "^2.7.6",
"ws": "^8.16.0"
},

@@ -56,3 +58,3 @@ "devDependencies": {

"license": "Apache-2.0",
"gitHead": "6771c2c6998f53effee9247347cb0ac71612b3dc"
"gitHead": "0d49986eb1cd77c969059bcb72857e90ba8ae4f8"
}

@@ -38,13 +38,10 @@ # Pyth Express Relay JS SDK

function calculateOpportunityBid(
opportunity: OpportunityParams
): BidInfo | null {
function calculateOpportunityBid(opportunity: Opportunity): BidInfo | null {
// searcher implementation here
// if the opportunity is not suitable for the searcher, return null
}
const opportunities = await client.getOpportunities();
for (const opportunity of opportunities) {
const bidInfo = calculateOpportunityBid(order);
if (bidInfo === null) continue;
client.setOpportunityHandler(async (opportunity: Opportunity) => {
const bidInfo = calculateOpportunityBid(opportunity);
if (bidInfo === null) return;
const opportunityBid = await client.signOpportunityBid(

@@ -56,3 +53,4 @@ opportunity,

await client.submitOpportunityBid(opportunityBid);
}
});
await client.subscribeChains([chain_id]); // chain id you want to subscribe to
```

@@ -59,0 +57,0 @@

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc