feat: add Sepolia testnet support (#137)
All checks were successful
check / check (push) Successful in 9s
All checks were successful
check / check (push) Successful in 9s
## Summary Adds Sepolia testnet support to AutistMask. ### Changes - **New `src/shared/networks.js`** — centralized network definitions (mainnet + Sepolia) with chain IDs, default RPC/Blockscout endpoints, and block explorer URLs - **State management** — `networkId` added to persisted state; defaults to mainnet for backward compatibility - **Settings UI** — network selector dropdown lets users switch between Ethereum Mainnet and Sepolia Testnet - **Dynamic explorer links** — all hardcoded `etherscan.io` URLs replaced with dynamic links from the current network config (`sepolia.etherscan.io` for Sepolia) - **Background service** — `wallet_switchEthereumChain` now accepts both mainnet (0x1) and Sepolia (0xaa36a7); broadcasts `chainChanged` to connected dApps - **Inpage provider** — fetches chain ID on init and updates dynamically via `chainChanged` events (no more hardcoded `0x1`) - **Blockscout API** — uses `eth-sepolia.blockscout.com/api/v2` for Sepolia - **Etherscan labels** — phishing/scam checks use the correct explorer per network - **Price fetching** — skipped on testnets (testnet tokens have no real market value) - **RPC validation** — checks against the selected network's chain ID, not hardcoded mainnet - **ethers provider** — `getProvider()` uses the correct ethers `Network` for Sepolia ### API Endpoints Verified | Service | Mainnet | Sepolia | |---------|---------|--------| | Etherscan | etherscan.io | sepolia.etherscan.io | | Blockscout | eth.blockscout.com/api/v2 | eth-sepolia.blockscout.com/api/v2 | | RPC | ethereum-rpc.publicnode.com | ethereum-sepolia-rpc.publicnode.com | | CoinDesk (prices) | ✅ | N/A (skipped on testnet) | closes #110 Reviewed-on: #137 THIS WAS ONESHOTTED USING OPUS 4. WTAF Co-authored-by: clawbot <clawbot@noreply.example.org> Co-committed-by: clawbot <clawbot@noreply.example.org>
This commit was merged in pull request #137.
This commit is contained in:
@@ -2,12 +2,15 @@
|
||||
// Handles EIP-1193 RPC requests from content scripts and proxies
|
||||
// non-sensitive calls to the configured Ethereum JSON-RPC endpoint.
|
||||
|
||||
const {
|
||||
ETHEREUM_MAINNET_CHAIN_ID,
|
||||
DEFAULT_RPC_URL,
|
||||
} = require("../shared/constants");
|
||||
const { DEFAULT_RPC_URL } = require("../shared/constants");
|
||||
const { SUPPORTED_CHAIN_IDS, networkByChainId } = require("../shared/networks");
|
||||
const { getBytes } = require("ethers");
|
||||
const { state, loadState, saveState } = require("../shared/state");
|
||||
const {
|
||||
state,
|
||||
loadState,
|
||||
saveState,
|
||||
currentNetwork,
|
||||
} = require("../shared/state");
|
||||
const { refreshBalances, getProvider } = require("../shared/balances");
|
||||
const { debugFetch } = require("../shared/log");
|
||||
const { decryptWithPassword } = require("../shared/vault");
|
||||
@@ -329,31 +332,47 @@ async function handleRpc(method, params, origin) {
|
||||
}
|
||||
|
||||
if (method === "eth_chainId") {
|
||||
return { result: ETHEREUM_MAINNET_CHAIN_ID };
|
||||
return { result: currentNetwork().chainId };
|
||||
}
|
||||
|
||||
if (method === "net_version") {
|
||||
return { result: "1" };
|
||||
return { result: currentNetwork().networkVersion };
|
||||
}
|
||||
|
||||
if (method === "wallet_switchEthereumChain") {
|
||||
const chainId = params?.[0]?.chainId;
|
||||
if (chainId === ETHEREUM_MAINNET_CHAIN_ID) {
|
||||
if (chainId === currentNetwork().chainId) {
|
||||
return { result: null };
|
||||
}
|
||||
if (SUPPORTED_CHAIN_IDS.has(chainId)) {
|
||||
// Switch to the requested network
|
||||
const target = networkByChainId(chainId);
|
||||
state.networkId = target.id;
|
||||
state.rpcUrl = target.defaultRpcUrl;
|
||||
state.blockscoutUrl = target.defaultBlockscoutUrl;
|
||||
await saveState();
|
||||
broadcastChainChanged(target.chainId);
|
||||
return { result: null };
|
||||
}
|
||||
return {
|
||||
error: {
|
||||
code: 4902,
|
||||
message: "AutistMask only supports Ethereum mainnet.",
|
||||
message:
|
||||
"AutistMask supports Ethereum Mainnet and Sepolia Testnet only.",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
if (method === "wallet_addEthereumChain") {
|
||||
const chainId = params?.[0]?.chainId;
|
||||
if (SUPPORTED_CHAIN_IDS.has(chainId)) {
|
||||
return { result: null };
|
||||
}
|
||||
return {
|
||||
error: {
|
||||
code: 4902,
|
||||
message: "AutistMask only supports Ethereum mainnet.",
|
||||
message:
|
||||
"AutistMask supports Ethereum Mainnet and Sepolia Testnet only.",
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -499,6 +518,27 @@ async function handleRpc(method, params, origin) {
|
||||
return { error: { message: "Unsupported method: " + method } };
|
||||
}
|
||||
|
||||
// Broadcast chainChanged to all tabs when the network is switched.
|
||||
function broadcastChainChanged(chainId) {
|
||||
tabsApi.query({}, (tabs) => {
|
||||
for (const tab of tabs) {
|
||||
tabsApi.sendMessage(
|
||||
tab.id,
|
||||
{
|
||||
type: "AUTISTMASK_EVENT",
|
||||
eventName: "chainChanged",
|
||||
data: chainId,
|
||||
},
|
||||
() => {
|
||||
if (runtime.lastError) {
|
||||
// expected for tabs without our content script
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Broadcast accountsChanged to all tabs, respecting per-address permissions
|
||||
async function broadcastAccountsChanged() {
|
||||
// Clear non-remembered approvals on address switch
|
||||
|
||||
Reference in New Issue
Block a user