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
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,8 @@ npm install
#### Network Configuration

- `TRONGRID_API_KEY`: (Optional) Your TronGrid API key.
- **Why**: TRON mainnet RPCs have strict rate limits. Using an API key from [TronGrid](https://www.trongrid.io/) ensures reliable performance and higher throughput.
- **Why**: TRON mainnet RPCs have strict rate limits. When `TRONGRID_API_KEY` is set (and non-empty), the server uses `https://api.trongrid.io` as the default RPC hosts.
- **Fallback**: When `TRONGRID_API_KEY` is not set, the server uses `https://hptg.bankofai.io` as the default RPC hosts for `mainnet`.
- **Usage**:
```bash
export TRONGRID_API_KEY="<YOUR_TRONGRID_API_KEY_HERE>"
Expand Down
26 changes: 25 additions & 1 deletion src/core/chains.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ export interface NetworkConfig {
explorer: string;
}

const BOA_MAINNET_HOST = "https://hptg.bankofai.io";

function isTronGridApiKeyConfigured(): boolean {
const apiKey = process.env.TRONGRID_API_KEY;
return typeof apiKey === "string" && apiKey.length > 0;
}

export const NETWORKS: Record<TronNetwork, NetworkConfig> = {
[TronNetwork.Mainnet]: {
name: "Mainnet",
Expand Down Expand Up @@ -45,7 +52,16 @@ export function getNetworkConfig(network: string = DEFAULT_NETWORK): NetworkConf

// Direct match
if (Object.values(TronNetwork).includes(normalizedNetwork as TronNetwork)) {
return NETWORKS[normalizedNetwork as TronNetwork];
const resolved = normalizedNetwork as TronNetwork;
if (resolved === TronNetwork.Mainnet && !isTronGridApiKeyConfigured()) {
return {
...NETWORKS[TronNetwork.Mainnet],
fullNode: BOA_MAINNET_HOST,
solidityNode: BOA_MAINNET_HOST,
eventServer: BOA_MAINNET_HOST,
};
}
return NETWORKS[resolved];
}

// Aliases
Expand All @@ -54,6 +70,14 @@ export function getNetworkConfig(network: string = DEFAULT_NETWORK): NetworkConf
normalizedNetwork === "trx" ||
normalizedNetwork === "mainnet"
) {
if (!isTronGridApiKeyConfigured()) {
return {
...NETWORKS[TronNetwork.Mainnet],
fullNode: BOA_MAINNET_HOST,
solidityNode: BOA_MAINNET_HOST,
eventServer: BOA_MAINNET_HOST,
};
}
return NETWORKS[TronNetwork.Mainnet];
}
if (normalizedNetwork === "testnet") {
Expand Down
50 changes: 43 additions & 7 deletions tests/core/chains.test.ts
Original file line number Diff line number Diff line change
@@ -1,45 +1,78 @@
import { describe, expect, it } from "vitest";
import { describe, expect, it, afterAll } from "vitest";
import {
getNetworkConfig,
getRpcUrl,
getSupportedNetworks,
TronNetwork,
DEFAULT_NETWORK,
NETWORKS,
} from "../../src/core/chains";

describe("Chains", () => {
const BOA_MAINNET_HOST = "https://hptg.bankofai.io";
const originalTronGridApiKey = process.env.TRONGRID_API_KEY;
const setEnv = (value: string | undefined) => {
if (value === undefined) {
delete process.env.TRONGRID_API_KEY;
} else {
process.env.TRONGRID_API_KEY = value;
}
};

afterAll(() => {
if (originalTronGridApiKey === undefined) {
delete process.env.TRONGRID_API_KEY;
} else {
process.env.TRONGRID_API_KEY = originalTronGridApiKey;
}
});

it("should export supported networks", () => {
const networks = getSupportedNetworks();
expect(networks).toEqual(["mainnet", "nile", "shasta"]);
});

it("should get network config for mainnet", () => {
it("should use hptg host for mainnet when TRONGRID_API_KEY not set", () => {
setEnv(undefined);
const config = getNetworkConfig(TronNetwork.Mainnet);
expect(config.name).toBe("Mainnet");
expect(config.fullNode).toBe(BOA_MAINNET_HOST);
expect(config.solidityNode).toBe(BOA_MAINNET_HOST);
expect(config.eventServer).toBe(BOA_MAINNET_HOST);
});

it("should use api.trongrid.io for mainnet when TRONGRID_API_KEY is set", () => {
setEnv("dummy_key");
const config = getNetworkConfig(TronNetwork.Mainnet);
expect(config.name).toBe("Mainnet");
expect(config.fullNode).toBe("https://api.trongrid.io");
});

it("should get network config for nile", () => {
setEnv(undefined);
const config = getNetworkConfig(TronNetwork.Nile);
expect(config.name).toBe("Nile");
expect(config.fullNode).toBe("https://nile.trongrid.io");
});

it("should get network config for shasta", () => {
setEnv(undefined);
const config = getNetworkConfig(TronNetwork.Shasta);
expect(config.name).toBe("Shasta");
expect(config.fullNode).toBe("https://api.shasta.trongrid.io");
});

it("should resolve aliases correctly", () => {
expect(getNetworkConfig("tron")).toBe(NETWORKS[TronNetwork.Mainnet]);
expect(getNetworkConfig("trx")).toBe(NETWORKS[TronNetwork.Mainnet]);
setEnv(undefined);
const hptgMainnet = getNetworkConfig("tron");
expect(hptgMainnet.fullNode).toBe(BOA_MAINNET_HOST);
const hptgMainnet2 = getNetworkConfig("trx");
expect(hptgMainnet2.fullNode).toBe(BOA_MAINNET_HOST);
expect(getNetworkConfig("testnet")).toBe(NETWORKS[TronNetwork.Nile]);
});

it("should return correct RPC URL", () => {
expect(getRpcUrl("mainnet")).toBe("https://api.trongrid.io");
setEnv(undefined);
expect(getRpcUrl("mainnet")).toBe(BOA_MAINNET_HOST);
expect(getRpcUrl("nile")).toBe("https://nile.trongrid.io");
});

Expand All @@ -50,6 +83,9 @@ describe("Chains", () => {
});

it("should use default network if none provided", () => {
expect(getNetworkConfig()).toBe(NETWORKS[DEFAULT_NETWORK]);
setEnv(undefined);
const config = getNetworkConfig();
expect(config.name).toBe("Mainnet");
expect(config.fullNode).toBe(BOA_MAINNET_HOST);
});
});
Loading