provider-jsonrpc.ts 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308
  1. /**
  2. * One of the most common ways to interact with the blockchain is
  3. * by a node running a JSON-RPC interface which can be connected to,
  4. * based on the transport, using:
  5. *
  6. * - HTTP or HTTPS - [[JsonRpcProvider]]
  7. * - WebSocket - [[WebSocketProvider]]
  8. * - IPC - [[IpcSocketProvider]]
  9. *
  10. * @_section: api/providers/jsonrpc:JSON-RPC Provider [about-jsonrpcProvider]
  11. */
  12. // @TODO:
  13. // - Add the batching API
  14. // https://playground.open-rpc.org/?schemaUrl=https://raw.githubusercontent.com/ethereum/eth1.0-apis/assembled-spec/openrpc.json&uiSchema%5BappBar%5D%5Bui:splitView%5D=true&uiSchema%5BappBar%5D%5Bui:input%5D=false&uiSchema%5BappBar%5D%5Bui:examplesDropdown%5D=false
  15. import { AbiCoder } from "../abi/index.js";
  16. import { getAddress, resolveAddress } from "../address/index.js";
  17. import { TypedDataEncoder } from "../hash/index.js";
  18. import { accessListify } from "../transaction/index.js";
  19. import {
  20. defineProperties, getBigInt, hexlify, isHexString, toQuantity, toUtf8Bytes,
  21. isError, makeError, assert, assertArgument,
  22. FetchRequest, resolveProperties
  23. } from "../utils/index.js";
  24. import { AbstractProvider, UnmanagedSubscriber } from "./abstract-provider.js";
  25. import { AbstractSigner } from "./abstract-signer.js";
  26. import { Network } from "./network.js";
  27. import { FilterIdEventSubscriber, FilterIdPendingSubscriber } from "./subscriber-filterid.js";
  28. import { PollingEventSubscriber } from "./subscriber-polling.js";
  29. import type { TypedDataDomain, TypedDataField } from "../hash/index.js";
  30. import type { TransactionLike } from "../transaction/index.js";
  31. import type { PerformActionRequest, Subscriber, Subscription } from "./abstract-provider.js";
  32. import type { Networkish } from "./network.js";
  33. import type { Provider, TransactionRequest, TransactionResponse } from "./provider.js";
  34. import type { Signer } from "./signer.js";
  35. type Timer = ReturnType<typeof setTimeout>;
  36. const Primitive = "bigint,boolean,function,number,string,symbol".split(/,/g);
  37. //const Methods = "getAddress,then".split(/,/g);
  38. function deepCopy<T = any>(value: T): T {
  39. if (value == null || Primitive.indexOf(typeof(value)) >= 0) {
  40. return value;
  41. }
  42. // Keep any Addressable
  43. if (typeof((<any>value).getAddress) === "function") {
  44. return value;
  45. }
  46. if (Array.isArray(value)) { return <any>(value.map(deepCopy)); }
  47. if (typeof(value) === "object") {
  48. return Object.keys(value).reduce((accum, key) => {
  49. accum[key] = (<any>value)[key];
  50. return accum;
  51. }, <any>{ });
  52. }
  53. throw new Error(`should not happen: ${ value } (${ typeof(value) })`);
  54. }
  55. function stall(duration: number): Promise<void> {
  56. return new Promise((resolve) => { setTimeout(resolve, duration); });
  57. }
  58. function getLowerCase(value: string): string {
  59. if (value) { return value.toLowerCase(); }
  60. return value;
  61. }
  62. interface Pollable {
  63. pollingInterval: number;
  64. }
  65. function isPollable(value: any): value is Pollable {
  66. return (value && typeof(value.pollingInterval) === "number");
  67. }
  68. /**
  69. * A JSON-RPC payload, which are sent to a JSON-RPC server.
  70. */
  71. export type JsonRpcPayload = {
  72. /**
  73. * The JSON-RPC request ID.
  74. */
  75. id: number;
  76. /**
  77. * The JSON-RPC request method.
  78. */
  79. method: string;
  80. /**
  81. * The JSON-RPC request parameters.
  82. */
  83. params: Array<any> | Record<string, any>;
  84. /**
  85. * A required constant in the JSON-RPC specification.
  86. */
  87. jsonrpc: "2.0";
  88. };
  89. /**
  90. * A JSON-RPC result, which are returned on success from a JSON-RPC server.
  91. */
  92. export type JsonRpcResult = {
  93. /**
  94. * The response ID to match it to the relevant request.
  95. */
  96. id: number;
  97. /**
  98. * The response result.
  99. */
  100. result: any;
  101. };
  102. /**
  103. * A JSON-RPC error, which are returned on failure from a JSON-RPC server.
  104. */
  105. export type JsonRpcError = {
  106. /**
  107. * The response ID to match it to the relevant request.
  108. */
  109. id: number;
  110. /**
  111. * The response error.
  112. */
  113. error: {
  114. code: number;
  115. message?: string;
  116. data?: any;
  117. }
  118. };
  119. /**
  120. * When subscribing to the ``"debug"`` event, the [[Listener]] will
  121. * receive this object as the first parameter.
  122. */
  123. export type DebugEventJsonRpcApiProvider = {
  124. action: "sendRpcPayload",
  125. payload: JsonRpcPayload | Array<JsonRpcPayload>
  126. } | {
  127. action: "receiveRpcResult",
  128. result: Array<JsonRpcResult | JsonRpcError>
  129. } | {
  130. action: "receiveRpcError",
  131. error: Error
  132. };
  133. /**
  134. * Options for configuring a [[JsonRpcApiProvider]]. Much of this
  135. * is targetted towards sub-classes, which often will not expose
  136. * any of these options to their consumers.
  137. *
  138. * **``polling``** - use the polling strategy is used immediately
  139. * for events; otherwise, attempt to use filters and fall back onto
  140. * polling (default: ``false``)
  141. *
  142. * **``staticNetwork``** - do not request chain ID on requests to
  143. * validate the underlying chain has not changed (default: ``null``)
  144. *
  145. * This should **ONLY** be used if it is **certain** that the network
  146. * cannot change, such as when using INFURA (since the URL dictates the
  147. * network). If the network is assumed static and it does change, this
  148. * can have tragic consequences. For example, this **CANNOT** be used
  149. * with MetaMask, since the user can select a new network from the
  150. * drop-down at any time.
  151. *
  152. * **``batchStallTime``** - how long (ms) to aggregate requests into a
  153. * single batch. ``0`` indicates batching will only encompass the current
  154. * event loop. If ``batchMaxCount = 1``, this is ignored. (default: ``10``)
  155. *
  156. * **``batchMaxSize``** - target maximum size (bytes) to allow per batch
  157. * request (default: 1Mb)
  158. *
  159. * **``batchMaxCount``** - maximum number of requests to allow in a batch.
  160. * If ``batchMaxCount = 1``, then batching is disabled. (default: ``100``)
  161. *
  162. * **``cacheTimeout``** - passed as [[AbstractProviderOptions]].
  163. */
  164. export type JsonRpcApiProviderOptions = {
  165. polling?: boolean;
  166. staticNetwork?: null | boolean | Network;
  167. batchStallTime?: number;
  168. batchMaxSize?: number;
  169. batchMaxCount?: number;
  170. cacheTimeout?: number;
  171. pollingInterval?: number;
  172. };
  173. const defaultOptions = {
  174. polling: false,
  175. staticNetwork: null,
  176. batchStallTime: 10, // 10ms
  177. batchMaxSize: (1 << 20), // 1Mb
  178. batchMaxCount: 100, // 100 requests
  179. cacheTimeout: 250,
  180. pollingInterval: 4000
  181. }
  182. /**
  183. * A **JsonRpcTransactionRequest** is formatted as needed by the JSON-RPC
  184. * Ethereum API specification.
  185. */
  186. export interface JsonRpcTransactionRequest {
  187. /**
  188. * The sender address to use when signing.
  189. */
  190. from?: string;
  191. /**
  192. * The target address.
  193. */
  194. to?: string;
  195. /**
  196. * The transaction data.
  197. */
  198. data?: string;
  199. /**
  200. * The chain ID the transaction is valid on.
  201. */
  202. chainId?: string;
  203. /**
  204. * The [[link-eip-2718]] transaction type.
  205. */
  206. type?: string;
  207. /**
  208. * The maximum amount of gas to allow a transaction to consume.
  209. *
  210. * In most other places in ethers, this is called ``gasLimit`` which
  211. * differs from the JSON-RPC Ethereum API specification.
  212. */
  213. gas?: string;
  214. /**
  215. * The gas price per wei for transactions prior to [[link-eip-1559]].
  216. */
  217. gasPrice?: string;
  218. /**
  219. * The maximum fee per gas for [[link-eip-1559]] transactions.
  220. */
  221. maxFeePerGas?: string;
  222. /**
  223. * The maximum priority fee per gas for [[link-eip-1559]] transactions.
  224. */
  225. maxPriorityFeePerGas?: string;
  226. /**
  227. * The nonce for the transaction.
  228. */
  229. nonce?: string;
  230. /**
  231. * The transaction value (in wei).
  232. */
  233. value?: string;
  234. /**
  235. * The transaction access list.
  236. */
  237. accessList?: Array<{ address: string, storageKeys: Array<string> }>;
  238. }
  239. // @TODO: Unchecked Signers
  240. export class JsonRpcSigner extends AbstractSigner<JsonRpcApiProvider> {
  241. address!: string;
  242. constructor(provider: JsonRpcApiProvider, address: string) {
  243. super(provider);
  244. address = getAddress(address);
  245. defineProperties<JsonRpcSigner>(this, { address });
  246. }
  247. connect(provider: null | Provider): Signer {
  248. assert(false, "cannot reconnect JsonRpcSigner", "UNSUPPORTED_OPERATION", {
  249. operation: "signer.connect"
  250. });
  251. }
  252. async getAddress(): Promise<string> {
  253. return this.address;
  254. }
  255. // JSON-RPC will automatially fill in nonce, etc. so we just check from
  256. async populateTransaction(tx: TransactionRequest): Promise<TransactionLike<string>> {
  257. return await this.populateCall(tx);
  258. }
  259. // Returns just the hash of the transaction after sent, which is what
  260. // the bare JSON-RPC API does;
  261. async sendUncheckedTransaction(_tx: TransactionRequest): Promise<string> {
  262. const tx = deepCopy(_tx);
  263. const promises: Array<Promise<void>> = [];
  264. // Make sure the from matches the sender
  265. if (tx.from) {
  266. const _from = tx.from;
  267. promises.push((async () => {
  268. const from = await resolveAddress(_from, this.provider);
  269. assertArgument(from != null && from.toLowerCase() === this.address.toLowerCase(),
  270. "from address mismatch", "transaction", _tx);
  271. tx.from = from;
  272. })());
  273. } else {
  274. tx.from = this.address;
  275. }
  276. // The JSON-RPC for eth_sendTransaction uses 90000 gas; if the user
  277. // wishes to use this, it is easy to specify explicitly, otherwise
  278. // we look it up for them.
  279. if (tx.gasLimit == null) {
  280. promises.push((async () => {
  281. tx.gasLimit = await this.provider.estimateGas({ ...tx, from: this.address});
  282. })());
  283. }
  284. // The address may be an ENS name or Addressable
  285. if (tx.to != null) {
  286. const _to = tx.to;
  287. promises.push((async () => {
  288. tx.to = await resolveAddress(_to, this.provider);
  289. })());
  290. }
  291. // Wait until all of our properties are filled in
  292. if (promises.length) { await Promise.all(promises); }
  293. const hexTx = this.provider.getRpcTransaction(tx);
  294. return this.provider.send("eth_sendTransaction", [ hexTx ]);
  295. }
  296. async sendTransaction(tx: TransactionRequest): Promise<TransactionResponse> {
  297. // This cannot be mined any earlier than any recent block
  298. const blockNumber = await this.provider.getBlockNumber();
  299. // Send the transaction
  300. const hash = await this.sendUncheckedTransaction(tx);
  301. // Unfortunately, JSON-RPC only provides and opaque transaction hash
  302. // for a response, and we need the actual transaction, so we poll
  303. // for it; it should show up very quickly
  304. return await (new Promise((resolve, reject) => {
  305. const timeouts = [ 1000, 100 ];
  306. let invalids = 0;
  307. const checkTx = async () => {
  308. try {
  309. // Try getting the transaction
  310. const tx = await this.provider.getTransaction(hash);
  311. if (tx != null) {
  312. resolve(tx.replaceableTransaction(blockNumber));
  313. return;
  314. }
  315. } catch (error) {
  316. // If we were cancelled: stop polling.
  317. // If the data is bad: the node returns bad transactions
  318. // If the network changed: calling again will also fail
  319. // If unsupported: likely destroyed
  320. if (isError(error, "CANCELLED") || isError(error, "BAD_DATA") ||
  321. isError(error, "NETWORK_ERROR") || isError(error, "UNSUPPORTED_OPERATION")) {
  322. if (error.info == null) { error.info = { }; }
  323. error.info.sendTransactionHash = hash;
  324. reject(error);
  325. return;
  326. }
  327. // Stop-gap for misbehaving backends; see #4513
  328. if (isError(error, "INVALID_ARGUMENT")) {
  329. invalids++;
  330. if (error.info == null) { error.info = { }; }
  331. error.info.sendTransactionHash = hash;
  332. if (invalids > 10) {
  333. reject(error);
  334. return;
  335. }
  336. }
  337. // Notify anyone that cares; but we will try again, since
  338. // it is likely an intermittent service error
  339. this.provider.emit("error", makeError("failed to fetch transation after sending (will try again)", "UNKNOWN_ERROR", { error }));
  340. }
  341. // Wait another 4 seconds
  342. this.provider._setTimeout(() => { checkTx(); }, timeouts.pop() || 4000);
  343. };
  344. checkTx();
  345. }));
  346. }
  347. async signTransaction(_tx: TransactionRequest): Promise<string> {
  348. const tx = deepCopy(_tx);
  349. // Make sure the from matches the sender
  350. if (tx.from) {
  351. const from = await resolveAddress(tx.from, this.provider);
  352. assertArgument(from != null && from.toLowerCase() === this.address.toLowerCase(),
  353. "from address mismatch", "transaction", _tx);
  354. tx.from = from;
  355. } else {
  356. tx.from = this.address;
  357. }
  358. const hexTx = this.provider.getRpcTransaction(tx);
  359. return await this.provider.send("eth_signTransaction", [ hexTx ]);
  360. }
  361. async signMessage(_message: string | Uint8Array): Promise<string> {
  362. const message = ((typeof(_message) === "string") ? toUtf8Bytes(_message): _message);
  363. return await this.provider.send("personal_sign", [
  364. hexlify(message), this.address.toLowerCase() ]);
  365. }
  366. async signTypedData(domain: TypedDataDomain, types: Record<string, Array<TypedDataField>>, _value: Record<string, any>): Promise<string> {
  367. const value = deepCopy(_value);
  368. // Populate any ENS names (in-place)
  369. const populated = await TypedDataEncoder.resolveNames(domain, types, value, async (value: string) => {
  370. const address = await resolveAddress(value);
  371. assertArgument(address != null, "TypedData does not support null address", "value", value);
  372. return address;
  373. });
  374. return await this.provider.send("eth_signTypedData_v4", [
  375. this.address.toLowerCase(),
  376. JSON.stringify(TypedDataEncoder.getPayload(populated.domain, types, populated.value))
  377. ]);
  378. }
  379. async unlock(password: string): Promise<boolean> {
  380. return this.provider.send("personal_unlockAccount", [
  381. this.address.toLowerCase(), password, null ]);
  382. }
  383. // https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign
  384. async _legacySignMessage(_message: string | Uint8Array): Promise<string> {
  385. const message = ((typeof(_message) === "string") ? toUtf8Bytes(_message): _message);
  386. return await this.provider.send("eth_sign", [
  387. this.address.toLowerCase(), hexlify(message) ]);
  388. }
  389. }
  390. type ResolveFunc = (result: JsonRpcResult) => void;
  391. type RejectFunc = (error: Error) => void;
  392. type Payload = { payload: JsonRpcPayload, resolve: ResolveFunc, reject: RejectFunc };
  393. /**
  394. * The JsonRpcApiProvider is an abstract class and **MUST** be
  395. * sub-classed.
  396. *
  397. * It provides the base for all JSON-RPC-based Provider interaction.
  398. *
  399. * Sub-classing Notes:
  400. * - a sub-class MUST override _send
  401. * - a sub-class MUST call the `_start()` method once connected
  402. */
  403. export abstract class JsonRpcApiProvider extends AbstractProvider {
  404. #options: Required<JsonRpcApiProviderOptions>;
  405. // The next ID to use for the JSON-RPC ID field
  406. #nextId: number;
  407. // Payloads are queued and triggered in batches using the drainTimer
  408. #payloads: Array<Payload>;
  409. #drainTimer: null | Timer;
  410. #notReady: null | {
  411. promise: Promise<void>,
  412. resolve: null | ((v: void) => void)
  413. };
  414. #network: null | Network;
  415. #pendingDetectNetwork: null | Promise<Network>;
  416. #scheduleDrain(): void {
  417. if (this.#drainTimer) { return; }
  418. // If we aren't using batching, no harm in sending it immediately
  419. const stallTime = (this._getOption("batchMaxCount") === 1) ? 0: this._getOption("batchStallTime");
  420. this.#drainTimer = setTimeout(() => {
  421. this.#drainTimer = null;
  422. const payloads = this.#payloads;
  423. this.#payloads = [ ];
  424. while (payloads.length) {
  425. // Create payload batches that satisfy our batch constraints
  426. const batch = [ <Payload>(payloads.shift()) ];
  427. while (payloads.length) {
  428. if (batch.length === this.#options.batchMaxCount) { break; }
  429. batch.push(<Payload>(payloads.shift()));
  430. const bytes = JSON.stringify(batch.map((p) => p.payload));
  431. if (bytes.length > this.#options.batchMaxSize) {
  432. payloads.unshift(<Payload>(batch.pop()));
  433. break;
  434. }
  435. }
  436. // Process the result to each payload
  437. (async () => {
  438. const payload = ((batch.length === 1) ? batch[0].payload: batch.map((p) => p.payload));
  439. this.emit("debug", { action: "sendRpcPayload", payload });
  440. try {
  441. const result = await this._send(payload);
  442. this.emit("debug", { action: "receiveRpcResult", result });
  443. // Process results in batch order
  444. for (const { resolve, reject, payload } of batch) {
  445. if (this.destroyed) {
  446. reject(makeError("provider destroyed; cancelled request", "UNSUPPORTED_OPERATION", { operation: payload.method }));
  447. continue;
  448. }
  449. // Find the matching result
  450. const resp = result.filter((r) => (r.id === payload.id))[0];
  451. // No result; the node failed us in unexpected ways
  452. if (resp == null) {
  453. const error = makeError("missing response for request", "BAD_DATA", {
  454. value: result, info: { payload }
  455. });
  456. this.emit("error", error);
  457. reject(error);
  458. continue;
  459. }
  460. // The response is an error
  461. if ("error" in resp) {
  462. reject(this.getRpcError(payload, resp));
  463. continue;
  464. }
  465. // All good; send the result
  466. resolve(resp.result);
  467. }
  468. } catch (error: any) {
  469. this.emit("debug", { action: "receiveRpcError", error });
  470. for (const { reject } of batch) {
  471. // @TODO: augment the error with the payload
  472. reject(error);
  473. }
  474. }
  475. })();
  476. }
  477. }, stallTime);
  478. }
  479. constructor(network?: Networkish, options?: JsonRpcApiProviderOptions) {
  480. super(network, options);
  481. this.#nextId = 1;
  482. this.#options = Object.assign({ }, defaultOptions, options || { });
  483. this.#payloads = [ ];
  484. this.#drainTimer = null;
  485. this.#network = null;
  486. this.#pendingDetectNetwork = null;
  487. {
  488. let resolve: null | ((value: void) => void) = null;
  489. const promise = new Promise((_resolve: (value: void) => void) => {
  490. resolve = _resolve;
  491. });
  492. this.#notReady = { promise, resolve };
  493. }
  494. const staticNetwork = this._getOption("staticNetwork");
  495. if (typeof(staticNetwork) === "boolean") {
  496. assertArgument(!staticNetwork || network !== "any", "staticNetwork cannot be used on special network 'any'", "options", options);
  497. if (staticNetwork && network != null) {
  498. this.#network = Network.from(network);
  499. }
  500. } else if (staticNetwork) {
  501. // Make sure any static network is compatbile with the provided netwrok
  502. assertArgument(network == null || staticNetwork.matches(network),
  503. "staticNetwork MUST match network object", "options", options);
  504. this.#network = staticNetwork;
  505. }
  506. }
  507. /**
  508. * Returns the value associated with the option %%key%%.
  509. *
  510. * Sub-classes can use this to inquire about configuration options.
  511. */
  512. _getOption<K extends keyof JsonRpcApiProviderOptions>(key: K): JsonRpcApiProviderOptions[K] {
  513. return this.#options[key];
  514. }
  515. /**
  516. * Gets the [[Network]] this provider has committed to. On each call, the network
  517. * is detected, and if it has changed, the call will reject.
  518. */
  519. get _network(): Network {
  520. assert (this.#network, "network is not available yet", "NETWORK_ERROR");
  521. return this.#network;
  522. }
  523. /**
  524. * Sends a JSON-RPC %%payload%% (or a batch) to the underlying channel.
  525. *
  526. * Sub-classes **MUST** override this.
  527. */
  528. abstract _send(payload: JsonRpcPayload | Array<JsonRpcPayload>): Promise<Array<JsonRpcResult | JsonRpcError>>;
  529. /**
  530. * Resolves to the non-normalized value by performing %%req%%.
  531. *
  532. * Sub-classes may override this to modify behavior of actions,
  533. * and should generally call ``super._perform`` as a fallback.
  534. */
  535. async _perform(req: PerformActionRequest): Promise<any> {
  536. // Legacy networks do not like the type field being passed along (which
  537. // is fair), so we delete type if it is 0 and a non-EIP-1559 network
  538. if (req.method === "call" || req.method === "estimateGas") {
  539. let tx = req.transaction;
  540. if (tx && tx.type != null && getBigInt(tx.type)) {
  541. // If there are no EIP-1559 or newer properties, it might be pre-EIP-1559
  542. if (tx.maxFeePerGas == null && tx.maxPriorityFeePerGas == null) {
  543. const feeData = await this.getFeeData();
  544. if (feeData.maxFeePerGas == null && feeData.maxPriorityFeePerGas == null) {
  545. // Network doesn't know about EIP-1559 (and hence type)
  546. req = Object.assign({ }, req, {
  547. transaction: Object.assign({ }, tx, { type: undefined })
  548. });
  549. }
  550. }
  551. }
  552. }
  553. const request = this.getRpcRequest(req);
  554. if (request != null) {
  555. return await this.send(request.method, request.args);
  556. }
  557. return super._perform(req);
  558. }
  559. /**
  560. * Sub-classes may override this; it detects the *actual* network that
  561. * we are **currently** connected to.
  562. *
  563. * Keep in mind that [[send]] may only be used once [[ready]], otherwise the
  564. * _send primitive must be used instead.
  565. */
  566. async _detectNetwork(): Promise<Network> {
  567. const network = this._getOption("staticNetwork");
  568. if (network) {
  569. if (network === true) {
  570. if (this.#network) { return this.#network; }
  571. } else {
  572. return network;
  573. }
  574. }
  575. if (this.#pendingDetectNetwork) {
  576. return await this.#pendingDetectNetwork;
  577. }
  578. // If we are ready, use ``send``, which enabled requests to be batched
  579. if (this.ready) {
  580. this.#pendingDetectNetwork = (async () => {
  581. try {
  582. const result = Network.from(getBigInt(await this.send("eth_chainId", [ ])));
  583. this.#pendingDetectNetwork = null;
  584. return result;
  585. } catch (error) {
  586. this.#pendingDetectNetwork = null;
  587. throw error;
  588. }
  589. })();
  590. return await this.#pendingDetectNetwork;
  591. }
  592. // We are not ready yet; use the primitive _send
  593. this.#pendingDetectNetwork = (async () => {
  594. const payload: JsonRpcPayload = {
  595. id: this.#nextId++, method: "eth_chainId", params: [ ], jsonrpc: "2.0"
  596. };
  597. this.emit("debug", { action: "sendRpcPayload", payload });
  598. let result: JsonRpcResult | JsonRpcError;
  599. try {
  600. result = (await this._send(payload))[0];
  601. this.#pendingDetectNetwork = null;
  602. } catch (error) {
  603. this.#pendingDetectNetwork = null;
  604. this.emit("debug", { action: "receiveRpcError", error });
  605. throw error;
  606. }
  607. this.emit("debug", { action: "receiveRpcResult", result });
  608. if ("result" in result) {
  609. return Network.from(getBigInt(result.result));
  610. }
  611. throw this.getRpcError(payload, result);
  612. })();
  613. return await this.#pendingDetectNetwork;
  614. }
  615. /**
  616. * Sub-classes **MUST** call this. Until [[_start]] has been called, no calls
  617. * will be passed to [[_send]] from [[send]]. If it is overridden, then
  618. * ``super._start()`` **MUST** be called.
  619. *
  620. * Calling it multiple times is safe and has no effect.
  621. */
  622. _start(): void {
  623. if (this.#notReady == null || this.#notReady.resolve == null) { return; }
  624. this.#notReady.resolve();
  625. this.#notReady = null;
  626. (async () => {
  627. // Bootstrap the network
  628. while (this.#network == null && !this.destroyed) {
  629. try {
  630. this.#network = await this._detectNetwork();
  631. } catch (error) {
  632. if (this.destroyed) { break; }
  633. console.log("JsonRpcProvider failed to detect network and cannot start up; retry in 1s (perhaps the URL is wrong or the node is not started)");
  634. this.emit("error", makeError("failed to bootstrap network detection", "NETWORK_ERROR", { event: "initial-network-discovery", info: { error } }));
  635. await stall(1000);
  636. }
  637. }
  638. // Start dispatching requests
  639. this.#scheduleDrain();
  640. })();
  641. }
  642. /**
  643. * Resolves once the [[_start]] has been called. This can be used in
  644. * sub-classes to defer sending data until the connection has been
  645. * established.
  646. */
  647. async _waitUntilReady(): Promise<void> {
  648. if (this.#notReady == null) { return; }
  649. return await this.#notReady.promise;
  650. }
  651. /**
  652. * Return a Subscriber that will manage the %%sub%%.
  653. *
  654. * Sub-classes may override this to modify the behavior of
  655. * subscription management.
  656. */
  657. _getSubscriber(sub: Subscription): Subscriber {
  658. // Pending Filters aren't availble via polling
  659. if (sub.type === "pending") { return new FilterIdPendingSubscriber(this); }
  660. if (sub.type === "event") {
  661. if (this._getOption("polling")) {
  662. return new PollingEventSubscriber(this, sub.filter);
  663. }
  664. return new FilterIdEventSubscriber(this, sub.filter);
  665. }
  666. // Orphaned Logs are handled automatically, by the filter, since
  667. // logs with removed are emitted by it
  668. if (sub.type === "orphan" && sub.filter.orphan === "drop-log") {
  669. return new UnmanagedSubscriber("orphan");
  670. }
  671. return super._getSubscriber(sub);
  672. }
  673. /**
  674. * Returns true only if the [[_start]] has been called.
  675. */
  676. get ready(): boolean { return this.#notReady == null; }
  677. /**
  678. * Returns %%tx%% as a normalized JSON-RPC transaction request,
  679. * which has all values hexlified and any numeric values converted
  680. * to Quantity values.
  681. */
  682. getRpcTransaction(tx: TransactionRequest): JsonRpcTransactionRequest {
  683. const result: JsonRpcTransactionRequest = {};
  684. // JSON-RPC now requires numeric values to be "quantity" values
  685. ["chainId", "gasLimit", "gasPrice", "type", "maxFeePerGas", "maxPriorityFeePerGas", "nonce", "value"].forEach((key) => {
  686. if ((<any>tx)[key] == null) { return; }
  687. let dstKey = key;
  688. if (key === "gasLimit") { dstKey = "gas"; }
  689. (<any>result)[dstKey] = toQuantity(getBigInt((<any>tx)[key], `tx.${ key }`));
  690. });
  691. // Make sure addresses and data are lowercase
  692. ["from", "to", "data"].forEach((key) => {
  693. if ((<any>tx)[key] == null) { return; }
  694. (<any>result)[key] = hexlify((<any>tx)[key]);
  695. });
  696. // Normalize the access list object
  697. if (tx.accessList) {
  698. result["accessList"] = accessListify(tx.accessList);
  699. }
  700. if (tx.blobVersionedHashes) {
  701. // @TODO: Remove this <any> case once EIP-4844 added to prepared tx
  702. (<any>result)["blobVersionedHashes"] = tx.blobVersionedHashes.map(h => h.toLowerCase());
  703. }
  704. // @TODO: blobs should probably also be copied over, optionally
  705. // accounting for the kzg property to backfill blobVersionedHashes
  706. // using the commitment. Or should that be left as an exercise to
  707. // the caller?
  708. return result;
  709. }
  710. /**
  711. * Returns the request method and arguments required to perform
  712. * %%req%%.
  713. */
  714. getRpcRequest(req: PerformActionRequest): null | { method: string, args: Array<any> } {
  715. switch (req.method) {
  716. case "chainId":
  717. return { method: "eth_chainId", args: [ ] };
  718. case "getBlockNumber":
  719. return { method: "eth_blockNumber", args: [ ] };
  720. case "getGasPrice":
  721. return { method: "eth_gasPrice", args: [] };
  722. case "getPriorityFee":
  723. return { method: "eth_maxPriorityFeePerGas", args: [ ] };
  724. case "getBalance":
  725. return {
  726. method: "eth_getBalance",
  727. args: [ getLowerCase(req.address), req.blockTag ]
  728. };
  729. case "getTransactionCount":
  730. return {
  731. method: "eth_getTransactionCount",
  732. args: [ getLowerCase(req.address), req.blockTag ]
  733. };
  734. case "getCode":
  735. return {
  736. method: "eth_getCode",
  737. args: [ getLowerCase(req.address), req.blockTag ]
  738. };
  739. case "getStorage":
  740. return {
  741. method: "eth_getStorageAt",
  742. args: [
  743. getLowerCase(req.address),
  744. ("0x" + req.position.toString(16)),
  745. req.blockTag
  746. ]
  747. };
  748. case "broadcastTransaction":
  749. return {
  750. method: "eth_sendRawTransaction",
  751. args: [ req.signedTransaction ]
  752. };
  753. case "getBlock":
  754. if ("blockTag" in req) {
  755. return {
  756. method: "eth_getBlockByNumber",
  757. args: [ req.blockTag, !!req.includeTransactions ]
  758. };
  759. } else if ("blockHash" in req) {
  760. return {
  761. method: "eth_getBlockByHash",
  762. args: [ req.blockHash, !!req.includeTransactions ]
  763. };
  764. }
  765. break;
  766. case "getTransaction":
  767. return {
  768. method: "eth_getTransactionByHash",
  769. args: [ req.hash ]
  770. };
  771. case "getTransactionReceipt":
  772. return {
  773. method: "eth_getTransactionReceipt",
  774. args: [ req.hash ]
  775. };
  776. case "call":
  777. return {
  778. method: "eth_call",
  779. args: [ this.getRpcTransaction(req.transaction), req.blockTag ]
  780. };
  781. case "estimateGas": {
  782. return {
  783. method: "eth_estimateGas",
  784. args: [ this.getRpcTransaction(req.transaction) ]
  785. };
  786. }
  787. case "getLogs":
  788. if (req.filter && req.filter.address != null) {
  789. if (Array.isArray(req.filter.address)) {
  790. req.filter.address = req.filter.address.map(getLowerCase);
  791. } else {
  792. req.filter.address = getLowerCase(req.filter.address);
  793. }
  794. }
  795. return { method: "eth_getLogs", args: [ req.filter ] };
  796. }
  797. return null;
  798. }
  799. /**
  800. * Returns an ethers-style Error for the given JSON-RPC error
  801. * %%payload%%, coalescing the various strings and error shapes
  802. * that different nodes return, coercing them into a machine-readable
  803. * standardized error.
  804. */
  805. getRpcError(payload: JsonRpcPayload, _error: JsonRpcError): Error {
  806. const { method } = payload;
  807. const { error } = _error;
  808. if (method === "eth_estimateGas" && error.message) {
  809. const msg = error.message;
  810. if (!msg.match(/revert/i) && msg.match(/insufficient funds/i)) {
  811. return makeError("insufficient funds", "INSUFFICIENT_FUNDS", {
  812. transaction: ((<any>payload).params[0]),
  813. info: { payload, error }
  814. });
  815. }
  816. }
  817. if (method === "eth_call" || method === "eth_estimateGas") {
  818. const result = spelunkData(error);
  819. const e = AbiCoder.getBuiltinCallException(
  820. (method === "eth_call") ? "call": "estimateGas",
  821. ((<any>payload).params[0]),
  822. (result ? result.data: null)
  823. );
  824. e.info = { error, payload };
  825. return e;
  826. }
  827. // Only estimateGas and call can return arbitrary contract-defined text, so now we
  828. // we can process text safely.
  829. const message = JSON.stringify(spelunkMessage(error));
  830. if (typeof(error.message) === "string" && error.message.match(/user denied|ethers-user-denied/i)) {
  831. const actionMap: Record<string, "requestAccess" | "sendTransaction" | "signMessage" | "signTransaction" | "signTypedData"> = {
  832. eth_sign: "signMessage",
  833. personal_sign: "signMessage",
  834. eth_signTypedData_v4: "signTypedData",
  835. eth_signTransaction: "signTransaction",
  836. eth_sendTransaction: "sendTransaction",
  837. eth_requestAccounts: "requestAccess",
  838. wallet_requestAccounts: "requestAccess",
  839. };
  840. return makeError(`user rejected action`, "ACTION_REJECTED", {
  841. action: (actionMap[method] || "unknown") ,
  842. reason: "rejected",
  843. info: { payload, error }
  844. });
  845. }
  846. if (method === "eth_sendRawTransaction" || method === "eth_sendTransaction") {
  847. const transaction = <TransactionLike<string>>((<any>payload).params[0]);
  848. if (message.match(/insufficient funds|base fee exceeds gas limit/i)) {
  849. return makeError("insufficient funds for intrinsic transaction cost", "INSUFFICIENT_FUNDS", {
  850. transaction, info: { error }
  851. });
  852. }
  853. if (message.match(/nonce/i) && message.match(/too low/i)) {
  854. return makeError("nonce has already been used", "NONCE_EXPIRED", { transaction, info: { error } });
  855. }
  856. // "replacement transaction underpriced"
  857. if (message.match(/replacement transaction/i) && message.match(/underpriced/i)) {
  858. return makeError("replacement fee too low", "REPLACEMENT_UNDERPRICED", { transaction, info: { error } });
  859. }
  860. if (message.match(/only replay-protected/i)) {
  861. return makeError("legacy pre-eip-155 transactions not supported", "UNSUPPORTED_OPERATION", {
  862. operation: method, info: { transaction, info: { error } }
  863. });
  864. }
  865. }
  866. let unsupported = !!message.match(/the method .* does not exist/i);
  867. if (!unsupported) {
  868. if (error && (<any>error).details && (<any>error).details.startsWith("Unauthorized method:")) {
  869. unsupported = true;
  870. }
  871. }
  872. if (unsupported) {
  873. return makeError("unsupported operation", "UNSUPPORTED_OPERATION", {
  874. operation: payload.method, info: { error, payload }
  875. });
  876. }
  877. return makeError("could not coalesce error", "UNKNOWN_ERROR", { error, payload });
  878. }
  879. /**
  880. * Requests the %%method%% with %%params%% via the JSON-RPC protocol
  881. * over the underlying channel. This can be used to call methods
  882. * on the backend that do not have a high-level API within the Provider
  883. * API.
  884. *
  885. * This method queues requests according to the batch constraints
  886. * in the options, assigns the request a unique ID.
  887. *
  888. * **Do NOT override** this method in sub-classes; instead
  889. * override [[_send]] or force the options values in the
  890. * call to the constructor to modify this method's behavior.
  891. */
  892. send(method: string, params: Array<any> | Record<string, any>): Promise<any> {
  893. // @TODO: cache chainId?? purge on switch_networks
  894. // We have been destroyed; no operations are supported anymore
  895. if (this.destroyed) {
  896. return Promise.reject(makeError("provider destroyed; cancelled request", "UNSUPPORTED_OPERATION", { operation: method }));
  897. }
  898. const id = this.#nextId++;
  899. const promise = new Promise((resolve, reject) => {
  900. this.#payloads.push({
  901. resolve, reject,
  902. payload: { method, params, id, jsonrpc: "2.0" }
  903. });
  904. });
  905. // If there is not a pending drainTimer, set one
  906. this.#scheduleDrain();
  907. return <Promise<JsonRpcResult>>promise;
  908. }
  909. /**
  910. * Resolves to the [[Signer]] account for %%address%% managed by
  911. * the client.
  912. *
  913. * If the %%address%% is a number, it is used as an index in the
  914. * the accounts from [[listAccounts]].
  915. *
  916. * This can only be used on clients which manage accounts (such as
  917. * Geth with imported account or MetaMask).
  918. *
  919. * Throws if the account doesn't exist.
  920. */
  921. async getSigner(address?: number | string): Promise<JsonRpcSigner> {
  922. if (address == null) { address = 0; }
  923. const accountsPromise = this.send("eth_accounts", [ ]);
  924. // Account index
  925. if (typeof(address) === "number") {
  926. const accounts = <Array<string>>(await accountsPromise);
  927. if (address >= accounts.length) { throw new Error("no such account"); }
  928. return new JsonRpcSigner(this, accounts[address]);
  929. }
  930. const { accounts } = await resolveProperties({
  931. network: this.getNetwork(),
  932. accounts: accountsPromise
  933. });
  934. // Account address
  935. address = getAddress(address);
  936. for (const account of accounts) {
  937. if (getAddress(account) === address) {
  938. return new JsonRpcSigner(this, address);
  939. }
  940. }
  941. throw new Error("invalid account");
  942. }
  943. async listAccounts(): Promise<Array<JsonRpcSigner>> {
  944. const accounts: Array<string> = await this.send("eth_accounts", [ ]);
  945. return accounts.map((a) => new JsonRpcSigner(this, a));
  946. }
  947. destroy(): void {
  948. // Stop processing requests
  949. if (this.#drainTimer) {
  950. clearTimeout(this.#drainTimer);
  951. this.#drainTimer = null;
  952. }
  953. // Cancel all pending requests
  954. for (const { payload, reject } of this.#payloads) {
  955. reject(makeError("provider destroyed; cancelled request", "UNSUPPORTED_OPERATION", { operation: payload.method }));
  956. }
  957. this.#payloads = [ ];
  958. // Parent clean-up
  959. super.destroy();
  960. }
  961. }
  962. // @TODO: remove this in v7, it is not exported because this functionality
  963. // is exposed in the JsonRpcApiProvider by setting polling to true. It should
  964. // be safe to remove regardless, because it isn't reachable, but just in case.
  965. /**
  966. * @_ignore:
  967. */
  968. export abstract class JsonRpcApiPollingProvider extends JsonRpcApiProvider {
  969. #pollingInterval: number;
  970. constructor(network?: Networkish, options?: JsonRpcApiProviderOptions) {
  971. super(network, options);
  972. let pollingInterval = this._getOption("pollingInterval");
  973. if (pollingInterval == null) { pollingInterval = defaultOptions.pollingInterval; }
  974. this.#pollingInterval = pollingInterval;
  975. }
  976. _getSubscriber(sub: Subscription): Subscriber {
  977. const subscriber = super._getSubscriber(sub);
  978. if (isPollable(subscriber)) {
  979. subscriber.pollingInterval = this.#pollingInterval;
  980. }
  981. return subscriber;
  982. }
  983. /**
  984. * The polling interval (default: 4000 ms)
  985. */
  986. get pollingInterval(): number { return this.#pollingInterval; }
  987. set pollingInterval(value: number) {
  988. if (!Number.isInteger(value) || value < 0) { throw new Error("invalid interval"); }
  989. this.#pollingInterval = value;
  990. this._forEachSubscriber((sub) => {
  991. if (isPollable(sub)) {
  992. sub.pollingInterval = this.#pollingInterval;
  993. }
  994. });
  995. }
  996. }
  997. /**
  998. * The JsonRpcProvider is one of the most common Providers,
  999. * which performs all operations over HTTP (or HTTPS) requests.
  1000. *
  1001. * Events are processed by polling the backend for the current block
  1002. * number; when it advances, all block-base events are then checked
  1003. * for updates.
  1004. */
  1005. export class JsonRpcProvider extends JsonRpcApiPollingProvider {
  1006. #connect: FetchRequest;
  1007. constructor(url?: string | FetchRequest, network?: Networkish, options?: JsonRpcApiProviderOptions) {
  1008. if (url == null) { url = "http:/\/localhost:8545"; }
  1009. super(network, options);
  1010. if (typeof(url) === "string") {
  1011. this.#connect = new FetchRequest(url);
  1012. } else {
  1013. this.#connect = url.clone();
  1014. }
  1015. }
  1016. _getConnection(): FetchRequest {
  1017. return this.#connect.clone();
  1018. }
  1019. async send(method: string, params: Array<any> | Record<string, any>): Promise<any> {
  1020. // All requests are over HTTP, so we can just start handling requests
  1021. // We do this here rather than the constructor so that we don't send any
  1022. // requests to the network (i.e. eth_chainId) until we absolutely have to.
  1023. await this._start();
  1024. return await super.send(method, params);
  1025. }
  1026. async _send(payload: JsonRpcPayload | Array<JsonRpcPayload>): Promise<Array<JsonRpcResult>> {
  1027. // Configure a POST connection for the requested method
  1028. const request = this._getConnection();
  1029. request.body = JSON.stringify(payload);
  1030. request.setHeader("content-type", "application/json");
  1031. const response = await request.send();
  1032. response.assertOk();
  1033. let resp = response.bodyJson;
  1034. if (!Array.isArray(resp)) { resp = [ resp ]; }
  1035. return resp;
  1036. }
  1037. }
  1038. function spelunkData(value: any): null | { message: string, data: string } {
  1039. if (value == null) { return null; }
  1040. // These *are* the droids we're looking for.
  1041. if (typeof(value.message) === "string" && value.message.match(/revert/i) && isHexString(value.data)) {
  1042. return { message: value.message, data: value.data };
  1043. }
  1044. // Spelunk further...
  1045. if (typeof(value) === "object") {
  1046. for (const key in value) {
  1047. const result = spelunkData(value[key]);
  1048. if (result) { return result; }
  1049. }
  1050. return null;
  1051. }
  1052. // Might be a JSON string we can further descend...
  1053. if (typeof(value) === "string") {
  1054. try {
  1055. return spelunkData(JSON.parse(value));
  1056. } catch (error) { }
  1057. }
  1058. return null;
  1059. }
  1060. function _spelunkMessage(value: any, result: Array<string>): void {
  1061. if (value == null) { return; }
  1062. // These *are* the droids we're looking for.
  1063. if (typeof(value.message) === "string") {
  1064. result.push(value.message);
  1065. }
  1066. // Spelunk further...
  1067. if (typeof(value) === "object") {
  1068. for (const key in value) {
  1069. _spelunkMessage(value[key], result);
  1070. }
  1071. }
  1072. // Might be a JSON string we can further descend...
  1073. if (typeof(value) === "string") {
  1074. try {
  1075. return _spelunkMessage(JSON.parse(value), result);
  1076. } catch (error) { }
  1077. }
  1078. }
  1079. function spelunkMessage(value: any): Array<string> {
  1080. const result: Array<string> = [ ];
  1081. _spelunkMessage(value, result);
  1082. return result;
  1083. }