All files / ethers.js/src.ts/providers default-provider.ts

34.65% Statements 70/202
100% Branches 0/0
0% Functions 0/2
34.65% Lines 70/202

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 2031x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x         1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x                                                                                                                                                                                                                                                                  
 
import { assert } from "../utils/index.js";
 
import { AnkrProvider } from "./provider-ankr.js";
import { AlchemyProvider } from "./provider-alchemy.js";
//import { BlockscoutProvider } from "./provider-blockscout.js";
import { ChainstackProvider } from "./provider-chainstack.js";
import { CloudflareProvider } from "./provider-cloudflare.js";
import { EtherscanProvider } from "./provider-etherscan.js";
import { InfuraProvider } from "./provider-infura.js";
//import { PocketProvider } from "./provider-pocket.js";
import { QuickNodeProvider } from "./provider-quicknode.js";
 
import { FallbackProvider } from "./provider-fallback.js";
import { JsonRpcProvider } from "./provider-jsonrpc.js";
import { Network } from "./network.js";
import { WebSocketProvider } from "./provider-websocket.js";
 
import type { AbstractProvider } from "./abstract-provider.js";
import type { Networkish } from "./network.js";
import { WebSocketLike } from "./provider-websocket.js";
 
function isWebSocketLike(value: any): value is WebSocketLike {
    return (value && typeof(value.send) === "function" &&
        typeof(value.close) === "function");
}
 
const Testnets = "goerli kovan sepolia classicKotti optimism-goerli arbitrum-goerli matic-mumbai bnbt".split(" ");
 
/**
 *  Returns a default provider for %%network%%.
 *
 *  If %%network%% is a [[WebSocketLike]] or string that begins with
 *  ``"ws:"`` or ``"wss:"``, a [[WebSocketProvider]] is returned backed
 *  by that WebSocket or URL.
 *
 *  If %%network%% is a string that begins with ``"HTTP:"`` or ``"HTTPS:"``,
 *  a [[JsonRpcProvider]] is returned connected to that URL.
 *
 *  Otherwise, a default provider is created backed by well-known public
 *  Web3 backends (such as [[link-infura]]) using community-provided API
 *  keys.
 *
 *  The %%options%% allows specifying custom API keys per backend (setting
 *  an API key to ``"-"`` will omit that provider) and ``options.exclusive``
 *  can be set to either a backend name or and array of backend names, which
 *  will whitelist **only** those backends.
 *
 *  Current backend strings supported are:
 *  - ``"alchemy"``
 *  - ``"ankr"``
 *  - ``"cloudflare"``
 *  - ``"chainstack"``
 *  - ``"etherscan"``
 *  - ``"infura"``
 *  - ``"publicPolygon"``
 *  - ``"quicknode"``
 *
 *  @example:
 *    // Connect to a local Geth node
 *    provider = getDefaultProvider("http://localhost:8545/");
 *
 *    // Connect to Ethereum mainnet with any current and future
 *    // third-party services available
 *    provider = getDefaultProvider("mainnet");
 *
 *    // Connect to Polygon, but only allow Etherscan and
 *    // INFURA and use "MY_API_KEY" in calls to Etherscan.
 *    provider = getDefaultProvider("matic", {
 *      etherscan: "MY_API_KEY",
 *      exclusive: [ "etherscan", "infura" ]
 *    });
 */
export function getDefaultProvider(network?: string | Networkish | WebSocketLike, options?: any): AbstractProvider {
    if (options == null) { options = { }; }

    const allowService = (name: string) => {
        if (options[name] === "-") { return false; }
        if (typeof(options.exclusive) === "string") {
            return (name === options.exclusive);
        }
        if (Array.isArray(options.exclusive)) {
            return (options.exclusive.indexOf(name) !== -1);
        }
        return true;
    };

    if (typeof(network) === "string" && network.match(/^https?:/)) {
        return new JsonRpcProvider(network);
    }

    if (typeof(network) === "string" && network.match(/^wss?:/) || isWebSocketLike(network)) {
        return new WebSocketProvider(network);
    }

    // Get the network and name, if possible
    let staticNetwork: null | Network = null;
    try {
        staticNetwork = Network.from(network);
    } catch (error) { }


    const providers: Array<AbstractProvider> = [ ];

    if (allowService("publicPolygon") && staticNetwork) {
        if (staticNetwork.name === "matic") {
            providers.push(new JsonRpcProvider("https:/\/polygon-rpc.com/", staticNetwork, { staticNetwork }));
        } else if (staticNetwork.name === "matic-amoy") {
            providers.push(new JsonRpcProvider("https:/\/rpc-amoy.polygon.technology/", staticNetwork, { staticNetwork }));
        }
    }

    if (allowService("alchemy")) {
        try {
            providers.push(new AlchemyProvider(network, options.alchemy));
        } catch (error) { }
    }

    if (allowService("ankr") && options.ankr != null) {
        try {
            providers.push(new AnkrProvider(network, options.ankr));
        } catch (error) { }
    }
/* Temporarily remove until custom error issue is fixed
    if (allowService("blockscout")) {
        try {
            providers.push(new BlockscoutProvider(network, options.blockscout));
        } catch (error) { }
    }
*/
    if (allowService("chainstack")) {
        try {
            providers.push(new ChainstackProvider(network, options.chainstack));
        } catch (error) { }
    }

    if (allowService("cloudflare")) {
        try {
            providers.push(new CloudflareProvider(network));
        } catch (error) { }
    }

    if (allowService("etherscan")) {
        try {
            providers.push(new EtherscanProvider(network, options.etherscan));
        } catch (error) { }
    }

    if (allowService("infura")) {
        try {
            let projectId = options.infura;
            let projectSecret: undefined | string = undefined;
            if (typeof(projectId) === "object") {
                projectSecret = projectId.projectSecret;
                projectId = projectId.projectId;
            }
            providers.push(new InfuraProvider(network, projectId, projectSecret));
        } catch (error) { }
    }
/*
    if (options.pocket !== "-") {
        try {
            let appId = options.pocket;
            let secretKey: undefined | string = undefined;
            let loadBalancer: undefined | boolean = undefined;
            if (typeof(appId) === "object") {
                loadBalancer = !!appId.loadBalancer;
                secretKey = appId.secretKey;
                appId = appId.appId;
            }
            providers.push(new PocketProvider(network, appId, secretKey, loadBalancer));
        } catch (error) { console.log(error); }
    }
*/
    if (allowService("quicknode")) {
        try {
            let token = options.quicknode;
            providers.push(new QuickNodeProvider(network, token));
        } catch (error) { }
    }

    assert(providers.length, "unsupported default network", "UNSUPPORTED_OPERATION", {
        operation: "getDefaultProvider"
    });

    // No need for a FallbackProvider
    if (providers.length === 1) { return providers[0]; }

    // We use the floor because public third-party providers can be unreliable,
    // so a low number of providers with a large quorum will fail too often
    let quorum = Math.floor(providers.length / 2);
    if (quorum > 2) { quorum = 2; }

    // Testnets don't need as strong a security gaurantee and speed is
    // more useful during testing
    if (staticNetwork && Testnets.indexOf(staticNetwork.name) !== -1) { quorum = 1; }

    // Provided override qorum takes priority
    if (options && options.quorum) { quorum = options.quorum; }

    return new FallbackProvider(providers, undefined, { quorum });
}