@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
package/src.ts/base-provider.ts
CHANGED
|
@@ -1,17 +1,44 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
|
-
Block,
|
|
5
|
-
|
|
4
|
+
Block,
|
|
5
|
+
BlockTag,
|
|
6
|
+
BlockWithTransactions,
|
|
7
|
+
EventType,
|
|
8
|
+
Filter,
|
|
9
|
+
FilterByBlockHash,
|
|
10
|
+
ForkEvent,
|
|
11
|
+
Listener,
|
|
12
|
+
Log,
|
|
13
|
+
Provider,
|
|
14
|
+
TransactionReceipt,
|
|
15
|
+
TransactionRequest,
|
|
16
|
+
TransactionResponse,
|
|
6
17
|
} from "@qevm/abstract-provider";
|
|
7
18
|
import { encode as base64Encode } from "@qevm/base64";
|
|
8
19
|
import { Base58 } from "@qevm/basex";
|
|
9
20
|
import { BigNumber, BigNumberish } from "@qevm/bignumber";
|
|
10
|
-
import {
|
|
21
|
+
import {
|
|
22
|
+
arrayify,
|
|
23
|
+
BytesLike,
|
|
24
|
+
concat,
|
|
25
|
+
hexConcat,
|
|
26
|
+
hexDataLength,
|
|
27
|
+
hexDataSlice,
|
|
28
|
+
hexlify,
|
|
29
|
+
hexValue,
|
|
30
|
+
hexZeroPad,
|
|
31
|
+
isHexString,
|
|
32
|
+
} from "@qevm/bytes";
|
|
11
33
|
import { HashZero } from "@qevm/constants";
|
|
12
34
|
import { dnsEncode, namehash } from "@qevm/hash";
|
|
13
|
-
import { getNetwork, Network, Networkish } from "@
|
|
14
|
-
import {
|
|
35
|
+
import { getNetwork, Network, Networkish } from "@qevm/networks";
|
|
36
|
+
import {
|
|
37
|
+
Deferrable,
|
|
38
|
+
defineReadOnly,
|
|
39
|
+
getStatic,
|
|
40
|
+
resolveProperties,
|
|
41
|
+
} from "@qevm/properties";
|
|
15
42
|
import { Transaction } from "@qevm/transactions";
|
|
16
43
|
import { sha256 } from "@qevm/sha2";
|
|
17
44
|
import { toUtf8Bytes, toUtf8String } from "@qevm/strings";
|
|
@@ -19,7 +46,7 @@ import { fetchJson, poll } from "@qevm/web";
|
|
|
19
46
|
|
|
20
47
|
import bech32 from "bech32";
|
|
21
48
|
|
|
22
|
-
import { Logger } from "@
|
|
49
|
+
import { Logger } from "@qevm/logger";
|
|
23
50
|
import { version } from "./_version";
|
|
24
51
|
const logger = new Logger(version);
|
|
25
52
|
|
|
@@ -31,55 +58,63 @@ const MAX_CCIP_REDIRECTS = 10;
|
|
|
31
58
|
// Event Serializeing
|
|
32
59
|
|
|
33
60
|
function checkTopic(topic: string): string {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
61
|
+
if (topic == null) {
|
|
62
|
+
return "null";
|
|
63
|
+
}
|
|
64
|
+
if (hexDataLength(topic) !== 32) {
|
|
65
|
+
logger.throwArgumentError("invalid topic", "topic", topic);
|
|
66
|
+
}
|
|
67
|
+
return topic.toLowerCase();
|
|
39
68
|
}
|
|
40
69
|
|
|
41
70
|
function serializeTopics(topics: Array<string | Array<string>>): string {
|
|
42
71
|
// Remove trailing null AND-topics; they are redundant
|
|
43
72
|
topics = topics.slice();
|
|
44
|
-
while (topics.length > 0 && topics[topics.length - 1] == null) {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
if (Array.isArray(topic)) {
|
|
48
|
-
|
|
49
|
-
// Only track unique OR-topics
|
|
50
|
-
const unique: { [ topic: string ]: boolean } = { }
|
|
51
|
-
topic.forEach((topic) => {
|
|
52
|
-
unique[checkTopic(topic)] = true;
|
|
53
|
-
});
|
|
73
|
+
while (topics.length > 0 && topics[topics.length - 1] == null) {
|
|
74
|
+
topics.pop();
|
|
75
|
+
}
|
|
54
76
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
77
|
+
return topics
|
|
78
|
+
.map((topic) => {
|
|
79
|
+
if (Array.isArray(topic)) {
|
|
80
|
+
// Only track unique OR-topics
|
|
81
|
+
const unique: { [topic: string]: boolean } = {};
|
|
82
|
+
topic.forEach((topic) => {
|
|
83
|
+
unique[checkTopic(topic)] = true;
|
|
84
|
+
});
|
|
58
85
|
|
|
59
|
-
|
|
86
|
+
// The order of OR-topics does not matter
|
|
87
|
+
const sorted = Object.keys(unique);
|
|
88
|
+
sorted.sort();
|
|
60
89
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
90
|
+
return sorted.join("|");
|
|
91
|
+
} else {
|
|
92
|
+
return checkTopic(topic);
|
|
93
|
+
}
|
|
94
|
+
})
|
|
95
|
+
.join("&");
|
|
65
96
|
}
|
|
66
97
|
|
|
67
98
|
function deserializeTopics(data: string): Array<string | Array<string>> {
|
|
68
|
-
if (data === "") {
|
|
99
|
+
if (data === "") {
|
|
100
|
+
return [];
|
|
101
|
+
}
|
|
69
102
|
|
|
70
103
|
return data.split(/&/g).map((topic) => {
|
|
71
|
-
if (topic === "") {
|
|
104
|
+
if (topic === "") {
|
|
105
|
+
return [];
|
|
106
|
+
}
|
|
72
107
|
|
|
73
108
|
const comps = topic.split("|").map((topic) => {
|
|
74
|
-
return
|
|
109
|
+
return topic === "null" ? null : topic;
|
|
75
110
|
});
|
|
76
111
|
|
|
77
|
-
return
|
|
112
|
+
return comps.length === 1 ? comps[0] : comps;
|
|
78
113
|
});
|
|
79
114
|
}
|
|
80
115
|
|
|
81
116
|
function getEventTag(eventName: EventType): string {
|
|
82
|
-
if (typeof
|
|
117
|
+
if (typeof eventName === "string") {
|
|
83
118
|
eventName = eventName.toLowerCase();
|
|
84
119
|
|
|
85
120
|
if (hexDataLength(eventName) === 32) {
|
|
@@ -89,16 +124,18 @@ function getEventTag(eventName: EventType): string {
|
|
|
89
124
|
if (eventName.indexOf(":") === -1) {
|
|
90
125
|
return eventName;
|
|
91
126
|
}
|
|
92
|
-
|
|
93
127
|
} else if (Array.isArray(eventName)) {
|
|
94
128
|
return "filter:*:" + serializeTopics(eventName);
|
|
95
|
-
|
|
96
129
|
} else if (ForkEvent.isForkEvent(eventName)) {
|
|
97
130
|
logger.warn("not implemented");
|
|
98
131
|
throw new Error("not implemented");
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
132
|
+
} else if (eventName && typeof eventName === "object") {
|
|
133
|
+
return (
|
|
134
|
+
"filter:" +
|
|
135
|
+
(eventName.address || "*") +
|
|
136
|
+
":" +
|
|
137
|
+
serializeTopics(eventName.topics || [])
|
|
138
|
+
);
|
|
102
139
|
}
|
|
103
140
|
|
|
104
141
|
throw new Error("invalid event - " + eventName);
|
|
@@ -108,7 +145,7 @@ function getEventTag(eventName: EventType): string {
|
|
|
108
145
|
// Helper Object
|
|
109
146
|
|
|
110
147
|
function getTime() {
|
|
111
|
-
return
|
|
148
|
+
return new Date().getTime();
|
|
112
149
|
}
|
|
113
150
|
|
|
114
151
|
function stall(duration: number): Promise<void> {
|
|
@@ -120,7 +157,6 @@ function stall(duration: number): Promise<void> {
|
|
|
120
157
|
//////////////////////////////
|
|
121
158
|
// Provider Object
|
|
122
159
|
|
|
123
|
-
|
|
124
160
|
/**
|
|
125
161
|
* EventType
|
|
126
162
|
* - "block"
|
|
@@ -134,14 +170,14 @@ function stall(duration: number): Promise<void> {
|
|
|
134
170
|
* - transaction hash
|
|
135
171
|
*/
|
|
136
172
|
|
|
137
|
-
const PollableEvents = [
|
|
173
|
+
const PollableEvents = ["block", "network", "pending", "poll"];
|
|
138
174
|
|
|
139
175
|
export class Event {
|
|
140
176
|
readonly listener: Listener;
|
|
141
177
|
readonly once: boolean;
|
|
142
178
|
readonly tag: string;
|
|
143
179
|
|
|
144
|
-
_lastBlockNumber: number
|
|
180
|
+
_lastBlockNumber: number;
|
|
145
181
|
_inflight: boolean;
|
|
146
182
|
|
|
147
183
|
constructor(tag: string, listener: Listener, once: boolean) {
|
|
@@ -156,44 +192,53 @@ export class Event {
|
|
|
156
192
|
get event(): EventType {
|
|
157
193
|
switch (this.type) {
|
|
158
194
|
case "tx":
|
|
159
|
-
|
|
195
|
+
return this.hash;
|
|
160
196
|
case "filter":
|
|
161
|
-
|
|
197
|
+
return this.filter;
|
|
162
198
|
}
|
|
163
199
|
return this.tag;
|
|
164
200
|
}
|
|
165
201
|
|
|
166
202
|
get type(): string {
|
|
167
|
-
return this.tag.split(":")[0]
|
|
203
|
+
return this.tag.split(":")[0];
|
|
168
204
|
}
|
|
169
205
|
|
|
170
206
|
get hash(): string {
|
|
171
207
|
const comps = this.tag.split(":");
|
|
172
|
-
if (comps[0] !== "tx") {
|
|
208
|
+
if (comps[0] !== "tx") {
|
|
209
|
+
return null;
|
|
210
|
+
}
|
|
173
211
|
return comps[1];
|
|
174
212
|
}
|
|
175
213
|
|
|
176
214
|
get filter(): Filter {
|
|
177
215
|
const comps = this.tag.split(":");
|
|
178
|
-
if (comps[0] !== "filter") {
|
|
216
|
+
if (comps[0] !== "filter") {
|
|
217
|
+
return null;
|
|
218
|
+
}
|
|
179
219
|
const address = comps[1];
|
|
180
220
|
|
|
181
221
|
const topics = deserializeTopics(comps[2]);
|
|
182
|
-
const filter: Filter = {
|
|
222
|
+
const filter: Filter = {};
|
|
183
223
|
|
|
184
|
-
if (topics.length > 0) {
|
|
185
|
-
|
|
224
|
+
if (topics.length > 0) {
|
|
225
|
+
filter.topics = topics;
|
|
226
|
+
}
|
|
227
|
+
if (address && address !== "*") {
|
|
228
|
+
filter.address = address;
|
|
229
|
+
}
|
|
186
230
|
|
|
187
231
|
return filter;
|
|
188
232
|
}
|
|
189
233
|
|
|
190
234
|
pollable(): boolean {
|
|
191
|
-
return (
|
|
235
|
+
return (
|
|
236
|
+
this.tag.indexOf(":") >= 0 || PollableEvents.indexOf(this.tag) >= 0
|
|
237
|
+
);
|
|
192
238
|
}
|
|
193
239
|
}
|
|
194
240
|
|
|
195
241
|
export interface EnsResolver {
|
|
196
|
-
|
|
197
242
|
// Name this Resolver is associated with
|
|
198
243
|
readonly name: string;
|
|
199
244
|
|
|
@@ -202,7 +247,7 @@ export interface EnsResolver {
|
|
|
202
247
|
|
|
203
248
|
// Multichain address resolution (also normal address resolution)
|
|
204
249
|
// See: https://eips.ethereum.org/EIPS/eip-2304
|
|
205
|
-
getAddress(coinType?: 60): Promise<null | string
|
|
250
|
+
getAddress(coinType?: 60): Promise<null | string>;
|
|
206
251
|
|
|
207
252
|
// Contenthash field
|
|
208
253
|
// See: https://eips.ethereum.org/EIPS/eip-1577
|
|
@@ -211,7 +256,7 @@ export interface EnsResolver {
|
|
|
211
256
|
// Storage of text records
|
|
212
257
|
// See: https://eips.ethereum.org/EIPS/eip-634
|
|
213
258
|
getText(key: string): Promise<null | string>;
|
|
214
|
-
}
|
|
259
|
+
}
|
|
215
260
|
|
|
216
261
|
export interface EnsProvider {
|
|
217
262
|
resolveName(name: string): Promise<null | string>;
|
|
@@ -220,20 +265,20 @@ export interface EnsProvider {
|
|
|
220
265
|
}
|
|
221
266
|
|
|
222
267
|
type CoinInfo = {
|
|
223
|
-
symbol: string
|
|
224
|
-
ilk?: string
|
|
225
|
-
prefix?: string
|
|
226
|
-
p2pkh?: number
|
|
227
|
-
p2sh?: number
|
|
268
|
+
symbol: string;
|
|
269
|
+
ilk?: string; // General family
|
|
270
|
+
prefix?: string; // Bech32 prefix
|
|
271
|
+
p2pkh?: number; // Pay-to-Public-Key-Hash Version
|
|
272
|
+
p2sh?: number; // Pay-to-Script-Hash Version
|
|
228
273
|
};
|
|
229
274
|
|
|
230
275
|
// https://github.com/satoshilabs/slips/blob/master/slip-0044.md
|
|
231
|
-
const coinInfos: { [
|
|
232
|
-
"0":
|
|
233
|
-
"2":
|
|
234
|
-
"3":
|
|
235
|
-
"60":
|
|
236
|
-
"61":
|
|
276
|
+
const coinInfos: { [coinType: string]: CoinInfo } = {
|
|
277
|
+
"0": { symbol: "btc", p2pkh: 0x00, p2sh: 0x05, prefix: "bc" },
|
|
278
|
+
"2": { symbol: "ltc", p2pkh: 0x30, p2sh: 0x32, prefix: "ltc" },
|
|
279
|
+
"3": { symbol: "doge", p2pkh: 0x1e, p2sh: 0x16 },
|
|
280
|
+
"60": { symbol: "eth", ilk: "eth" },
|
|
281
|
+
"61": { symbol: "etc", ilk: "eth" },
|
|
237
282
|
"700": { symbol: "xdai", ilk: "eth" },
|
|
238
283
|
};
|
|
239
284
|
|
|
@@ -243,12 +288,14 @@ function bytes32ify(value: number): string {
|
|
|
243
288
|
|
|
244
289
|
// Compute the Base58Check encoded data (checksum is first 4 bytes of sha256d)
|
|
245
290
|
function base58Encode(data: Uint8Array): string {
|
|
246
|
-
return Base58.encode(
|
|
291
|
+
return Base58.encode(
|
|
292
|
+
concat([data, hexDataSlice(sha256(sha256(data)), 0, 4)]),
|
|
293
|
+
);
|
|
247
294
|
}
|
|
248
295
|
|
|
249
296
|
export interface Avatar {
|
|
250
297
|
url: string;
|
|
251
|
-
linkage: Array<{ type: string
|
|
298
|
+
linkage: Array<{ type: string; content: string }>;
|
|
252
299
|
}
|
|
253
300
|
|
|
254
301
|
const matcherIpfs = new RegExp("^(ipfs):/\/(.*)$", "i");
|
|
@@ -262,15 +309,21 @@ const matchers = [
|
|
|
262
309
|
function _parseString(result: string, start: number): null | string {
|
|
263
310
|
try {
|
|
264
311
|
return toUtf8String(_parseBytes(result, start));
|
|
265
|
-
} catch(error) {
|
|
312
|
+
} catch (error) {}
|
|
266
313
|
return null;
|
|
267
314
|
}
|
|
268
315
|
|
|
269
316
|
function _parseBytes(result: string, start: number): null | string {
|
|
270
|
-
if (result === "0x") {
|
|
317
|
+
if (result === "0x") {
|
|
318
|
+
return null;
|
|
319
|
+
}
|
|
271
320
|
|
|
272
|
-
const offset = BigNumber.from(
|
|
273
|
-
|
|
321
|
+
const offset = BigNumber.from(
|
|
322
|
+
hexDataSlice(result, start, start + 32),
|
|
323
|
+
).toNumber();
|
|
324
|
+
const length = BigNumber.from(
|
|
325
|
+
hexDataSlice(result, offset, offset + 32),
|
|
326
|
+
).toNumber();
|
|
274
327
|
|
|
275
328
|
return hexDataSlice(result, offset + 32, offset + 32 + length);
|
|
276
329
|
}
|
|
@@ -285,12 +338,14 @@ function getIpfsLink(link: string): string {
|
|
|
285
338
|
logger.throwArgumentError("unsupported IPFS format", "link", link);
|
|
286
339
|
}
|
|
287
340
|
|
|
288
|
-
return `https:/\/gateway.ipfs.io/ipfs/${
|
|
341
|
+
return `https:/\/gateway.ipfs.io/ipfs/${link}`;
|
|
289
342
|
}
|
|
290
343
|
|
|
291
344
|
function numPad(value: number): Uint8Array {
|
|
292
345
|
const result = arrayify(value);
|
|
293
|
-
if (result.length > 32) {
|
|
346
|
+
if (result.length > 32) {
|
|
347
|
+
throw new Error("internal; should not happen");
|
|
348
|
+
}
|
|
294
349
|
|
|
295
350
|
const padded = new Uint8Array(32);
|
|
296
351
|
padded.set(result, 32 - result.length);
|
|
@@ -298,7 +353,9 @@ function numPad(value: number): Uint8Array {
|
|
|
298
353
|
}
|
|
299
354
|
|
|
300
355
|
function bytesPad(value: Uint8Array): Uint8Array {
|
|
301
|
-
if (
|
|
356
|
+
if (value.length % 32 === 0) {
|
|
357
|
+
return value;
|
|
358
|
+
}
|
|
302
359
|
|
|
303
360
|
const result = new Uint8Array(Math.ceil(value.length / 32) * 32);
|
|
304
361
|
result.set(value);
|
|
@@ -307,7 +364,7 @@ function bytesPad(value: Uint8Array): Uint8Array {
|
|
|
307
364
|
|
|
308
365
|
// ABI Encodes a series of (bytes, bytes, ...)
|
|
309
366
|
function encodeBytes(datas: Array<BytesLike>) {
|
|
310
|
-
const result: Array<Uint8Array> = [
|
|
367
|
+
const result: Array<Uint8Array> = [];
|
|
311
368
|
|
|
312
369
|
let byteCount = 0;
|
|
313
370
|
|
|
@@ -344,7 +401,12 @@ export class Resolver implements EnsResolver {
|
|
|
344
401
|
_supportsEip2544: null | Promise<boolean>;
|
|
345
402
|
|
|
346
403
|
// The resolvedAddress is only for creating a ReverseLookup resolver
|
|
347
|
-
constructor(
|
|
404
|
+
constructor(
|
|
405
|
+
provider: BaseProvider,
|
|
406
|
+
address: string,
|
|
407
|
+
name: string,
|
|
408
|
+
resolvedAddress?: string,
|
|
409
|
+
) {
|
|
348
410
|
defineReadOnly(this, "provider", provider);
|
|
349
411
|
defineReadOnly(this, "name", name);
|
|
350
412
|
defineReadOnly(this, "address", provider.formatter.address(address));
|
|
@@ -354,29 +416,40 @@ export class Resolver implements EnsResolver {
|
|
|
354
416
|
supportsWildcard(): Promise<boolean> {
|
|
355
417
|
if (!this._supportsEip2544) {
|
|
356
418
|
// supportsInterface(bytes4 = selector("resolve(bytes,bytes)"))
|
|
357
|
-
this._supportsEip2544 = this.provider
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
419
|
+
this._supportsEip2544 = this.provider
|
|
420
|
+
.call({
|
|
421
|
+
to: this.address,
|
|
422
|
+
data: "0x01ffc9a79061b92300000000000000000000000000000000000000000000000000000000",
|
|
423
|
+
})
|
|
424
|
+
.then((result) => {
|
|
425
|
+
return BigNumber.from(result).eq(1);
|
|
426
|
+
})
|
|
427
|
+
.catch((error) => {
|
|
428
|
+
if (error.code === Logger.errors.CALL_EXCEPTION) {
|
|
429
|
+
return false;
|
|
430
|
+
}
|
|
431
|
+
// Rethrow the error: link is down, etc. Let future attempts retry.
|
|
432
|
+
this._supportsEip2544 = null;
|
|
433
|
+
throw error;
|
|
434
|
+
});
|
|
368
435
|
}
|
|
369
436
|
|
|
370
437
|
return this._supportsEip2544;
|
|
371
438
|
}
|
|
372
439
|
|
|
373
|
-
async _fetch(
|
|
374
|
-
|
|
440
|
+
async _fetch(
|
|
441
|
+
selector: string,
|
|
442
|
+
parameters?: string,
|
|
443
|
+
): Promise<null | string> {
|
|
375
444
|
// e.g. keccak256("addr(bytes32,uint256)")
|
|
376
445
|
const tx = {
|
|
377
446
|
to: this.address,
|
|
378
447
|
ccipReadEnabled: true,
|
|
379
|
-
data: hexConcat([
|
|
448
|
+
data: hexConcat([
|
|
449
|
+
selector,
|
|
450
|
+
namehash(this.name),
|
|
451
|
+
parameters || "0x",
|
|
452
|
+
]),
|
|
380
453
|
};
|
|
381
454
|
|
|
382
455
|
// Wildcard support; use EIP-2544 to resolve the request
|
|
@@ -385,27 +458,44 @@ export class Resolver implements EnsResolver {
|
|
|
385
458
|
parseBytes = true;
|
|
386
459
|
|
|
387
460
|
// selector("resolve(bytes,bytes)")
|
|
388
|
-
tx.data = hexConcat([
|
|
461
|
+
tx.data = hexConcat([
|
|
462
|
+
"0x9061b923",
|
|
463
|
+
encodeBytes([dnsEncode(this.name), tx.data]),
|
|
464
|
+
]);
|
|
389
465
|
}
|
|
390
466
|
|
|
391
467
|
try {
|
|
392
468
|
let result = await this.provider.call(tx);
|
|
393
|
-
if (
|
|
394
|
-
logger.throwError(
|
|
395
|
-
|
|
396
|
-
|
|
469
|
+
if (arrayify(result).length % 32 === 4) {
|
|
470
|
+
logger.throwError(
|
|
471
|
+
"resolver threw error",
|
|
472
|
+
Logger.errors.CALL_EXCEPTION,
|
|
473
|
+
{
|
|
474
|
+
transaction: tx,
|
|
475
|
+
data: result,
|
|
476
|
+
},
|
|
477
|
+
);
|
|
478
|
+
}
|
|
479
|
+
if (parseBytes) {
|
|
480
|
+
result = _parseBytes(result, 0);
|
|
397
481
|
}
|
|
398
|
-
if (parseBytes) { result = _parseBytes(result, 0); }
|
|
399
482
|
return result;
|
|
400
483
|
} catch (error) {
|
|
401
|
-
if (error.code === Logger.errors.CALL_EXCEPTION) {
|
|
484
|
+
if (error.code === Logger.errors.CALL_EXCEPTION) {
|
|
485
|
+
return null;
|
|
486
|
+
}
|
|
402
487
|
throw error;
|
|
403
488
|
}
|
|
404
489
|
}
|
|
405
490
|
|
|
406
|
-
async _fetchBytes(
|
|
491
|
+
async _fetchBytes(
|
|
492
|
+
selector: string,
|
|
493
|
+
parameters?: string,
|
|
494
|
+
): Promise<null | string> {
|
|
407
495
|
const result = await this._fetch(selector, parameters);
|
|
408
|
-
if (result != null) {
|
|
496
|
+
if (result != null) {
|
|
497
|
+
return _parseBytes(result, 0);
|
|
498
|
+
}
|
|
409
499
|
return null;
|
|
410
500
|
}
|
|
411
501
|
|
|
@@ -413,9 +503,13 @@ export class Resolver implements EnsResolver {
|
|
|
413
503
|
const coinInfo = coinInfos[String(coinType)];
|
|
414
504
|
|
|
415
505
|
if (coinInfo == null) {
|
|
416
|
-
logger.throwError(
|
|
417
|
-
|
|
418
|
-
|
|
506
|
+
logger.throwError(
|
|
507
|
+
`unsupported coin type: ${coinType}`,
|
|
508
|
+
Logger.errors.UNSUPPORTED_OPERATION,
|
|
509
|
+
{
|
|
510
|
+
operation: `getAddress(${coinType})`,
|
|
511
|
+
},
|
|
512
|
+
);
|
|
419
513
|
}
|
|
420
514
|
|
|
421
515
|
if (coinInfo.ilk === "eth") {
|
|
@@ -426,22 +520,38 @@ export class Resolver implements EnsResolver {
|
|
|
426
520
|
|
|
427
521
|
// P2PKH: OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
|
|
428
522
|
if (coinInfo.p2pkh != null) {
|
|
429
|
-
const p2pkh = hexBytes.match(
|
|
523
|
+
const p2pkh = hexBytes.match(
|
|
524
|
+
/^0x76a9([0-9a-f][0-9a-f])([0-9a-f]*)88ac$/,
|
|
525
|
+
);
|
|
430
526
|
if (p2pkh) {
|
|
431
527
|
const length = parseInt(p2pkh[1], 16);
|
|
432
|
-
if (
|
|
433
|
-
|
|
528
|
+
if (
|
|
529
|
+
p2pkh[2].length === length * 2 &&
|
|
530
|
+
length >= 1 &&
|
|
531
|
+
length <= 75
|
|
532
|
+
) {
|
|
533
|
+
return base58Encode(
|
|
534
|
+
concat([[coinInfo.p2pkh], "0x" + p2pkh[2]]),
|
|
535
|
+
);
|
|
434
536
|
}
|
|
435
537
|
}
|
|
436
538
|
}
|
|
437
539
|
|
|
438
540
|
// P2SH: OP_HASH160 <scriptHash> OP_EQUAL
|
|
439
541
|
if (coinInfo.p2sh != null) {
|
|
440
|
-
const p2sh = hexBytes.match(
|
|
542
|
+
const p2sh = hexBytes.match(
|
|
543
|
+
/^0xa9([0-9a-f][0-9a-f])([0-9a-f]*)87$/,
|
|
544
|
+
);
|
|
441
545
|
if (p2sh) {
|
|
442
546
|
const length = parseInt(p2sh[1], 16);
|
|
443
|
-
if (
|
|
444
|
-
|
|
547
|
+
if (
|
|
548
|
+
p2sh[2].length === length * 2 &&
|
|
549
|
+
length >= 1 &&
|
|
550
|
+
length <= 75
|
|
551
|
+
) {
|
|
552
|
+
return base58Encode(
|
|
553
|
+
concat([[coinInfo.p2sh], "0x" + p2sh[2]]),
|
|
554
|
+
);
|
|
445
555
|
}
|
|
446
556
|
}
|
|
447
557
|
}
|
|
@@ -460,7 +570,12 @@ export class Resolver implements EnsResolver {
|
|
|
460
570
|
version = -1;
|
|
461
571
|
}
|
|
462
572
|
|
|
463
|
-
if (
|
|
573
|
+
if (
|
|
574
|
+
version >= 0 &&
|
|
575
|
+
bytes.length === 2 + length &&
|
|
576
|
+
length >= 1 &&
|
|
577
|
+
length <= 75
|
|
578
|
+
) {
|
|
464
579
|
const words = bech32.toWords(bytes.slice(2));
|
|
465
580
|
words.unshift(version);
|
|
466
581
|
return bech32.encode(coinInfo.prefix, words);
|
|
@@ -470,9 +585,10 @@ export class Resolver implements EnsResolver {
|
|
|
470
585
|
return null;
|
|
471
586
|
}
|
|
472
587
|
|
|
473
|
-
|
|
474
588
|
async getAddress(coinType?: number): Promise<string> {
|
|
475
|
-
if (coinType == null) {
|
|
589
|
+
if (coinType == null) {
|
|
590
|
+
coinType = 60;
|
|
591
|
+
}
|
|
476
592
|
|
|
477
593
|
// If Ethereum, use the standard `addr(bytes32)`
|
|
478
594
|
if (coinType === 60) {
|
|
@@ -481,46 +597,65 @@ export class Resolver implements EnsResolver {
|
|
|
481
597
|
const result = await this._fetch("0x3b3b57de");
|
|
482
598
|
|
|
483
599
|
// No address
|
|
484
|
-
if (result === "0x" || result === HashZero) {
|
|
600
|
+
if (result === "0x" || result === HashZero) {
|
|
601
|
+
return null;
|
|
602
|
+
}
|
|
485
603
|
|
|
486
604
|
return this.provider.formatter.callAddress(result);
|
|
487
605
|
} catch (error) {
|
|
488
|
-
if (error.code === Logger.errors.CALL_EXCEPTION) {
|
|
606
|
+
if (error.code === Logger.errors.CALL_EXCEPTION) {
|
|
607
|
+
return null;
|
|
608
|
+
}
|
|
489
609
|
throw error;
|
|
490
610
|
}
|
|
491
611
|
}
|
|
492
612
|
|
|
493
613
|
// keccak256("addr(bytes32,uint256")
|
|
494
|
-
const hexBytes = await this._fetchBytes(
|
|
614
|
+
const hexBytes = await this._fetchBytes(
|
|
615
|
+
"0xf1cb7e06",
|
|
616
|
+
bytes32ify(coinType),
|
|
617
|
+
);
|
|
495
618
|
|
|
496
619
|
// No address
|
|
497
|
-
if (hexBytes == null || hexBytes === "0x") {
|
|
620
|
+
if (hexBytes == null || hexBytes === "0x") {
|
|
621
|
+
return null;
|
|
622
|
+
}
|
|
498
623
|
|
|
499
624
|
// Compute the address
|
|
500
625
|
const address = this._getAddress(coinType, hexBytes);
|
|
501
626
|
|
|
502
627
|
if (address == null) {
|
|
503
|
-
logger.throwError(
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
628
|
+
logger.throwError(
|
|
629
|
+
`invalid or unsupported coin data`,
|
|
630
|
+
Logger.errors.UNSUPPORTED_OPERATION,
|
|
631
|
+
{
|
|
632
|
+
operation: `getAddress(${coinType})`,
|
|
633
|
+
coinType: coinType,
|
|
634
|
+
data: hexBytes,
|
|
635
|
+
},
|
|
636
|
+
);
|
|
508
637
|
}
|
|
509
638
|
|
|
510
639
|
return address;
|
|
511
640
|
}
|
|
512
641
|
|
|
513
642
|
async getAvatar(): Promise<null | Avatar> {
|
|
514
|
-
const linkage: Array<{ type: string
|
|
643
|
+
const linkage: Array<{ type: string; content: string }> = [
|
|
644
|
+
{ type: "name", content: this.name },
|
|
645
|
+
];
|
|
515
646
|
try {
|
|
516
647
|
// test data for ricmoo.eth
|
|
517
648
|
//const avatar = "eip155:1/erc721:0x265385c7f4132228A0d54EB1A9e7460b91c0cC68/29233";
|
|
518
649
|
const avatar = await this.getText("avatar");
|
|
519
|
-
if (avatar == null) {
|
|
650
|
+
if (avatar == null) {
|
|
651
|
+
return null;
|
|
652
|
+
}
|
|
520
653
|
|
|
521
654
|
for (let i = 0; i < matchers.length; i++) {
|
|
522
655
|
const match = avatar.match(matchers[i]);
|
|
523
|
-
if (match == null) {
|
|
656
|
+
if (match == null) {
|
|
657
|
+
continue;
|
|
658
|
+
}
|
|
524
659
|
|
|
525
660
|
const scheme = match[1].toLowerCase();
|
|
526
661
|
|
|
@@ -540,50 +675,96 @@ export class Resolver implements EnsResolver {
|
|
|
540
675
|
case "erc721":
|
|
541
676
|
case "erc1155": {
|
|
542
677
|
// Depending on the ERC type, use tokenURI(uint256) or url(uint256)
|
|
543
|
-
const selector =
|
|
678
|
+
const selector =
|
|
679
|
+
scheme === "erc721" ? "0xc87b56dd" : "0x0e89341c";
|
|
544
680
|
linkage.push({ type: scheme, content: avatar });
|
|
545
681
|
|
|
546
682
|
// The owner of this name
|
|
547
|
-
const owner =
|
|
683
|
+
const owner =
|
|
684
|
+
this._resolvedAddress || (await this.getAddress());
|
|
548
685
|
|
|
549
686
|
const comps = (match[2] || "").split("/");
|
|
550
|
-
if (comps.length !== 2) {
|
|
687
|
+
if (comps.length !== 2) {
|
|
688
|
+
return null;
|
|
689
|
+
}
|
|
551
690
|
|
|
552
|
-
const addr = await this.provider.formatter.address(
|
|
553
|
-
|
|
691
|
+
const addr = await this.provider.formatter.address(
|
|
692
|
+
comps[0],
|
|
693
|
+
);
|
|
694
|
+
const tokenId = hexZeroPad(
|
|
695
|
+
BigNumber.from(comps[1]).toHexString(),
|
|
696
|
+
32,
|
|
697
|
+
);
|
|
554
698
|
|
|
555
699
|
// Check that this account owns the token
|
|
556
700
|
if (scheme === "erc721") {
|
|
557
701
|
// ownerOf(uint256 tokenId)
|
|
558
|
-
const tokenOwner =
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
702
|
+
const tokenOwner =
|
|
703
|
+
this.provider.formatter.callAddress(
|
|
704
|
+
await this.provider.call({
|
|
705
|
+
to: addr,
|
|
706
|
+
data: hexConcat([
|
|
707
|
+
"0x6352211e",
|
|
708
|
+
tokenId,
|
|
709
|
+
]),
|
|
710
|
+
}),
|
|
711
|
+
);
|
|
712
|
+
if (owner !== tokenOwner) {
|
|
713
|
+
return null;
|
|
714
|
+
}
|
|
715
|
+
linkage.push({
|
|
716
|
+
type: "owner",
|
|
717
|
+
content: tokenOwner,
|
|
718
|
+
});
|
|
564
719
|
} else if (scheme === "erc1155") {
|
|
565
720
|
// balanceOf(address owner, uint256 tokenId)
|
|
566
|
-
const balance = BigNumber.from(
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
721
|
+
const balance = BigNumber.from(
|
|
722
|
+
await this.provider.call({
|
|
723
|
+
to: addr,
|
|
724
|
+
data: hexConcat([
|
|
725
|
+
"0x00fdd58e",
|
|
726
|
+
hexZeroPad(owner, 32),
|
|
727
|
+
tokenId,
|
|
728
|
+
]),
|
|
729
|
+
}),
|
|
730
|
+
);
|
|
731
|
+
if (balance.isZero()) {
|
|
732
|
+
return null;
|
|
733
|
+
}
|
|
734
|
+
linkage.push({
|
|
735
|
+
type: "balance",
|
|
736
|
+
content: balance.toString(),
|
|
737
|
+
});
|
|
571
738
|
}
|
|
572
739
|
|
|
573
740
|
// Call the token contract for the metadata URL
|
|
574
741
|
const tx = {
|
|
575
742
|
to: this.provider.formatter.address(comps[0]),
|
|
576
|
-
data: hexConcat([
|
|
743
|
+
data: hexConcat([selector, tokenId]),
|
|
577
744
|
};
|
|
578
745
|
|
|
579
|
-
let metadataUrl = _parseString(
|
|
580
|
-
|
|
581
|
-
|
|
746
|
+
let metadataUrl = _parseString(
|
|
747
|
+
await this.provider.call(tx),
|
|
748
|
+
0,
|
|
749
|
+
);
|
|
750
|
+
if (metadataUrl == null) {
|
|
751
|
+
return null;
|
|
752
|
+
}
|
|
753
|
+
linkage.push({
|
|
754
|
+
type: "metadata-url-base",
|
|
755
|
+
content: metadataUrl,
|
|
756
|
+
});
|
|
582
757
|
|
|
583
758
|
// ERC-1155 allows a generic {id} in the URL
|
|
584
759
|
if (scheme === "erc1155") {
|
|
585
|
-
metadataUrl = metadataUrl.replace(
|
|
586
|
-
|
|
760
|
+
metadataUrl = metadataUrl.replace(
|
|
761
|
+
"{id}",
|
|
762
|
+
tokenId.substring(2),
|
|
763
|
+
);
|
|
764
|
+
linkage.push({
|
|
765
|
+
type: "metadata-url-expanded",
|
|
766
|
+
content: metadataUrl,
|
|
767
|
+
});
|
|
587
768
|
}
|
|
588
769
|
|
|
589
770
|
// Transform IPFS metadata links
|
|
@@ -591,25 +772,40 @@ export class Resolver implements EnsResolver {
|
|
|
591
772
|
metadataUrl = getIpfsLink(metadataUrl);
|
|
592
773
|
}
|
|
593
774
|
|
|
594
|
-
linkage.push({
|
|
775
|
+
linkage.push({
|
|
776
|
+
type: "metadata-url",
|
|
777
|
+
content: metadataUrl,
|
|
778
|
+
});
|
|
595
779
|
|
|
596
780
|
// Get the token metadata
|
|
597
781
|
const metadata = await fetchJson(metadataUrl);
|
|
598
|
-
if (!metadata) {
|
|
599
|
-
|
|
782
|
+
if (!metadata) {
|
|
783
|
+
return null;
|
|
784
|
+
}
|
|
785
|
+
linkage.push({
|
|
786
|
+
type: "metadata",
|
|
787
|
+
content: JSON.stringify(metadata),
|
|
788
|
+
});
|
|
600
789
|
|
|
601
790
|
// Pull the image URL out
|
|
602
791
|
let imageUrl = metadata.image;
|
|
603
|
-
if (typeof
|
|
792
|
+
if (typeof imageUrl !== "string") {
|
|
793
|
+
return null;
|
|
794
|
+
}
|
|
604
795
|
|
|
605
796
|
if (imageUrl.match(/^(https:\/\/|data:)/i)) {
|
|
606
797
|
// Allow
|
|
607
798
|
} else {
|
|
608
799
|
// Transform IPFS link to gateway
|
|
609
800
|
const ipfs = imageUrl.match(matcherIpfs);
|
|
610
|
-
if (ipfs == null) {
|
|
801
|
+
if (ipfs == null) {
|
|
802
|
+
return null;
|
|
803
|
+
}
|
|
611
804
|
|
|
612
|
-
linkage.push({
|
|
805
|
+
linkage.push({
|
|
806
|
+
type: "url-ipfs",
|
|
807
|
+
content: imageUrl,
|
|
808
|
+
});
|
|
613
809
|
imageUrl = getIpfsLink(imageUrl);
|
|
614
810
|
}
|
|
615
811
|
|
|
@@ -619,21 +815,24 @@ export class Resolver implements EnsResolver {
|
|
|
619
815
|
}
|
|
620
816
|
}
|
|
621
817
|
}
|
|
622
|
-
} catch (error) {
|
|
818
|
+
} catch (error) {}
|
|
623
819
|
|
|
624
820
|
return null;
|
|
625
821
|
}
|
|
626
822
|
|
|
627
823
|
async getContentHash(): Promise<string> {
|
|
628
|
-
|
|
629
824
|
// keccak256("contenthash()")
|
|
630
825
|
const hexBytes = await this._fetchBytes("0xbc1c58d1");
|
|
631
826
|
|
|
632
827
|
// No contenthash
|
|
633
|
-
if (hexBytes == null || hexBytes === "0x") {
|
|
828
|
+
if (hexBytes == null || hexBytes === "0x") {
|
|
829
|
+
return null;
|
|
830
|
+
}
|
|
634
831
|
|
|
635
832
|
// IPFS (CID: 1, Type: DAG-PB)
|
|
636
|
-
const ipfs = hexBytes.match(
|
|
833
|
+
const ipfs = hexBytes.match(
|
|
834
|
+
/^0xe3010170(([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f]*))$/,
|
|
835
|
+
);
|
|
637
836
|
if (ipfs) {
|
|
638
837
|
const length = parseInt(ipfs[3], 16);
|
|
639
838
|
if (ipfs[4].length === length * 2) {
|
|
@@ -642,7 +841,9 @@ export class Resolver implements EnsResolver {
|
|
|
642
841
|
}
|
|
643
842
|
|
|
644
843
|
// IPNS (CID: 1, Type: libp2p-key)
|
|
645
|
-
const ipns = hexBytes.match(
|
|
844
|
+
const ipns = hexBytes.match(
|
|
845
|
+
/^0xe5010172(([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f]*))$/,
|
|
846
|
+
);
|
|
646
847
|
if (ipns) {
|
|
647
848
|
const length = parseInt(ipns[3], 16);
|
|
648
849
|
if (ipns[4].length === length * 2) {
|
|
@@ -651,45 +852,67 @@ export class Resolver implements EnsResolver {
|
|
|
651
852
|
}
|
|
652
853
|
|
|
653
854
|
// Swarm (CID: 1, Type: swarm-manifest; hash/length hard-coded to keccak256/32)
|
|
654
|
-
const swarm = hexBytes.match(/^0xe40101fa011b20([0-9a-f]*)$/)
|
|
855
|
+
const swarm = hexBytes.match(/^0xe40101fa011b20([0-9a-f]*)$/);
|
|
655
856
|
if (swarm) {
|
|
656
|
-
if (swarm[1].length ===
|
|
657
|
-
return "bzz:/\/" + swarm[1]
|
|
857
|
+
if (swarm[1].length === 32 * 2) {
|
|
858
|
+
return "bzz:/\/" + swarm[1];
|
|
658
859
|
}
|
|
659
860
|
}
|
|
660
861
|
|
|
661
862
|
const skynet = hexBytes.match(/^0x90b2c605([0-9a-f]*)$/);
|
|
662
863
|
if (skynet) {
|
|
663
|
-
if (skynet[1].length ===
|
|
864
|
+
if (skynet[1].length === 34 * 2) {
|
|
664
865
|
// URL Safe base64; https://datatracker.ietf.org/doc/html/rfc4648#section-5
|
|
665
|
-
const urlSafe: Record<string, string> = {
|
|
666
|
-
|
|
866
|
+
const urlSafe: Record<string, string> = {
|
|
867
|
+
"=": "",
|
|
868
|
+
"+": "-",
|
|
869
|
+
"/": "_",
|
|
870
|
+
};
|
|
871
|
+
const hash = base64Encode("0x" + skynet[1]).replace(
|
|
872
|
+
/[=+\/]/g,
|
|
873
|
+
(a) => urlSafe[a],
|
|
874
|
+
);
|
|
667
875
|
return "sia:/\/" + hash;
|
|
668
876
|
}
|
|
669
877
|
}
|
|
670
878
|
|
|
671
|
-
return logger.throwError(
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
879
|
+
return logger.throwError(
|
|
880
|
+
`invalid or unsupported content hash data`,
|
|
881
|
+
Logger.errors.UNSUPPORTED_OPERATION,
|
|
882
|
+
{
|
|
883
|
+
operation: "getContentHash()",
|
|
884
|
+
data: hexBytes,
|
|
885
|
+
},
|
|
886
|
+
);
|
|
675
887
|
}
|
|
676
888
|
|
|
677
889
|
async getText(key: string): Promise<string> {
|
|
678
|
-
|
|
679
890
|
// The key encoded as parameter to fetchBytes
|
|
680
891
|
let keyBytes = toUtf8Bytes(key);
|
|
681
892
|
|
|
682
893
|
// The nodehash consumes the first slot, so the string pointer targets
|
|
683
894
|
// offset 64, with the length at offset 64 and data starting at offset 96
|
|
684
|
-
keyBytes = concat([
|
|
895
|
+
keyBytes = concat([
|
|
896
|
+
bytes32ify(64),
|
|
897
|
+
bytes32ify(keyBytes.length),
|
|
898
|
+
keyBytes,
|
|
899
|
+
]);
|
|
685
900
|
|
|
686
901
|
// Pad to word-size (32 bytes)
|
|
687
|
-
if (
|
|
688
|
-
keyBytes = concat([
|
|
902
|
+
if (keyBytes.length % 32 !== 0) {
|
|
903
|
+
keyBytes = concat([
|
|
904
|
+
keyBytes,
|
|
905
|
+
hexZeroPad("0x", 32 - (key.length % 32)),
|
|
906
|
+
]);
|
|
689
907
|
}
|
|
690
908
|
|
|
691
|
-
const hexBytes = await this._fetchBytes(
|
|
692
|
-
|
|
909
|
+
const hexBytes = await this._fetchBytes(
|
|
910
|
+
"0x59d1d43c",
|
|
911
|
+
hexlify(keyBytes),
|
|
912
|
+
);
|
|
913
|
+
if (hexBytes == null || hexBytes === "0x") {
|
|
914
|
+
return null;
|
|
915
|
+
}
|
|
693
916
|
|
|
694
917
|
return toUtf8String(hexBytes);
|
|
695
918
|
}
|
|
@@ -717,7 +940,7 @@ export class BaseProvider extends Provider implements EnsProvider {
|
|
|
717
940
|
// - t:{hash} - Transaction hash
|
|
718
941
|
// - b:{hash} - BlockHash
|
|
719
942
|
// - block - The most recent emitted block
|
|
720
|
-
_emitted: { [
|
|
943
|
+
_emitted: { [eventName: string]: number | "pending" };
|
|
721
944
|
|
|
722
945
|
_pollingInterval: number;
|
|
723
946
|
_poller: NodeJS.Timeout;
|
|
@@ -731,13 +954,16 @@ export class BaseProvider extends Provider implements EnsProvider {
|
|
|
731
954
|
_fastQueryDate: number;
|
|
732
955
|
|
|
733
956
|
_maxInternalBlockNumber: number;
|
|
734
|
-
_internalBlockNumber: Promise<{
|
|
957
|
+
_internalBlockNumber: Promise<{
|
|
958
|
+
blockNumber: number;
|
|
959
|
+
reqTime: number;
|
|
960
|
+
respTime: number;
|
|
961
|
+
}>;
|
|
735
962
|
|
|
736
963
|
readonly anyNetwork: boolean;
|
|
737
964
|
|
|
738
965
|
disableCcipRead: boolean;
|
|
739
966
|
|
|
740
|
-
|
|
741
967
|
/**
|
|
742
968
|
* ready
|
|
743
969
|
*
|
|
@@ -763,26 +989,33 @@ export class BaseProvider extends Provider implements EnsProvider {
|
|
|
763
989
|
// If network is any, this Provider allows the underlying
|
|
764
990
|
// network to change dynamically, and we auto-detect the
|
|
765
991
|
// current network
|
|
766
|
-
defineReadOnly(this, "anyNetwork",
|
|
767
|
-
if (this.anyNetwork) {
|
|
992
|
+
defineReadOnly(this, "anyNetwork", network === "any");
|
|
993
|
+
if (this.anyNetwork) {
|
|
994
|
+
network = this.detectNetwork();
|
|
995
|
+
}
|
|
768
996
|
|
|
769
997
|
if (network instanceof Promise) {
|
|
770
998
|
this._networkPromise = network;
|
|
771
999
|
|
|
772
1000
|
// Squash any "unhandled promise" errors; that do not need to be handled
|
|
773
|
-
network.catch((error) => {
|
|
1001
|
+
network.catch((error) => {});
|
|
774
1002
|
|
|
775
1003
|
// Trigger initial network setting (async)
|
|
776
|
-
this._ready().catch((error) => {
|
|
777
|
-
|
|
1004
|
+
this._ready().catch((error) => {});
|
|
778
1005
|
} else {
|
|
779
|
-
const knownNetwork = getStatic<(network: Networkish) => Network>(
|
|
1006
|
+
const knownNetwork = getStatic<(network: Networkish) => Network>(
|
|
1007
|
+
new.target,
|
|
1008
|
+
"getNetwork",
|
|
1009
|
+
)(network);
|
|
780
1010
|
if (knownNetwork) {
|
|
781
1011
|
defineReadOnly(this, "_network", knownNetwork);
|
|
782
1012
|
this.emit("network", knownNetwork, null);
|
|
783
|
-
|
|
784
1013
|
} else {
|
|
785
|
-
logger.throwArgumentError(
|
|
1014
|
+
logger.throwArgumentError(
|
|
1015
|
+
"invalid network",
|
|
1016
|
+
"network",
|
|
1017
|
+
network,
|
|
1018
|
+
);
|
|
786
1019
|
}
|
|
787
1020
|
}
|
|
788
1021
|
|
|
@@ -802,7 +1035,7 @@ export class BaseProvider extends Provider implements EnsProvider {
|
|
|
802
1035
|
if (this._networkPromise) {
|
|
803
1036
|
try {
|
|
804
1037
|
network = await this._networkPromise;
|
|
805
|
-
} catch (error) {
|
|
1038
|
+
} catch (error) {}
|
|
806
1039
|
}
|
|
807
1040
|
|
|
808
1041
|
// Try the Provider's network detection (this MUST throw if it cannot)
|
|
@@ -813,7 +1046,11 @@ export class BaseProvider extends Provider implements EnsProvider {
|
|
|
813
1046
|
// This should never happen; every Provider sub-class should have
|
|
814
1047
|
// suggested a network by here (or have thrown).
|
|
815
1048
|
if (!network) {
|
|
816
|
-
logger.throwError(
|
|
1049
|
+
logger.throwError(
|
|
1050
|
+
"no network detected",
|
|
1051
|
+
Logger.errors.UNKNOWN_ERROR,
|
|
1052
|
+
{},
|
|
1053
|
+
);
|
|
817
1054
|
}
|
|
818
1055
|
|
|
819
1056
|
// Possible this call stacked so do not call defineReadOnly again
|
|
@@ -835,15 +1072,21 @@ export class BaseProvider extends Provider implements EnsProvider {
|
|
|
835
1072
|
// any change is reflected); otherwise this cannot change
|
|
836
1073
|
get ready(): Promise<Network> {
|
|
837
1074
|
return poll(() => {
|
|
838
|
-
return this._ready().then(
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
1075
|
+
return this._ready().then(
|
|
1076
|
+
(network) => {
|
|
1077
|
+
return network;
|
|
1078
|
+
},
|
|
1079
|
+
(error): any => {
|
|
1080
|
+
// If the network isn't running yet, we will wait
|
|
1081
|
+
if (
|
|
1082
|
+
error.code === Logger.errors.NETWORK_ERROR &&
|
|
1083
|
+
error.event === "noNetwork"
|
|
1084
|
+
) {
|
|
1085
|
+
return undefined;
|
|
1086
|
+
}
|
|
1087
|
+
throw error;
|
|
1088
|
+
},
|
|
1089
|
+
);
|
|
847
1090
|
});
|
|
848
1091
|
}
|
|
849
1092
|
|
|
@@ -857,47 +1100,73 @@ export class BaseProvider extends Provider implements EnsProvider {
|
|
|
857
1100
|
|
|
858
1101
|
// @TODO: Remove this and just use getNetwork
|
|
859
1102
|
static getNetwork(network: Networkish): Network {
|
|
860
|
-
return getNetwork(
|
|
1103
|
+
return getNetwork(network == null ? "homestead" : network);
|
|
861
1104
|
}
|
|
862
1105
|
|
|
863
|
-
async ccipReadFetch(
|
|
864
|
-
|
|
1106
|
+
async ccipReadFetch(
|
|
1107
|
+
tx: Transaction,
|
|
1108
|
+
calldata: string,
|
|
1109
|
+
urls: Array<string>,
|
|
1110
|
+
): Promise<null | string> {
|
|
1111
|
+
if (this.disableCcipRead || urls.length === 0) {
|
|
1112
|
+
return null;
|
|
1113
|
+
}
|
|
865
1114
|
|
|
866
1115
|
const sender = tx.to.toLowerCase();
|
|
867
1116
|
const data = calldata.toLowerCase();
|
|
868
1117
|
|
|
869
|
-
const errorMessages: Array<string> = [
|
|
1118
|
+
const errorMessages: Array<string> = [];
|
|
870
1119
|
|
|
871
1120
|
for (let i = 0; i < urls.length; i++) {
|
|
872
1121
|
const url = urls[i];
|
|
873
1122
|
|
|
874
1123
|
// URL expansion
|
|
875
|
-
const href = url
|
|
1124
|
+
const href = url
|
|
1125
|
+
.replace("{sender}", sender)
|
|
1126
|
+
.replace("{data}", data);
|
|
876
1127
|
|
|
877
1128
|
// If no {data} is present, use POST; otherwise GET
|
|
878
|
-
const json: string | null =
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
1129
|
+
const json: string | null =
|
|
1130
|
+
url.indexOf("{data}") >= 0
|
|
1131
|
+
? null
|
|
1132
|
+
: JSON.stringify({ data, sender });
|
|
1133
|
+
|
|
1134
|
+
const result = await fetchJson(
|
|
1135
|
+
{ url: href, errorPassThrough: true },
|
|
1136
|
+
json,
|
|
1137
|
+
(value, response) => {
|
|
1138
|
+
value.status = response.statusCode;
|
|
1139
|
+
return value;
|
|
1140
|
+
},
|
|
1141
|
+
);
|
|
884
1142
|
|
|
885
|
-
if (result.data) {
|
|
1143
|
+
if (result.data) {
|
|
1144
|
+
return result.data;
|
|
1145
|
+
}
|
|
886
1146
|
|
|
887
|
-
const errorMessage =
|
|
1147
|
+
const errorMessage = result.message || "unknown error";
|
|
888
1148
|
|
|
889
1149
|
// 4xx indicates the result is not present; stop
|
|
890
1150
|
if (result.status >= 400 && result.status < 500) {
|
|
891
|
-
return logger.throwError(
|
|
1151
|
+
return logger.throwError(
|
|
1152
|
+
`response not found during CCIP fetch: ${errorMessage}`,
|
|
1153
|
+
Logger.errors.SERVER_ERROR,
|
|
1154
|
+
{ url, errorMessage },
|
|
1155
|
+
);
|
|
892
1156
|
}
|
|
893
1157
|
|
|
894
1158
|
// 5xx indicates server issue; try the next url
|
|
895
1159
|
errorMessages.push(errorMessage);
|
|
896
1160
|
}
|
|
897
1161
|
|
|
898
|
-
return logger.throwError(
|
|
899
|
-
|
|
900
|
-
|
|
1162
|
+
return logger.throwError(
|
|
1163
|
+
`error encountered during CCIP fetch: ${errorMessages.map((m) => JSON.stringify(m)).join(", ")}`,
|
|
1164
|
+
Logger.errors.SERVER_ERROR,
|
|
1165
|
+
{
|
|
1166
|
+
urls,
|
|
1167
|
+
errorMessages,
|
|
1168
|
+
},
|
|
1169
|
+
);
|
|
901
1170
|
}
|
|
902
1171
|
|
|
903
1172
|
// Fetches the blockNumber, but will reuse any result that is less
|
|
@@ -907,25 +1176,21 @@ export class BaseProvider extends Provider implements EnsProvider {
|
|
|
907
1176
|
|
|
908
1177
|
// Allowing stale data up to maxAge old
|
|
909
1178
|
if (maxAge > 0) {
|
|
910
|
-
|
|
911
1179
|
// While there are pending internal block requests...
|
|
912
1180
|
while (this._internalBlockNumber) {
|
|
913
|
-
|
|
914
1181
|
// ..."remember" which fetch we started with
|
|
915
1182
|
const internalBlockNumber = this._internalBlockNumber;
|
|
916
1183
|
|
|
917
1184
|
try {
|
|
918
1185
|
// Check the result is not too stale
|
|
919
1186
|
const result = await internalBlockNumber;
|
|
920
|
-
if (
|
|
1187
|
+
if (getTime() - result.respTime <= maxAge) {
|
|
921
1188
|
return result.blockNumber;
|
|
922
1189
|
}
|
|
923
1190
|
|
|
924
1191
|
// Too old; fetch a new value
|
|
925
1192
|
break;
|
|
926
|
-
|
|
927
|
-
} catch(error) {
|
|
928
|
-
|
|
1193
|
+
} catch (error) {
|
|
929
1194
|
// The fetch rejected; if we are the first to get the
|
|
930
1195
|
// rejection, drop through so we replace it with a new
|
|
931
1196
|
// fetch; all others blocked will then get that fetch
|
|
@@ -940,8 +1205,11 @@ export class BaseProvider extends Provider implements EnsProvider {
|
|
|
940
1205
|
const reqTime = getTime();
|
|
941
1206
|
|
|
942
1207
|
const checkInternalBlockNumber = resolveProperties({
|
|
943
|
-
blockNumber: this.perform("getBlockNumber", {
|
|
944
|
-
networkError: this.getNetwork().then(
|
|
1208
|
+
blockNumber: this.perform("getBlockNumber", {}),
|
|
1209
|
+
networkError: this.getNetwork().then(
|
|
1210
|
+
(network): any => null,
|
|
1211
|
+
(error) => error,
|
|
1212
|
+
),
|
|
945
1213
|
}).then(({ blockNumber, networkError }) => {
|
|
946
1214
|
if (networkError) {
|
|
947
1215
|
// Unremember this bad internal block number
|
|
@@ -954,7 +1222,9 @@ export class BaseProvider extends Provider implements EnsProvider {
|
|
|
954
1222
|
const respTime = getTime();
|
|
955
1223
|
|
|
956
1224
|
blockNumber = BigNumber.from(blockNumber).toNumber();
|
|
957
|
-
if (blockNumber < this._maxInternalBlockNumber) {
|
|
1225
|
+
if (blockNumber < this._maxInternalBlockNumber) {
|
|
1226
|
+
blockNumber = this._maxInternalBlockNumber;
|
|
1227
|
+
}
|
|
958
1228
|
|
|
959
1229
|
this._maxInternalBlockNumber = blockNumber;
|
|
960
1230
|
this._setFastBlockNumber(blockNumber); // @TODO: Still need this?
|
|
@@ -982,7 +1252,9 @@ export class BaseProvider extends Provider implements EnsProvider {
|
|
|
982
1252
|
|
|
983
1253
|
let blockNumber: number = null;
|
|
984
1254
|
try {
|
|
985
|
-
blockNumber = await this._getInternalBlockNumber(
|
|
1255
|
+
blockNumber = await this._getInternalBlockNumber(
|
|
1256
|
+
100 + this.pollingInterval / 2,
|
|
1257
|
+
);
|
|
986
1258
|
} catch (error) {
|
|
987
1259
|
this.emit("error", error);
|
|
988
1260
|
return;
|
|
@@ -1003,29 +1275,43 @@ export class BaseProvider extends Provider implements EnsProvider {
|
|
|
1003
1275
|
this._emitted.block = blockNumber - 1;
|
|
1004
1276
|
}
|
|
1005
1277
|
|
|
1006
|
-
if (Math.abs(
|
|
1007
|
-
logger.warn(
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1278
|
+
if (Math.abs(<number>this._emitted.block - blockNumber) > 1000) {
|
|
1279
|
+
logger.warn(
|
|
1280
|
+
`network block skew detected; skipping block events (emitted=${this._emitted.block} blockNumber${blockNumber})`,
|
|
1281
|
+
);
|
|
1282
|
+
this.emit(
|
|
1283
|
+
"error",
|
|
1284
|
+
logger.makeError(
|
|
1285
|
+
"network block skew detected",
|
|
1286
|
+
Logger.errors.NETWORK_ERROR,
|
|
1287
|
+
{
|
|
1288
|
+
blockNumber: blockNumber,
|
|
1289
|
+
event: "blockSkew",
|
|
1290
|
+
previousBlockNumber: this._emitted.block,
|
|
1291
|
+
},
|
|
1292
|
+
),
|
|
1293
|
+
);
|
|
1013
1294
|
this.emit("block", blockNumber);
|
|
1014
|
-
|
|
1015
1295
|
} else {
|
|
1016
1296
|
// Notify all listener for each block that has passed
|
|
1017
|
-
for (
|
|
1297
|
+
for (
|
|
1298
|
+
let i = <number>this._emitted.block + 1;
|
|
1299
|
+
i <= blockNumber;
|
|
1300
|
+
i++
|
|
1301
|
+
) {
|
|
1018
1302
|
this.emit("block", i);
|
|
1019
1303
|
}
|
|
1020
1304
|
}
|
|
1021
1305
|
|
|
1022
1306
|
// The emitted block was updated, check for obsolete events
|
|
1023
|
-
if (
|
|
1307
|
+
if (<number>this._emitted.block !== blockNumber) {
|
|
1024
1308
|
this._emitted.block = blockNumber;
|
|
1025
1309
|
|
|
1026
1310
|
Object.keys(this._emitted).forEach((key) => {
|
|
1027
1311
|
// The block event does not expire
|
|
1028
|
-
if (key === "block") {
|
|
1312
|
+
if (key === "block") {
|
|
1313
|
+
return;
|
|
1314
|
+
}
|
|
1029
1315
|
|
|
1030
1316
|
// The block we were at when we emitted this event
|
|
1031
1317
|
const eventBlockNumber = this._emitted[key];
|
|
@@ -1033,7 +1319,9 @@ export class BaseProvider extends Provider implements EnsProvider {
|
|
|
1033
1319
|
// We cannot garbage collect pending transactions or blocks here
|
|
1034
1320
|
// They should be garbage collected by the Provider when setting
|
|
1035
1321
|
// "pending" events
|
|
1036
|
-
if (eventBlockNumber === "pending") {
|
|
1322
|
+
if (eventBlockNumber === "pending") {
|
|
1323
|
+
return;
|
|
1324
|
+
}
|
|
1037
1325
|
|
|
1038
1326
|
// Evict any transaction hashes or block hashes over 12 blocks
|
|
1039
1327
|
// old, since they should not return null anyways
|
|
@@ -1052,12 +1340,18 @@ export class BaseProvider extends Provider implements EnsProvider {
|
|
|
1052
1340
|
switch (event.type) {
|
|
1053
1341
|
case "tx": {
|
|
1054
1342
|
const hash = event.hash;
|
|
1055
|
-
let runner = this.getTransactionReceipt(hash)
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1343
|
+
let runner = this.getTransactionReceipt(hash)
|
|
1344
|
+
.then((receipt): any => {
|
|
1345
|
+
if (!receipt || receipt.blockNumber == null) {
|
|
1346
|
+
return null;
|
|
1347
|
+
}
|
|
1348
|
+
this._emitted["t:" + hash] = receipt.blockNumber;
|
|
1349
|
+
this.emit(hash, receipt);
|
|
1350
|
+
return null;
|
|
1351
|
+
})
|
|
1352
|
+
.catch((error: Error) => {
|
|
1353
|
+
this.emit("error", error);
|
|
1354
|
+
});
|
|
1061
1355
|
|
|
1062
1356
|
runners.push(runner);
|
|
1063
1357
|
|
|
@@ -1085,36 +1379,50 @@ export class BaseProvider extends Provider implements EnsProvider {
|
|
|
1085
1379
|
|
|
1086
1380
|
// Prevent fitler ranges from growing too wild, since it is quite
|
|
1087
1381
|
// likely there just haven't been any events to move the lastBlockNumber.
|
|
1088
|
-
const minFromBlock =
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1382
|
+
const minFromBlock =
|
|
1383
|
+
filter.toBlock - this._maxFilterBlockRange;
|
|
1384
|
+
if (minFromBlock > filter.fromBlock) {
|
|
1385
|
+
filter.fromBlock = minFromBlock;
|
|
1386
|
+
}
|
|
1092
1387
|
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1388
|
+
if (filter.fromBlock < 0) {
|
|
1389
|
+
filter.fromBlock = 0;
|
|
1390
|
+
}
|
|
1096
1391
|
|
|
1097
|
-
|
|
1392
|
+
const runner = this.getLogs(filter)
|
|
1393
|
+
.then((logs) => {
|
|
1394
|
+
// Allow the next getLogs
|
|
1395
|
+
event._inflight = false;
|
|
1098
1396
|
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
// can we trust the events are indexed
|
|
1102
|
-
if (log.blockNumber > event._lastBlockNumber) {
|
|
1103
|
-
event._lastBlockNumber = log.blockNumber;
|
|
1397
|
+
if (logs.length === 0) {
|
|
1398
|
+
return;
|
|
1104
1399
|
}
|
|
1105
1400
|
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1401
|
+
logs.forEach((log: Log) => {
|
|
1402
|
+
// Only when we get an event for a given block number
|
|
1403
|
+
// can we trust the events are indexed
|
|
1404
|
+
if (
|
|
1405
|
+
log.blockNumber > event._lastBlockNumber
|
|
1406
|
+
) {
|
|
1407
|
+
event._lastBlockNumber =
|
|
1408
|
+
log.blockNumber;
|
|
1409
|
+
}
|
|
1109
1410
|
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1411
|
+
// Make sure we stall requests to fetch blocks and txs
|
|
1412
|
+
this._emitted["b:" + log.blockHash] =
|
|
1413
|
+
log.blockNumber;
|
|
1414
|
+
this._emitted["t:" + log.transactionHash] =
|
|
1415
|
+
log.blockNumber;
|
|
1114
1416
|
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1417
|
+
this.emit(filter, log);
|
|
1418
|
+
});
|
|
1419
|
+
})
|
|
1420
|
+
.catch((error: Error) => {
|
|
1421
|
+
this.emit("error", error);
|
|
1422
|
+
|
|
1423
|
+
// Allow another getLogs (the range was not updated)
|
|
1424
|
+
event._inflight = false;
|
|
1425
|
+
});
|
|
1118
1426
|
runners.push(runner);
|
|
1119
1427
|
}
|
|
1120
1428
|
|
|
@@ -1126,9 +1434,13 @@ export class BaseProvider extends Provider implements EnsProvider {
|
|
|
1126
1434
|
this._lastBlockNumber = blockNumber;
|
|
1127
1435
|
|
|
1128
1436
|
// Once all events for this loop have been processed, emit "didPoll"
|
|
1129
|
-
Promise.all(runners)
|
|
1130
|
-
|
|
1131
|
-
|
|
1437
|
+
Promise.all(runners)
|
|
1438
|
+
.then(() => {
|
|
1439
|
+
this.emit("didPoll", pollId);
|
|
1440
|
+
})
|
|
1441
|
+
.catch((error) => {
|
|
1442
|
+
this.emit("error", error);
|
|
1443
|
+
});
|
|
1132
1444
|
|
|
1133
1445
|
return;
|
|
1134
1446
|
}
|
|
@@ -1136,7 +1448,9 @@ export class BaseProvider extends Provider implements EnsProvider {
|
|
|
1136
1448
|
// Deprecated; do not use this
|
|
1137
1449
|
resetEventsBlock(blockNumber: number): void {
|
|
1138
1450
|
this._lastBlockNumber = blockNumber - 1;
|
|
1139
|
-
if (this.polling) {
|
|
1451
|
+
if (this.polling) {
|
|
1452
|
+
this.poll();
|
|
1453
|
+
}
|
|
1140
1454
|
}
|
|
1141
1455
|
|
|
1142
1456
|
get network(): Network {
|
|
@@ -1146,9 +1460,13 @@ export class BaseProvider extends Provider implements EnsProvider {
|
|
|
1146
1460
|
// This method should query the network if the underlying network
|
|
1147
1461
|
// can change, such as when connected to a JSON-RPC backend
|
|
1148
1462
|
async detectNetwork(): Promise<Network> {
|
|
1149
|
-
return logger.throwError(
|
|
1150
|
-
|
|
1151
|
-
|
|
1463
|
+
return logger.throwError(
|
|
1464
|
+
"provider does not support network detection",
|
|
1465
|
+
Logger.errors.UNSUPPORTED_OPERATION,
|
|
1466
|
+
{
|
|
1467
|
+
operation: "provider.detectNetwork",
|
|
1468
|
+
},
|
|
1469
|
+
);
|
|
1152
1470
|
}
|
|
1153
1471
|
|
|
1154
1472
|
async getNetwork(): Promise<Network> {
|
|
@@ -1159,7 +1477,6 @@ export class BaseProvider extends Provider implements EnsProvider {
|
|
|
1159
1477
|
// network change spontaneously
|
|
1160
1478
|
const currentNetwork = await this.detectNetwork();
|
|
1161
1479
|
if (network.chainId !== currentNetwork.chainId) {
|
|
1162
|
-
|
|
1163
1480
|
// We are allowing network changes, things can get complex fast;
|
|
1164
1481
|
// make sure you know what you are doing if you use "any"
|
|
1165
1482
|
if (this.anyNetwork) {
|
|
@@ -1183,11 +1500,15 @@ export class BaseProvider extends Provider implements EnsProvider {
|
|
|
1183
1500
|
return this._network;
|
|
1184
1501
|
}
|
|
1185
1502
|
|
|
1186
|
-
const error = logger.makeError(
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1503
|
+
const error = logger.makeError(
|
|
1504
|
+
"underlying network changed",
|
|
1505
|
+
Logger.errors.NETWORK_ERROR,
|
|
1506
|
+
{
|
|
1507
|
+
event: "changed",
|
|
1508
|
+
network: network,
|
|
1509
|
+
detectedNetwork: currentNetwork,
|
|
1510
|
+
},
|
|
1511
|
+
);
|
|
1191
1512
|
|
|
1192
1513
|
this.emit("error", error);
|
|
1193
1514
|
throw error;
|
|
@@ -1197,20 +1518,25 @@ export class BaseProvider extends Provider implements EnsProvider {
|
|
|
1197
1518
|
}
|
|
1198
1519
|
|
|
1199
1520
|
get blockNumber(): number {
|
|
1200
|
-
this._getInternalBlockNumber(100 + this.pollingInterval / 2).then(
|
|
1201
|
-
|
|
1202
|
-
|
|
1521
|
+
this._getInternalBlockNumber(100 + this.pollingInterval / 2).then(
|
|
1522
|
+
(blockNumber) => {
|
|
1523
|
+
this._setFastBlockNumber(blockNumber);
|
|
1524
|
+
},
|
|
1525
|
+
(error) => {},
|
|
1526
|
+
);
|
|
1203
1527
|
|
|
1204
|
-
return
|
|
1528
|
+
return this._fastBlockNumber != null ? this._fastBlockNumber : -1;
|
|
1205
1529
|
}
|
|
1206
1530
|
|
|
1207
1531
|
get polling(): boolean {
|
|
1208
|
-
return
|
|
1532
|
+
return this._poller != null;
|
|
1209
1533
|
}
|
|
1210
1534
|
|
|
1211
1535
|
set polling(value: boolean) {
|
|
1212
1536
|
if (value && !this._poller) {
|
|
1213
|
-
this._poller = setInterval(() => {
|
|
1537
|
+
this._poller = setInterval(() => {
|
|
1538
|
+
this.poll();
|
|
1539
|
+
}, this.pollingInterval);
|
|
1214
1540
|
|
|
1215
1541
|
if (!this._bootstrapPoll) {
|
|
1216
1542
|
this._bootstrapPoll = setTimeout(() => {
|
|
@@ -1221,14 +1547,15 @@ export class BaseProvider extends Provider implements EnsProvider {
|
|
|
1221
1547
|
this._bootstrapPoll = setTimeout(() => {
|
|
1222
1548
|
// If polling was disabled, something may require a poke
|
|
1223
1549
|
// since starting the bootstrap poll and it was disabled
|
|
1224
|
-
if (!this._poller) {
|
|
1550
|
+
if (!this._poller) {
|
|
1551
|
+
this.poll();
|
|
1552
|
+
}
|
|
1225
1553
|
|
|
1226
1554
|
// Clear out the bootstrap so we can do another
|
|
1227
1555
|
this._bootstrapPoll = null;
|
|
1228
1556
|
}, this.pollingInterval);
|
|
1229
1557
|
}, 0);
|
|
1230
1558
|
}
|
|
1231
|
-
|
|
1232
1559
|
} else if (!value && this._poller) {
|
|
1233
1560
|
clearInterval(this._poller);
|
|
1234
1561
|
this._poller = null;
|
|
@@ -1240,7 +1567,11 @@ export class BaseProvider extends Provider implements EnsProvider {
|
|
|
1240
1567
|
}
|
|
1241
1568
|
|
|
1242
1569
|
set pollingInterval(value: number) {
|
|
1243
|
-
if (
|
|
1570
|
+
if (
|
|
1571
|
+
typeof value !== "number" ||
|
|
1572
|
+
value <= 0 ||
|
|
1573
|
+
parseInt(String(value)) != value
|
|
1574
|
+
) {
|
|
1244
1575
|
throw new Error("invalid polling interval");
|
|
1245
1576
|
}
|
|
1246
1577
|
|
|
@@ -1248,7 +1579,9 @@ export class BaseProvider extends Provider implements EnsProvider {
|
|
|
1248
1579
|
|
|
1249
1580
|
if (this._poller) {
|
|
1250
1581
|
clearInterval(this._poller);
|
|
1251
|
-
this._poller = setInterval(() => {
|
|
1582
|
+
this._poller = setInterval(() => {
|
|
1583
|
+
this.poll();
|
|
1584
|
+
}, this._pollingInterval);
|
|
1252
1585
|
}
|
|
1253
1586
|
}
|
|
1254
1587
|
|
|
@@ -1256,14 +1589,19 @@ export class BaseProvider extends Provider implements EnsProvider {
|
|
|
1256
1589
|
const now = getTime();
|
|
1257
1590
|
|
|
1258
1591
|
// Stale block number, request a newer value
|
|
1259
|
-
if (
|
|
1592
|
+
if (now - this._fastQueryDate > 2 * this._pollingInterval) {
|
|
1260
1593
|
this._fastQueryDate = now;
|
|
1261
|
-
this._fastBlockNumberPromise = this.getBlockNumber().then(
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1594
|
+
this._fastBlockNumberPromise = this.getBlockNumber().then(
|
|
1595
|
+
(blockNumber) => {
|
|
1596
|
+
if (
|
|
1597
|
+
this._fastBlockNumber == null ||
|
|
1598
|
+
blockNumber > this._fastBlockNumber
|
|
1599
|
+
) {
|
|
1600
|
+
this._fastBlockNumber = blockNumber;
|
|
1601
|
+
}
|
|
1602
|
+
return this._fastBlockNumber;
|
|
1603
|
+
},
|
|
1604
|
+
);
|
|
1267
1605
|
}
|
|
1268
1606
|
|
|
1269
1607
|
return this._fastBlockNumberPromise;
|
|
@@ -1271,137 +1609,238 @@ export class BaseProvider extends Provider implements EnsProvider {
|
|
|
1271
1609
|
|
|
1272
1610
|
_setFastBlockNumber(blockNumber: number): void {
|
|
1273
1611
|
// Older block, maybe a stale request
|
|
1274
|
-
if (
|
|
1612
|
+
if (
|
|
1613
|
+
this._fastBlockNumber != null &&
|
|
1614
|
+
blockNumber < this._fastBlockNumber
|
|
1615
|
+
) {
|
|
1616
|
+
return;
|
|
1617
|
+
}
|
|
1275
1618
|
|
|
1276
1619
|
// Update the time we updated the blocknumber
|
|
1277
1620
|
this._fastQueryDate = getTime();
|
|
1278
1621
|
|
|
1279
1622
|
// Newer block number, use it
|
|
1280
|
-
if (
|
|
1623
|
+
if (
|
|
1624
|
+
this._fastBlockNumber == null ||
|
|
1625
|
+
blockNumber > this._fastBlockNumber
|
|
1626
|
+
) {
|
|
1281
1627
|
this._fastBlockNumber = blockNumber;
|
|
1282
1628
|
this._fastBlockNumberPromise = Promise.resolve(blockNumber);
|
|
1283
1629
|
}
|
|
1284
1630
|
}
|
|
1285
1631
|
|
|
1286
|
-
async waitForTransaction(
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1632
|
+
async waitForTransaction(
|
|
1633
|
+
transactionHash: string,
|
|
1634
|
+
confirmations?: number,
|
|
1635
|
+
timeout?: number,
|
|
1636
|
+
): Promise<TransactionReceipt> {
|
|
1637
|
+
return this._waitForTransaction(
|
|
1638
|
+
transactionHash,
|
|
1639
|
+
confirmations == null ? 1 : confirmations,
|
|
1640
|
+
timeout || 0,
|
|
1641
|
+
null,
|
|
1642
|
+
);
|
|
1643
|
+
}
|
|
1644
|
+
|
|
1645
|
+
async _waitForTransaction(
|
|
1646
|
+
transactionHash: string,
|
|
1647
|
+
confirmations: number,
|
|
1648
|
+
timeout: number,
|
|
1649
|
+
replaceable: {
|
|
1650
|
+
data: string;
|
|
1651
|
+
from: string;
|
|
1652
|
+
nonce: number;
|
|
1653
|
+
to: string;
|
|
1654
|
+
value: BigNumber;
|
|
1655
|
+
startBlock: number;
|
|
1656
|
+
},
|
|
1657
|
+
): Promise<TransactionReceipt> {
|
|
1291
1658
|
const receipt = await this.getTransactionReceipt(transactionHash);
|
|
1292
1659
|
|
|
1293
1660
|
// Receipt is already good
|
|
1294
|
-
if ((receipt ? receipt.confirmations: 0) >= confirmations) {
|
|
1661
|
+
if ((receipt ? receipt.confirmations : 0) >= confirmations) {
|
|
1662
|
+
return receipt;
|
|
1663
|
+
}
|
|
1295
1664
|
|
|
1296
1665
|
// Poll until the receipt is good...
|
|
1297
1666
|
return new Promise((resolve, reject) => {
|
|
1298
1667
|
const cancelFuncs: Array<() => void> = [];
|
|
1299
1668
|
|
|
1300
1669
|
let done = false;
|
|
1301
|
-
const alreadyDone = function() {
|
|
1302
|
-
if (done) {
|
|
1670
|
+
const alreadyDone = function () {
|
|
1671
|
+
if (done) {
|
|
1672
|
+
return true;
|
|
1673
|
+
}
|
|
1303
1674
|
done = true;
|
|
1304
|
-
cancelFuncs.forEach((func) => {
|
|
1675
|
+
cancelFuncs.forEach((func) => {
|
|
1676
|
+
func();
|
|
1677
|
+
});
|
|
1305
1678
|
return false;
|
|
1306
1679
|
};
|
|
1307
1680
|
|
|
1308
1681
|
const minedHandler = (receipt: TransactionReceipt) => {
|
|
1309
|
-
if (receipt.confirmations < confirmations) {
|
|
1310
|
-
|
|
1682
|
+
if (receipt.confirmations < confirmations) {
|
|
1683
|
+
return;
|
|
1684
|
+
}
|
|
1685
|
+
if (alreadyDone()) {
|
|
1686
|
+
return;
|
|
1687
|
+
}
|
|
1311
1688
|
resolve(receipt);
|
|
1312
|
-
}
|
|
1689
|
+
};
|
|
1313
1690
|
this.on(transactionHash, minedHandler);
|
|
1314
|
-
cancelFuncs.push(() => {
|
|
1691
|
+
cancelFuncs.push(() => {
|
|
1692
|
+
this.removeListener(transactionHash, minedHandler);
|
|
1693
|
+
});
|
|
1315
1694
|
|
|
1316
1695
|
if (replaceable) {
|
|
1317
1696
|
let lastBlockNumber = replaceable.startBlock;
|
|
1318
1697
|
let scannedBlock: number = null;
|
|
1319
1698
|
const replaceHandler = async (blockNumber: number) => {
|
|
1320
|
-
if (done) {
|
|
1699
|
+
if (done) {
|
|
1700
|
+
return;
|
|
1701
|
+
}
|
|
1321
1702
|
|
|
1322
1703
|
// Wait 1 second; this is only used in the case of a fault, so
|
|
1323
1704
|
// we will trade off a little bit of latency for more consistent
|
|
1324
1705
|
// results and fewer JSON-RPC calls
|
|
1325
1706
|
await stall(1000);
|
|
1326
1707
|
|
|
1327
|
-
this.getTransactionCount(replaceable.from).then(
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
lastBlockNumber = blockNumber;
|
|
1332
|
-
|
|
1333
|
-
} else {
|
|
1334
|
-
// First check if the transaction was mined
|
|
1335
|
-
{
|
|
1336
|
-
const mined = await this.getTransaction(transactionHash);
|
|
1337
|
-
if (mined && mined.blockNumber != null) { return; }
|
|
1708
|
+
this.getTransactionCount(replaceable.from).then(
|
|
1709
|
+
async (nonce) => {
|
|
1710
|
+
if (done) {
|
|
1711
|
+
return;
|
|
1338
1712
|
}
|
|
1339
1713
|
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1714
|
+
if (nonce <= replaceable.nonce) {
|
|
1715
|
+
lastBlockNumber = blockNumber;
|
|
1716
|
+
} else {
|
|
1717
|
+
// First check if the transaction was mined
|
|
1718
|
+
{
|
|
1719
|
+
const mined =
|
|
1720
|
+
await this.getTransaction(
|
|
1721
|
+
transactionHash,
|
|
1722
|
+
);
|
|
1723
|
+
if (mined && mined.blockNumber != null) {
|
|
1724
|
+
return;
|
|
1725
|
+
}
|
|
1348
1726
|
}
|
|
1349
|
-
}
|
|
1350
|
-
|
|
1351
|
-
while (scannedBlock <= blockNumber) {
|
|
1352
|
-
if (done) { return; }
|
|
1353
|
-
|
|
1354
|
-
const block = await this.getBlockWithTransactions(scannedBlock);
|
|
1355
|
-
for (let ti = 0; ti < block.transactions.length; ti++) {
|
|
1356
|
-
const tx = block.transactions[ti];
|
|
1357
|
-
|
|
1358
|
-
// Successfully mined!
|
|
1359
|
-
if (tx.hash === transactionHash) { return; }
|
|
1360
1727
|
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1728
|
+
// First time scanning. We start a little earlier for some
|
|
1729
|
+
// wiggle room here to handle the eventually consistent nature
|
|
1730
|
+
// of blockchain (e.g. the getTransactionCount was for a
|
|
1731
|
+
// different block)
|
|
1732
|
+
if (scannedBlock == null) {
|
|
1733
|
+
scannedBlock = lastBlockNumber - 3;
|
|
1734
|
+
if (scannedBlock < replaceable.startBlock) {
|
|
1735
|
+
scannedBlock = replaceable.startBlock;
|
|
1736
|
+
}
|
|
1737
|
+
}
|
|
1367
1738
|
|
|
1368
|
-
|
|
1369
|
-
|
|
1739
|
+
while (scannedBlock <= blockNumber) {
|
|
1740
|
+
if (done) {
|
|
1741
|
+
return;
|
|
1742
|
+
}
|
|
1370
1743
|
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1744
|
+
const block =
|
|
1745
|
+
await this.getBlockWithTransactions(
|
|
1746
|
+
scannedBlock,
|
|
1747
|
+
);
|
|
1748
|
+
for (
|
|
1749
|
+
let ti = 0;
|
|
1750
|
+
ti < block.transactions.length;
|
|
1751
|
+
ti++
|
|
1752
|
+
) {
|
|
1753
|
+
const tx = block.transactions[ti];
|
|
1754
|
+
|
|
1755
|
+
// Successfully mined!
|
|
1756
|
+
if (tx.hash === transactionHash) {
|
|
1757
|
+
return;
|
|
1377
1758
|
}
|
|
1378
1759
|
|
|
1379
|
-
//
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1760
|
+
// Matches our transaction from and nonce; its a replacement
|
|
1761
|
+
if (
|
|
1762
|
+
tx.from === replaceable.from &&
|
|
1763
|
+
tx.nonce === replaceable.nonce
|
|
1764
|
+
) {
|
|
1765
|
+
if (done) {
|
|
1766
|
+
return;
|
|
1767
|
+
}
|
|
1768
|
+
|
|
1769
|
+
// Get the receipt of the replacement
|
|
1770
|
+
const receipt =
|
|
1771
|
+
await this.waitForTransaction(
|
|
1772
|
+
tx.hash,
|
|
1773
|
+
confirmations,
|
|
1774
|
+
);
|
|
1775
|
+
|
|
1776
|
+
// Already resolved or rejected (prolly a timeout)
|
|
1777
|
+
if (alreadyDone()) {
|
|
1778
|
+
return;
|
|
1779
|
+
}
|
|
1780
|
+
|
|
1781
|
+
// The reason we were replaced
|
|
1782
|
+
let reason = "replaced";
|
|
1783
|
+
if (
|
|
1784
|
+
tx.data === replaceable.data &&
|
|
1785
|
+
tx.to === replaceable.to &&
|
|
1786
|
+
tx.value.eq(replaceable.value)
|
|
1787
|
+
) {
|
|
1788
|
+
reason = "repriced";
|
|
1789
|
+
} else if (
|
|
1790
|
+
tx.data === "0x" &&
|
|
1791
|
+
tx.from === tx.to &&
|
|
1792
|
+
tx.value.isZero()
|
|
1793
|
+
) {
|
|
1794
|
+
reason = "cancelled";
|
|
1795
|
+
}
|
|
1796
|
+
|
|
1797
|
+
// Explain why we were replaced
|
|
1798
|
+
reject(
|
|
1799
|
+
logger.makeError(
|
|
1800
|
+
"transaction was replaced",
|
|
1801
|
+
Logger.errors
|
|
1802
|
+
.TRANSACTION_REPLACED,
|
|
1803
|
+
{
|
|
1804
|
+
cancelled:
|
|
1805
|
+
reason ===
|
|
1806
|
+
"replaced" ||
|
|
1807
|
+
reason ===
|
|
1808
|
+
"cancelled",
|
|
1809
|
+
reason,
|
|
1810
|
+
replacement:
|
|
1811
|
+
this._wrapTransaction(
|
|
1812
|
+
tx,
|
|
1813
|
+
),
|
|
1814
|
+
hash: transactionHash,
|
|
1815
|
+
receipt,
|
|
1816
|
+
},
|
|
1817
|
+
),
|
|
1818
|
+
);
|
|
1819
|
+
|
|
1820
|
+
return;
|
|
1821
|
+
}
|
|
1389
1822
|
}
|
|
1823
|
+
scannedBlock++;
|
|
1390
1824
|
}
|
|
1391
|
-
scannedBlock++;
|
|
1392
1825
|
}
|
|
1393
|
-
}
|
|
1394
|
-
|
|
1395
|
-
if (done) { return; }
|
|
1396
|
-
this.once("block", replaceHandler);
|
|
1397
1826
|
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1827
|
+
if (done) {
|
|
1828
|
+
return;
|
|
1829
|
+
}
|
|
1830
|
+
this.once("block", replaceHandler);
|
|
1831
|
+
},
|
|
1832
|
+
(error) => {
|
|
1833
|
+
if (done) {
|
|
1834
|
+
return;
|
|
1835
|
+
}
|
|
1836
|
+
this.once("block", replaceHandler);
|
|
1837
|
+
},
|
|
1838
|
+
);
|
|
1402
1839
|
};
|
|
1403
1840
|
|
|
1404
|
-
if (done) {
|
|
1841
|
+
if (done) {
|
|
1842
|
+
return;
|
|
1843
|
+
}
|
|
1405
1844
|
this.once("block", replaceHandler);
|
|
1406
1845
|
|
|
1407
1846
|
cancelFuncs.push(() => {
|
|
@@ -1409,14 +1848,26 @@ export class BaseProvider extends Provider implements EnsProvider {
|
|
|
1409
1848
|
});
|
|
1410
1849
|
}
|
|
1411
1850
|
|
|
1412
|
-
if (typeof
|
|
1851
|
+
if (typeof timeout === "number" && timeout > 0) {
|
|
1413
1852
|
const timer = setTimeout(() => {
|
|
1414
|
-
if (alreadyDone()) {
|
|
1415
|
-
|
|
1853
|
+
if (alreadyDone()) {
|
|
1854
|
+
return;
|
|
1855
|
+
}
|
|
1856
|
+
reject(
|
|
1857
|
+
logger.makeError(
|
|
1858
|
+
"timeout exceeded",
|
|
1859
|
+
Logger.errors.TIMEOUT,
|
|
1860
|
+
{ timeout: timeout },
|
|
1861
|
+
),
|
|
1862
|
+
);
|
|
1416
1863
|
}, timeout);
|
|
1417
|
-
if (timer.unref) {
|
|
1864
|
+
if (timer.unref) {
|
|
1865
|
+
timer.unref();
|
|
1866
|
+
}
|
|
1418
1867
|
|
|
1419
|
-
cancelFuncs.push(() => {
|
|
1868
|
+
cancelFuncs.push(() => {
|
|
1869
|
+
clearTimeout(timer);
|
|
1870
|
+
});
|
|
1420
1871
|
}
|
|
1421
1872
|
});
|
|
1422
1873
|
}
|
|
@@ -1428,103 +1879,159 @@ export class BaseProvider extends Provider implements EnsProvider {
|
|
|
1428
1879
|
async getGasPrice(): Promise<BigNumber> {
|
|
1429
1880
|
await this.getNetwork();
|
|
1430
1881
|
|
|
1431
|
-
const result = await this.perform("getGasPrice", {
|
|
1882
|
+
const result = await this.perform("getGasPrice", {});
|
|
1432
1883
|
try {
|
|
1433
1884
|
return BigNumber.from(result);
|
|
1434
1885
|
} catch (error) {
|
|
1435
|
-
return logger.throwError(
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1886
|
+
return logger.throwError(
|
|
1887
|
+
"bad result from backend",
|
|
1888
|
+
Logger.errors.SERVER_ERROR,
|
|
1889
|
+
{
|
|
1890
|
+
method: "getGasPrice",
|
|
1891
|
+
result,
|
|
1892
|
+
error,
|
|
1893
|
+
},
|
|
1894
|
+
);
|
|
1439
1895
|
}
|
|
1440
1896
|
}
|
|
1441
1897
|
|
|
1442
|
-
async getBalance(
|
|
1898
|
+
async getBalance(
|
|
1899
|
+
addressOrName: string | Promise<string>,
|
|
1900
|
+
blockTag?: BlockTag | Promise<BlockTag>,
|
|
1901
|
+
): Promise<BigNumber> {
|
|
1443
1902
|
await this.getNetwork();
|
|
1444
1903
|
const params = await resolveProperties({
|
|
1445
1904
|
address: this._getAddress(addressOrName),
|
|
1446
|
-
blockTag: this._getBlockTag(blockTag)
|
|
1905
|
+
blockTag: this._getBlockTag(blockTag),
|
|
1447
1906
|
});
|
|
1448
1907
|
|
|
1449
1908
|
const result = await this.perform("getBalance", params);
|
|
1450
1909
|
try {
|
|
1451
1910
|
return BigNumber.from(result);
|
|
1452
1911
|
} catch (error) {
|
|
1453
|
-
return logger.throwError(
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1912
|
+
return logger.throwError(
|
|
1913
|
+
"bad result from backend",
|
|
1914
|
+
Logger.errors.SERVER_ERROR,
|
|
1915
|
+
{
|
|
1916
|
+
method: "getBalance",
|
|
1917
|
+
params,
|
|
1918
|
+
result,
|
|
1919
|
+
error,
|
|
1920
|
+
},
|
|
1921
|
+
);
|
|
1457
1922
|
}
|
|
1458
1923
|
}
|
|
1459
1924
|
|
|
1460
|
-
async getTransactionCount(
|
|
1925
|
+
async getTransactionCount(
|
|
1926
|
+
addressOrName: string | Promise<string>,
|
|
1927
|
+
blockTag?: BlockTag | Promise<BlockTag>,
|
|
1928
|
+
): Promise<number> {
|
|
1461
1929
|
await this.getNetwork();
|
|
1462
1930
|
const params = await resolveProperties({
|
|
1463
1931
|
address: this._getAddress(addressOrName),
|
|
1464
|
-
blockTag: this._getBlockTag(blockTag)
|
|
1932
|
+
blockTag: this._getBlockTag(blockTag),
|
|
1465
1933
|
});
|
|
1466
1934
|
|
|
1467
1935
|
const result = await this.perform("getTransactionCount", params);
|
|
1468
1936
|
try {
|
|
1469
1937
|
return BigNumber.from(result).toNumber();
|
|
1470
1938
|
} catch (error) {
|
|
1471
|
-
return logger.throwError(
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1939
|
+
return logger.throwError(
|
|
1940
|
+
"bad result from backend",
|
|
1941
|
+
Logger.errors.SERVER_ERROR,
|
|
1942
|
+
{
|
|
1943
|
+
method: "getTransactionCount",
|
|
1944
|
+
params,
|
|
1945
|
+
result,
|
|
1946
|
+
error,
|
|
1947
|
+
},
|
|
1948
|
+
);
|
|
1475
1949
|
}
|
|
1476
1950
|
}
|
|
1477
1951
|
|
|
1478
|
-
async getCode(
|
|
1952
|
+
async getCode(
|
|
1953
|
+
addressOrName: string | Promise<string>,
|
|
1954
|
+
blockTag?: BlockTag | Promise<BlockTag>,
|
|
1955
|
+
): Promise<string> {
|
|
1479
1956
|
await this.getNetwork();
|
|
1480
1957
|
const params = await resolveProperties({
|
|
1481
1958
|
address: this._getAddress(addressOrName),
|
|
1482
|
-
blockTag: this._getBlockTag(blockTag)
|
|
1959
|
+
blockTag: this._getBlockTag(blockTag),
|
|
1483
1960
|
});
|
|
1484
1961
|
|
|
1485
1962
|
const result = await this.perform("getCode", params);
|
|
1486
1963
|
try {
|
|
1487
1964
|
return hexlify(result);
|
|
1488
1965
|
} catch (error) {
|
|
1489
|
-
return logger.throwError(
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1966
|
+
return logger.throwError(
|
|
1967
|
+
"bad result from backend",
|
|
1968
|
+
Logger.errors.SERVER_ERROR,
|
|
1969
|
+
{
|
|
1970
|
+
method: "getCode",
|
|
1971
|
+
params,
|
|
1972
|
+
result,
|
|
1973
|
+
error,
|
|
1974
|
+
},
|
|
1975
|
+
);
|
|
1493
1976
|
}
|
|
1494
1977
|
}
|
|
1495
1978
|
|
|
1496
|
-
async getStorageAt(
|
|
1979
|
+
async getStorageAt(
|
|
1980
|
+
addressOrName: string | Promise<string>,
|
|
1981
|
+
position: BigNumberish | Promise<BigNumberish>,
|
|
1982
|
+
blockTag?: BlockTag | Promise<BlockTag>,
|
|
1983
|
+
): Promise<string> {
|
|
1497
1984
|
await this.getNetwork();
|
|
1498
1985
|
const params = await resolveProperties({
|
|
1499
1986
|
address: this._getAddress(addressOrName),
|
|
1500
1987
|
blockTag: this._getBlockTag(blockTag),
|
|
1501
|
-
position: Promise.resolve(position).then((p) => hexValue(p))
|
|
1988
|
+
position: Promise.resolve(position).then((p) => hexValue(p)),
|
|
1502
1989
|
});
|
|
1503
1990
|
const result = await this.perform("getStorageAt", params);
|
|
1504
1991
|
try {
|
|
1505
1992
|
return hexlify(result);
|
|
1506
1993
|
} catch (error) {
|
|
1507
|
-
return logger.throwError(
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1994
|
+
return logger.throwError(
|
|
1995
|
+
"bad result from backend",
|
|
1996
|
+
Logger.errors.SERVER_ERROR,
|
|
1997
|
+
{
|
|
1998
|
+
method: "getStorageAt",
|
|
1999
|
+
params,
|
|
2000
|
+
result,
|
|
2001
|
+
error,
|
|
2002
|
+
},
|
|
2003
|
+
);
|
|
1511
2004
|
}
|
|
1512
2005
|
}
|
|
1513
2006
|
|
|
1514
2007
|
// This should be called by any subclass wrapping a TransactionResponse
|
|
1515
|
-
_wrapTransaction(
|
|
1516
|
-
|
|
2008
|
+
_wrapTransaction(
|
|
2009
|
+
tx: Transaction,
|
|
2010
|
+
hash?: string,
|
|
2011
|
+
startBlock?: number,
|
|
2012
|
+
): TransactionResponse {
|
|
2013
|
+
if (hash != null && hexDataLength(hash) !== 32) {
|
|
2014
|
+
throw new Error("invalid response - sendTransaction");
|
|
2015
|
+
}
|
|
1517
2016
|
|
|
1518
2017
|
const result = <TransactionResponse>tx;
|
|
1519
2018
|
|
|
1520
2019
|
// Check the hash we expect is the same as the hash the server reported
|
|
1521
2020
|
if (hash != null && tx.hash !== hash) {
|
|
1522
|
-
logger.throwError(
|
|
2021
|
+
logger.throwError(
|
|
2022
|
+
"Transaction hash mismatch from Provider.sendTransaction.",
|
|
2023
|
+
Logger.errors.UNKNOWN_ERROR,
|
|
2024
|
+
{ expectedHash: tx.hash, returnedHash: hash },
|
|
2025
|
+
);
|
|
1523
2026
|
}
|
|
1524
2027
|
|
|
1525
2028
|
result.wait = async (confirms?: number, timeout?: number) => {
|
|
1526
|
-
if (confirms == null) {
|
|
1527
|
-
|
|
2029
|
+
if (confirms == null) {
|
|
2030
|
+
confirms = 1;
|
|
2031
|
+
}
|
|
2032
|
+
if (timeout == null) {
|
|
2033
|
+
timeout = 0;
|
|
2034
|
+
}
|
|
1528
2035
|
|
|
1529
2036
|
// Get the details to detect replacement
|
|
1530
2037
|
let replacement = undefined;
|
|
@@ -1535,22 +2042,33 @@ export class BaseProvider extends Provider implements EnsProvider {
|
|
|
1535
2042
|
nonce: tx.nonce,
|
|
1536
2043
|
to: tx.to,
|
|
1537
2044
|
value: tx.value,
|
|
1538
|
-
startBlock
|
|
2045
|
+
startBlock,
|
|
1539
2046
|
};
|
|
1540
2047
|
}
|
|
1541
2048
|
|
|
1542
|
-
const receipt = await this._waitForTransaction(
|
|
1543
|
-
|
|
2049
|
+
const receipt = await this._waitForTransaction(
|
|
2050
|
+
tx.hash,
|
|
2051
|
+
confirms,
|
|
2052
|
+
timeout,
|
|
2053
|
+
replacement,
|
|
2054
|
+
);
|
|
2055
|
+
if (receipt == null && confirms === 0) {
|
|
2056
|
+
return null;
|
|
2057
|
+
}
|
|
1544
2058
|
|
|
1545
2059
|
// No longer pending, allow the polling loop to garbage collect this
|
|
1546
2060
|
this._emitted["t:" + tx.hash] = receipt.blockNumber;
|
|
1547
2061
|
|
|
1548
2062
|
if (receipt.status === 0) {
|
|
1549
|
-
logger.throwError(
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
2063
|
+
logger.throwError(
|
|
2064
|
+
"transaction failed",
|
|
2065
|
+
Logger.errors.CALL_EXCEPTION,
|
|
2066
|
+
{
|
|
2067
|
+
transactionHash: tx.hash,
|
|
2068
|
+
transaction: tx,
|
|
2069
|
+
receipt: receipt,
|
|
2070
|
+
},
|
|
2071
|
+
);
|
|
1554
2072
|
}
|
|
1555
2073
|
return receipt;
|
|
1556
2074
|
};
|
|
@@ -1558,14 +2076,24 @@ export class BaseProvider extends Provider implements EnsProvider {
|
|
|
1558
2076
|
return result;
|
|
1559
2077
|
}
|
|
1560
2078
|
|
|
1561
|
-
async sendTransaction(
|
|
2079
|
+
async sendTransaction(
|
|
2080
|
+
signedTransaction: string | Promise<string>,
|
|
2081
|
+
): Promise<TransactionResponse> {
|
|
1562
2082
|
await this.getNetwork();
|
|
1563
|
-
const hexTx = await Promise.resolve(signedTransaction).then(t =>
|
|
2083
|
+
const hexTx = await Promise.resolve(signedTransaction).then((t) =>
|
|
2084
|
+
hexlify(t),
|
|
2085
|
+
);
|
|
1564
2086
|
const tx = this.formatter.transaction(signedTransaction);
|
|
1565
|
-
if (tx.confirmations == null) {
|
|
1566
|
-
|
|
2087
|
+
if (tx.confirmations == null) {
|
|
2088
|
+
tx.confirmations = 0;
|
|
2089
|
+
}
|
|
2090
|
+
const blockNumber = await this._getInternalBlockNumber(
|
|
2091
|
+
100 + 2 * this.pollingInterval,
|
|
2092
|
+
);
|
|
1567
2093
|
try {
|
|
1568
|
-
const hash = await this.perform("sendTransaction", {
|
|
2094
|
+
const hash = await this.perform("sendTransaction", {
|
|
2095
|
+
signedTransaction: hexTx,
|
|
2096
|
+
});
|
|
1569
2097
|
return this._wrapTransaction(tx, hash, blockNumber);
|
|
1570
2098
|
} catch (error) {
|
|
1571
2099
|
(<any>error).transaction = tx;
|
|
@@ -1574,24 +2102,44 @@ export class BaseProvider extends Provider implements EnsProvider {
|
|
|
1574
2102
|
}
|
|
1575
2103
|
}
|
|
1576
2104
|
|
|
1577
|
-
async _getTransactionRequest(
|
|
2105
|
+
async _getTransactionRequest(
|
|
2106
|
+
transaction: Deferrable<TransactionRequest>,
|
|
2107
|
+
): Promise<Transaction> {
|
|
1578
2108
|
const values: any = await transaction;
|
|
1579
2109
|
|
|
1580
|
-
const tx: any = {
|
|
2110
|
+
const tx: any = {};
|
|
1581
2111
|
|
|
1582
2112
|
["from", "to"].forEach((key) => {
|
|
1583
|
-
if (values[key] == null) {
|
|
1584
|
-
|
|
2113
|
+
if (values[key] == null) {
|
|
2114
|
+
return;
|
|
2115
|
+
}
|
|
2116
|
+
tx[key] = Promise.resolve(values[key]).then((v) =>
|
|
2117
|
+
v ? this._getAddress(v) : null,
|
|
2118
|
+
);
|
|
1585
2119
|
});
|
|
1586
2120
|
|
|
1587
|
-
[
|
|
1588
|
-
|
|
1589
|
-
|
|
2121
|
+
[
|
|
2122
|
+
"gasLimit",
|
|
2123
|
+
"gasPrice",
|
|
2124
|
+
"maxFeePerGas",
|
|
2125
|
+
"maxPriorityFeePerGas",
|
|
2126
|
+
"value",
|
|
2127
|
+
].forEach((key) => {
|
|
2128
|
+
if (values[key] == null) {
|
|
2129
|
+
return;
|
|
2130
|
+
}
|
|
2131
|
+
tx[key] = Promise.resolve(values[key]).then((v) =>
|
|
2132
|
+
v ? BigNumber.from(v) : null,
|
|
2133
|
+
);
|
|
1590
2134
|
});
|
|
1591
2135
|
|
|
1592
2136
|
["type"].forEach((key) => {
|
|
1593
|
-
if (values[key] == null) {
|
|
1594
|
-
|
|
2137
|
+
if (values[key] == null) {
|
|
2138
|
+
return;
|
|
2139
|
+
}
|
|
2140
|
+
tx[key] = Promise.resolve(values[key]).then((v) =>
|
|
2141
|
+
v != null ? v : null,
|
|
2142
|
+
);
|
|
1595
2143
|
});
|
|
1596
2144
|
|
|
1597
2145
|
if (values.accessList) {
|
|
@@ -1599,40 +2147,62 @@ export class BaseProvider extends Provider implements EnsProvider {
|
|
|
1599
2147
|
}
|
|
1600
2148
|
|
|
1601
2149
|
["data"].forEach((key) => {
|
|
1602
|
-
if (values[key] == null) {
|
|
1603
|
-
|
|
2150
|
+
if (values[key] == null) {
|
|
2151
|
+
return;
|
|
2152
|
+
}
|
|
2153
|
+
tx[key] = Promise.resolve(values[key]).then((v) =>
|
|
2154
|
+
v ? hexlify(v) : null,
|
|
2155
|
+
);
|
|
1604
2156
|
});
|
|
1605
2157
|
|
|
1606
2158
|
return this.formatter.transactionRequest(await resolveProperties(tx));
|
|
1607
2159
|
}
|
|
1608
2160
|
|
|
1609
|
-
async _getFilter(
|
|
2161
|
+
async _getFilter(
|
|
2162
|
+
filter:
|
|
2163
|
+
| Filter
|
|
2164
|
+
| FilterByBlockHash
|
|
2165
|
+
| Promise<Filter | FilterByBlockHash>,
|
|
2166
|
+
): Promise<Filter | FilterByBlockHash> {
|
|
1610
2167
|
filter = await filter;
|
|
1611
2168
|
|
|
1612
|
-
const result: any = {
|
|
2169
|
+
const result: any = {};
|
|
1613
2170
|
|
|
1614
2171
|
if (filter.address != null) {
|
|
1615
2172
|
result.address = this._getAddress(filter.address);
|
|
1616
2173
|
}
|
|
1617
2174
|
|
|
1618
2175
|
["blockHash", "topics"].forEach((key) => {
|
|
1619
|
-
if ((<any>filter)[key] == null) {
|
|
2176
|
+
if ((<any>filter)[key] == null) {
|
|
2177
|
+
return;
|
|
2178
|
+
}
|
|
1620
2179
|
result[key] = (<any>filter)[key];
|
|
1621
2180
|
});
|
|
1622
2181
|
|
|
1623
2182
|
["fromBlock", "toBlock"].forEach((key) => {
|
|
1624
|
-
if ((<any>filter)[key] == null) {
|
|
2183
|
+
if ((<any>filter)[key] == null) {
|
|
2184
|
+
return;
|
|
2185
|
+
}
|
|
1625
2186
|
result[key] = this._getBlockTag((<any>filter)[key]);
|
|
1626
2187
|
});
|
|
1627
2188
|
|
|
1628
2189
|
return this.formatter.filter(await resolveProperties(result));
|
|
1629
2190
|
}
|
|
1630
2191
|
|
|
1631
|
-
async _call(
|
|
2192
|
+
async _call(
|
|
2193
|
+
transaction: TransactionRequest,
|
|
2194
|
+
blockTag: BlockTag,
|
|
2195
|
+
attempt: number,
|
|
2196
|
+
): Promise<string> {
|
|
1632
2197
|
if (attempt >= MAX_CCIP_REDIRECTS) {
|
|
1633
|
-
logger.throwError(
|
|
1634
|
-
|
|
1635
|
-
|
|
2198
|
+
logger.throwError(
|
|
2199
|
+
"CCIP read exceeded maximum redirections",
|
|
2200
|
+
Logger.errors.SERVER_ERROR,
|
|
2201
|
+
{
|
|
2202
|
+
redirects: attempt,
|
|
2203
|
+
transaction,
|
|
2204
|
+
},
|
|
2205
|
+
);
|
|
1636
2206
|
}
|
|
1637
2207
|
|
|
1638
2208
|
const txSender = transaction.to;
|
|
@@ -1640,33 +2210,55 @@ export class BaseProvider extends Provider implements EnsProvider {
|
|
|
1640
2210
|
const result = await this.perform("call", { transaction, blockTag });
|
|
1641
2211
|
|
|
1642
2212
|
// CCIP Read request via OffchainLookup(address,string[],bytes,bytes4,bytes)
|
|
1643
|
-
if (
|
|
2213
|
+
if (
|
|
2214
|
+
attempt >= 0 &&
|
|
2215
|
+
blockTag === "latest" &&
|
|
2216
|
+
txSender != null &&
|
|
2217
|
+
result.substring(0, 10) === "0x556f1830" &&
|
|
2218
|
+
hexDataLength(result) % 32 === 4
|
|
2219
|
+
) {
|
|
1644
2220
|
try {
|
|
1645
2221
|
const data = hexDataSlice(result, 4);
|
|
1646
2222
|
|
|
1647
2223
|
// Check the sender of the OffchainLookup matches the transaction
|
|
1648
2224
|
const sender = hexDataSlice(data, 0, 32);
|
|
1649
2225
|
if (!BigNumber.from(sender).eq(txSender)) {
|
|
1650
|
-
logger.throwError(
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
2226
|
+
logger.throwError(
|
|
2227
|
+
"CCIP Read sender did not match",
|
|
2228
|
+
Logger.errors.CALL_EXCEPTION,
|
|
2229
|
+
{
|
|
2230
|
+
name: "OffchainLookup",
|
|
2231
|
+
signature:
|
|
2232
|
+
"OffchainLookup(address,string[],bytes,bytes4,bytes)",
|
|
2233
|
+
transaction,
|
|
2234
|
+
data: result,
|
|
2235
|
+
},
|
|
2236
|
+
);
|
|
1655
2237
|
}
|
|
1656
2238
|
|
|
1657
2239
|
// Read the URLs from the response
|
|
1658
2240
|
const urls: Array<string> = [];
|
|
1659
|
-
const urlsOffset = BigNumber.from(
|
|
1660
|
-
|
|
2241
|
+
const urlsOffset = BigNumber.from(
|
|
2242
|
+
hexDataSlice(data, 32, 64),
|
|
2243
|
+
).toNumber();
|
|
2244
|
+
const urlsLength = BigNumber.from(
|
|
2245
|
+
hexDataSlice(data, urlsOffset, urlsOffset + 32),
|
|
2246
|
+
).toNumber();
|
|
1661
2247
|
const urlsData = hexDataSlice(data, urlsOffset + 32);
|
|
1662
2248
|
for (let u = 0; u < urlsLength; u++) {
|
|
1663
2249
|
const url = _parseString(urlsData, u * 32);
|
|
1664
2250
|
if (url == null) {
|
|
1665
|
-
logger.throwError(
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
2251
|
+
logger.throwError(
|
|
2252
|
+
"CCIP Read contained corrupt URL string",
|
|
2253
|
+
Logger.errors.CALL_EXCEPTION,
|
|
2254
|
+
{
|
|
2255
|
+
name: "OffchainLookup",
|
|
2256
|
+
signature:
|
|
2257
|
+
"OffchainLookup(address,string[],bytes,bytes4,bytes)",
|
|
2258
|
+
transaction,
|
|
2259
|
+
data: result,
|
|
2260
|
+
},
|
|
2261
|
+
);
|
|
1670
2262
|
}
|
|
1671
2263
|
urls.push(url);
|
|
1672
2264
|
}
|
|
@@ -1676,92 +2268,145 @@ export class BaseProvider extends Provider implements EnsProvider {
|
|
|
1676
2268
|
|
|
1677
2269
|
// Get the callbackSelector (bytes4)
|
|
1678
2270
|
if (!BigNumber.from(hexDataSlice(data, 100, 128)).isZero()) {
|
|
1679
|
-
logger.throwError(
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
2271
|
+
logger.throwError(
|
|
2272
|
+
"CCIP Read callback selector included junk",
|
|
2273
|
+
Logger.errors.CALL_EXCEPTION,
|
|
2274
|
+
{
|
|
2275
|
+
name: "OffchainLookup",
|
|
2276
|
+
signature:
|
|
2277
|
+
"OffchainLookup(address,string[],bytes,bytes4,bytes)",
|
|
2278
|
+
transaction,
|
|
2279
|
+
data: result,
|
|
2280
|
+
},
|
|
2281
|
+
);
|
|
1684
2282
|
}
|
|
1685
2283
|
const callbackSelector = hexDataSlice(data, 96, 100);
|
|
1686
2284
|
|
|
1687
2285
|
// Get the extra data to send back to the contract as context
|
|
1688
2286
|
const extraData = _parseBytes(data, 128);
|
|
1689
2287
|
|
|
1690
|
-
const ccipResult = await this.ccipReadFetch(
|
|
2288
|
+
const ccipResult = await this.ccipReadFetch(
|
|
2289
|
+
<Transaction>transaction,
|
|
2290
|
+
calldata,
|
|
2291
|
+
urls,
|
|
2292
|
+
);
|
|
1691
2293
|
if (ccipResult == null) {
|
|
1692
|
-
logger.throwError(
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
2294
|
+
logger.throwError(
|
|
2295
|
+
"CCIP Read disabled or provided no URLs",
|
|
2296
|
+
Logger.errors.CALL_EXCEPTION,
|
|
2297
|
+
{
|
|
2298
|
+
name: "OffchainLookup",
|
|
2299
|
+
signature:
|
|
2300
|
+
"OffchainLookup(address,string[],bytes,bytes4,bytes)",
|
|
2301
|
+
transaction,
|
|
2302
|
+
data: result,
|
|
2303
|
+
},
|
|
2304
|
+
);
|
|
1697
2305
|
}
|
|
1698
2306
|
|
|
1699
2307
|
const tx = {
|
|
1700
2308
|
to: txSender,
|
|
1701
|
-
data: hexConcat([
|
|
2309
|
+
data: hexConcat([
|
|
2310
|
+
callbackSelector,
|
|
2311
|
+
encodeBytes([ccipResult, extraData]),
|
|
2312
|
+
]),
|
|
1702
2313
|
};
|
|
1703
2314
|
|
|
1704
2315
|
return this._call(tx, blockTag, attempt + 1);
|
|
1705
|
-
|
|
1706
2316
|
} catch (error) {
|
|
1707
|
-
if (error.code === Logger.errors.SERVER_ERROR) {
|
|
2317
|
+
if (error.code === Logger.errors.SERVER_ERROR) {
|
|
2318
|
+
throw error;
|
|
2319
|
+
}
|
|
1708
2320
|
}
|
|
1709
2321
|
}
|
|
1710
2322
|
|
|
1711
2323
|
try {
|
|
1712
2324
|
return hexlify(result);
|
|
1713
2325
|
} catch (error) {
|
|
1714
|
-
return logger.throwError(
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
2326
|
+
return logger.throwError(
|
|
2327
|
+
"bad result from backend",
|
|
2328
|
+
Logger.errors.SERVER_ERROR,
|
|
2329
|
+
{
|
|
2330
|
+
method: "call",
|
|
2331
|
+
params: { transaction, blockTag },
|
|
2332
|
+
result,
|
|
2333
|
+
error,
|
|
2334
|
+
},
|
|
2335
|
+
);
|
|
1718
2336
|
}
|
|
1719
|
-
|
|
1720
2337
|
}
|
|
1721
2338
|
|
|
1722
|
-
async call(
|
|
2339
|
+
async call(
|
|
2340
|
+
transaction: Deferrable<TransactionRequest>,
|
|
2341
|
+
blockTag?: BlockTag | Promise<BlockTag>,
|
|
2342
|
+
): Promise<string> {
|
|
1723
2343
|
await this.getNetwork();
|
|
1724
2344
|
const resolved = await resolveProperties({
|
|
1725
2345
|
transaction: this._getTransactionRequest(transaction),
|
|
1726
2346
|
blockTag: this._getBlockTag(blockTag),
|
|
1727
|
-
ccipReadEnabled: Promise.resolve(transaction.ccipReadEnabled)
|
|
2347
|
+
ccipReadEnabled: Promise.resolve(transaction.ccipReadEnabled),
|
|
1728
2348
|
});
|
|
1729
|
-
return this._call(
|
|
2349
|
+
return this._call(
|
|
2350
|
+
resolved.transaction,
|
|
2351
|
+
resolved.blockTag,
|
|
2352
|
+
resolved.ccipReadEnabled ? 0 : -1,
|
|
2353
|
+
);
|
|
1730
2354
|
}
|
|
1731
2355
|
|
|
1732
|
-
async estimateGas(
|
|
2356
|
+
async estimateGas(
|
|
2357
|
+
transaction: Deferrable<TransactionRequest>,
|
|
2358
|
+
): Promise<BigNumber> {
|
|
1733
2359
|
await this.getNetwork();
|
|
1734
2360
|
const params = await resolveProperties({
|
|
1735
|
-
transaction: this._getTransactionRequest(transaction)
|
|
2361
|
+
transaction: this._getTransactionRequest(transaction),
|
|
1736
2362
|
});
|
|
1737
2363
|
|
|
1738
2364
|
const result = await this.perform("estimateGas", params);
|
|
1739
2365
|
try {
|
|
1740
2366
|
return BigNumber.from(result);
|
|
1741
2367
|
} catch (error) {
|
|
1742
|
-
return logger.throwError(
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
2368
|
+
return logger.throwError(
|
|
2369
|
+
"bad result from backend",
|
|
2370
|
+
Logger.errors.SERVER_ERROR,
|
|
2371
|
+
{
|
|
2372
|
+
method: "estimateGas",
|
|
2373
|
+
params,
|
|
2374
|
+
result,
|
|
2375
|
+
error,
|
|
2376
|
+
},
|
|
2377
|
+
);
|
|
1746
2378
|
}
|
|
1747
2379
|
}
|
|
1748
2380
|
|
|
1749
|
-
async _getAddress(
|
|
2381
|
+
async _getAddress(
|
|
2382
|
+
addressOrName: string | Promise<string>,
|
|
2383
|
+
): Promise<string> {
|
|
1750
2384
|
addressOrName = await addressOrName;
|
|
1751
|
-
if (typeof
|
|
1752
|
-
logger.throwArgumentError(
|
|
2385
|
+
if (typeof addressOrName !== "string") {
|
|
2386
|
+
logger.throwArgumentError(
|
|
2387
|
+
"invalid address or ENS name",
|
|
2388
|
+
"name",
|
|
2389
|
+
addressOrName,
|
|
2390
|
+
);
|
|
1753
2391
|
}
|
|
1754
2392
|
|
|
1755
2393
|
const address = await this.resolveName(addressOrName);
|
|
1756
2394
|
if (address == null) {
|
|
1757
|
-
logger.throwError(
|
|
1758
|
-
|
|
1759
|
-
|
|
2395
|
+
logger.throwError(
|
|
2396
|
+
"ENS name not configured",
|
|
2397
|
+
Logger.errors.UNSUPPORTED_OPERATION,
|
|
2398
|
+
{
|
|
2399
|
+
operation: `resolveName(${JSON.stringify(addressOrName)})`,
|
|
2400
|
+
},
|
|
2401
|
+
);
|
|
1760
2402
|
}
|
|
1761
2403
|
return address;
|
|
1762
2404
|
}
|
|
1763
2405
|
|
|
1764
|
-
async _getBlock(
|
|
2406
|
+
async _getBlock(
|
|
2407
|
+
blockHashOrBlockTag: BlockTag | string | Promise<BlockTag | string>,
|
|
2408
|
+
includeTransactions?: boolean,
|
|
2409
|
+
): Promise<Block | BlockWithTransactions> {
|
|
1765
2410
|
await this.getNetwork();
|
|
1766
2411
|
|
|
1767
2412
|
blockHashOrBlockTag = await blockHashOrBlockTag;
|
|
@@ -1770,7 +2415,7 @@ export class BaseProvider extends Provider implements EnsProvider {
|
|
|
1770
2415
|
let blockNumber = -128;
|
|
1771
2416
|
|
|
1772
2417
|
const params: { [key: string]: any } = {
|
|
1773
|
-
includeTransactions: !!includeTransactions
|
|
2418
|
+
includeTransactions: !!includeTransactions,
|
|
1774
2419
|
};
|
|
1775
2420
|
|
|
1776
2421
|
if (isHexString(blockHashOrBlockTag, 32)) {
|
|
@@ -1782,182 +2427,254 @@ export class BaseProvider extends Provider implements EnsProvider {
|
|
|
1782
2427
|
blockNumber = parseInt(params.blockTag.substring(2), 16);
|
|
1783
2428
|
}
|
|
1784
2429
|
} catch (error) {
|
|
1785
|
-
logger.throwArgumentError(
|
|
2430
|
+
logger.throwArgumentError(
|
|
2431
|
+
"invalid block hash or block tag",
|
|
2432
|
+
"blockHashOrBlockTag",
|
|
2433
|
+
blockHashOrBlockTag,
|
|
2434
|
+
);
|
|
1786
2435
|
}
|
|
1787
2436
|
}
|
|
1788
2437
|
|
|
1789
|
-
return poll(
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
2438
|
+
return poll(
|
|
2439
|
+
async () => {
|
|
2440
|
+
const block = await this.perform("getBlock", params);
|
|
2441
|
+
|
|
2442
|
+
// Block was not found
|
|
2443
|
+
if (block == null) {
|
|
2444
|
+
// For blockhashes, if we didn't say it existed, that blockhash may
|
|
2445
|
+
// not exist. If we did see it though, perhaps from a log, we know
|
|
2446
|
+
// it exists, and this node is just not caught up yet.
|
|
2447
|
+
if (params.blockHash != null) {
|
|
2448
|
+
if (this._emitted["b:" + params.blockHash] == null) {
|
|
2449
|
+
return null;
|
|
2450
|
+
}
|
|
2451
|
+
}
|
|
1794
2452
|
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
2453
|
+
// For block tags, if we are asking for a future block, we return null
|
|
2454
|
+
if (params.blockTag != null) {
|
|
2455
|
+
if (blockNumber > (this._emitted.block as number)) {
|
|
2456
|
+
return null;
|
|
2457
|
+
}
|
|
2458
|
+
}
|
|
1801
2459
|
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
if (blockNumber > (this._emitted.block as number)) { return null; }
|
|
2460
|
+
// Retry on the next block
|
|
2461
|
+
return undefined;
|
|
1805
2462
|
}
|
|
1806
2463
|
|
|
1807
|
-
//
|
|
1808
|
-
|
|
1809
|
-
|
|
2464
|
+
// Add transactions
|
|
2465
|
+
if (includeTransactions) {
|
|
2466
|
+
let blockNumber: number = null;
|
|
2467
|
+
for (let i = 0; i < block.transactions.length; i++) {
|
|
2468
|
+
const tx = block.transactions[i];
|
|
2469
|
+
if (tx.blockNumber == null) {
|
|
2470
|
+
tx.confirmations = 0;
|
|
2471
|
+
} else if (tx.confirmations == null) {
|
|
2472
|
+
if (blockNumber == null) {
|
|
2473
|
+
blockNumber =
|
|
2474
|
+
await this._getInternalBlockNumber(
|
|
2475
|
+
100 + 2 * this.pollingInterval,
|
|
2476
|
+
);
|
|
2477
|
+
}
|
|
1810
2478
|
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
} else if (tx.confirmations == null) {
|
|
1820
|
-
if (blockNumber == null) {
|
|
1821
|
-
blockNumber = await this._getInternalBlockNumber(100 + 2 * this.pollingInterval);
|
|
2479
|
+
// Add the confirmations using the fast block number (pessimistic)
|
|
2480
|
+
let confirmations =
|
|
2481
|
+
blockNumber - tx.blockNumber + 1;
|
|
2482
|
+
if (confirmations <= 0) {
|
|
2483
|
+
confirmations = 1;
|
|
2484
|
+
}
|
|
2485
|
+
tx.confirmations = confirmations;
|
|
1822
2486
|
}
|
|
1823
|
-
|
|
1824
|
-
// Add the confirmations using the fast block number (pessimistic)
|
|
1825
|
-
let confirmations = (blockNumber - tx.blockNumber) + 1;
|
|
1826
|
-
if (confirmations <= 0) { confirmations = 1; }
|
|
1827
|
-
tx.confirmations = confirmations;
|
|
1828
2487
|
}
|
|
1829
|
-
}
|
|
1830
|
-
|
|
1831
|
-
const blockWithTxs: any = this.formatter.blockWithTransactions(block);
|
|
1832
|
-
blockWithTxs.transactions = blockWithTxs.transactions.map((tx: TransactionResponse) => this._wrapTransaction(tx));
|
|
1833
|
-
return blockWithTxs;
|
|
1834
|
-
}
|
|
1835
|
-
return this.formatter.block(block);
|
|
1836
2488
|
|
|
1837
|
-
|
|
2489
|
+
const blockWithTxs: any =
|
|
2490
|
+
this.formatter.blockWithTransactions(block);
|
|
2491
|
+
blockWithTxs.transactions = blockWithTxs.transactions.map(
|
|
2492
|
+
(tx: TransactionResponse) => this._wrapTransaction(tx),
|
|
2493
|
+
);
|
|
2494
|
+
return blockWithTxs;
|
|
2495
|
+
}
|
|
2496
|
+
return this.formatter.block(block);
|
|
2497
|
+
},
|
|
2498
|
+
{ oncePoll: this },
|
|
2499
|
+
);
|
|
1838
2500
|
}
|
|
1839
2501
|
|
|
1840
|
-
getBlock(
|
|
1841
|
-
|
|
2502
|
+
getBlock(
|
|
2503
|
+
blockHashOrBlockTag: BlockTag | string | Promise<BlockTag | string>,
|
|
2504
|
+
): Promise<Block> {
|
|
2505
|
+
return <Promise<Block>>this._getBlock(blockHashOrBlockTag, false);
|
|
1842
2506
|
}
|
|
1843
2507
|
|
|
1844
|
-
getBlockWithTransactions(
|
|
1845
|
-
|
|
2508
|
+
getBlockWithTransactions(
|
|
2509
|
+
blockHashOrBlockTag: BlockTag | string | Promise<BlockTag | string>,
|
|
2510
|
+
): Promise<BlockWithTransactions> {
|
|
2511
|
+
return <Promise<BlockWithTransactions>>(
|
|
2512
|
+
this._getBlock(blockHashOrBlockTag, true)
|
|
2513
|
+
);
|
|
1846
2514
|
}
|
|
1847
2515
|
|
|
1848
|
-
async getTransaction(
|
|
2516
|
+
async getTransaction(
|
|
2517
|
+
transactionHash: string | Promise<string>,
|
|
2518
|
+
): Promise<TransactionResponse> {
|
|
1849
2519
|
await this.getNetwork();
|
|
1850
2520
|
transactionHash = await transactionHash;
|
|
1851
2521
|
|
|
1852
|
-
const params = {
|
|
2522
|
+
const params = {
|
|
2523
|
+
transactionHash: this.formatter.hash(transactionHash, true),
|
|
2524
|
+
};
|
|
1853
2525
|
|
|
1854
|
-
return poll(
|
|
1855
|
-
|
|
2526
|
+
return poll(
|
|
2527
|
+
async () => {
|
|
2528
|
+
const result = await this.perform("getTransaction", params);
|
|
1856
2529
|
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
2530
|
+
if (result == null) {
|
|
2531
|
+
if (this._emitted["t:" + transactionHash] == null) {
|
|
2532
|
+
return null;
|
|
2533
|
+
}
|
|
2534
|
+
return undefined;
|
|
1860
2535
|
}
|
|
1861
|
-
return undefined;
|
|
1862
|
-
}
|
|
1863
2536
|
|
|
1864
|
-
|
|
2537
|
+
const tx = this.formatter.transactionResponse(result);
|
|
1865
2538
|
|
|
1866
|
-
|
|
1867
|
-
|
|
2539
|
+
if (tx.blockNumber == null) {
|
|
2540
|
+
tx.confirmations = 0;
|
|
2541
|
+
} else if (tx.confirmations == null) {
|
|
2542
|
+
const blockNumber = await this._getInternalBlockNumber(
|
|
2543
|
+
100 + 2 * this.pollingInterval,
|
|
2544
|
+
);
|
|
1868
2545
|
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
}
|
|
2546
|
+
// Add the confirmations using the fast block number (pessimistic)
|
|
2547
|
+
let confirmations = blockNumber - tx.blockNumber + 1;
|
|
2548
|
+
if (confirmations <= 0) {
|
|
2549
|
+
confirmations = 1;
|
|
2550
|
+
}
|
|
2551
|
+
tx.confirmations = confirmations;
|
|
2552
|
+
}
|
|
1877
2553
|
|
|
1878
|
-
|
|
1879
|
-
|
|
2554
|
+
return this._wrapTransaction(tx);
|
|
2555
|
+
},
|
|
2556
|
+
{ oncePoll: this },
|
|
2557
|
+
);
|
|
1880
2558
|
}
|
|
1881
2559
|
|
|
1882
|
-
async getTransactionReceipt(
|
|
2560
|
+
async getTransactionReceipt(
|
|
2561
|
+
transactionHash: string | Promise<string>,
|
|
2562
|
+
): Promise<TransactionReceipt> {
|
|
1883
2563
|
await this.getNetwork();
|
|
1884
2564
|
|
|
1885
2565
|
transactionHash = await transactionHash;
|
|
1886
2566
|
|
|
1887
|
-
const params = {
|
|
2567
|
+
const params = {
|
|
2568
|
+
transactionHash: this.formatter.hash(transactionHash, true),
|
|
2569
|
+
};
|
|
1888
2570
|
|
|
1889
|
-
return poll(
|
|
1890
|
-
|
|
2571
|
+
return poll(
|
|
2572
|
+
async () => {
|
|
2573
|
+
const result = await this.perform(
|
|
2574
|
+
"getTransactionReceipt",
|
|
2575
|
+
params,
|
|
2576
|
+
);
|
|
1891
2577
|
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
2578
|
+
if (result == null) {
|
|
2579
|
+
if (this._emitted["t:" + transactionHash] == null) {
|
|
2580
|
+
return null;
|
|
2581
|
+
}
|
|
2582
|
+
return undefined;
|
|
1895
2583
|
}
|
|
1896
|
-
return undefined;
|
|
1897
|
-
}
|
|
1898
2584
|
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
2585
|
+
// "geth-etc" returns receipts before they are ready
|
|
2586
|
+
if (result.blockHash == null) {
|
|
2587
|
+
return undefined;
|
|
2588
|
+
}
|
|
1903
2589
|
|
|
1904
|
-
|
|
1905
|
-
receipt.confirmations = 0;
|
|
2590
|
+
const receipt = this.formatter.receipt(result);
|
|
1906
2591
|
|
|
1907
|
-
|
|
1908
|
-
|
|
2592
|
+
if (receipt.blockNumber == null) {
|
|
2593
|
+
receipt.confirmations = 0;
|
|
2594
|
+
} else if (receipt.confirmations == null) {
|
|
2595
|
+
const blockNumber = await this._getInternalBlockNumber(
|
|
2596
|
+
100 + 2 * this.pollingInterval,
|
|
2597
|
+
);
|
|
1909
2598
|
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
2599
|
+
// Add the confirmations using the fast block number (pessimistic)
|
|
2600
|
+
let confirmations = blockNumber - receipt.blockNumber + 1;
|
|
2601
|
+
if (confirmations <= 0) {
|
|
2602
|
+
confirmations = 1;
|
|
2603
|
+
}
|
|
2604
|
+
receipt.confirmations = confirmations;
|
|
2605
|
+
}
|
|
1915
2606
|
|
|
1916
|
-
|
|
1917
|
-
|
|
2607
|
+
return receipt;
|
|
2608
|
+
},
|
|
2609
|
+
{ oncePoll: this },
|
|
2610
|
+
);
|
|
1918
2611
|
}
|
|
1919
2612
|
|
|
1920
|
-
async getLogs(
|
|
2613
|
+
async getLogs(
|
|
2614
|
+
filter:
|
|
2615
|
+
| Filter
|
|
2616
|
+
| FilterByBlockHash
|
|
2617
|
+
| Promise<Filter | FilterByBlockHash>,
|
|
2618
|
+
): Promise<Array<Log>> {
|
|
1921
2619
|
await this.getNetwork();
|
|
1922
|
-
const params = await resolveProperties({
|
|
2620
|
+
const params = await resolveProperties({
|
|
2621
|
+
filter: this._getFilter(filter),
|
|
2622
|
+
});
|
|
1923
2623
|
const logs: Array<Log> = await this.perform("getLogs", params);
|
|
1924
2624
|
logs.forEach((log) => {
|
|
1925
|
-
if (log.removed == null) {
|
|
2625
|
+
if (log.removed == null) {
|
|
2626
|
+
log.removed = false;
|
|
2627
|
+
}
|
|
1926
2628
|
});
|
|
1927
|
-
return Formatter.arrayOf(this.formatter.filterLog.bind(this.formatter))(
|
|
2629
|
+
return Formatter.arrayOf(this.formatter.filterLog.bind(this.formatter))(
|
|
2630
|
+
logs,
|
|
2631
|
+
);
|
|
1928
2632
|
}
|
|
1929
2633
|
|
|
1930
2634
|
async getEtherPrice(): Promise<number> {
|
|
1931
2635
|
await this.getNetwork();
|
|
1932
|
-
return this.perform("getEtherPrice", {
|
|
2636
|
+
return this.perform("getEtherPrice", {});
|
|
1933
2637
|
}
|
|
1934
2638
|
|
|
1935
|
-
async _getBlockTag(
|
|
2639
|
+
async _getBlockTag(
|
|
2640
|
+
blockTag: BlockTag | Promise<BlockTag>,
|
|
2641
|
+
): Promise<BlockTag> {
|
|
1936
2642
|
blockTag = await blockTag;
|
|
1937
2643
|
|
|
1938
|
-
if (typeof
|
|
2644
|
+
if (typeof blockTag === "number" && blockTag < 0) {
|
|
1939
2645
|
if (blockTag % 1) {
|
|
1940
|
-
logger.throwArgumentError(
|
|
2646
|
+
logger.throwArgumentError(
|
|
2647
|
+
"invalid BlockTag",
|
|
2648
|
+
"blockTag",
|
|
2649
|
+
blockTag,
|
|
2650
|
+
);
|
|
1941
2651
|
}
|
|
1942
2652
|
|
|
1943
|
-
let blockNumber = await this._getInternalBlockNumber(
|
|
2653
|
+
let blockNumber = await this._getInternalBlockNumber(
|
|
2654
|
+
100 + 2 * this.pollingInterval,
|
|
2655
|
+
);
|
|
1944
2656
|
blockNumber += blockTag;
|
|
1945
|
-
if (blockNumber < 0) {
|
|
1946
|
-
|
|
2657
|
+
if (blockNumber < 0) {
|
|
2658
|
+
blockNumber = 0;
|
|
2659
|
+
}
|
|
2660
|
+
return this.formatter.blockTag(blockNumber);
|
|
1947
2661
|
}
|
|
1948
2662
|
|
|
1949
2663
|
return this.formatter.blockTag(blockTag);
|
|
1950
2664
|
}
|
|
1951
2665
|
|
|
1952
|
-
|
|
1953
2666
|
async getResolver(name: string): Promise<null | Resolver> {
|
|
1954
2667
|
let currentName = name;
|
|
1955
2668
|
while (true) {
|
|
1956
|
-
if (currentName === "" || currentName === ".") {
|
|
2669
|
+
if (currentName === "" || currentName === ".") {
|
|
2670
|
+
return null;
|
|
2671
|
+
}
|
|
1957
2672
|
|
|
1958
2673
|
// Optimization since the eth node cannot change and does
|
|
1959
2674
|
// not have a wildcard resolver
|
|
1960
|
-
if (name !== "eth" && currentName === "eth") {
|
|
2675
|
+
if (name !== "eth" && currentName === "eth") {
|
|
2676
|
+
return null;
|
|
2677
|
+
}
|
|
1961
2678
|
|
|
1962
2679
|
// Check the current node for a resolver
|
|
1963
2680
|
const addr = await this._getResolver(currentName, "getResolver");
|
|
@@ -1967,7 +2684,12 @@ export class BaseProvider extends Provider implements EnsProvider {
|
|
|
1967
2684
|
const resolver = new Resolver(this, addr, name);
|
|
1968
2685
|
|
|
1969
2686
|
// Legacy resolver found, using EIP-2544 so it isn't safe to use
|
|
1970
|
-
if (
|
|
2687
|
+
if (
|
|
2688
|
+
currentName !== name &&
|
|
2689
|
+
!(await resolver.supportsWildcard())
|
|
2690
|
+
) {
|
|
2691
|
+
return null;
|
|
2692
|
+
}
|
|
1971
2693
|
|
|
1972
2694
|
return resolver;
|
|
1973
2695
|
}
|
|
@@ -1975,11 +2697,12 @@ export class BaseProvider extends Provider implements EnsProvider {
|
|
|
1975
2697
|
// Get the parent node
|
|
1976
2698
|
currentName = currentName.split(".").slice(1).join(".");
|
|
1977
2699
|
}
|
|
1978
|
-
|
|
1979
2700
|
}
|
|
1980
2701
|
|
|
1981
2702
|
async _getResolver(name: string, operation?: string): Promise<string> {
|
|
1982
|
-
if (operation == null) {
|
|
2703
|
+
if (operation == null) {
|
|
2704
|
+
operation = "ENS";
|
|
2705
|
+
}
|
|
1983
2706
|
|
|
1984
2707
|
const network = await this.getNetwork();
|
|
1985
2708
|
|
|
@@ -1988,7 +2711,7 @@ export class BaseProvider extends Provider implements EnsProvider {
|
|
|
1988
2711
|
logger.throwError(
|
|
1989
2712
|
"network does not support ENS",
|
|
1990
2713
|
Logger.errors.UNSUPPORTED_OPERATION,
|
|
1991
|
-
{ operation, network: network.name }
|
|
2714
|
+
{ operation, network: network.name },
|
|
1992
2715
|
);
|
|
1993
2716
|
}
|
|
1994
2717
|
|
|
@@ -1996,7 +2719,7 @@ export class BaseProvider extends Provider implements EnsProvider {
|
|
|
1996
2719
|
// keccak256("resolver(bytes32)")
|
|
1997
2720
|
const addrData = await this.call({
|
|
1998
2721
|
to: network.ensAddress,
|
|
1999
|
-
data:
|
|
2722
|
+
data: "0x0178b8bf" + namehash(name).substring(2),
|
|
2000
2723
|
});
|
|
2001
2724
|
return this.formatter.callAddress(addrData);
|
|
2002
2725
|
} catch (error) {
|
|
@@ -2014,37 +2737,50 @@ export class BaseProvider extends Provider implements EnsProvider {
|
|
|
2014
2737
|
return Promise.resolve(this.formatter.address(name));
|
|
2015
2738
|
} catch (error) {
|
|
2016
2739
|
// If is is a hexstring, the address is bad (See #694)
|
|
2017
|
-
if (isHexString(name)) {
|
|
2740
|
+
if (isHexString(name)) {
|
|
2741
|
+
throw error;
|
|
2742
|
+
}
|
|
2018
2743
|
}
|
|
2019
2744
|
|
|
2020
|
-
if (typeof
|
|
2745
|
+
if (typeof name !== "string") {
|
|
2021
2746
|
logger.throwArgumentError("invalid ENS name", "name", name);
|
|
2022
2747
|
}
|
|
2023
2748
|
|
|
2024
2749
|
// Get the addr from the resolver
|
|
2025
2750
|
const resolver = await this.getResolver(name);
|
|
2026
|
-
if (!resolver) {
|
|
2751
|
+
if (!resolver) {
|
|
2752
|
+
return null;
|
|
2753
|
+
}
|
|
2027
2754
|
|
|
2028
2755
|
return await resolver.getAddress();
|
|
2029
2756
|
}
|
|
2030
2757
|
|
|
2031
|
-
async lookupAddress(
|
|
2758
|
+
async lookupAddress(
|
|
2759
|
+
address: string | Promise<string>,
|
|
2760
|
+
): Promise<null | string> {
|
|
2032
2761
|
address = await address;
|
|
2033
2762
|
address = this.formatter.address(address);
|
|
2034
2763
|
|
|
2035
2764
|
const node = address.substring(2).toLowerCase() + ".addr.reverse";
|
|
2036
2765
|
|
|
2037
2766
|
const resolverAddr = await this._getResolver(node, "lookupAddress");
|
|
2038
|
-
if (resolverAddr == null) {
|
|
2767
|
+
if (resolverAddr == null) {
|
|
2768
|
+
return null;
|
|
2769
|
+
}
|
|
2039
2770
|
|
|
2040
2771
|
// keccak("name(bytes32)")
|
|
2041
|
-
const name = _parseString(
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2772
|
+
const name = _parseString(
|
|
2773
|
+
await this.call({
|
|
2774
|
+
to: resolverAddr,
|
|
2775
|
+
data: "0x691f3431" + namehash(node).substring(2),
|
|
2776
|
+
}),
|
|
2777
|
+
0,
|
|
2778
|
+
);
|
|
2045
2779
|
|
|
2046
2780
|
const addr = await this.resolveName(name);
|
|
2047
|
-
if (addr != address) {
|
|
2781
|
+
if (addr != address) {
|
|
2782
|
+
return null;
|
|
2783
|
+
}
|
|
2048
2784
|
|
|
2049
2785
|
return name;
|
|
2050
2786
|
}
|
|
@@ -2058,56 +2794,78 @@ export class BaseProvider extends Provider implements EnsProvider {
|
|
|
2058
2794
|
const node = address.substring(2).toLowerCase() + ".addr.reverse";
|
|
2059
2795
|
|
|
2060
2796
|
const resolverAddress = await this._getResolver(node, "getAvatar");
|
|
2061
|
-
if (!resolverAddress) {
|
|
2797
|
+
if (!resolverAddress) {
|
|
2798
|
+
return null;
|
|
2799
|
+
}
|
|
2062
2800
|
|
|
2063
2801
|
// Try resolving the avatar against the addr.reverse resolver
|
|
2064
2802
|
resolver = new Resolver(this, resolverAddress, node);
|
|
2065
2803
|
try {
|
|
2066
2804
|
const avatar = await resolver.getAvatar();
|
|
2067
|
-
if (avatar) {
|
|
2805
|
+
if (avatar) {
|
|
2806
|
+
return avatar.url;
|
|
2807
|
+
}
|
|
2068
2808
|
} catch (error) {
|
|
2069
|
-
if (error.code !== Logger.errors.CALL_EXCEPTION) {
|
|
2809
|
+
if (error.code !== Logger.errors.CALL_EXCEPTION) {
|
|
2810
|
+
throw error;
|
|
2811
|
+
}
|
|
2070
2812
|
}
|
|
2071
2813
|
|
|
2072
2814
|
// Try getting the name and performing forward lookup; allowing wildcards
|
|
2073
2815
|
try {
|
|
2074
2816
|
// keccak("name(bytes32)")
|
|
2075
|
-
const name = _parseString(
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2817
|
+
const name = _parseString(
|
|
2818
|
+
await this.call({
|
|
2819
|
+
to: resolverAddress,
|
|
2820
|
+
data: "0x691f3431" + namehash(node).substring(2),
|
|
2821
|
+
}),
|
|
2822
|
+
0,
|
|
2823
|
+
);
|
|
2079
2824
|
resolver = await this.getResolver(name);
|
|
2080
2825
|
} catch (error) {
|
|
2081
|
-
if (error.code !== Logger.errors.CALL_EXCEPTION) {
|
|
2826
|
+
if (error.code !== Logger.errors.CALL_EXCEPTION) {
|
|
2827
|
+
throw error;
|
|
2828
|
+
}
|
|
2082
2829
|
return null;
|
|
2083
2830
|
}
|
|
2084
|
-
|
|
2085
2831
|
} else {
|
|
2086
2832
|
// ENS name; forward lookup with wildcard
|
|
2087
2833
|
resolver = await this.getResolver(nameOrAddress);
|
|
2088
|
-
if (!resolver) {
|
|
2834
|
+
if (!resolver) {
|
|
2835
|
+
return null;
|
|
2836
|
+
}
|
|
2089
2837
|
}
|
|
2090
2838
|
|
|
2091
2839
|
const avatar = await resolver.getAvatar();
|
|
2092
|
-
if (avatar == null) {
|
|
2840
|
+
if (avatar == null) {
|
|
2841
|
+
return null;
|
|
2842
|
+
}
|
|
2093
2843
|
|
|
2094
2844
|
return avatar.url;
|
|
2095
2845
|
}
|
|
2096
2846
|
|
|
2097
2847
|
perform(method: string, params: any): Promise<any> {
|
|
2098
|
-
return logger.throwError(
|
|
2848
|
+
return logger.throwError(
|
|
2849
|
+
method + " not implemented",
|
|
2850
|
+
Logger.errors.NOT_IMPLEMENTED,
|
|
2851
|
+
{ operation: method },
|
|
2852
|
+
);
|
|
2099
2853
|
}
|
|
2100
2854
|
|
|
2101
2855
|
_startEvent(event: Event): void {
|
|
2102
|
-
this.polling =
|
|
2856
|
+
this.polling = this._events.filter((e) => e.pollable()).length > 0;
|
|
2103
2857
|
}
|
|
2104
2858
|
|
|
2105
2859
|
_stopEvent(event: Event): void {
|
|
2106
|
-
this.polling =
|
|
2860
|
+
this.polling = this._events.filter((e) => e.pollable()).length > 0;
|
|
2107
2861
|
}
|
|
2108
2862
|
|
|
2109
|
-
_addEventListener(
|
|
2110
|
-
|
|
2863
|
+
_addEventListener(
|
|
2864
|
+
eventName: EventType,
|
|
2865
|
+
listener: Listener,
|
|
2866
|
+
once: boolean,
|
|
2867
|
+
): this {
|
|
2868
|
+
const event = new Event(getEventTag(eventName), listener, once);
|
|
2111
2869
|
this._events.push(event);
|
|
2112
2870
|
this._startEvent(event);
|
|
2113
2871
|
|
|
@@ -2122,15 +2880,16 @@ export class BaseProvider extends Provider implements EnsProvider {
|
|
|
2122
2880
|
return this._addEventListener(eventName, listener, true);
|
|
2123
2881
|
}
|
|
2124
2882
|
|
|
2125
|
-
|
|
2126
2883
|
emit(eventName: EventType, ...args: Array<any>): boolean {
|
|
2127
2884
|
let result = false;
|
|
2128
2885
|
|
|
2129
|
-
let stopped: Array<Event> = [
|
|
2886
|
+
let stopped: Array<Event> = [];
|
|
2130
2887
|
|
|
2131
2888
|
let eventTag = getEventTag(eventName);
|
|
2132
2889
|
this._events = this._events.filter((event) => {
|
|
2133
|
-
if (event.tag !== eventTag) {
|
|
2890
|
+
if (event.tag !== eventTag) {
|
|
2891
|
+
return true;
|
|
2892
|
+
}
|
|
2134
2893
|
|
|
2135
2894
|
setTimeout(() => {
|
|
2136
2895
|
event.listener.apply(this, args);
|
|
@@ -2146,17 +2905,21 @@ export class BaseProvider extends Provider implements EnsProvider {
|
|
|
2146
2905
|
return true;
|
|
2147
2906
|
});
|
|
2148
2907
|
|
|
2149
|
-
stopped.forEach((event) => {
|
|
2908
|
+
stopped.forEach((event) => {
|
|
2909
|
+
this._stopEvent(event);
|
|
2910
|
+
});
|
|
2150
2911
|
|
|
2151
2912
|
return result;
|
|
2152
2913
|
}
|
|
2153
2914
|
|
|
2154
2915
|
listenerCount(eventName?: EventType): number {
|
|
2155
|
-
if (!eventName) {
|
|
2916
|
+
if (!eventName) {
|
|
2917
|
+
return this._events.length;
|
|
2918
|
+
}
|
|
2156
2919
|
|
|
2157
2920
|
let eventTag = getEventTag(eventName);
|
|
2158
2921
|
return this._events.filter((event) => {
|
|
2159
|
-
return
|
|
2922
|
+
return event.tag === eventTag;
|
|
2160
2923
|
}).length;
|
|
2161
2924
|
}
|
|
2162
2925
|
|
|
@@ -2167,7 +2930,7 @@ export class BaseProvider extends Provider implements EnsProvider {
|
|
|
2167
2930
|
|
|
2168
2931
|
let eventTag = getEventTag(eventName);
|
|
2169
2932
|
return this._events
|
|
2170
|
-
.filter((event) =>
|
|
2933
|
+
.filter((event) => event.tag === eventTag)
|
|
2171
2934
|
.map((event) => event.listener);
|
|
2172
2935
|
}
|
|
2173
2936
|
|
|
@@ -2176,40 +2939,50 @@ export class BaseProvider extends Provider implements EnsProvider {
|
|
|
2176
2939
|
return this.removeAllListeners(eventName);
|
|
2177
2940
|
}
|
|
2178
2941
|
|
|
2179
|
-
const stopped: Array<Event> = [
|
|
2942
|
+
const stopped: Array<Event> = [];
|
|
2180
2943
|
|
|
2181
2944
|
let found = false;
|
|
2182
2945
|
|
|
2183
2946
|
let eventTag = getEventTag(eventName);
|
|
2184
2947
|
this._events = this._events.filter((event) => {
|
|
2185
|
-
if (event.tag !== eventTag || event.listener != listener) {
|
|
2186
|
-
|
|
2948
|
+
if (event.tag !== eventTag || event.listener != listener) {
|
|
2949
|
+
return true;
|
|
2950
|
+
}
|
|
2951
|
+
if (found) {
|
|
2952
|
+
return true;
|
|
2953
|
+
}
|
|
2187
2954
|
found = true;
|
|
2188
2955
|
stopped.push(event);
|
|
2189
2956
|
return false;
|
|
2190
2957
|
});
|
|
2191
2958
|
|
|
2192
|
-
stopped.forEach((event) => {
|
|
2959
|
+
stopped.forEach((event) => {
|
|
2960
|
+
this._stopEvent(event);
|
|
2961
|
+
});
|
|
2193
2962
|
|
|
2194
2963
|
return this;
|
|
2195
2964
|
}
|
|
2196
2965
|
|
|
2197
2966
|
removeAllListeners(eventName?: EventType): this {
|
|
2198
|
-
let stopped: Array<Event> = [
|
|
2967
|
+
let stopped: Array<Event> = [];
|
|
2199
2968
|
if (eventName == null) {
|
|
2200
2969
|
stopped = this._events;
|
|
2201
2970
|
|
|
2202
|
-
this._events = [
|
|
2971
|
+
this._events = [];
|
|
2203
2972
|
} else {
|
|
2204
2973
|
const eventTag = getEventTag(eventName);
|
|
2205
2974
|
this._events = this._events.filter((event) => {
|
|
2206
|
-
if (event.tag !== eventTag) {
|
|
2975
|
+
if (event.tag !== eventTag) {
|
|
2976
|
+
return true;
|
|
2977
|
+
}
|
|
2207
2978
|
stopped.push(event);
|
|
2208
2979
|
return false;
|
|
2209
2980
|
});
|
|
2210
2981
|
}
|
|
2211
2982
|
|
|
2212
|
-
stopped.forEach((event) => {
|
|
2983
|
+
stopped.forEach((event) => {
|
|
2984
|
+
this._stopEvent(event);
|
|
2985
|
+
});
|
|
2213
2986
|
|
|
2214
2987
|
return this;
|
|
2215
2988
|
}
|