import { ethers } from 'ethers' ; import { Domain } from './domains' ; type Provider = ethers . providers . Provider ; /**
 * The MultiProvider manages a collection of [Domains] Domain and allows
 * developers to enroll ethers Providers and Signers for each domain. It is
 * intended to enable faster multi-chain development by grouping all chain
 * connections under a single roof.
 *
 *  example export class MultiProvider { private domains : Map < number , Domain > ; private providers : Map < number , Provider > ; private signers : Map < number , ethers . Signer > ; constructor ( ) { this . domains = new Map ( ) ; this . providers = new Map ( ) ; this . signers = new Map ( ) ; } param domain registerDomain ( domain ) { this . domains . set ( domain . id , domain ) ; } get domainNumbers ( ) : number [ ] { return Array . from ( this . domains . keys ( ) ) ; } get missingProviders ( ) : number [ ] { const numbers = this . domainNumbers ; return numbers . filter ( ( number ) => this . providers . has ( number ) ) ; } param nameOrDomain returns resolveDomain ( nameOrDomain ) { if ( typeof nameOrDomain === 'string' ) { const domains = Array . from ( this . domains . values ( ) ) . filter ( ( domain ) => domain . name . toLowerCase ( ) === nameOrDomain . toLowerCase ( ) ) ; if ( domains . length === 0 ) { throw new Error ( `Domain not found: ${ nameOrDomain }` ) ; } return domains [ 0 ] . id ; } else { return nameOrDomain ; } } /**
     * Check whether the  MultiProvider is aware of a domain.
     *
     *  param nameOrDomain returns true if the  Domain has been registered, else false.
      knownDomain ( nameOrDomain ) { try { this . resolveDomain ( nameOrDomain ) ; return true ; } catch ( e ) { return false ; } } /**
     * Get the registered  Domain object (if any)
     *
     *  param nameOrDomain returns A  Domain (if the domain has been registered)
      getDomain ( nameOrDomain ) { return this . domains . get ( this . resolveDomain ( nameOrDomain ) ) ; } /**
     * Get the registered  Domain object (or error)
     *
     *  param nameOrDomain returns A  Domain throws mustGetDomain ( nameOrDomain ) { const domain = this . getDomain ( nameOrDomain ) ; if ( ! domain ) { throw new Error ( `Domain not found: ${ nameOrDomain }` ) ; } return domain ; } /**
     * Resolve the name of a registered  Domain , from its name or number.
     *
     * Similar to `resolveDomain`.
     *
     *  param nameOrDomain returns resolveDomainName ( nameOrDomain ) { return this . getDomain ( nameOrDomain ) ?. name ; } param nameOrDomain param provider registerProvider ( nameOrDomain , provider ) { const domain = this . mustGetDomain ( nameOrDomain ) . id ; try { const signer = this . signers . get ( domain ) ; if ( signer ) { this . signers . set ( domain , signer . connect ( provider ) ) ; } } catch ( e ) { this . unregisterSigner ( domain ) ; } this . providers . set ( domain , provider ) ; } param nameOrDomain param rpc registerRpcProvider ( nameOrDomain , rpc ) { const domain = this . resolveDomain ( nameOrDomain ) ; const provider = new ethers . providers . StaticJsonRpcProvider ( rpc ) ; this . registerProvider ( domain , provider ) ; } param nameOrDomain returns getProvider ( nameOrDomain ) { const domain = this . resolveDomain ( nameOrDomain ) ; return this . providers . get ( domain ) ; } param nameOrDomain returns throws mustGetProvider ( nameOrDomain ) { const provider = this . getProvider ( nameOrDomain ) ; if ( ! provider ) { throw new Error ( 'unregistered name or domain' ) ; } return provider ; } param nameOrDomain param signer registerSigner ( nameOrDomain , signer ) { const domain = this . resolveDomain ( nameOrDomain ) ; const provider = this . providers . get ( domain ) ; if ( ! provider && ! signer . provider ) { throw new Error ( 'Must have a provider before registering signer' ) ; } if ( provider ) { try { signer = signer . connect ( provider ) ; this . signers . set ( domain , signer . connect ( provider ) ) ; return ; } catch ( _ ) { } } if ( ! signer . provider ) { throw new Error ( 'Signer does not permit reconnect and has no provider' ) ; } this . registerProvider ( domain , signer . provider ) ; this . signers . set ( domain , signer ) ; } param nameOrDomain unregisterSigner ( nameOrDomain ) { const domain = this . resolveDomain ( nameOrDomain ) ; if ( ! this . signers . has ( domain ) ) { return ; } const signer = this . signers . get ( domain ) ; if ( signer == null || signer . provider == null ) { throw new Error ( 'signer was missing provider. How?' ) ; } this . signers . delete ( domain ) ; if ( ! this . getProvider ( nameOrDomain ) ) { this . providers . set ( domain , signer . provider ) ; } } /**
     * Clear all signers from all registered domains.
     */ clearSigners ( ) { this . domainNumbers . forEach ( ( domain ) => this . unregisterSigner ( domain ) ) ; } param nameOrDomain param privkey registerWalletSigner ( nameOrDomain , privkey ) { const domain = this . resolveDomain ( nameOrDomain ) ; const wallet = new ethers . Wallet ( privkey ) ; this . registerSigner ( domain , wallet ) ; } param nameOrDomain returns getSigner ( nameOrDomain ) { const domain = this . resolveDomain ( nameOrDomain ) ; return this . signers . get ( domain ) ; } param nameOrDomain returns getConnection ( nameOrDomain ) { return this . getSigner ( nameOrDomain ) ?? this . getProvider ( nameOrDomain ) ; } param nameOrDomain returns async getAddress ( nameOrDomain ) { const signer = this . getSigner ( nameOrDomain ) ; return await signer ?. getAddress ( ) ; } }