Added Chainstack provider (#2741).

This commit is contained in:
Richard Moore 2024-04-09 20:36:16 -04:00
parent 03bfe2a4f7
commit 014004d940
6 changed files with 135 additions and 3 deletions

@ -1,5 +1,6 @@
link-alchemy [Alchemy](https://alchemy.com/?a=ethers) link-alchemy [Alchemy](https://alchemy.com/?a=ethers)
link-ankr [Ankr](https://www.ankr.com) link-ankr [Ankr](https://www.ankr.com)
link-chainstack [Chainstack](https://chainstack.com)
link-cloudflare [Cloudflare](https://developers.cloudflare.com/distributed-web/ethereum-gateway/) link-cloudflare [Cloudflare](https://developers.cloudflare.com/distributed-web/ethereum-gateway/)
link-ens [ENS](https://ens.domains/) link-ens [ENS](https://ens.domains/)
link-ethereum [Ethereum](https://ethereumorg) link-ethereum [Ethereum](https://ethereumorg)

@ -2,6 +2,7 @@ import {
AlchemyProvider, AlchemyProvider,
// AnkrProvider, // AnkrProvider,
// CloudflareProvider, // CloudflareProvider,
ChainstackProvider,
EtherscanProvider, EtherscanProvider,
InfuraProvider, InfuraProvider,
// PocketProvider, // PocketProvider,
@ -48,6 +49,13 @@ const ProviderCreators: Array<ProviderCreator> = [
} }
}, },
*/ */
{
name: "ChainstackProvider",
networks: [ "default", "mainnet", "arbitrum", "bnb", "matic" ],
create: function(network: string) {
return new ChainstackProvider(network);
}
},
{ {
name: "EtherscanProvider", name: "EtherscanProvider",
networks: ethNetworks, networks: ethNetworks,
@ -143,7 +151,7 @@ export function getProvider(provider: string, network: string): null | AbstractP
export function checkProvider(provider: string, network: string): boolean { export function checkProvider(provider: string, network: string): boolean {
const creator = getCreator(provider); const creator = getCreator(provider);
return (creator != null); return (creator != null && creator.networks.indexOf(network) >= 0);
} }
export function connect(network: string): AbstractProvider { export function connect(network: string): AbstractProvider {

@ -69,8 +69,9 @@ export {
BrowserProvider, BrowserProvider,
AlchemyProvider, AnkrProvider, CloudflareProvider, EtherscanProvider, AlchemyProvider, AnkrProvider, ChainstackProvider, CloudflareProvider,
InfuraProvider, InfuraWebSocketProvider, PocketProvider, QuickNodeProvider, EtherscanProvider, InfuraProvider, InfuraWebSocketProvider, PocketProvider,
QuickNodeProvider,
IpcSocketProvider, SocketProvider, WebSocketProvider, IpcSocketProvider, SocketProvider, WebSocketProvider,

@ -3,6 +3,7 @@ import { assert } from "../utils/index.js";
import { AnkrProvider } from "./provider-ankr.js"; import { AnkrProvider } from "./provider-ankr.js";
import { AlchemyProvider } from "./provider-alchemy.js"; import { AlchemyProvider } from "./provider-alchemy.js";
import { ChainstackProvider } from "./provider-chainstack.js";
import { CloudflareProvider } from "./provider-cloudflare.js"; import { CloudflareProvider } from "./provider-cloudflare.js";
import { EtherscanProvider } from "./provider-etherscan.js"; import { EtherscanProvider } from "./provider-etherscan.js";
import { InfuraProvider } from "./provider-infura.js"; import { InfuraProvider } from "./provider-infura.js";
@ -48,6 +49,7 @@ const Testnets = "goerli kovan sepolia classicKotti optimism-goerli arbitrum-goe
* - ``"alchemy"`` * - ``"alchemy"``
* - ``"ankr"`` * - ``"ankr"``
* - ``"cloudflare"`` * - ``"cloudflare"``
* - ``"chainstack"``
* - ``"etherscan"`` * - ``"etherscan"``
* - ``"infura"`` * - ``"infura"``
* - ``"publicPolygon"`` * - ``"publicPolygon"``
@ -117,6 +119,12 @@ export function getDefaultProvider(network?: string | Networkish | WebSocketLike
} catch (error) { } } catch (error) { }
} }
if (allowService("chainstack")) {
try {
providers.push(new ChainstackProvider(network, options.chainstack));
} catch (error) { }
}
if (allowService("cloudflare")) { if (allowService("cloudflare")) {
try { try {
providers.push(new CloudflareProvider(network)); providers.push(new CloudflareProvider(network));

@ -62,6 +62,7 @@ export { BrowserProvider } from "./provider-browser.js";
export { AlchemyProvider } from "./provider-alchemy.js"; export { AlchemyProvider } from "./provider-alchemy.js";
export { AnkrProvider } from "./provider-ankr.js"; export { AnkrProvider } from "./provider-ankr.js";
export { CloudflareProvider } from "./provider-cloudflare.js"; export { CloudflareProvider } from "./provider-cloudflare.js";
export { ChainstackProvider } from "./provider-chainstack.js";
export { EtherscanProvider, EtherscanPlugin } from "./provider-etherscan.js"; export { EtherscanProvider, EtherscanPlugin } from "./provider-etherscan.js";
export { InfuraProvider, InfuraWebSocketProvider } from "./provider-infura.js"; export { InfuraProvider, InfuraWebSocketProvider } from "./provider-infura.js";
export { PocketProvider } from "./provider-pocket.js"; export { PocketProvider } from "./provider-pocket.js";

@ -0,0 +1,113 @@
/**
* [[link-chainstack]] provides a third-party service for connecting to
* various blockchains over JSON-RPC.
*
* **Supported Networks**
*
* - Ethereum Mainnet (``mainnet``)
* - Arbitrum (``arbitrum``)
* - BNB Smart Chain Mainnet (``bnb``)
* - Polygon (``matic``)
*
* @_subsection: api/providers/thirdparty:Chainstack [providers-chainstack]
*/
import {
defineProperties, FetchRequest, assertArgument
} from "../utils/index.js";
import { showThrottleMessage } from "./community.js";
import { Network } from "./network.js";
import { JsonRpcProvider } from "./provider-jsonrpc.js";
import type { AbstractProvider } from "./abstract-provider.js";
import type { CommunityResourcable } from "./community.js";
import type { Networkish } from "./network.js";
function getApiKey(name: string): string {
switch (name) {
case "mainnet": return "39f1d67cedf8b7831010a665328c9197";
case "arbitrum": return "0550c209db33c3abf4cc927e1e18cea1"
case "bnb": return "98b5a77e531614387366f6fc5da097f8";
case "matic": return "cd9d4d70377471aa7c142ec4a4205249";
}
assertArgument(false, "unsupported network", "network", name);
}
function getHost(name: string): string {
switch(name) {
case "mainnet":
return "ethereum-mainnet.core.chainstack.com";
case "arbitrum":
return "arbitrum-mainnet.core.chainstack.com";
case "bnb":
return "bsc-mainnet.core.chainstack.com";
case "matic":
return "polygon-mainnet.core.chainstack.com";
}
assertArgument(false, "unsupported network", "network", name);
}
/**
* The **ChainstackProvider** connects to the [[link-chainstack]]
* JSON-RPC end-points.
*
* By default, a highly-throttled API key is used, which is
* appropriate for quick prototypes and simple scripts. To
* gain access to an increased rate-limit, it is highly
* recommended to [sign up here](link-chainstack).
*/
export class ChainstackProvider extends JsonRpcProvider implements CommunityResourcable {
/**
* The API key for the Chainstack connection.
*/
readonly apiKey!: string;
/**
* Creates a new **ChainstackProvider**.
*/
constructor(_network?: Networkish, apiKey?: null | string) {
if (_network == null) { _network = "mainnet"; }
const network = Network.from(_network);
if (apiKey == null) { apiKey = getApiKey(network.name); }
const request = ChainstackProvider.getRequest(network, apiKey);
super(request, network, { staticNetwork: network });
defineProperties<ChainstackProvider>(this, { apiKey });
}
_getProvider(chainId: number): AbstractProvider {
try {
return new ChainstackProvider(chainId, this.apiKey);
} catch (error) { }
return super._getProvider(chainId);
}
isCommunityResource(): boolean {
return (this.apiKey === getApiKey(this._network.name));
}
/**
* Returns a prepared request for connecting to %%network%%
* with %%apiKey%% and %%projectSecret%%.
*/
static getRequest(network: Network, apiKey?: null | string): FetchRequest {
if (apiKey == null) { apiKey = getApiKey(network.name); }
const request = new FetchRequest(`https:/\/${ getHost(network.name) }/${ apiKey }`);
request.allowGzip = true;
if (apiKey === getApiKey(network.name)) {
request.retryFunc = async (request, response, attempt) => {
showThrottleMessage("ChainstackProvider");
return true;
};
}
return request;
}
}