Skip to content

Commit b59b5a4

Browse files
committed
Added BlockscoutProvider (#4790).
1 parent 844ae68 commit b59b5a4

File tree

6 files changed

+141
-4
lines changed

6 files changed

+141
-4
lines changed

src.ts/_tests/create-provider.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {
22
AlchemyProvider,
3+
BlockscoutProvider,
34
// AnkrProvider,
45
// CloudflareProvider,
56
ChainstackProvider,
@@ -34,6 +35,15 @@ const ProviderCreators: Array<ProviderCreator> = [
3435
return new AlchemyProvider(network, "YrPw6SWb20vJDRFkhWq8aKnTQ8JRNRHM");
3536
}
3637
},
38+
{
39+
name: "BlockscoutProvider",
40+
//networks: ethNetworks, // @TODO: they are backfilling some Sepolia txs
41+
networks: [ "mainnet" ],
42+
create: function(network: string) {
43+
//return new BlockscoutProvider(network);
44+
return new BlockscoutProvider(network, "fdbfa288-1695-454e-a369-4501253a120");
45+
}
46+
},
3747
/*
3848
{
3949
name: "AnkrProvider",

src.ts/_tests/test-providers-data.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ describe("Test Provider Transaction operations", function() {
223223

224224
// Cloudflare doesn't return the root in legacy receipts; but it isn't
225225
// *actually* that important, so we'll give it a pass...
226-
if (providerName === "CloudflareProvider" || providerName === "AnkrProvider" || providerName === "PocketProvider") {
226+
if (providerName === "CloudflareProvider" || providerName === "AnkrProvider" || providerName === "PocketProvider" || providerName === "BlockscoutProvider") {
227227
test = Object.assign({ } , test, { root: undefined });
228228
}
229229

src.ts/ethers.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,9 @@ export {
6969

7070
BrowserProvider,
7171

72-
AlchemyProvider, AnkrProvider, ChainstackProvider, CloudflareProvider,
73-
EtherscanProvider, InfuraProvider, InfuraWebSocketProvider, PocketProvider,
74-
QuickNodeProvider,
72+
AlchemyProvider, AnkrProvider, BlockscoutProvider, ChainstackProvider,
73+
CloudflareProvider, EtherscanProvider, InfuraProvider,
74+
InfuraWebSocketProvider, PocketProvider, QuickNodeProvider,
7575

7676
IpcSocketProvider, SocketProvider, WebSocketProvider,
7777

src.ts/providers/default-provider.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { assert } from "../utils/index.js";
33

44
import { AnkrProvider } from "./provider-ankr.js";
55
import { AlchemyProvider } from "./provider-alchemy.js";
6+
import { BlockscoutProvider } from "./provider-blockscout.js";
67
import { ChainstackProvider } from "./provider-chainstack.js";
78
import { CloudflareProvider } from "./provider-cloudflare.js";
89
import { EtherscanProvider } from "./provider-etherscan.js";
@@ -121,6 +122,12 @@ export function getDefaultProvider(network?: string | Networkish | WebSocketLike
121122
} catch (error) { }
122123
}
123124

125+
if (allowService("blockscout")) {
126+
try {
127+
providers.push(new BlockscoutProvider(network, options.blockscout));
128+
} catch (error) { }
129+
}
130+
124131
if (allowService("chainstack")) {
125132
try {
126133
providers.push(new ChainstackProvider(network, options.chainstack));

src.ts/providers/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ export { JsonRpcApiProvider, JsonRpcProvider, JsonRpcSigner } from "./provider-j
6060
export { BrowserProvider } from "./provider-browser.js";
6161

6262
export { AlchemyProvider } from "./provider-alchemy.js";
63+
export { BlockscoutProvider } from "./provider-blockscout.js";
6364
export { AnkrProvider } from "./provider-ankr.js";
6465
export { CloudflareProvider } from "./provider-cloudflare.js";
6566
export { ChainstackProvider } from "./provider-chainstack.js";
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
2+
/**
3+
* [[link-blockscout]] provides a third-party service for connecting to
4+
* various blockchains over JSON-RPC.
5+
*
6+
* **Supported Networks**
7+
*
8+
* - Ethereum Mainnet (``mainnet``)
9+
* - Sepolia Testnet (``sepolia``)
10+
* - Ethereum Classic (``classic``)
11+
* - Arbitrum (``arbitrum``)
12+
* - Base (``base``)
13+
* - Base Sepolia Testnet (``base-sepolia``)
14+
* - Gnosis (``xdai``)
15+
* - Optimism (``optimism``)
16+
* - Optimism Sepolia Testnet (``optimism-sepolia``)
17+
* - Polygon (``matic``)
18+
*
19+
* @_subsection: api/providers/thirdparty:Blockscout [providers-blockscout]
20+
*/
21+
import {
22+
defineProperties, FetchRequest, assertArgument
23+
} from "../utils/index.js";
24+
25+
import { Network } from "./network.js";
26+
import { JsonRpcProvider } from "./provider-jsonrpc.js";
27+
28+
import type { AbstractProvider } from "./abstract-provider.js";
29+
import type { CommunityResourcable } from "./community.js";
30+
import type { Networkish } from "./network.js";
31+
32+
33+
function getUrl(name: string): string {
34+
switch(name) {
35+
case "mainnet":
36+
return "https:/\/eth.blockscout.com/api/eth-rpc";
37+
case "sepolia":
38+
return "https:/\/eth-sepolia.blockscout.com/api/eth-rpc";
39+
case "holesky":
40+
return "https:/\/eth-holesky.blockscout.com/api/eth-rpc";
41+
42+
case "classic":
43+
return "https:/\/etc.blockscout.com/api/eth-rpc";
44+
45+
case "arbitrum":
46+
return "https:/\/arbitrum.blockscout.com/api/eth-rpc";
47+
48+
case "base":
49+
return "https:/\/base.blockscout.com/api/eth-rpc";
50+
case "base-sepolia":
51+
return "https:/\/base-sepolia.blockscout.com/api/eth-rpc";
52+
53+
case "matic":
54+
return "https:/\/polygon.blockscout.com/api/eth-rpc";
55+
56+
case "optimism":
57+
return "https:/\/optimism.blockscout.com/api/eth-rpc";
58+
case "optimism-sepolia":
59+
return "https:/\/optimism-sepolia.blockscout.com/api/eth-rpc";
60+
61+
case "xdai":
62+
return "https:/\/gnosis.blockscout.com/api/eth-rpc";
63+
}
64+
65+
assertArgument(false, "unsupported network", "network", name);
66+
}
67+
68+
69+
/**
70+
* The **BlockscoutProvider** connects to the [[link-blockscout]]
71+
* JSON-RPC end-points.
72+
*
73+
* By default, a highly-throttled API key is used, which is
74+
* appropriate for quick prototypes and simple scripts. To
75+
* gain access to an increased rate-limit, it is highly
76+
* recommended to [sign up here](link-blockscout).
77+
*/
78+
export class BlockscoutProvider extends JsonRpcProvider implements CommunityResourcable {
79+
/**
80+
* The API key.
81+
*/
82+
readonly apiKey!: null | string;
83+
84+
/**
85+
* Creates a new **BlockscoutProvider**.
86+
*/
87+
constructor(_network?: Networkish, apiKey?: null | string) {
88+
if (_network == null) { _network = "mainnet"; }
89+
const network = Network.from(_network);
90+
91+
if (apiKey == null) { apiKey = null; }
92+
93+
const request = BlockscoutProvider.getRequest(network);
94+
super(request, network, { staticNetwork: network });
95+
96+
defineProperties<BlockscoutProvider>(this, { apiKey });
97+
}
98+
99+
_getProvider(chainId: number): AbstractProvider {
100+
try {
101+
return new BlockscoutProvider(chainId, this.apiKey);
102+
} catch (error) { }
103+
return super._getProvider(chainId);
104+
}
105+
106+
isCommunityResource(): boolean {
107+
return (this.apiKey === null);
108+
}
109+
110+
/**
111+
* Returns a prepared request for connecting to %%network%%
112+
* with %%apiKey%%.
113+
*/
114+
static getRequest(network: Network): FetchRequest {
115+
const request = new FetchRequest(getUrl(network.name));
116+
request.allowGzip = true;
117+
return request;
118+
}
119+
}

0 commit comments

Comments
 (0)