|
20 | 20 | * @_subsection: api/providers/thirdparty:Blockscout [providers-blockscout]
|
21 | 21 | */
|
22 | 22 | import {
|
23 |
| - defineProperties, FetchRequest, assertArgument |
| 23 | + assertArgument, defineProperties, FetchRequest, isHexString |
24 | 24 | } from "../utils/index.js";
|
25 | 25 |
|
26 | 26 | import { Network } from "./network.js";
|
27 | 27 | import { JsonRpcProvider } from "./provider-jsonrpc.js";
|
28 | 28 |
|
29 |
| -import type { AbstractProvider } from "./abstract-provider.js"; |
| 29 | +import type { AbstractProvider, PerformActionRequest } from "./abstract-provider.js"; |
30 | 30 | import type { CommunityResourcable } from "./community.js";
|
31 | 31 | import type { Networkish } from "./network.js";
|
| 32 | +import type { JsonRpcPayload, JsonRpcError } from "./provider-jsonrpc.js"; |
32 | 33 |
|
33 | 34 |
|
34 | 35 | function getUrl(name: string): string {
|
@@ -108,6 +109,52 @@ export class BlockscoutProvider extends JsonRpcProvider implements CommunityReso
|
108 | 109 | return (this.apiKey === null);
|
109 | 110 | }
|
110 | 111 |
|
| 112 | + getRpcRequest(req: PerformActionRequest): null | { method: string, args: Array<any> } { |
| 113 | + // Blockscout enforces the TAG argument for estimateGas |
| 114 | + const resp = super.getRpcRequest(req); |
| 115 | + if (resp && resp.method === "eth_estimateGas" && resp.args.length == 1) { |
| 116 | + resp.args = resp.args.slice(); |
| 117 | + resp.args.push("latest"); |
| 118 | + } |
| 119 | + return resp; |
| 120 | + } |
| 121 | + |
| 122 | + getRpcError(payload: JsonRpcPayload, _error: JsonRpcError): Error { |
| 123 | + const error = _error ? _error.error: null; |
| 124 | + |
| 125 | + // Blockscout currently drops the VM result and replaces it with a |
| 126 | + // human-readable string, so we need to make it machine-readable. |
| 127 | + if (error && error.code === -32015 && !isHexString(error.data || "", true)) { |
| 128 | + const panicCodes = <Record<string, string>>{ |
| 129 | + "assert(false)": "01", |
| 130 | + "arithmetic underflow or overflow": "11", |
| 131 | + "division or modulo by zero": "12", |
| 132 | + "out-of-bounds array access; popping on an empty array": "31", |
| 133 | + "out-of-bounds access of an array or bytesN": "32" |
| 134 | + }; |
| 135 | + |
| 136 | + let panicCode = ""; |
| 137 | + if (error.message === "VM execution error.") { |
| 138 | + // eth_call passes this message |
| 139 | + panicCode = panicCodes[error.data] || ""; |
| 140 | + } else if (panicCodes[error.message || ""]) { |
| 141 | + panicCode = panicCodes[error.message || ""]; |
| 142 | + } |
| 143 | + |
| 144 | + if (panicCode) { |
| 145 | + error.message += ` (reverted: ${ error.data })`; |
| 146 | + error.data = "0x4e487b7100000000000000000000000000000000000000000000000000000000000000" + panicCode; |
| 147 | + } |
| 148 | + |
| 149 | + } else if (error && error.code === -32000) { |
| 150 | + if (error.message === "wrong transaction nonce") { |
| 151 | + error.message += " (nonce too low)"; |
| 152 | + } |
| 153 | + } |
| 154 | + |
| 155 | + return super.getRpcError(payload, _error); |
| 156 | + } |
| 157 | + |
111 | 158 | /**
|
112 | 159 | * Returns a prepared request for connecting to %%network%%
|
113 | 160 | * with %%apiKey%%.
|
|
0 commit comments