Skip to content

Commit

Permalink
Added Chainstack provider (#2741).
Browse files Browse the repository at this point in the history
  • Loading branch information
ricmoo committed Apr 10, 2024
1 parent 03bfe2a commit 014004d
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 3 deletions.
1 change: 1 addition & 0 deletions docs.wrm/links/projects.txt
@@ -1,5 +1,6 @@
link-alchemy [Alchemy](https://alchemy.com/?a=ethers)
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-ens [ENS](https://ens.domains/)
link-ethereum [Ethereum](https://ethereumorg)
Expand Down
10 changes: 9 additions & 1 deletion src.ts/_tests/create-provider.ts
Expand Up @@ -2,6 +2,7 @@ import {
AlchemyProvider,
// AnkrProvider,
// CloudflareProvider,
ChainstackProvider,
EtherscanProvider,
InfuraProvider,
// PocketProvider,
Expand Down Expand Up @@ -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",
networks: ethNetworks,
Expand Down Expand Up @@ -143,7 +151,7 @@ export function getProvider(provider: string, network: string): null | AbstractP

export function checkProvider(provider: string, network: string): boolean {
const creator = getCreator(provider);
return (creator != null);
return (creator != null && creator.networks.indexOf(network) >= 0);
}

export function connect(network: string): AbstractProvider {
Expand Down
5 changes: 3 additions & 2 deletions src.ts/ethers.ts
Expand Up @@ -69,8 +69,9 @@ export {

BrowserProvider,

AlchemyProvider, AnkrProvider, CloudflareProvider, EtherscanProvider,
InfuraProvider, InfuraWebSocketProvider, PocketProvider, QuickNodeProvider,
AlchemyProvider, AnkrProvider, ChainstackProvider, CloudflareProvider,
EtherscanProvider, InfuraProvider, InfuraWebSocketProvider, PocketProvider,
QuickNodeProvider,

IpcSocketProvider, SocketProvider, WebSocketProvider,

Expand Down
8 changes: 8 additions & 0 deletions src.ts/providers/default-provider.ts
Expand Up @@ -3,6 +3,7 @@ import { assert } from "../utils/index.js";

import { AnkrProvider } from "./provider-ankr.js";
import { AlchemyProvider } from "./provider-alchemy.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";
Expand Down Expand Up @@ -48,6 +49,7 @@ const Testnets = "goerli kovan sepolia classicKotti optimism-goerli arbitrum-goe
* - ``"alchemy"``
* - ``"ankr"``
* - ``"cloudflare"``
* - ``"chainstack"``
* - ``"etherscan"``
* - ``"infura"``
* - ``"publicPolygon"``
Expand Down Expand Up @@ -117,6 +119,12 @@ export function getDefaultProvider(network?: string | Networkish | WebSocketLike
} catch (error) { }
}

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

if (allowService("cloudflare")) {
try {
providers.push(new CloudflareProvider(network));
Expand Down
1 change: 1 addition & 0 deletions src.ts/providers/index.ts
Expand Up @@ -62,6 +62,7 @@ export { BrowserProvider } from "./provider-browser.js";
export { AlchemyProvider } from "./provider-alchemy.js";
export { AnkrProvider } from "./provider-ankr.js";
export { CloudflareProvider } from "./provider-cloudflare.js";
export { ChainstackProvider } from "./provider-chainstack.js";
export { EtherscanProvider, EtherscanPlugin } from "./provider-etherscan.js";
export { InfuraProvider, InfuraWebSocketProvider } from "./provider-infura.js";
export { PocketProvider } from "./provider-pocket.js";
Expand Down
113 changes: 113 additions & 0 deletions src.ts/providers/provider-chainstack.ts
@@ -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;
}
}

0 comments on commit 014004d

Please sign in to comment.