/* This file is part of web3.js. web3.js is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. web3.js is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ import { QRLExecutionAPI, HexString, ProviderConnectInfo, Web3APIMethod, Web3APIPayload, Web3APISpec, Web3BaseProvider, } from '@theqrl/web3-types'; import { EventEmitter } from 'events'; import { EIP1193ProviderRpcError } from '@theqrl/web3-errors'; import { toPayload } from './json_rpc.js'; /** * This is an abstract class, which extends {@link Web3BaseProvider} class. This class is used to implement a provider that adheres to the EIP-1193 standard for QRL providers. */ export abstract class Eip1193Provider< API extends Web3APISpec = QRLExecutionAPI, > extends Web3BaseProvider { protected readonly _eventEmitter: EventEmitter = new EventEmitter(); private _chainId: HexString = ''; private _accounts: HexString[] = []; protected _emitError(error: unknown): void { if (this._eventEmitter.listenerCount('error') > 0) { this._eventEmitter.emit('error', error); } } private async _getChainId(): Promise { const data = await (this as Web3BaseProvider).request< Web3APIMethod, ResponseType >( toPayload({ method: 'qrl_chainId', params: [], }) as Web3APIPayload>, ); return data?.result ?? ''; } private async _getAccounts(): Promise { const data = await (this as Web3BaseProvider).request, HexString[]>( toPayload({ method: 'qrl_accounts', params: [], }) as Web3APIPayload>, ); return data?.result ?? []; } protected _onConnect() { Promise.all([ this._getChainId() .then(chainId => { if (chainId !== this._chainId) { this._chainId = chainId; this._eventEmitter.emit('chainChanged', this._chainId); } }) .catch(err => this._emitError(err)), this._getAccounts() .then(accounts => { if ( !( this._accounts.length === accounts.length && accounts.every(v => accounts.includes(v)) ) ) { this._accounts = accounts; this._onAccountsChanged(); } }) .catch(err => this._emitError(err)), ]) .then(() => this._eventEmitter.emit('connect', { chainId: this._chainId, } as ProviderConnectInfo), ) .catch(err => this._emitError(err)); } // todo this must be ProvideRpcError with a message too protected _onDisconnect(code: number, data?: unknown) { this._eventEmitter.emit('disconnect', new EIP1193ProviderRpcError(code, data)); } private _onAccountsChanged() { // get chainId and safe to local this._eventEmitter.emit('accountsChanged', this._accounts); } }