ServerJsonRpcProvider.ts
1 import { Network } from '@ethersproject/networks'; 2 import { StaticJsonRpcProvider } from '@ethersproject/providers'; 3 4 /** 5 * A JsonRpcProvider that routes requests through the server to keep private RPC URLs hidden 6 */ 7 8 export class ServerJsonRpcProvider extends StaticJsonRpcProvider { 9 private readonly chainId: number; 10 11 constructor(chainId: number) { 12 // Use a dummy URL that will never be used 13 super('http://localhost', chainId); 14 this.chainId = chainId; 15 } 16 17 /** 18 * Override the send method to route through our API instead of direct to RPC 19 * @param method The JSON-RPC method to call 20 * @param params The parameters for the JSON-RPC method 21 * @returns The result from the JSON-RPC method 22 */ 23 // eslint-disable-next-line @typescript-eslint/no-explicit-any 24 public async send<P = any, R = any>(method: string, params: Array<P>): Promise<R> { 25 const apiUrl = '/api/rpc-proxy/'; 26 27 try { 28 const response = await fetch(apiUrl, { 29 method: 'POST', 30 headers: { 31 'Content-Type': 'application/json', 32 }, 33 body: JSON.stringify({ 34 chainId: this.chainId, 35 method, 36 params, 37 }), 38 }); 39 40 if (!response.ok) { 41 const errorText = await response.text(); 42 try { 43 const errorData = JSON.parse(errorText); 44 throw new Error(errorData.error || `Failed with status ${response.status}`); 45 } catch (e) { 46 throw new Error(`Failed with status ${response.status}: ${errorText}`); 47 } 48 } 49 50 const data = await response.json(); 51 52 if (data.error) { 53 throw new Error(data.error.message || 'RPC error'); 54 } 55 56 return data.result as R; 57 } catch (error) { 58 console.error('Error making RPC request through server proxy:', error); 59 throw error; 60 } 61 } 62 63 // Override detectNetwork to manually set the network to avoid making requests 64 public async detectNetwork(): Promise<Network> { 65 return this.network; 66 } 67 }