@qevm/providers 1.0.2 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -9
- package/lib/_version.d.ts +1 -1
- package/lib/_version.js +1 -1
- package/lib/base-provider.d.ts +2 -2
- package/lib/base-provider.d.ts.map +1 -1
- package/lib/base-provider.js +300 -145
- package/lib/base-provider.js.map +1 -1
- package/lib/browser-ipc-provider.d.ts.map +1 -1
- package/lib/browser-ipc-provider.js.map +1 -1
- package/lib/browser-net.d.ts.map +1 -1
- package/lib/browser-net.js.map +1 -1
- package/lib/browser-ws.d.ts.map +1 -1
- package/lib/browser-ws.js +2 -2
- package/lib/browser-ws.js.map +1 -1
- package/lib/fallback-provider.d.ts +1 -1
- package/lib/fallback-provider.d.ts.map +1 -1
- package/lib/fallback-provider.js +86 -55
- package/lib/fallback-provider.js.map +1 -1
- package/lib/formatter.d.ts.map +1 -1
- package/lib/formatter.js +35 -29
- package/lib/formatter.js.map +1 -1
- package/lib/index.d.ts +3 -10
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +5 -28
- package/lib/index.js.map +1 -1
- package/lib/ipc-provider.d.ts +1 -1
- package/lib/ipc-provider.d.ts.map +1 -1
- package/lib/ipc-provider.js +6 -4
- package/lib/ipc-provider.js.map +1 -1
- package/lib/json-rpc-batch-provider.d.ts.map +1 -1
- package/lib/json-rpc-batch-provider.js +6 -6
- package/lib/json-rpc-batch-provider.js.map +1 -1
- package/lib/json-rpc-provider.d.ts +2 -2
- package/lib/json-rpc-provider.d.ts.map +1 -1
- package/lib/json-rpc-provider.js +167 -69
- package/lib/json-rpc-provider.js.map +1 -1
- package/lib/url-json-rpc-provider.d.ts +1 -1
- package/lib/url-json-rpc-provider.d.ts.map +1 -1
- package/lib/url-json-rpc-provider.js +4 -4
- package/lib/url-json-rpc-provider.js.map +1 -1
- package/lib/web3-provider.d.ts +1 -2
- package/lib/web3-provider.d.ts.map +1 -1
- package/lib/web3-provider.js +11 -14
- package/lib/web3-provider.js.map +1 -1
- package/lib/websocket-provider.d.ts +1 -1
- package/lib/websocket-provider.d.ts.map +1 -1
- package/lib/websocket-provider.js +21 -17
- package/lib/websocket-provider.js.map +1 -1
- package/lib/ws.d.ts.map +1 -1
- package/package.json +61 -58
- package/src.ts/_version.ts +1 -1
- package/src.ts/base-provider.ts +1418 -645
- package/src.ts/browser-ipc-provider.ts +1 -3
- package/src.ts/browser-net.ts +1 -1
- package/src.ts/browser-ws.ts +14 -8
- package/src.ts/fallback-provider.ts +375 -198
- package/src.ts/formatter.ts +161 -81
- package/src.ts/index.ts +54 -68
- package/src.ts/ipc-provider.ts +8 -7
- package/src.ts/json-rpc-batch-provider.ts +48 -44
- package/src.ts/json-rpc-provider.ts +594 -245
- package/src.ts/url-json-rpc-provider.ts +34 -15
- package/src.ts/web3-provider.ts +87 -54
- package/src.ts/websocket-provider.ts +124 -66
- package/src.ts/ws.ts +1 -1
- package/lib/alchemy-provider.d.ts +0 -17
- package/lib/alchemy-provider.d.ts.map +0 -1
- package/lib/alchemy-provider.js +0 -88
- package/lib/alchemy-provider.js.map +0 -1
- package/lib/ankr-provider.d.ts +0 -10
- package/lib/ankr-provider.d.ts.map +0 -1
- package/lib/ankr-provider.js +0 -59
- package/lib/ankr-provider.js.map +0 -1
- package/lib/cloudflare-provider.d.ts +0 -8
- package/lib/cloudflare-provider.d.ts.map +0 -1
- package/lib/cloudflare-provider.js +0 -37
- package/lib/cloudflare-provider.js.map +0 -1
- package/lib/etherscan-provider.d.ts +0 -18
- package/lib/etherscan-provider.d.ts.map +0 -1
- package/lib/etherscan-provider.js +0 -408
- package/lib/etherscan-provider.js.map +0 -1
- package/lib/infura-provider.d.ts +0 -21
- package/lib/infura-provider.d.ts.map +0 -1
- package/lib/infura-provider.js +0 -117
- package/lib/infura-provider.js.map +0 -1
- package/lib/nodesmith-provider.d.ts +0 -7
- package/lib/nodesmith-provider.d.ts.map +0 -1
- package/lib/nodesmith-provider.js +0 -44
- package/lib/nodesmith-provider.js.map +0 -1
- package/lib/pocket-provider.d.ts +0 -12
- package/lib/pocket-provider.d.ts.map +0 -1
- package/lib/pocket-provider.js +0 -78
- package/lib/pocket-provider.js.map +0 -1
- package/src.ts/alchemy-provider.ts +0 -101
- package/src.ts/ankr-provider.ts +0 -68
- package/src.ts/cloudflare-provider.ts +0 -42
- package/src.ts/etherscan-provider.ts +0 -454
- package/src.ts/infura-provider.ts +0 -143
- package/src.ts/nodesmith-provider.ts +0 -50
- package/src.ts/pocket-provider.ts +0 -93
|
@@ -2,141 +2,230 @@
|
|
|
2
2
|
|
|
3
3
|
// See: https://github.com/ethereum/wiki/wiki/JSON-RPC
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
|
|
5
|
+
import {
|
|
6
|
+
Provider,
|
|
7
|
+
TransactionRequest,
|
|
8
|
+
TransactionResponse,
|
|
9
|
+
} from "@qevm/abstract-provider";
|
|
10
|
+
import {
|
|
11
|
+
Signer,
|
|
12
|
+
TypedDataDomain,
|
|
13
|
+
TypedDataField,
|
|
14
|
+
TypedDataSigner,
|
|
15
|
+
} from "@qevm/abstract-signer";
|
|
7
16
|
import { BigNumber } from "@qevm/bignumber";
|
|
8
17
|
import { Bytes, hexlify, hexValue, hexZeroPad, isHexString } from "@qevm/bytes";
|
|
9
18
|
import { _TypedDataEncoder } from "@qevm/hash";
|
|
10
|
-
import { Network, Networkish } from "@
|
|
11
|
-
import {
|
|
19
|
+
import { Network, Networkish } from "@qevm/networks";
|
|
20
|
+
import {
|
|
21
|
+
checkProperties,
|
|
22
|
+
deepCopy,
|
|
23
|
+
Deferrable,
|
|
24
|
+
defineReadOnly,
|
|
25
|
+
getStatic,
|
|
26
|
+
resolveProperties,
|
|
27
|
+
shallowCopy,
|
|
28
|
+
} from "@qevm/properties";
|
|
12
29
|
import { toUtf8Bytes } from "@qevm/strings";
|
|
13
30
|
import { AccessList, accessListify } from "@qevm/transactions";
|
|
14
31
|
import { ConnectionInfo, fetchJson, poll } from "@qevm/web";
|
|
15
32
|
|
|
16
|
-
import { Logger } from "@
|
|
33
|
+
import { Logger } from "@qevm/logger";
|
|
17
34
|
import { version } from "./_version";
|
|
18
35
|
const logger = new Logger(version);
|
|
19
36
|
|
|
20
37
|
import { BaseProvider, Event } from "./base-provider";
|
|
21
38
|
|
|
39
|
+
const errorGas = ["call", "estimateGas"];
|
|
22
40
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
41
|
+
function spelunk(
|
|
42
|
+
value: any,
|
|
43
|
+
requireData: boolean,
|
|
44
|
+
): null | { message: string; data: null | string } {
|
|
45
|
+
if (value == null) {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
27
48
|
|
|
28
49
|
// These *are* the droids we're looking for.
|
|
29
|
-
if (typeof
|
|
30
|
-
const data = isHexString(value.data) ? value.data: null;
|
|
50
|
+
if (typeof value.message === "string" && value.message.match("reverted")) {
|
|
51
|
+
const data = isHexString(value.data) ? value.data : null;
|
|
31
52
|
if (!requireData || data) {
|
|
32
53
|
return { message: value.message, data };
|
|
33
54
|
}
|
|
34
55
|
}
|
|
35
56
|
|
|
36
57
|
// Spelunk further...
|
|
37
|
-
if (typeof
|
|
58
|
+
if (typeof value === "object") {
|
|
38
59
|
for (const key in value) {
|
|
39
60
|
const result = spelunk(value[key], requireData);
|
|
40
|
-
if (result) {
|
|
61
|
+
if (result) {
|
|
62
|
+
return result;
|
|
63
|
+
}
|
|
41
64
|
}
|
|
42
65
|
return null;
|
|
43
66
|
}
|
|
44
67
|
|
|
45
68
|
// Might be a JSON string we can further descend...
|
|
46
|
-
if (typeof
|
|
69
|
+
if (typeof value === "string") {
|
|
47
70
|
try {
|
|
48
71
|
return spelunk(JSON.parse(value), requireData);
|
|
49
|
-
} catch (error) {
|
|
72
|
+
} catch (error) {}
|
|
50
73
|
}
|
|
51
74
|
|
|
52
75
|
return null;
|
|
53
76
|
}
|
|
54
77
|
|
|
55
78
|
function checkError(method: string, error: any, params: any): any {
|
|
56
|
-
|
|
57
79
|
const transaction = params.transaction || params.signedTransaction;
|
|
58
80
|
|
|
59
81
|
// Undo the "convenience" some nodes are attempting to prevent backwards
|
|
60
82
|
// incompatibility; maybe for v6 consider forwarding reverts as errors
|
|
61
83
|
if (method === "call") {
|
|
62
84
|
const result = spelunk(error, true);
|
|
63
|
-
if (result) {
|
|
85
|
+
if (result) {
|
|
86
|
+
return result.data;
|
|
87
|
+
}
|
|
64
88
|
|
|
65
89
|
// Nothing descriptive..
|
|
66
|
-
logger.throwError(
|
|
67
|
-
data
|
|
68
|
-
|
|
90
|
+
logger.throwError(
|
|
91
|
+
"missing revert data in call exception; Transaction reverted without a reason string",
|
|
92
|
+
Logger.errors.CALL_EXCEPTION,
|
|
93
|
+
{
|
|
94
|
+
data: "0x",
|
|
95
|
+
transaction,
|
|
96
|
+
error,
|
|
97
|
+
},
|
|
98
|
+
);
|
|
69
99
|
}
|
|
70
100
|
|
|
71
101
|
if (method === "estimateGas") {
|
|
72
102
|
// Try to find something, with a preference on SERVER_ERROR body
|
|
73
103
|
let result = spelunk(error.body, false);
|
|
74
|
-
if (result == null) {
|
|
104
|
+
if (result == null) {
|
|
105
|
+
result = spelunk(error, false);
|
|
106
|
+
}
|
|
75
107
|
|
|
76
108
|
// Found "reverted", this is a CALL_EXCEPTION
|
|
77
109
|
if (result) {
|
|
78
|
-
logger.throwError(
|
|
79
|
-
|
|
80
|
-
|
|
110
|
+
logger.throwError(
|
|
111
|
+
"cannot estimate gas; transaction may fail or may require manual gas limit",
|
|
112
|
+
Logger.errors.UNPREDICTABLE_GAS_LIMIT,
|
|
113
|
+
{
|
|
114
|
+
reason: result.message,
|
|
115
|
+
method,
|
|
116
|
+
transaction,
|
|
117
|
+
error,
|
|
118
|
+
},
|
|
119
|
+
);
|
|
81
120
|
}
|
|
82
121
|
}
|
|
83
122
|
|
|
84
123
|
// @TODO: Should we spelunk for message too?
|
|
85
124
|
|
|
86
125
|
let message = error.message;
|
|
87
|
-
if (
|
|
126
|
+
if (
|
|
127
|
+
error.code === Logger.errors.SERVER_ERROR &&
|
|
128
|
+
error.error &&
|
|
129
|
+
typeof error.error.message === "string"
|
|
130
|
+
) {
|
|
88
131
|
message = error.error.message;
|
|
89
|
-
} else if (typeof
|
|
132
|
+
} else if (typeof error.body === "string") {
|
|
90
133
|
message = error.body;
|
|
91
|
-
} else if (typeof
|
|
134
|
+
} else if (typeof error.responseText === "string") {
|
|
92
135
|
message = error.responseText;
|
|
93
136
|
}
|
|
94
137
|
message = (message || "").toLowerCase();
|
|
95
138
|
|
|
96
139
|
// "insufficient funds for gas * price + value + cost(data)"
|
|
97
|
-
if (
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
140
|
+
if (
|
|
141
|
+
message.match(
|
|
142
|
+
/insufficient funds|base fee exceeds gas limit|InsufficientFunds/i,
|
|
143
|
+
)
|
|
144
|
+
) {
|
|
145
|
+
logger.throwError(
|
|
146
|
+
"insufficient funds for intrinsic transaction cost",
|
|
147
|
+
Logger.errors.INSUFFICIENT_FUNDS,
|
|
148
|
+
{
|
|
149
|
+
error,
|
|
150
|
+
method,
|
|
151
|
+
transaction,
|
|
152
|
+
},
|
|
153
|
+
);
|
|
101
154
|
}
|
|
102
155
|
|
|
103
156
|
// "nonce too low"
|
|
104
157
|
if (message.match(/nonce (is )?too low/i)) {
|
|
105
|
-
logger.throwError(
|
|
106
|
-
|
|
107
|
-
|
|
158
|
+
logger.throwError(
|
|
159
|
+
"nonce has already been used",
|
|
160
|
+
Logger.errors.NONCE_EXPIRED,
|
|
161
|
+
{
|
|
162
|
+
error,
|
|
163
|
+
method,
|
|
164
|
+
transaction,
|
|
165
|
+
},
|
|
166
|
+
);
|
|
108
167
|
}
|
|
109
168
|
|
|
110
169
|
// "replacement transaction underpriced"
|
|
111
|
-
if (
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
170
|
+
if (
|
|
171
|
+
message.match(
|
|
172
|
+
/replacement transaction underpriced|transaction gas price.*too low/i,
|
|
173
|
+
)
|
|
174
|
+
) {
|
|
175
|
+
logger.throwError(
|
|
176
|
+
"replacement fee too low",
|
|
177
|
+
Logger.errors.REPLACEMENT_UNDERPRICED,
|
|
178
|
+
{
|
|
179
|
+
error,
|
|
180
|
+
method,
|
|
181
|
+
transaction,
|
|
182
|
+
},
|
|
183
|
+
);
|
|
115
184
|
}
|
|
116
185
|
|
|
117
186
|
// "replacement transaction underpriced"
|
|
118
187
|
if (message.match(/only replay-protected/i)) {
|
|
119
|
-
logger.throwError(
|
|
120
|
-
|
|
121
|
-
|
|
188
|
+
logger.throwError(
|
|
189
|
+
"legacy pre-eip-155 transactions not supported",
|
|
190
|
+
Logger.errors.UNSUPPORTED_OPERATION,
|
|
191
|
+
{
|
|
192
|
+
error,
|
|
193
|
+
method,
|
|
194
|
+
transaction,
|
|
195
|
+
},
|
|
196
|
+
);
|
|
122
197
|
}
|
|
123
198
|
|
|
124
|
-
if (
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
199
|
+
if (
|
|
200
|
+
errorGas.indexOf(method) >= 0 &&
|
|
201
|
+
message.match(
|
|
202
|
+
/gas required exceeds allowance|always failing transaction|execution reverted|revert/,
|
|
203
|
+
)
|
|
204
|
+
) {
|
|
205
|
+
logger.throwError(
|
|
206
|
+
"cannot estimate gas; transaction may fail or may require manual gas limit",
|
|
207
|
+
Logger.errors.UNPREDICTABLE_GAS_LIMIT,
|
|
208
|
+
{
|
|
209
|
+
error,
|
|
210
|
+
method,
|
|
211
|
+
transaction,
|
|
212
|
+
},
|
|
213
|
+
);
|
|
128
214
|
}
|
|
129
215
|
|
|
130
216
|
throw error;
|
|
131
217
|
}
|
|
132
218
|
|
|
133
219
|
function timer(timeout: number): Promise<any> {
|
|
134
|
-
return new Promise(function(resolve) {
|
|
220
|
+
return new Promise(function (resolve) {
|
|
135
221
|
setTimeout(resolve, timeout);
|
|
136
222
|
});
|
|
137
223
|
}
|
|
138
224
|
|
|
139
|
-
function getResult(payload: {
|
|
225
|
+
function getResult(payload: {
|
|
226
|
+
error?: { code?: number; data?: any; message?: string };
|
|
227
|
+
result?: any;
|
|
228
|
+
}): any {
|
|
140
229
|
if (payload.error) {
|
|
141
230
|
// @TODO: not any
|
|
142
231
|
const error: any = new Error(payload.error.message);
|
|
@@ -149,7 +238,9 @@ function getResult(payload: { error?: { code?: number, data?: any, message?: str
|
|
|
149
238
|
}
|
|
150
239
|
|
|
151
240
|
function getLowerCase(value: string): string {
|
|
152
|
-
if (value) {
|
|
241
|
+
if (value) {
|
|
242
|
+
return value.toLowerCase();
|
|
243
|
+
}
|
|
153
244
|
return value;
|
|
154
245
|
}
|
|
155
246
|
|
|
@@ -160,38 +251,60 @@ export class JsonRpcSigner extends Signer implements TypedDataSigner {
|
|
|
160
251
|
_index: number;
|
|
161
252
|
_address: string;
|
|
162
253
|
|
|
163
|
-
constructor(
|
|
254
|
+
constructor(
|
|
255
|
+
constructorGuard: any,
|
|
256
|
+
provider: JsonRpcProvider,
|
|
257
|
+
addressOrIndex?: string | number,
|
|
258
|
+
) {
|
|
164
259
|
super();
|
|
165
260
|
|
|
166
261
|
if (constructorGuard !== _constructorGuard) {
|
|
167
|
-
throw new Error(
|
|
262
|
+
throw new Error(
|
|
263
|
+
"do not call the JsonRpcSigner constructor directly; use provider.getSigner",
|
|
264
|
+
);
|
|
168
265
|
}
|
|
169
266
|
|
|
170
267
|
defineReadOnly(this, "provider", provider);
|
|
171
268
|
|
|
172
|
-
if (addressOrIndex == null) {
|
|
269
|
+
if (addressOrIndex == null) {
|
|
270
|
+
addressOrIndex = 0;
|
|
271
|
+
}
|
|
173
272
|
|
|
174
|
-
if (typeof
|
|
175
|
-
defineReadOnly(
|
|
273
|
+
if (typeof addressOrIndex === "string") {
|
|
274
|
+
defineReadOnly(
|
|
275
|
+
this,
|
|
276
|
+
"_address",
|
|
277
|
+
this.provider.formatter.address(addressOrIndex),
|
|
278
|
+
);
|
|
176
279
|
defineReadOnly(this, "_index", null);
|
|
177
|
-
|
|
178
|
-
} else if (typeof(addressOrIndex) === "number") {
|
|
280
|
+
} else if (typeof addressOrIndex === "number") {
|
|
179
281
|
defineReadOnly(this, "_index", addressOrIndex);
|
|
180
282
|
defineReadOnly(this, "_address", null);
|
|
181
|
-
|
|
182
283
|
} else {
|
|
183
|
-
logger.throwArgumentError(
|
|
284
|
+
logger.throwArgumentError(
|
|
285
|
+
"invalid address or index",
|
|
286
|
+
"addressOrIndex",
|
|
287
|
+
addressOrIndex,
|
|
288
|
+
);
|
|
184
289
|
}
|
|
185
290
|
}
|
|
186
291
|
|
|
187
292
|
connect(provider: Provider): JsonRpcSigner {
|
|
188
|
-
return logger.throwError(
|
|
189
|
-
|
|
190
|
-
|
|
293
|
+
return logger.throwError(
|
|
294
|
+
"cannot alter JSON-RPC Signer connection",
|
|
295
|
+
Logger.errors.UNSUPPORTED_OPERATION,
|
|
296
|
+
{
|
|
297
|
+
operation: "connect",
|
|
298
|
+
},
|
|
299
|
+
);
|
|
191
300
|
}
|
|
192
301
|
|
|
193
302
|
connectUnchecked(): JsonRpcSigner {
|
|
194
|
-
return new UncheckedJsonRpcSigner(
|
|
303
|
+
return new UncheckedJsonRpcSigner(
|
|
304
|
+
_constructorGuard,
|
|
305
|
+
this.provider,
|
|
306
|
+
this._address || this._index,
|
|
307
|
+
);
|
|
195
308
|
}
|
|
196
309
|
|
|
197
310
|
getAddress(): Promise<string> {
|
|
@@ -201,19 +314,27 @@ export class JsonRpcSigner extends Signer implements TypedDataSigner {
|
|
|
201
314
|
|
|
202
315
|
return this.provider.send("eth_accounts", []).then((accounts) => {
|
|
203
316
|
if (accounts.length <= this._index) {
|
|
204
|
-
logger.throwError(
|
|
205
|
-
|
|
206
|
-
|
|
317
|
+
logger.throwError(
|
|
318
|
+
"unknown account #" + this._index,
|
|
319
|
+
Logger.errors.UNSUPPORTED_OPERATION,
|
|
320
|
+
{
|
|
321
|
+
operation: "getAddress",
|
|
322
|
+
},
|
|
323
|
+
);
|
|
207
324
|
}
|
|
208
|
-
return this.provider.formatter.address(accounts[this._index])
|
|
325
|
+
return this.provider.formatter.address(accounts[this._index]);
|
|
209
326
|
});
|
|
210
327
|
}
|
|
211
328
|
|
|
212
|
-
sendUncheckedTransaction(
|
|
329
|
+
sendUncheckedTransaction(
|
|
330
|
+
transaction: Deferrable<TransactionRequest>,
|
|
331
|
+
): Promise<string> {
|
|
213
332
|
transaction = shallowCopy(transaction);
|
|
214
333
|
|
|
215
334
|
const fromAddress = this.getAddress().then((address) => {
|
|
216
|
-
if (address) {
|
|
335
|
+
if (address) {
|
|
336
|
+
address = address.toLowerCase();
|
|
337
|
+
}
|
|
217
338
|
return address;
|
|
218
339
|
});
|
|
219
340
|
|
|
@@ -227,55 +348,89 @@ export class JsonRpcSigner extends Signer implements TypedDataSigner {
|
|
|
227
348
|
}
|
|
228
349
|
|
|
229
350
|
if (transaction.to != null) {
|
|
230
|
-
transaction.to = Promise.resolve(transaction.to).then(
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
351
|
+
transaction.to = Promise.resolve(transaction.to).then(
|
|
352
|
+
async (to) => {
|
|
353
|
+
if (to == null) {
|
|
354
|
+
return null;
|
|
355
|
+
}
|
|
356
|
+
const address = await this.provider.resolveName(to);
|
|
357
|
+
if (address == null) {
|
|
358
|
+
logger.throwArgumentError(
|
|
359
|
+
"provided ENS name resolves to null",
|
|
360
|
+
"tx.to",
|
|
361
|
+
to,
|
|
362
|
+
);
|
|
363
|
+
}
|
|
364
|
+
return address;
|
|
365
|
+
},
|
|
366
|
+
);
|
|
238
367
|
}
|
|
239
368
|
|
|
240
369
|
return resolveProperties({
|
|
241
370
|
tx: resolveProperties(transaction),
|
|
242
|
-
sender: fromAddress
|
|
371
|
+
sender: fromAddress,
|
|
243
372
|
}).then(({ tx, sender }) => {
|
|
244
|
-
|
|
245
373
|
if (tx.from != null) {
|
|
246
374
|
if (tx.from.toLowerCase() !== sender) {
|
|
247
|
-
logger.throwArgumentError(
|
|
375
|
+
logger.throwArgumentError(
|
|
376
|
+
"from address mismatch",
|
|
377
|
+
"transaction",
|
|
378
|
+
transaction,
|
|
379
|
+
);
|
|
248
380
|
}
|
|
249
381
|
} else {
|
|
250
382
|
tx.from = sender;
|
|
251
383
|
}
|
|
252
384
|
|
|
253
|
-
const hexTx = (<any>this.provider.constructor).hexlifyTransaction(
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
385
|
+
const hexTx = (<any>this.provider.constructor).hexlifyTransaction(
|
|
386
|
+
tx,
|
|
387
|
+
{ from: true },
|
|
388
|
+
);
|
|
389
|
+
|
|
390
|
+
return this.provider.send("eth_sendTransaction", [hexTx]).then(
|
|
391
|
+
(hash) => {
|
|
392
|
+
return hash;
|
|
393
|
+
},
|
|
394
|
+
(error) => {
|
|
395
|
+
if (
|
|
396
|
+
typeof error.message === "string" &&
|
|
397
|
+
error.message.match(/user denied/i)
|
|
398
|
+
) {
|
|
399
|
+
logger.throwError(
|
|
400
|
+
"user rejected transaction",
|
|
401
|
+
Logger.errors.ACTION_REJECTED,
|
|
402
|
+
{
|
|
403
|
+
action: "sendTransaction",
|
|
404
|
+
transaction: tx,
|
|
405
|
+
},
|
|
406
|
+
);
|
|
407
|
+
}
|
|
264
408
|
|
|
265
|
-
|
|
266
|
-
|
|
409
|
+
return checkError("sendTransaction", error, hexTx);
|
|
410
|
+
},
|
|
411
|
+
);
|
|
267
412
|
});
|
|
268
413
|
}
|
|
269
414
|
|
|
270
|
-
signTransaction(
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
415
|
+
signTransaction(
|
|
416
|
+
transaction: Deferrable<TransactionRequest>,
|
|
417
|
+
): Promise<string> {
|
|
418
|
+
return logger.throwError(
|
|
419
|
+
"signing transactions is unsupported",
|
|
420
|
+
Logger.errors.UNSUPPORTED_OPERATION,
|
|
421
|
+
{
|
|
422
|
+
operation: "signTransaction",
|
|
423
|
+
},
|
|
424
|
+
);
|
|
274
425
|
}
|
|
275
426
|
|
|
276
|
-
async sendTransaction(
|
|
427
|
+
async sendTransaction(
|
|
428
|
+
transaction: Deferrable<TransactionRequest>,
|
|
429
|
+
): Promise<TransactionResponse> {
|
|
277
430
|
// This cannot be mined any earlier than any recent block
|
|
278
|
-
const blockNumber = await this.provider._getInternalBlockNumber(
|
|
431
|
+
const blockNumber = await this.provider._getInternalBlockNumber(
|
|
432
|
+
100 + 2 * this.provider.pollingInterval,
|
|
433
|
+
);
|
|
279
434
|
|
|
280
435
|
// Send the transaction
|
|
281
436
|
const hash = await this.sendUncheckedTransaction(transaction);
|
|
@@ -284,11 +439,20 @@ export class JsonRpcSigner extends Signer implements TypedDataSigner {
|
|
|
284
439
|
// Unfortunately, JSON-RPC only provides and opaque transaction hash
|
|
285
440
|
// for a response, and we need the actual transaction, so we poll
|
|
286
441
|
// for it; it should show up very quickly
|
|
287
|
-
return await poll(
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
442
|
+
return await poll(
|
|
443
|
+
async () => {
|
|
444
|
+
const tx = await this.provider.getTransaction(hash);
|
|
445
|
+
if (tx === null) {
|
|
446
|
+
return undefined;
|
|
447
|
+
}
|
|
448
|
+
return this.provider._wrapTransaction(
|
|
449
|
+
tx,
|
|
450
|
+
hash,
|
|
451
|
+
blockNumber,
|
|
452
|
+
);
|
|
453
|
+
},
|
|
454
|
+
{ oncePoll: this.provider },
|
|
455
|
+
);
|
|
292
456
|
} catch (error) {
|
|
293
457
|
(<any>error).transactionHash = hash;
|
|
294
458
|
throw error;
|
|
@@ -296,61 +460,109 @@ export class JsonRpcSigner extends Signer implements TypedDataSigner {
|
|
|
296
460
|
}
|
|
297
461
|
|
|
298
462
|
async signMessage(message: Bytes | string): Promise<string> {
|
|
299
|
-
const data =
|
|
463
|
+
const data =
|
|
464
|
+
typeof message === "string" ? toUtf8Bytes(message) : message;
|
|
300
465
|
const address = await this.getAddress();
|
|
301
466
|
try {
|
|
302
|
-
return await this.provider.send("personal_sign", [
|
|
467
|
+
return await this.provider.send("personal_sign", [
|
|
468
|
+
hexlify(data),
|
|
469
|
+
address.toLowerCase(),
|
|
470
|
+
]);
|
|
303
471
|
} catch (error) {
|
|
304
|
-
if (
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
472
|
+
if (
|
|
473
|
+
typeof error.message === "string" &&
|
|
474
|
+
error.message.match(/user denied/i)
|
|
475
|
+
) {
|
|
476
|
+
logger.throwError(
|
|
477
|
+
"user rejected signing",
|
|
478
|
+
Logger.errors.ACTION_REJECTED,
|
|
479
|
+
{
|
|
480
|
+
action: "signMessage",
|
|
481
|
+
from: address,
|
|
482
|
+
messageData: message,
|
|
483
|
+
},
|
|
484
|
+
);
|
|
310
485
|
}
|
|
311
486
|
throw error;
|
|
312
487
|
}
|
|
313
488
|
}
|
|
314
489
|
|
|
315
490
|
async _legacySignMessage(message: Bytes | string): Promise<string> {
|
|
316
|
-
const data =
|
|
491
|
+
const data =
|
|
492
|
+
typeof message === "string" ? toUtf8Bytes(message) : message;
|
|
317
493
|
const address = await this.getAddress();
|
|
318
494
|
|
|
319
495
|
try {
|
|
320
496
|
// https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign
|
|
321
|
-
return await this.provider.send("eth_sign", [
|
|
497
|
+
return await this.provider.send("eth_sign", [
|
|
498
|
+
address.toLowerCase(),
|
|
499
|
+
hexlify(data),
|
|
500
|
+
]);
|
|
322
501
|
} catch (error) {
|
|
323
|
-
if (
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
502
|
+
if (
|
|
503
|
+
typeof error.message === "string" &&
|
|
504
|
+
error.message.match(/user denied/i)
|
|
505
|
+
) {
|
|
506
|
+
logger.throwError(
|
|
507
|
+
"user rejected signing",
|
|
508
|
+
Logger.errors.ACTION_REJECTED,
|
|
509
|
+
{
|
|
510
|
+
action: "_legacySignMessage",
|
|
511
|
+
from: address,
|
|
512
|
+
messageData: message,
|
|
513
|
+
},
|
|
514
|
+
);
|
|
329
515
|
}
|
|
330
516
|
throw error;
|
|
331
517
|
}
|
|
332
518
|
}
|
|
333
519
|
|
|
334
|
-
async _signTypedData(
|
|
520
|
+
async _signTypedData(
|
|
521
|
+
domain: TypedDataDomain,
|
|
522
|
+
types: Record<string, Array<TypedDataField>>,
|
|
523
|
+
value: Record<string, any>,
|
|
524
|
+
): Promise<string> {
|
|
335
525
|
// Populate any ENS names (in-place)
|
|
336
|
-
const populated = await _TypedDataEncoder.resolveNames(
|
|
337
|
-
|
|
338
|
-
|
|
526
|
+
const populated = await _TypedDataEncoder.resolveNames(
|
|
527
|
+
domain,
|
|
528
|
+
types,
|
|
529
|
+
value,
|
|
530
|
+
(name: string) => {
|
|
531
|
+
return this.provider.resolveName(name);
|
|
532
|
+
},
|
|
533
|
+
);
|
|
339
534
|
|
|
340
535
|
const address = await this.getAddress();
|
|
341
536
|
|
|
342
537
|
try {
|
|
343
538
|
return await this.provider.send("eth_signTypedData_v4", [
|
|
344
539
|
address.toLowerCase(),
|
|
345
|
-
JSON.stringify(
|
|
540
|
+
JSON.stringify(
|
|
541
|
+
_TypedDataEncoder.getPayload(
|
|
542
|
+
populated.domain,
|
|
543
|
+
types,
|
|
544
|
+
populated.value,
|
|
545
|
+
),
|
|
546
|
+
),
|
|
346
547
|
]);
|
|
347
548
|
} catch (error) {
|
|
348
|
-
if (
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
549
|
+
if (
|
|
550
|
+
typeof error.message === "string" &&
|
|
551
|
+
error.message.match(/user denied/i)
|
|
552
|
+
) {
|
|
553
|
+
logger.throwError(
|
|
554
|
+
"user rejected signing",
|
|
555
|
+
Logger.errors.ACTION_REJECTED,
|
|
556
|
+
{
|
|
557
|
+
action: "_signTypedData",
|
|
558
|
+
from: address,
|
|
559
|
+
messageData: {
|
|
560
|
+
domain: populated.domain,
|
|
561
|
+
types,
|
|
562
|
+
value: populated.value,
|
|
563
|
+
},
|
|
564
|
+
},
|
|
565
|
+
);
|
|
354
566
|
}
|
|
355
567
|
throw error;
|
|
356
568
|
}
|
|
@@ -361,12 +573,18 @@ export class JsonRpcSigner extends Signer implements TypedDataSigner {
|
|
|
361
573
|
|
|
362
574
|
const address = await this.getAddress();
|
|
363
575
|
|
|
364
|
-
return provider.send("personal_unlockAccount", [
|
|
576
|
+
return provider.send("personal_unlockAccount", [
|
|
577
|
+
address.toLowerCase(),
|
|
578
|
+
password,
|
|
579
|
+
null,
|
|
580
|
+
]);
|
|
365
581
|
}
|
|
366
582
|
}
|
|
367
583
|
|
|
368
584
|
class UncheckedJsonRpcSigner extends JsonRpcSigner {
|
|
369
|
-
sendTransaction(
|
|
585
|
+
sendTransaction(
|
|
586
|
+
transaction: Deferrable<TransactionRequest>,
|
|
587
|
+
): Promise<TransactionResponse> {
|
|
370
588
|
return this.sendUncheckedTransaction(transaction).then((hash) => {
|
|
371
589
|
return <TransactionResponse>{
|
|
372
590
|
hash: hash,
|
|
@@ -378,17 +596,30 @@ class UncheckedJsonRpcSigner extends JsonRpcSigner {
|
|
|
378
596
|
chainId: null,
|
|
379
597
|
confirmations: 0,
|
|
380
598
|
from: null,
|
|
381
|
-
wait: (confirmations?: number) => {
|
|
599
|
+
wait: (confirmations?: number) => {
|
|
600
|
+
return this.provider.waitForTransaction(
|
|
601
|
+
hash,
|
|
602
|
+
confirmations,
|
|
603
|
+
);
|
|
604
|
+
},
|
|
382
605
|
};
|
|
383
606
|
});
|
|
384
607
|
}
|
|
385
608
|
}
|
|
386
609
|
|
|
387
|
-
const allowedTransactionKeys: { [
|
|
388
|
-
chainId: true,
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
610
|
+
const allowedTransactionKeys: { [key: string]: boolean } = {
|
|
611
|
+
chainId: true,
|
|
612
|
+
data: true,
|
|
613
|
+
gasLimit: true,
|
|
614
|
+
gasPrice: true,
|
|
615
|
+
nonce: true,
|
|
616
|
+
to: true,
|
|
617
|
+
value: true,
|
|
618
|
+
type: true,
|
|
619
|
+
accessList: true,
|
|
620
|
+
maxFeePerGas: true,
|
|
621
|
+
maxPriorityFeePerGas: true,
|
|
622
|
+
};
|
|
392
623
|
|
|
393
624
|
export class JsonRpcProvider extends BaseProvider {
|
|
394
625
|
readonly connection: ConnectionInfo;
|
|
@@ -402,7 +633,7 @@ export class JsonRpcProvider extends BaseProvider {
|
|
|
402
633
|
_eventLoopCache: Record<string, Promise<any>>;
|
|
403
634
|
get _cache(): Record<string, Promise<any>> {
|
|
404
635
|
if (this._eventLoopCache == null) {
|
|
405
|
-
this._eventLoopCache = {
|
|
636
|
+
this._eventLoopCache = {};
|
|
406
637
|
}
|
|
407
638
|
return this._eventLoopCache;
|
|
408
639
|
}
|
|
@@ -414,11 +645,14 @@ export class JsonRpcProvider extends BaseProvider {
|
|
|
414
645
|
if (networkOrReady == null) {
|
|
415
646
|
networkOrReady = new Promise((resolve, reject) => {
|
|
416
647
|
setTimeout(() => {
|
|
417
|
-
this.detectNetwork().then(
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
648
|
+
this.detectNetwork().then(
|
|
649
|
+
(network) => {
|
|
650
|
+
resolve(network);
|
|
651
|
+
},
|
|
652
|
+
(error) => {
|
|
653
|
+
reject(error);
|
|
654
|
+
},
|
|
655
|
+
);
|
|
422
656
|
}, 0);
|
|
423
657
|
});
|
|
424
658
|
}
|
|
@@ -426,12 +660,18 @@ export class JsonRpcProvider extends BaseProvider {
|
|
|
426
660
|
super(networkOrReady);
|
|
427
661
|
|
|
428
662
|
// Default URL
|
|
429
|
-
if (!url) {
|
|
663
|
+
if (!url) {
|
|
664
|
+
url = getStatic<() => string>(this.constructor, "defaultUrl")();
|
|
665
|
+
}
|
|
430
666
|
|
|
431
|
-
if (typeof
|
|
432
|
-
defineReadOnly(
|
|
433
|
-
|
|
434
|
-
|
|
667
|
+
if (typeof url === "string") {
|
|
668
|
+
defineReadOnly(
|
|
669
|
+
this,
|
|
670
|
+
"connection",
|
|
671
|
+
Object.freeze({
|
|
672
|
+
url: url,
|
|
673
|
+
}),
|
|
674
|
+
);
|
|
435
675
|
} else {
|
|
436
676
|
defineReadOnly(this, "connection", Object.freeze(shallowCopy(url)));
|
|
437
677
|
}
|
|
@@ -460,36 +700,49 @@ export class JsonRpcProvider extends BaseProvider {
|
|
|
460
700
|
|
|
461
701
|
let chainId = null;
|
|
462
702
|
try {
|
|
463
|
-
chainId = await this.send("eth_chainId", [
|
|
703
|
+
chainId = await this.send("eth_chainId", []);
|
|
464
704
|
} catch (error) {
|
|
465
705
|
try {
|
|
466
|
-
chainId = await this.send("net_version", [
|
|
467
|
-
} catch (error) {
|
|
706
|
+
chainId = await this.send("net_version", []);
|
|
707
|
+
} catch (error) {}
|
|
468
708
|
}
|
|
469
709
|
|
|
470
710
|
if (chainId != null) {
|
|
471
|
-
const getNetwork = getStatic<(network: Networkish) => Network>(
|
|
711
|
+
const getNetwork = getStatic<(network: Networkish) => Network>(
|
|
712
|
+
this.constructor,
|
|
713
|
+
"getNetwork",
|
|
714
|
+
);
|
|
472
715
|
try {
|
|
473
716
|
return getNetwork(BigNumber.from(chainId).toNumber());
|
|
474
717
|
} catch (error) {
|
|
475
|
-
return logger.throwError(
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
718
|
+
return logger.throwError(
|
|
719
|
+
"could not detect network",
|
|
720
|
+
Logger.errors.NETWORK_ERROR,
|
|
721
|
+
{
|
|
722
|
+
chainId: chainId,
|
|
723
|
+
event: "invalidNetwork",
|
|
724
|
+
serverError: error,
|
|
725
|
+
},
|
|
726
|
+
);
|
|
480
727
|
}
|
|
481
728
|
}
|
|
482
729
|
|
|
483
|
-
return logger.throwError(
|
|
484
|
-
|
|
485
|
-
|
|
730
|
+
return logger.throwError(
|
|
731
|
+
"could not detect network",
|
|
732
|
+
Logger.errors.NETWORK_ERROR,
|
|
733
|
+
{
|
|
734
|
+
event: "noNetwork",
|
|
735
|
+
},
|
|
736
|
+
);
|
|
486
737
|
}
|
|
487
738
|
|
|
488
739
|
getSigner(addressOrIndex?: string | number): JsonRpcSigner {
|
|
489
740
|
return new JsonRpcSigner(_constructorGuard, this, addressOrIndex);
|
|
490
741
|
}
|
|
491
742
|
|
|
492
|
-
getUncheckedSigner(
|
|
743
|
+
getUncheckedSigner(
|
|
744
|
+
addressOrIndex?: string | number,
|
|
745
|
+
): UncheckedJsonRpcSigner {
|
|
493
746
|
return this.getSigner(addressOrIndex).connectUnchecked();
|
|
494
747
|
}
|
|
495
748
|
|
|
@@ -503,43 +756,49 @@ export class JsonRpcProvider extends BaseProvider {
|
|
|
503
756
|
const request = {
|
|
504
757
|
method: method,
|
|
505
758
|
params: params,
|
|
506
|
-
id:
|
|
507
|
-
jsonrpc: "2.0"
|
|
759
|
+
id: this._nextId++,
|
|
760
|
+
jsonrpc: "2.0",
|
|
508
761
|
};
|
|
509
762
|
|
|
510
763
|
this.emit("debug", {
|
|
511
764
|
action: "request",
|
|
512
765
|
request: deepCopy(request),
|
|
513
|
-
provider: this
|
|
766
|
+
provider: this,
|
|
514
767
|
});
|
|
515
768
|
|
|
516
769
|
// We can expand this in the future to any call, but for now these
|
|
517
770
|
// are the biggest wins and do not require any serializing parameters.
|
|
518
|
-
const cache =
|
|
771
|
+
const cache = ["eth_chainId", "eth_blockNumber"].indexOf(method) >= 0;
|
|
519
772
|
if (cache && this._cache[method]) {
|
|
520
773
|
return this._cache[method];
|
|
521
774
|
}
|
|
522
775
|
|
|
523
|
-
const result = fetchJson(
|
|
524
|
-
this.
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
776
|
+
const result = fetchJson(
|
|
777
|
+
this.connection,
|
|
778
|
+
JSON.stringify(request),
|
|
779
|
+
getResult,
|
|
780
|
+
).then(
|
|
781
|
+
(result) => {
|
|
782
|
+
this.emit("debug", {
|
|
783
|
+
action: "response",
|
|
784
|
+
request: request,
|
|
785
|
+
response: result,
|
|
786
|
+
provider: this,
|
|
787
|
+
});
|
|
532
788
|
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
789
|
+
return result;
|
|
790
|
+
},
|
|
791
|
+
(error) => {
|
|
792
|
+
this.emit("debug", {
|
|
793
|
+
action: "response",
|
|
794
|
+
error: error,
|
|
795
|
+
request: request,
|
|
796
|
+
provider: this,
|
|
797
|
+
});
|
|
540
798
|
|
|
541
|
-
|
|
542
|
-
|
|
799
|
+
throw error;
|
|
800
|
+
},
|
|
801
|
+
);
|
|
543
802
|
|
|
544
803
|
// Cache the fetch, but clear it on the next event loop
|
|
545
804
|
if (cache) {
|
|
@@ -552,58 +811,99 @@ export class JsonRpcProvider extends BaseProvider {
|
|
|
552
811
|
return result;
|
|
553
812
|
}
|
|
554
813
|
|
|
555
|
-
prepareRequest(method: string, params: any): [
|
|
814
|
+
prepareRequest(method: string, params: any): [string, Array<any>] {
|
|
556
815
|
switch (method) {
|
|
557
816
|
case "getBlockNumber":
|
|
558
|
-
return [
|
|
817
|
+
return ["eth_blockNumber", []];
|
|
559
818
|
|
|
560
819
|
case "getGasPrice":
|
|
561
|
-
return [
|
|
820
|
+
return ["eth_gasPrice", []];
|
|
562
821
|
|
|
563
822
|
case "getBalance":
|
|
564
|
-
return [
|
|
823
|
+
return [
|
|
824
|
+
"eth_getBalance",
|
|
825
|
+
[getLowerCase(params.address), params.blockTag],
|
|
826
|
+
];
|
|
565
827
|
|
|
566
828
|
case "getTransactionCount":
|
|
567
|
-
return [
|
|
829
|
+
return [
|
|
830
|
+
"eth_getTransactionCount",
|
|
831
|
+
[getLowerCase(params.address), params.blockTag],
|
|
832
|
+
];
|
|
568
833
|
|
|
569
834
|
case "getCode":
|
|
570
|
-
return [
|
|
835
|
+
return [
|
|
836
|
+
"eth_getCode",
|
|
837
|
+
[getLowerCase(params.address), params.blockTag],
|
|
838
|
+
];
|
|
571
839
|
|
|
572
840
|
case "getStorageAt":
|
|
573
|
-
return [
|
|
841
|
+
return [
|
|
842
|
+
"eth_getStorageAt",
|
|
843
|
+
[
|
|
844
|
+
getLowerCase(params.address),
|
|
845
|
+
hexZeroPad(params.position, 32),
|
|
846
|
+
params.blockTag,
|
|
847
|
+
],
|
|
848
|
+
];
|
|
574
849
|
|
|
575
850
|
case "sendTransaction":
|
|
576
|
-
return [
|
|
851
|
+
return ["eth_sendRawTransaction", [params.signedTransaction]];
|
|
577
852
|
|
|
578
853
|
case "getBlock":
|
|
579
854
|
if (params.blockTag) {
|
|
580
|
-
return [
|
|
855
|
+
return [
|
|
856
|
+
"eth_getBlockByNumber",
|
|
857
|
+
[params.blockTag, !!params.includeTransactions],
|
|
858
|
+
];
|
|
581
859
|
} else if (params.blockHash) {
|
|
582
|
-
return [
|
|
860
|
+
return [
|
|
861
|
+
"eth_getBlockByHash",
|
|
862
|
+
[params.blockHash, !!params.includeTransactions],
|
|
863
|
+
];
|
|
583
864
|
}
|
|
584
865
|
return null;
|
|
585
866
|
|
|
586
867
|
case "getTransaction":
|
|
587
|
-
return [
|
|
868
|
+
return ["eth_getTransactionByHash", [params.transactionHash]];
|
|
588
869
|
|
|
589
870
|
case "getTransactionReceipt":
|
|
590
|
-
return [
|
|
871
|
+
return ["eth_getTransactionReceipt", [params.transactionHash]];
|
|
591
872
|
|
|
592
873
|
case "call": {
|
|
593
|
-
const hexlifyTransaction = getStatic<
|
|
594
|
-
|
|
874
|
+
const hexlifyTransaction = getStatic<
|
|
875
|
+
(
|
|
876
|
+
t: TransactionRequest,
|
|
877
|
+
a?: { [key: string]: boolean },
|
|
878
|
+
) => { [key: string]: string }
|
|
879
|
+
>(this.constructor, "hexlifyTransaction");
|
|
880
|
+
return [
|
|
881
|
+
"eth_call",
|
|
882
|
+
[
|
|
883
|
+
hexlifyTransaction(params.transaction, { from: true }),
|
|
884
|
+
params.blockTag,
|
|
885
|
+
],
|
|
886
|
+
];
|
|
595
887
|
}
|
|
596
888
|
|
|
597
889
|
case "estimateGas": {
|
|
598
|
-
const hexlifyTransaction = getStatic<
|
|
599
|
-
|
|
890
|
+
const hexlifyTransaction = getStatic<
|
|
891
|
+
(
|
|
892
|
+
t: TransactionRequest,
|
|
893
|
+
a?: { [key: string]: boolean },
|
|
894
|
+
) => { [key: string]: string }
|
|
895
|
+
>(this.constructor, "hexlifyTransaction");
|
|
896
|
+
return [
|
|
897
|
+
"eth_estimateGas",
|
|
898
|
+
[hexlifyTransaction(params.transaction, { from: true })],
|
|
899
|
+
];
|
|
600
900
|
}
|
|
601
901
|
|
|
602
902
|
case "getLogs":
|
|
603
903
|
if (params.filter && params.filter.address != null) {
|
|
604
904
|
params.filter.address = getLowerCase(params.filter.address);
|
|
605
905
|
}
|
|
606
|
-
return [
|
|
906
|
+
return ["eth_getLogs", [params.filter]];
|
|
607
907
|
|
|
608
908
|
default:
|
|
609
909
|
break;
|
|
@@ -619,9 +919,15 @@ export class JsonRpcProvider extends BaseProvider {
|
|
|
619
919
|
const tx = params.transaction;
|
|
620
920
|
if (tx && tx.type != null && BigNumber.from(tx.type).isZero()) {
|
|
621
921
|
// If there are no EIP-1559 properties, it might be non-EIP-1559
|
|
622
|
-
if (
|
|
922
|
+
if (
|
|
923
|
+
tx.maxFeePerGas == null &&
|
|
924
|
+
tx.maxPriorityFeePerGas == null
|
|
925
|
+
) {
|
|
623
926
|
const feeData = await this.getFeeData();
|
|
624
|
-
if (
|
|
927
|
+
if (
|
|
928
|
+
feeData.maxFeePerGas == null &&
|
|
929
|
+
feeData.maxPriorityFeePerGas == null
|
|
930
|
+
) {
|
|
625
931
|
// Network doesn't know about EIP-1559 (and hence type)
|
|
626
932
|
params = shallowCopy(params);
|
|
627
933
|
params.transaction = shallowCopy(tx);
|
|
@@ -631,64 +937,87 @@ export class JsonRpcProvider extends BaseProvider {
|
|
|
631
937
|
}
|
|
632
938
|
}
|
|
633
939
|
|
|
634
|
-
const args = this.prepareRequest(method,
|
|
940
|
+
const args = this.prepareRequest(method, params);
|
|
635
941
|
|
|
636
942
|
if (args == null) {
|
|
637
|
-
logger.throwError(
|
|
943
|
+
logger.throwError(
|
|
944
|
+
method + " not implemented",
|
|
945
|
+
Logger.errors.NOT_IMPLEMENTED,
|
|
946
|
+
{ operation: method },
|
|
947
|
+
);
|
|
638
948
|
}
|
|
639
949
|
try {
|
|
640
|
-
return await this.send(args[0], args[1])
|
|
950
|
+
return await this.send(args[0], args[1]);
|
|
641
951
|
} catch (error) {
|
|
642
952
|
return checkError(method, error, params);
|
|
643
953
|
}
|
|
644
954
|
}
|
|
645
955
|
|
|
646
956
|
_startEvent(event: Event): void {
|
|
647
|
-
if (event.tag === "pending") {
|
|
957
|
+
if (event.tag === "pending") {
|
|
958
|
+
this._startPending();
|
|
959
|
+
}
|
|
648
960
|
super._startEvent(event);
|
|
649
961
|
}
|
|
650
962
|
|
|
651
963
|
_startPending(): void {
|
|
652
|
-
if (this._pendingFilter != null) {
|
|
964
|
+
if (this._pendingFilter != null) {
|
|
965
|
+
return;
|
|
966
|
+
}
|
|
653
967
|
const self = this;
|
|
654
968
|
|
|
655
|
-
const pendingFilter: Promise<number> = this.send(
|
|
969
|
+
const pendingFilter: Promise<number> = this.send(
|
|
970
|
+
"eth_newPendingTransactionFilter",
|
|
971
|
+
[],
|
|
972
|
+
);
|
|
656
973
|
this._pendingFilter = pendingFilter;
|
|
657
974
|
|
|
658
|
-
pendingFilter
|
|
659
|
-
function
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
hashes.forEach(function(hash) {
|
|
665
|
-
// @TODO: This should be garbage collected at some point... How? When?
|
|
666
|
-
self._emitted["t:" + hash.toLowerCase()] = "pending";
|
|
667
|
-
seq = seq.then(function() {
|
|
668
|
-
return self.getTransaction(hash).then(function(tx): any {
|
|
669
|
-
self.emit("pending", tx);
|
|
975
|
+
pendingFilter
|
|
976
|
+
.then(function (filterId) {
|
|
977
|
+
function poll() {
|
|
978
|
+
self.send("eth_getFilterChanges", [filterId])
|
|
979
|
+
.then(function (hashes: Array<string>) {
|
|
980
|
+
if (self._pendingFilter != pendingFilter) {
|
|
670
981
|
return null;
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
let seq = Promise.resolve();
|
|
985
|
+
hashes.forEach(function (hash) {
|
|
986
|
+
// @TODO: This should be garbage collected at some point... How? When?
|
|
987
|
+
self._emitted["t:" + hash.toLowerCase()] =
|
|
988
|
+
"pending";
|
|
989
|
+
seq = seq.then(function () {
|
|
990
|
+
return self
|
|
991
|
+
.getTransaction(hash)
|
|
992
|
+
.then(function (tx): any {
|
|
993
|
+
self.emit("pending", tx);
|
|
994
|
+
return null;
|
|
995
|
+
});
|
|
996
|
+
});
|
|
671
997
|
});
|
|
672
|
-
});
|
|
673
|
-
});
|
|
674
|
-
|
|
675
|
-
return seq.then(function() {
|
|
676
|
-
return timer(1000);
|
|
677
|
-
});
|
|
678
|
-
}).then(function(): any {
|
|
679
|
-
if (self._pendingFilter != pendingFilter) {
|
|
680
|
-
self.send("eth_uninstallFilter", [ filterId ]);
|
|
681
|
-
return;
|
|
682
|
-
}
|
|
683
|
-
setTimeout(function() { poll(); }, 0);
|
|
684
998
|
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
999
|
+
return seq.then(function () {
|
|
1000
|
+
return timer(1000);
|
|
1001
|
+
});
|
|
1002
|
+
})
|
|
1003
|
+
.then(function (): any {
|
|
1004
|
+
if (self._pendingFilter != pendingFilter) {
|
|
1005
|
+
self.send("eth_uninstallFilter", [filterId]);
|
|
1006
|
+
return;
|
|
1007
|
+
}
|
|
1008
|
+
setTimeout(function () {
|
|
1009
|
+
poll();
|
|
1010
|
+
}, 0);
|
|
1011
|
+
|
|
1012
|
+
return null;
|
|
1013
|
+
})
|
|
1014
|
+
.catch((error: Error) => {});
|
|
1015
|
+
}
|
|
1016
|
+
poll();
|
|
689
1017
|
|
|
690
|
-
|
|
691
|
-
|
|
1018
|
+
return filterId;
|
|
1019
|
+
})
|
|
1020
|
+
.catch((error: Error) => {});
|
|
692
1021
|
}
|
|
693
1022
|
|
|
694
1023
|
_stopEvent(event: Event): void {
|
|
@@ -707,12 +1036,17 @@ export class JsonRpcProvider extends BaseProvider {
|
|
|
707
1036
|
// before this is called
|
|
708
1037
|
// @TODO: This will likely be removed in future versions and prepareRequest
|
|
709
1038
|
// will be the preferred method for this.
|
|
710
|
-
static hexlifyTransaction(
|
|
1039
|
+
static hexlifyTransaction(
|
|
1040
|
+
transaction: TransactionRequest,
|
|
1041
|
+
allowExtra?: { [key: string]: boolean },
|
|
1042
|
+
): { [key: string]: string | AccessList } {
|
|
711
1043
|
// Check only allowed properties are given
|
|
712
1044
|
const allowed = shallowCopy(allowedTransactionKeys);
|
|
713
1045
|
if (allowExtra) {
|
|
714
1046
|
for (const key in allowExtra) {
|
|
715
|
-
if (allowExtra[key]) {
|
|
1047
|
+
if (allowExtra[key]) {
|
|
1048
|
+
allowed[key] = true;
|
|
1049
|
+
}
|
|
716
1050
|
}
|
|
717
1051
|
}
|
|
718
1052
|
|
|
@@ -721,15 +1055,30 @@ export class JsonRpcProvider extends BaseProvider {
|
|
|
721
1055
|
const result: { [key: string]: string | AccessList } = {};
|
|
722
1056
|
|
|
723
1057
|
// JSON-RPC now requires numeric values to be "quantity" values
|
|
724
|
-
[
|
|
725
|
-
|
|
1058
|
+
[
|
|
1059
|
+
"chainId",
|
|
1060
|
+
"gasLimit",
|
|
1061
|
+
"gasPrice",
|
|
1062
|
+
"type",
|
|
1063
|
+
"maxFeePerGas",
|
|
1064
|
+
"maxPriorityFeePerGas",
|
|
1065
|
+
"nonce",
|
|
1066
|
+
"value",
|
|
1067
|
+
].forEach(function (key) {
|
|
1068
|
+
if ((<any>transaction)[key] == null) {
|
|
1069
|
+
return;
|
|
1070
|
+
}
|
|
726
1071
|
const value = hexValue(BigNumber.from((<any>transaction)[key]));
|
|
727
|
-
if (key === "gasLimit") {
|
|
1072
|
+
if (key === "gasLimit") {
|
|
1073
|
+
key = "gas";
|
|
1074
|
+
}
|
|
728
1075
|
result[key] = value;
|
|
729
1076
|
});
|
|
730
1077
|
|
|
731
|
-
["from", "to", "data"].forEach(function(key) {
|
|
732
|
-
if ((<any>transaction)[key] == null) {
|
|
1078
|
+
["from", "to", "data"].forEach(function (key) {
|
|
1079
|
+
if ((<any>transaction)[key] == null) {
|
|
1080
|
+
return;
|
|
1081
|
+
}
|
|
733
1082
|
result[key] = hexlify((<any>transaction)[key]);
|
|
734
1083
|
});
|
|
735
1084
|
|