Skip to content

Commit e97ca3b

Browse files
committed
Merge branch 'wip-6.13'
2 parents 2d2572a + c2d5346 commit e97ca3b

File tree

8 files changed

+126
-39
lines changed

8 files changed

+126
-39
lines changed

src.ts/_tests/test-providers-data.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ describe("Test Networks", function() {
249249
"base", "base-sepolia",
250250
"bnb", "bnbt",
251251
"linea", "linea-sepolia",
252-
"matic", "matic-mumbai", "matic-amoy",
252+
"matic", "matic-amoy",
253253
"optimism", "optimism-sepolia",
254254
"xdai",
255255
];

src.ts/_tests/test-providers-wildcard.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,11 @@ describe("Test EIP-2544 ENS wildcards", function() {
2424
});
2525

2626
describe("Test ENS-DNS gasless resolver", function() {
27-
it("Resolved almonit.org", async function() {
27+
it("Resolved firefly.app", async function() {
2828
this.timeout(10000);
2929

3030
const provider = connect("mainnet");
31-
const addr = await provider.resolveName("almonit.org");
32-
assert.equal(addr, "0x0D59d0f7DcC0fBF0A3305cE0261863aAf7Ab685c", "addr");
31+
const addr = await provider.resolveName("firefly.app");
32+
assert.equal(addr, "0x643aA0A61eADCC9Cc202D1915D942d35D005400C", "addr");
3333
});
3434
});

src.ts/abi/coders/abstract-coder.ts

Lines changed: 56 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
defineProperties, concat, getBytesCopy, getNumber, hexlify,
44
toBeArray, toBigInt, toNumber,
55
assert, assertArgument
6+
/*, isError*/
67
} from "../../utils/index.js";
78

89
import type { BigNumberish, BytesLike } from "../../utils/index.js";
@@ -19,12 +20,44 @@ const passProperties = [ "then" ];
1920

2021
const _guard = { };
2122

23+
const resultNames: WeakMap<Result, ReadonlyArray<null | string>> = new WeakMap();
24+
25+
function getNames(result: Result): ReadonlyArray<null | string> {
26+
return resultNames.get(result)!;
27+
}
28+
function setNames(result: Result, names: ReadonlyArray<null | string>): void {
29+
resultNames.set(result, names);
30+
}
31+
2232
function throwError(name: string, error: Error): never {
2333
const wrapped = new Error(`deferred error during ABI decoding triggered accessing ${ name }`);
2434
(<any>wrapped).error = error;
2535
throw wrapped;
2636
}
2737

38+
function toObject(names: ReadonlyArray<null | string>, items: Result, deep?: boolean): Record<string, any> | Array<any> {
39+
if (names.indexOf(null) >= 0) {
40+
return items.map((item, index) => {
41+
if (item instanceof Result) {
42+
return toObject(getNames(item), item, deep);
43+
}
44+
return item;
45+
});
46+
}
47+
48+
return (<Array<string>>names).reduce((accum, name, index) => {
49+
let item = items.getValue(name);
50+
if (!(name in accum)) {
51+
if (deep && item instanceof Result) {
52+
item = toObject(getNames(item), item, deep);
53+
}
54+
accum[name] = item;
55+
}
56+
return accum;
57+
}, <Record<string, any>>{ });
58+
}
59+
60+
2861
/**
2962
* A [[Result]] is a sub-class of Array, which allows accessing any
3063
* of its values either positionally by its index or, if keys are
@@ -33,6 +66,9 @@ function throwError(name: string, error: Error): never {
3366
* @_docloc: api/abi
3467
*/
3568
export class Result extends Array<any> {
69+
// No longer used; but cannot be removed as it will remove the
70+
// #private field from the .d.ts which may break backwards
71+
// compatibility
3672
readonly #names: ReadonlyArray<null | string>;
3773

3874
[ K: string | number ]: any
@@ -73,21 +109,25 @@ export class Result extends Array<any> {
73109
}, <Map<string, number>>(new Map()));
74110

75111
// Remove any key thats not unique
76-
this.#names = Object.freeze(items.map((item, index) => {
112+
setNames(this, Object.freeze(items.map((item, index) => {
77113
const name = names[index];
78114
if (name != null && nameCounts.get(name) === 1) {
79115
return name;
80116
}
81117
return null;
82-
}));
118+
})));
119+
120+
// Dummy operations to prevent TypeScript from complaining
121+
this.#names = [ ];
122+
if (this.#names == null) { void(this.#names); }
83123

84124
if (!wrap) { return; }
85125

86126
// A wrapped Result is immutable
87127
Object.freeze(this);
88128

89129
// Proxy indices and names so we can trap deferred errors
90-
return new Proxy(this, {
130+
const proxy = new Proxy(this, {
91131
get: (target, prop, receiver) => {
92132
if (typeof(prop) === "string") {
93133

@@ -127,6 +167,7 @@ export class Result extends Array<any> {
127167
return Reflect.get(target, prop, receiver);
128168
}
129169
});
170+
setNames(proxy, getNames(this));
130171
}
131172

132173
/**
@@ -157,21 +198,14 @@ export class Result extends Array<any> {
157198
* any outstanding deferred errors.
158199
*/
159200
toObject(deep?: boolean): Record<string, any> {
160-
return this.#names.reduce((accum, name, index) => {
161-
assert(name != null, "value at index ${ index } unnamed", "UNSUPPORTED_OPERATION", {
201+
const names = getNames(this);
202+
return names.reduce((accum, name, index) => {
203+
204+
assert(name != null, `value at index ${ index } unnamed`, "UNSUPPORTED_OPERATION", {
162205
operation: "toObject()"
163206
});
164207

165-
// Add values for names that don't conflict
166-
if (!(name in accum)) {
167-
let child = this.getValue(name);
168-
if (deep && child instanceof Result) {
169-
child = child.toObject(deep);
170-
}
171-
accum[name] = child;
172-
}
173-
174-
return accum;
208+
return toObject(names, this, deep);
175209
}, <Record<string, any>>{});
176210
}
177211

@@ -192,10 +226,12 @@ export class Result extends Array<any> {
192226
}
193227
if (end > this.length) { end = this.length; }
194228

229+
const _names = getNames(this);
230+
195231
const result: Array<any> = [ ], names: Array<null | string> = [ ];
196232
for (let i = start; i < end; i++) {
197233
result.push(this[i]);
198-
names.push(this.#names[i]);
234+
names.push(_names[i]);
199235
}
200236

201237
return new Result(_guard, result, names);
@@ -205,6 +241,8 @@ export class Result extends Array<any> {
205241
* @_ignore
206242
*/
207243
filter(callback: (el: any, index: number, array: Result) => boolean, thisArg?: any): Result {
244+
const _names = getNames(this);
245+
208246
const result: Array<any> = [ ], names: Array<null | string> = [ ];
209247
for (let i = 0; i < this.length; i++) {
210248
const item = this[i];
@@ -214,7 +252,7 @@ export class Result extends Array<any> {
214252

215253
if (callback.call(thisArg, item, i, this)) {
216254
result.push(item);
217-
names.push(this.#names[i]);
255+
names.push(_names[i]);
218256
}
219257
}
220258

@@ -248,7 +286,7 @@ export class Result extends Array<any> {
248286
* accessible by name.
249287
*/
250288
getValue(name: string): any {
251-
const index = this.#names.indexOf(name);
289+
const index = getNames(this).indexOf(name);
252290
if (index === -1) { return undefined; }
253291

254292
const value = this[index];

src.ts/ethers.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ export type { TypedDataDomain, TypedDataField } from "./hash/index.js";
164164
export type {
165165
Provider, Signer,
166166

167-
AbstractProviderOptions, FallbackProviderOptions,
167+
AbstractProviderOptions, BrowserProviderOptions, FallbackProviderOptions,
168168

169169
AbstractProviderPlugin, BlockParams, BlockTag, ContractRunner, DebugEventBrowserProvider,
170170
Eip1193Provider, EventFilter, Filter, FilterByBlockHash, GasCostParameters,

src.ts/providers/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ export type {
114114
} from "./provider.js";
115115

116116
export type {
117-
DebugEventBrowserProvider, Eip1193Provider
117+
BrowserProviderOptions, DebugEventBrowserProvider, Eip1193Provider
118118
} from "./provider-browser.js";
119119

120120
export type { FallbackProviderOptions } from "./provider-fallback.js";

src.ts/providers/provider-browser.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@ import { assertArgument } from "../utils/index.js";
33
import { JsonRpcApiPollingProvider } from "./provider-jsonrpc.js";
44

55
import type {
6+
JsonRpcApiProviderOptions,
67
JsonRpcError, JsonRpcPayload, JsonRpcResult,
78
JsonRpcSigner
89
} from "./provider-jsonrpc.js";
9-
import type { Networkish } from "./network.js";
10+
import type { Network, Networkish } from "./network.js";
1011

1112
/**
1213
* The interface to an [[link-eip-1193]] provider, which is a standard
@@ -35,6 +36,13 @@ export type DebugEventBrowserProvider = {
3536
error: Error
3637
};
3738

39+
export type BrowserProviderOptions = {
40+
polling?: boolean;
41+
staticNetwork?: null | boolean | Network;
42+
43+
cacheTimeout?: number;
44+
pollingInterval?: number;
45+
};
3846

3947
/**
4048
* A **BrowserProvider** is intended to wrap an injected provider which
@@ -48,10 +56,15 @@ export class BrowserProvider extends JsonRpcApiPollingProvider {
4856
* Connnect to the %%ethereum%% provider, optionally forcing the
4957
* %%network%%.
5058
*/
51-
constructor(ethereum: Eip1193Provider, network?: Networkish) {
59+
constructor(ethereum: Eip1193Provider, network?: Networkish, _options?: BrowserProviderOptions) {
60+
// Copy the options
61+
const options: JsonRpcApiProviderOptions = Object.assign({ },
62+
((_options != null) ? _options: { }),
63+
{ batchMaxCount: 1 });
64+
5265
assertArgument(ethereum && ethereum.request, "invalid EIP-1193 provider", "ethereum", ethereum);
5366

54-
super(network, { batchMaxCount: 1 });
67+
super(network, options);
5568

5669
this.#request = async (method: string, params: Array<any> | Record<string, any>) => {
5770
const payload = { method, params };

src.ts/utils/geturl-browser.ts

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { assert } from "./errors.js";
1+
import { assert, makeError } from "./errors.js";
22

33
import type {
44
FetchGetUrlFunc, FetchRequest, FetchCancelSignal, GetUrlResponse
@@ -27,11 +27,11 @@ declare global {
2727
function fetch(url: string, init: FetchInit): Promise<Response>;
2828
}
2929

30-
// @TODO: timeout is completely ignored; start a Promise.any with a reject?
31-
3230
export function createGetUrl(options?: Record<string, any>): FetchGetUrlFunc {
3331

3432
async function getUrl(req: FetchRequest, _signal?: FetchCancelSignal): Promise<GetUrlResponse> {
33+
assert(_signal == null || !_signal.cancelled, "request cancelled before sending", "CANCELLED");
34+
3535
const protocol = req.url.split(":")[0].toLowerCase();
3636

3737
assert(protocol === "http" || protocol === "https", `unsupported protocol ${ protocol }`, "UNSUPPORTED_OPERATION", {
@@ -43,21 +43,39 @@ export function createGetUrl(options?: Record<string, any>): FetchGetUrlFunc {
4343
operation: "request"
4444
});
4545

46-
let signal: undefined | AbortSignal = undefined;
46+
let error: null | Error = null;
47+
48+
const controller = new AbortController();
49+
50+
const timer = setTimeout(() => {
51+
error = makeError("request timeout", "TIMEOUT");
52+
controller.abort();
53+
}, req.timeout);
54+
4755
if (_signal) {
48-
const controller = new AbortController();
49-
signal = controller.signal;
50-
_signal.addListener(() => { controller.abort(); });
56+
_signal.addListener(() => {
57+
error = makeError("request cancelled", "CANCELLED");
58+
controller.abort();
59+
});
5160
}
5261

5362
const init = {
5463
method: req.method,
5564
headers: new Headers(Array.from(req)),
5665
body: req.body || undefined,
57-
signal
66+
signal: controller.signal
5867
};
5968

60-
const resp = await fetch(req.url, init);
69+
let resp: Awaited<ReturnType<typeof fetch>>;
70+
try {
71+
resp = await fetch(req.url, init);
72+
} catch (_error) {
73+
clearTimeout(timer);
74+
if (error) { throw error; }
75+
throw _error;
76+
}
77+
78+
clearTimeout(timer);
6179

6280
const headers: Record<string, string> = { };
6381
resp.headers.forEach((value, key) => {

src.ts/utils/geturl.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import http from "http";
22
import https from "https";
33
import { gunzipSync } from "zlib";
44

5-
import { assert } from "./errors.js";
5+
import { assert, makeError } from "./errors.js";
66
import { getBytes } from "./data.js";
77

88
import type {
@@ -15,6 +15,8 @@ import type {
1515
export function createGetUrl(options?: Record<string, any>): FetchGetUrlFunc {
1616

1717
async function getUrl(req: FetchRequest, signal?: FetchCancelSignal): Promise<GetUrlResponse> {
18+
// Make sure we weren't cancelled before sending
19+
assert(signal == null || !signal.cancelled, "request cancelled before sending", "CANCELLED");
1820

1921
const protocol = req.url.split(":")[0].toLowerCase();
2022

@@ -35,6 +37,13 @@ export function createGetUrl(options?: Record<string, any>): FetchGetUrlFunc {
3537
if (options.agent) { reqOptions.agent = options.agent; }
3638
}
3739

40+
// Create a Node-specific AbortController, if available
41+
let abort: null | AbortController = null;
42+
try {
43+
abort = new AbortController();
44+
reqOptions.abort = abort.signal;
45+
} catch (e) { console.log(e); }
46+
3847
const request = ((protocol === "http") ? http: https).request(req.url, reqOptions);
3948

4049
request.setTimeout(req.timeout);
@@ -45,8 +54,17 @@ export function createGetUrl(options?: Record<string, any>): FetchGetUrlFunc {
4554
request.end();
4655

4756
return new Promise((resolve, reject) => {
48-
// @TODO: Node 15 added AbortSignal; once we drop support for
49-
// Node14, we can add that in here too
57+
58+
if (signal) {
59+
signal.addListener(() => {
60+
if (abort) { abort.abort(); }
61+
reject(makeError("request cancelled", "CANCELLED"));
62+
});
63+
}
64+
65+
request.on("timeout", () => {
66+
reject(makeError("request timeout", "TIMEOUT"));
67+
});
5068

5169
request.once("response", (resp: http.IncomingMessage) => {
5270
const statusCode = resp.statusCode || 0;

0 commit comments

Comments
 (0)