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
7 changes: 6 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,15 @@
# .env.local 文件不会被提交到 git

# ==================== API Keys ====================
# 支持逗号分隔多个 API Key,应用启动时随机选中一个并锁定(会话期间不变)

# TronGrid API Key(用于高频率 Tron 请求)
# 申请地址: https://www.trongrid.io/
# VITE_TRONGRID_API_KEY=""
# TRONGRID_API_KEY="uuid1,uuid2,uuid3"

# Etherscan API Key(用于 EVM 链交易历史查询)
# 申请地址: https://etherscan.io/myapikey
# ETHERSCAN_API_KEY="key1,key2,key3"

# ==================== E2E 测试 ====================

Expand Down
15 changes: 15 additions & 0 deletions .storybook/main.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { StorybookConfig } from '@storybook/react-vite'
import { loadEnv } from 'vite'
import { resolve, dirname } from 'node:path'
import { fileURLToPath } from 'node:url'

Expand All @@ -10,6 +11,8 @@ const config: StorybookConfig = {
options: {},
},
viteFinal: async (config) => {
const env = loadEnv(config.mode ?? 'development', process.cwd(), '')

// Keep Storybook deterministic: use mock exchange rates instead of network calls.
config.resolve ??= {}
const storybookDir = dirname(fileURLToPath(import.meta.url))
Expand All @@ -23,6 +26,18 @@ const config: StorybookConfig = {
'#currency-exchange-impl': replacement,
}
}

// Inject API keys for dynamic access
const tronGridApiKey = env.TRONGRID_API_KEY ?? process.env.TRONGRID_API_KEY ?? ''
const etherscanApiKey = env.ETHERSCAN_API_KEY ?? process.env.ETHERSCAN_API_KEY ?? ''
config.define = {
...config.define,
'__API_KEYS__': JSON.stringify({
TRONGRID_API_KEY: tronGridApiKey,
ETHERSCAN_API_KEY: etherscanApiKey,
}),
}

return config
},
}
Expand Down
12 changes: 11 additions & 1 deletion public/configs/default-chains.json
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,11 @@
"apis": [
{ "type": "blockscout-v1", "endpoint": "https://eth.blockscout.com/api" },
{ "type": "ethereum-rpc", "endpoint": "https://ethereum-rpc.publicnode.com" },
{
"type": "etherscan-v2",
"endpoint": "https://api.etherscan.io/v2/api",
"config": { "apiKeyEnv": "ETHERSCAN_API_KEY" }
},
{ "type": "ethwallet-v1", "endpoint": "https://walletapi.bfmeta.info/wallet/eth" }
],
"explorer": {
Expand All @@ -166,6 +171,11 @@
"decimals": 18,
"apis": [
{ "type": "bsc-rpc", "endpoint": "https://bsc-rpc.publicnode.com" },
{
"type": "etherscan-v2",
"endpoint": "https://api.etherscan.io/v2/api",
"config": { "apiKeyEnv": "ETHERSCAN_API_KEY" }
},
{ "type": "bscwallet-v1", "endpoint": "https://walletapi.bfmeta.info/wallet/bsc" }
],
"explorer": {
Expand All @@ -192,7 +202,7 @@
{
"type": "tron-rpc-pro",
"endpoint": "https://api.trongrid.io",
"config": { "apiKeyEnv": "VITE_TRONGRID_API_KEY" }
"config": { "apiKeyEnv": "TRONGRID_API_KEY" }
},
{ "type": "tronwallet-v1", "endpoint": "https://walletapi.bfmeta.info/wallet/tron" }
],
Expand Down
29 changes: 25 additions & 4 deletions scripts/set-secret.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,14 +115,35 @@ const SECRET_DEFINITIONS: SecretDefinition[] = [

// API Keys
{
key: 'VITE_TRONGRID_API_KEY',
description: 'TronGrid API Key(用于高频率 Tron 请求)',
key: 'TRONGRID_API_KEY',
description: 'TronGrid API Key(支持逗号分隔多个,启动时随机选中一个)',
category: 'api-keys',
required: false,
isPassword: true,
validate: (v) => {
if (v && !/^[a-f0-9-]{36}$/i.test(v)) {
return 'API Key 格式无效(应为 UUID)'
if (!v) return true
const keys = v.split(',').map(k => k.trim()).filter(Boolean)
for (const key of keys) {
if (!/^[a-f0-9-]{36}$/i.test(key)) {
return `API Key 格式无效: ${key}(应为 UUID)`
}
}
return true
},
},
{
key: 'ETHERSCAN_API_KEY',
description: 'Etherscan API Key(支持逗号分隔多个,启动时随机选中一个)',
category: 'api-keys',
required: false,
isPassword: true,
validate: (v) => {
if (!v) return true
const keys = v.split(',').map(k => k.trim()).filter(Boolean)
for (const key of keys) {
if (!/^[A-Z0-9]{34}$/i.test(key)) {
return `API Key 格式无效: ${key}(应为 34 位字母数字)`
}
}
return true
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ describe.skipIf(!process.env.TEST_REAL_API)("WalletAddressPortfolio Real Provide
source: "default",
apis: [
{ type: "tron-rpc", endpoint: "https://api.trongrid.io" },
{ type: "tron-rpc-pro", endpoint: "https://api.trongrid.io", config: { apiKeyEnv: "VITE_TRONGRID_API_KEY" } },
{ type: "tron-rpc-pro", endpoint: "https://api.trongrid.io", config: { apiKeyEnv: "TRONGRID_API_KEY" } },
{ type: "tronwallet-v1", endpoint: "https://walletapi.bfmeta.info/wallet/tron" },
],
},
Expand Down
Loading