import { Vessel, VesselMessage, VesselMessageListener } from "@opensea/vessel" import { ProviderRPCError, isProviderRPCErrorLike } from "./errors" import { EventCallbackByEventName, EventName, emitter, isEventMessage, } from "./events" export class EIP1193Provider { private vessel: Vessel private messageListener: VesselMessageListener constructor({ vessel }: { vessel: Vessel }) { this.vessel = vessel this.messageListener = this.handleInboundMessage.bind(this) this.vessel.addListener("message", this.messageListener) } private handleInboundMessage( message: VesselMessage, reply: () => void, ): boolean { if (isEventMessage(message.payload)) { emitter.emit(message.payload.event, message.payload.data) reply() return true } return false } public async request(request: { method: string params?: readonly unknown[] | object }): Promise { try { const response = await this.vessel.send( { type: "action", action: "HeadlessRPCRequest", payload: request, }, { timeout: undefined, }, ) return response } catch (error) { if (isProviderRPCErrorLike(error)) { throw new ProviderRPCError(error) } if (typeof error === "string" && error === "MFA canceled") { throw new ProviderRPCError({ code: 4001, message: error, name: "UserRejectedRequestError", }) } if (error instanceof Error) { error.message = `Error sending message to wallet: ${error.message}` throw error } throw new Error( `Error sending message to wallet: ${JSON.stringify(error)}`, ) } } public on( eventName: TEventName, callback: EventCallbackByEventName[TEventName], ): void { emitter.on(eventName, callback) } public removeListener( eventName: TEventName, callback?: EventCallbackByEventName[TEventName], ): void { emitter.removeListener(eventName, callback) } public async disconnect(): Promise { await this.vessel.send({ type: "action", action: "Logout", }) } }