Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"generate": "tsx scripts/generate.ts",
"sync": "tsx scripts/sync.ts",
"typecheck": "tsc --noEmit",
"test": "tsx --test scripts/sync.test.ts",
"test": "tsx --test scripts/sync.test.ts scripts/providers/drpc.test.ts",
"test:integration": "tsx --test --test-reporter=spec --test-reporter-destination=stdout --test-reporter=junit --test-reporter-destination=junit.xml tests/chain-tests.test.ts tests/etherscan-instances.test.ts",
"test:integration:chain": "tsx --test --test-reporter=spec --test-reporter-destination=stdout --test-reporter=junit --test-reporter-destination=junit-chain.xml tests/chain-tests.test.ts",
"test:integration:etherscan": "tsx --test --test-reporter=spec --test-reporter-destination=stdout --test-reporter=junit --test-reporter-destination=junit-etherscan.xml tests/etherscan-instances.test.ts"
Expand Down
1 change: 1 addition & 0 deletions scripts/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,7 @@ async function main() {
etherscan?.chainName ??
blockscoutName ??
meta?.name ??
drpc?.name ??
`Chain ${chainId}`;

const rpcSlots: RpcSlot[] = [];
Expand Down
30 changes: 30 additions & 0 deletions scripts/providers/drpc.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { describe, it } from "node:test";
import assert from "node:assert/strict";
import { buildDrpcChainName } from "./drpc.js";

describe("buildDrpcChainName", () => {
it("joins the protocol label and the network id", () => {
// The case that motivated this: chain 61900 is known only to dRPC.
assert.equal(buildDrpcChainName("Mova", "Mainnet"), "Mova Mainnet");
assert.equal(buildDrpcChainName("Polygon", "Amoy"), "Polygon Amoy");
});

it("does not repeat the label when the network id already starts with it", () => {
assert.equal(buildDrpcChainName("megaETH", "MegaETH Testnet"), "MegaETH Testnet");
assert.equal(buildDrpcChainName("Moonriver", "Moonriver"), "Moonriver");
assert.equal(buildDrpcChainName("Ozean", "Ozean Poseidon Testnet"), "Ozean Poseidon Testnet");
});

it("capitalises an all-lowercase network id", () => {
assert.equal(buildDrpcChainName("Ethereum Classic", "mainnet"), "Ethereum Classic Mainnet");
});

it("leaves mixed-case network ids alone", () => {
assert.equal(buildDrpcChainName("Berachain", "bArtio"), "Berachain bArtio");
});

it("returns undefined without a label, and the label alone without a network id", () => {
assert.equal(buildDrpcChainName(undefined, "Mainnet"), undefined);
assert.equal(buildDrpcChainName("Mova", undefined), "Mova");
});
});
25 changes: 24 additions & 1 deletion scripts/providers/drpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,20 @@ import YAML from "yaml";

export interface DrpcChainData {
shortName: string;
/** Human-readable name, e.g. "Mova Mainnet". Absent when the YAML has no label. */
name?: string;
}

// chains.yaml shape (only the fields we consume).
interface DrpcYamlChain {
id?: string;
"chain-id"?: string | number;
"short-names"?: string[];
}

interface DrpcYamlProtocol {
type?: string;
label?: string;
chains?: DrpcYamlChain[];
}

Expand Down Expand Up @@ -40,6 +44,25 @@ function parseChainId(raw: string | number | undefined): number | null {
return Number.isNaN(id) || id <= 0 ? null : id;
}

/**
* Build a display name from a protocol label and a network id, e.g.
* `label: Mova` + `id: Mainnet` -> "Mova Mainnet".
*
* Two touch-ups keep the result readable:
* - When the network id already starts with the label (`megaETH` +
* `MegaETH Testnet`, `Moonriver` + `Moonriver`), the label is dropped
* instead of repeated.
* - An all-lowercase network id (only `mainnet` today) is capitalised.
*/
export function buildDrpcChainName(label: string | undefined, networkId: string | undefined): string | undefined {
if (!label) return undefined;
if (!networkId) return label;

const network = /^[a-z]+$/.test(networkId) ? networkId[0].toUpperCase() + networkId.slice(1) : networkId;
if (network.toLowerCase().startsWith(label.toLowerCase())) return network;
return `${label} ${network}`;
}

/**
* Fetches the list of EVM chains supported by dRPC from their public
* chains.yaml config.
Expand Down Expand Up @@ -78,7 +101,7 @@ export async function fetchDrpcChains(): Promise<Map<number, DrpcChainData>> {

// First occurrence wins — don't let a later mislabelled entry overwrite.
if (!result.has(chainId)) {
result.set(chainId, { shortName });
result.set(chainId, { shortName, name: buildDrpcChainName(protocol.label, chain.id) });
}
}
}
Expand Down
Loading