Skip to content

Commit

Permalink
feat: add websocket support
Browse files Browse the repository at this point in the history
  • Loading branch information
denis-pingin committed Sep 24, 2023
1 parent b3a620c commit 6f8edad
Show file tree
Hide file tree
Showing 9 changed files with 249 additions and 23 deletions.
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@
},
"dependencies": {
"axios": "0.27.2",
"ethers": "6.7.0"
"ethers": "6.7.0",
"isomorphic-ws": "^5.0.0",
"ws": "^8.5.0"
},
"lint-staged": {
"*.{js,json,md,ts}": "yarn format",
Expand Down
110 changes: 92 additions & 18 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
GELATO_RELAY_CONCURRENT_ERC2771_ZKSYNC_ADDRESS,
GELATO_RELAY_1BALANCE_CONCURRENT_ERC2771_ZKSYNC_ADDRESS,
} from "./constants";
import { WebsocketHandler } from "./utils/index.js";

export {
CallWithSyncFeeRequest,
Expand All @@ -47,11 +48,18 @@ export {
CallWithConcurrentERC2771Request,
Config,
};

export class GelatoRelay {
#config: Config;
readonly #websocketHandler?: WebsocketHandler;

constructor(config?: Partial<Config>) {
this.#config = this._getConfiguration(config);

if (this.#config.useWebsocket) {
const websocketUrl = this.#config.url.replace(/^http/, "ws");
this.#websocketHandler = new WebsocketHandler(websocketUrl);
}
}

/**
Expand Down Expand Up @@ -89,6 +97,7 @@ export class GelatoRelay {
config?.contract?.relay1BalanceConcurrentERC2771zkSync ??
GELATO_RELAY_1BALANCE_CONCURRENT_ERC2771_ZKSYNC_ADDRESS,
},
useWebsocket: config?.useWebsocket ?? true,
};
};

Expand All @@ -99,12 +108,22 @@ export class GelatoRelay {
* @returns {Promise<RelayResponse>} Response object with taskId parameter
*
*/
callWithSyncFee = (
callWithSyncFee = async (
request: CallWithSyncFeeRequest,
options?: RelayRequestOptions,
sponsorApiKey?: string
): Promise<RelayResponse> =>
library.relayWithSyncFee({ request, sponsorApiKey, options }, this.#config);
): Promise<RelayResponse> => {
const response = await library.relayWithSyncFee(
{ request, sponsorApiKey, options },
this.#config
);

if (this.#websocketHandler) {
this.#websocketHandler.subscribe(response.taskId);
}

return response;
};

/**
* @param {CallWithSyncFeeERC2771Request | CallWithSyncFeeConcurrentERC2771Request} request - Call with sync fee: Sequential ERC2771 or Concurrent ERC2771 request to be relayed by Gelato Executors
Expand All @@ -114,15 +133,15 @@ export class GelatoRelay {
* @returns {Promise<RelayResponse>} Response object with taskId parameter
*
*/
callWithSyncFeeERC2771 = (
callWithSyncFeeERC2771 = async (
request:
| CallWithSyncFeeERC2771Request
| CallWithSyncFeeConcurrentERC2771Request,
walletOrProvider: ethers.BrowserProvider | ethers.Wallet,
options?: RelayRequestOptions,
sponsorApiKey?: string
): Promise<RelayResponse> =>
library.relayWithCallWithSyncFeeERC2771(
): Promise<RelayResponse> => {
const response = await library.relayWithCallWithSyncFeeERC2771(
{
request,
walletOrProvider,
Expand All @@ -132,23 +151,37 @@ export class GelatoRelay {
this.#config
);

if (this.#websocketHandler) {
this.#websocketHandler.subscribe(response.taskId);
}

return response;
};

/**
* @param {SponsoredCallRequest} request SponsoredCallRequest to be relayed by the Gelato Executors.
* @param {string} sponsorApiKey Sponsor API key to be used for the call
* @param {RelayRequestOptions} [options] Optional Relay configuration
* @returns {Promise<RelayResponse>} Response object with taskId parameter
*
*/
sponsoredCall = (
sponsoredCall = async (
request: SponsoredCallRequest,
sponsorApiKey: string,
options?: RelayRequestOptions
): Promise<RelayResponse> =>
library.relayWithSponsoredCall(
): Promise<RelayResponse> => {
const response = await library.relayWithSponsoredCall(
{ request, sponsorApiKey, options },
this.#config
);

if (this.#websocketHandler) {
this.#websocketHandler.subscribe(response.taskId);
}

return response;
};

/**
* @param {CallWithERC2771Request | CallWithConcurrentERC2771Request} request - Sponsored: Sequential ERC2771 or Concurrent ERC2771 request to be relayed by Gelato Executors
* @param {ethers.BrowserProvider | ethers.Wallet} walletOrProvider - BrowserProvider [front-end] or Wallet [back-end] to sign the payload
Expand All @@ -157,13 +190,13 @@ export class GelatoRelay {
* @returns {Promise<RelayResponse>} Response object with taskId parameter
*
*/
sponsoredCallERC2771 = (
sponsoredCallERC2771 = async (
request: CallWithERC2771Request | CallWithConcurrentERC2771Request,
walletOrProvider: ethers.BrowserProvider | ethers.Wallet,
sponsorApiKey: string,
options?: RelayRequestOptions
): Promise<RelayResponse> =>
library.relayWithSponsoredCallERC2771(
): Promise<RelayResponse> => {
const response = await library.relayWithSponsoredCallERC2771(
{
request,
walletOrProvider,
Expand All @@ -173,6 +206,13 @@ export class GelatoRelay {
this.#config
);

if (this.#websocketHandler) {
this.#websocketHandler.subscribe(response.taskId);
}

return response;
};

/**
* @param {CallWithERC2771Request | CallWithConcurrentERC2771Request} request - Sequential ERC2771 or Concurrent ERC2771 request to be relayed by Gelato Executors
* @param {ethers.BrowserProvider | ethers.Wallet} walletOrProvider - BrowserProvider [front-end] or Wallet [back-end] to sign the payload
Expand Down Expand Up @@ -215,13 +255,13 @@ export class GelatoRelay {
* @returns {Promise<RelayResponse>} Response object with taskId parameter
*
*/
sponsoredCallERC2771WithSignature = (
sponsoredCallERC2771WithSignature = async (
struct: SignatureData["struct"],
signature: SignatureData["signature"],
sponsorApiKey: string,
options?: RelayRequestOptions
): Promise<RelayResponse> =>
library.sponsoredCallERC2771WithSignature(
): Promise<RelayResponse> => {
const response = await library.sponsoredCallERC2771WithSignature(
{
struct,
signature,
Expand All @@ -231,6 +271,13 @@ export class GelatoRelay {
this.#config
);

if (this.#websocketHandler) {
this.#websocketHandler.subscribe(response.taskId);
}

return response;
};

/**
* @param {SignatureData["struct"]} struct - Struct that can be obtained from getSignatureDataERC2771
* @param {BaseCallWithSyncFeeParams} syncFeeParams - Call with Sync Fee parameters
Expand All @@ -240,14 +287,14 @@ export class GelatoRelay {
* @returns {Promise<RelayResponse>} Response object with taskId parameter
*
*/
callWithSyncFeeERC2771WithSignature = (
callWithSyncFeeERC2771WithSignature = async (
struct: SignatureData["struct"],
syncFeeParams: BaseCallWithSyncFeeParams,
signature: SignatureData["signature"],
options?: RelayRequestOptions,
sponsorApiKey?: string
): Promise<RelayResponse> =>
library.callWithSyncFeeERC2771WithSignature(
): Promise<RelayResponse> => {
const response = await library.callWithSyncFeeERC2771WithSignature(
{
struct,
syncFeeParams,
Expand All @@ -258,6 +305,13 @@ export class GelatoRelay {
this.#config
);

if (this.#websocketHandler) {
this.#websocketHandler.subscribe(response.taskId);
}

return response;
};

/**
* @param {bigint} chainId - Chain Id
* @returns {Promise<boolean>} Boolean to demonstrate if Relay V2 is supported on the provided chain
Expand Down Expand Up @@ -322,4 +376,24 @@ export class GelatoRelay {
taskId: string
): Promise<TransactionStatusResponse | undefined> =>
library.getTaskStatus({ taskId }, this.#config);

/**
* @param {callback} handler - Callback function to be called when the task status changes
*
*/
onTaskStatusUpdate = (
handler: (taskStatus: TransactionStatusResponse) => void
): void => {
if (this.#websocketHandler) {
this.#websocketHandler.onUpdate(handler);
}
};

offTaskStatusUpdate = (
handler: (taskStatus: TransactionStatusResponse) => void
): void => {
if (this.#websocketHandler) {
this.#websocketHandler.offUpdate(handler);
}
};
}
8 changes: 4 additions & 4 deletions src/lib/status/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ export type TransactionStatusResponse = {
transactionHash?: string;
blockNumber?: number;
executionDate?: string;
gasUsed?: string;
effectiveGasPrice?: string;
};

enum TaskState {
export enum TaskState {
CheckPending = "CheckPending",
ExecPending = "ExecPending",
WaitingForConfirmation = "WaitingForConfirmation",
ExecSuccess = "ExecSuccess",
ExecReverted = "ExecReverted",
WaitingForConfirmation = "WaitingForConfirmation",
Blacklisted = "Blacklisted",
Cancelled = "Cancelled",
NotFound = "NotFound",
}
1 change: 1 addition & 0 deletions src/lib/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export type Config = {
relayConcurrentERC2771zkSync: string;
relay1BalanceConcurrentERC2771zkSync: string;
};
useWebsocket: boolean;
};

export type SafeRequestPayload<T> = {
Expand Down
2 changes: 2 additions & 0 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,5 @@ export * from "./axios";
export * from "./isConcurrentStruct";
export * from "./isConcurrentRequest";
export * from "./generateSalt";
export * from "./isFinalTaskState";
export * from "./websocketHandler";
12 changes: 12 additions & 0 deletions src/utils/isFinalTaskState.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { TaskState } from "../lib/status/types/index.js";

export const isFinalTaskState = (taskState: TaskState): boolean => {
switch (taskState) {
case TaskState.ExecSuccess:
case TaskState.ExecReverted:
case TaskState.Cancelled:
return true;
default:
return false;
}
};
Loading

0 comments on commit 6f8edad

Please sign in to comment.