@@ -36,14 +36,69 @@ export type DebugEventBrowserProvider = {
3636 error : Error
3737} ;
3838
39+ /**
40+ * Provider info provided by the [[link-eip-6963]] discovery mechanism.
41+ */
42+ export interface Eip6963ProviderInfo {
43+ uuid : string ;
44+ name : string ;
45+ icon : string ;
46+ rdns : string ;
47+ }
48+
49+ interface Eip6963ProviderDetail {
50+ info : Eip6963ProviderInfo ;
51+ provider : Eip1193Provider ;
52+ }
53+
54+ interface Eip6963Announcement {
55+ type : "eip6963:announceProvider" ;
56+ detail : Eip6963ProviderDetail
57+ }
58+
3959export type BrowserProviderOptions = {
4060 polling ?: boolean ;
4161 staticNetwork ?: null | boolean | Network ;
4262
4363 cacheTimeout ?: number ;
4464 pollingInterval ?: number ;
65+
66+ providerInfo ?: Eip6963ProviderInfo ;
4567} ;
4668
69+ /**
70+ * Specifies how [[link-eip-6963]] discovery should proceed.
71+ *
72+ * See: [[BrowserProvider-discover]]
73+ */
74+ export interface BrowserDiscoverOptions {
75+ /**
76+ * Override provider detection with this provider.
77+ */
78+ provider ?: Eip1193Provider ;
79+
80+ /**
81+ * Duration to wait to detect providers. (default: 300ms)
82+ */
83+ timeout ?: number ;
84+
85+ /**
86+ * Return the first detected provider. Otherwise wait for %%timeout%%
87+ * and allowing filtering before selecting the desired provider.
88+ */
89+ anyProvider ?: boolean ;
90+
91+ /**
92+ * Use the provided window context. Useful in non-standard
93+ * environments or to hijack where a provider comes from.
94+ */
95+ window ?: any ;
96+ }
97+
98+ // @TODO : Future, provide some sort of filter mechansm callback along
99+ // with exposing the following types
100+
101+
47102/**
48103 * A **BrowserProvider** is intended to wrap an injected provider which
49104 * adheres to the [[link-eip-1193]] standard, which most (if not all)
@@ -52,11 +107,14 @@ export type BrowserProviderOptions = {
52107export class BrowserProvider extends JsonRpcApiPollingProvider {
53108 #request: ( method : string , params : Array < any > | Record < string , any > ) => Promise < any > ;
54109
110+ #providerInfo: null | Eip6963ProviderInfo ;
111+
55112 /**
56113 * Connect to the %%ethereum%% provider, optionally forcing the
57114 * %%network%%.
58115 */
59116 constructor ( ethereum : Eip1193Provider , network ?: Networkish , _options ?: BrowserProviderOptions ) {
117+
60118 // Copy the options
61119 const options : JsonRpcApiProviderOptions = Object . assign ( { } ,
62120 ( ( _options != null ) ? _options : { } ) ,
@@ -66,6 +124,11 @@ export class BrowserProvider extends JsonRpcApiPollingProvider {
66124
67125 super ( network , options ) ;
68126
127+ this . #providerInfo = null ;
128+ if ( _options && _options . providerInfo ) {
129+ this . #providerInfo = _options . providerInfo ;
130+ }
131+
69132 this . #request = async ( method : string , params : Array < any > | Record < string , any > ) => {
70133 const payload = { method, params } ;
71134 this . emit ( "debug" , { action : "sendEip1193Request" , payload } ) ;
@@ -84,6 +147,10 @@ export class BrowserProvider extends JsonRpcApiPollingProvider {
84147 } ;
85148 }
86149
150+ get providerInfo ( ) : null | Eip6963ProviderInfo {
151+ return this . #providerInfo;
152+ }
153+
87154 async send ( method : string , params : Array < any > | Record < string , any > ) : Promise < any > {
88155 await this . _start ( ) ;
89156
@@ -109,7 +176,7 @@ export class BrowserProvider extends JsonRpcApiPollingProvider {
109176 error = JSON . parse ( JSON . stringify ( error ) ) ;
110177
111178 // EIP-1193 gives us some machine-readable error codes, so rewrite
112- // them into
179+ // them into Ethers standard errors.
113180 switch ( error . error . code || - 1 ) {
114181 case 4001 :
115182 error . error . message = `ethers-user-denied: ${ error . error . message } ` ;
@@ -142,9 +209,7 @@ export class BrowserProvider extends JsonRpcApiPollingProvider {
142209
143210 if ( ! ( await this . hasSigner ( address ) ) ) {
144211 try {
145- //const resp =
146212 await this . #request( "eth_requestAccounts" , [ ] ) ;
147- //console.log("RESP", resp);
148213
149214 } catch ( error : any ) {
150215 const payload = error . payload ;
@@ -154,4 +219,60 @@ export class BrowserProvider extends JsonRpcApiPollingProvider {
154219
155220 return await super . getSigner ( address ) ;
156221 }
222+
223+ /**
224+ * Discover and connect to a Provider in the Browser using the
225+ * [[link-eip-6963]] discovery mechanism. If no providers are
226+ * present, ``null`` is resolved.
227+ */
228+ static async discover ( options ?: BrowserDiscoverOptions ) : Promise < null | BrowserProvider > {
229+ if ( options == null ) { options = { } ; }
230+
231+ if ( options . provider ) {
232+ return new BrowserProvider ( options . provider ) ;
233+ }
234+
235+ const context = options . window ? options . window :
236+ ( typeof ( window ) !== "undefined" ) ? window : null ;
237+
238+ if ( context == null ) { return null ; }
239+
240+ const anyProvider = options . anyProvider ;
241+ if ( anyProvider && context . ethereum ) {
242+ return new BrowserProvider ( context . ethereum ) ;
243+ }
244+
245+ const timeout = options . timeout ? options . timeout : 300 ;
246+ if ( timeout === 0 ) { return null ; }
247+
248+ return await ( new Promise ( ( resolve ) => {
249+ let found : Array < any > = [ ] ;
250+
251+ const addProvider = ( event : Eip6963Announcement ) => {
252+ found . push ( event . detail ) ;
253+ if ( anyProvider ) { finalize ( ) ; }
254+ } ;
255+
256+ const finalize = ( ) => {
257+ clearTimeout ( timer ) ;
258+ if ( found . length ) {
259+ const { provider, info } = found [ 0 ] ;
260+ resolve ( new BrowserProvider ( provider , undefined , {
261+ providerInfo : info
262+ } ) ) ;
263+ } else {
264+ resolve ( null ) ;
265+ }
266+ context . removeEventListener ( < any > "eip6963:announceProvider" ,
267+ addProvider ) ;
268+ } ;
269+
270+ const timer = setTimeout ( ( ) => { finalize ( ) ; } , timeout ) ;
271+
272+ context . addEventListener ( < any > "eip6963:announceProvider" ,
273+ addProvider ) ;
274+
275+ context . dispatchEvent ( new Event ( "eip6963:requestProvider" ) ) ;
276+ } ) ) ;
277+ }
157278}
0 commit comments