mirror of
https://github.com/NoFxAiOS/nofx.git
synced 2025-12-06 13:54:41 +08:00
Merge branch 'beta' into nofxos-beta
# Conflicts: # config/database.go # config/database_pg.go # docker-compose.yml # main.go # manager/trader_manager.go # web/src/components/AITradersPage.tsx
This commit is contained in:
@@ -742,6 +742,48 @@ func (d *Database) GetExchanges(userID string) ([]*ExchangeConfig, error) {
|
||||
return exchanges, nil
|
||||
}
|
||||
|
||||
// GetExchangesForAPI 获取交易所配置(专用于API返回,排除敏感字段)
|
||||
func (d *Database) GetExchangesForAPI(userID string) ([]*ExchangeConfig, error) {
|
||||
rows, err := d.db.Query(`
|
||||
SELECT id, user_id, name, type, enabled,
|
||||
CASE
|
||||
WHEN type = 'hyperliquid' THEN ''
|
||||
ELSE COALESCE(api_key, '')
|
||||
END as api_key,
|
||||
'' as secret_key,
|
||||
testnet,
|
||||
COALESCE(hyperliquid_wallet_addr, '') as hyperliquid_wallet_addr,
|
||||
COALESCE(aster_user, '') as aster_user,
|
||||
COALESCE(aster_signer, '') as aster_signer,
|
||||
'' as aster_private_key,
|
||||
created_at, updated_at
|
||||
FROM exchanges WHERE user_id = ? ORDER BY id
|
||||
`, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
// 初始化为空切片而不是nil,确保JSON序列化为[]而不是null
|
||||
exchanges := make([]*ExchangeConfig, 0)
|
||||
for rows.Next() {
|
||||
var exchange ExchangeConfig
|
||||
err := rows.Scan(
|
||||
&exchange.ID, &exchange.UserID, &exchange.Name, &exchange.Type,
|
||||
&exchange.Enabled, &exchange.APIKey, &exchange.SecretKey, &exchange.Testnet,
|
||||
&exchange.HyperliquidWalletAddr, &exchange.AsterUser,
|
||||
&exchange.AsterSigner, &exchange.AsterPrivateKey,
|
||||
&exchange.CreatedAt, &exchange.UpdatedAt,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
exchanges = append(exchanges, &exchange)
|
||||
}
|
||||
|
||||
return exchanges, nil
|
||||
}
|
||||
|
||||
// UpdateExchange 更新交易所配置,如果不存在则创建用户特定配置
|
||||
func (d *Database) UpdateExchange(userID, id string, enabled bool, apiKey, secretKey string, testnet bool, hyperliquidWalletAddr, asterUser, asterSigner, asterPrivateKey string) error {
|
||||
log.Printf("🔧 UpdateExchange: userID=%s, id=%s, enabled=%v", userID, id, enabled)
|
||||
|
||||
@@ -1092,6 +1092,7 @@ export function AITradersPage({ onTraderSelect }: AITradersPageProps) {
|
||||
{showExchangeModal && (
|
||||
<ExchangeConfigModal
|
||||
allExchanges={supportedExchanges}
|
||||
configuredExchanges={allExchanges}
|
||||
editingExchangeId={editingExchange}
|
||||
onSave={handleSaveExchangeConfig}
|
||||
onDelete={handleDeleteExchangeConfig}
|
||||
@@ -1560,6 +1561,7 @@ function ModelConfigModal({
|
||||
// Exchange Configuration Modal Component
|
||||
function ExchangeConfigModal({
|
||||
allExchanges,
|
||||
configuredExchanges,
|
||||
editingExchangeId,
|
||||
onSave,
|
||||
onDelete,
|
||||
@@ -1567,6 +1569,7 @@ function ExchangeConfigModal({
|
||||
language,
|
||||
}: {
|
||||
allExchanges: Exchange[]
|
||||
configuredExchanges: Exchange[]
|
||||
editingExchangeId: string | null
|
||||
onSave: (
|
||||
exchangeId: string,
|
||||
@@ -1600,15 +1603,20 @@ function ExchangeConfigModal({
|
||||
// 币安配置指南展开状态
|
||||
const [showBinanceGuide, setShowBinanceGuide] = useState(false)
|
||||
|
||||
// Hyperliquid 特定字段
|
||||
const [hyperliquidWalletAddr, setHyperliquidWalletAddr] = useState('')
|
||||
|
||||
// Aster 特定字段
|
||||
const [asterUser, setAsterUser] = useState('')
|
||||
const [asterSigner, setAsterSigner] = useState('')
|
||||
const [asterPrivateKey, setAsterPrivateKey] = useState('')
|
||||
|
||||
// 获取当前编辑的交易所信息
|
||||
const selectedExchange = allExchanges?.find(
|
||||
(e) => e.id === selectedExchangeId
|
||||
)
|
||||
// 获取当前选择的交易所信息
|
||||
// 编辑模式:从 configuredExchanges 查找(包含用户配置的 apiKey、secretKey 等)
|
||||
// 新增模式:从 allExchanges 查找(系统支持的交易所列表)
|
||||
const selectedExchange = editingExchangeId
|
||||
? configuredExchanges?.find(e => e.id === selectedExchangeId)
|
||||
: allExchanges?.find(e => e.id === selectedExchangeId);
|
||||
|
||||
// 如果是编辑现有交易所,初始化表单数据
|
||||
useEffect(() => {
|
||||
@@ -1618,6 +1626,9 @@ function ExchangeConfigModal({
|
||||
setPassphrase('') // Don't load existing passphrase for security
|
||||
setTestnet(selectedExchange.testnet || false)
|
||||
|
||||
// Hyperliquid 字段
|
||||
setHyperliquidWalletAddr(selectedExchange.hyperliquidWalletAddr || '')
|
||||
|
||||
// Aster 字段
|
||||
setAsterUser(selectedExchange.asterUser || '')
|
||||
setAsterSigner(selectedExchange.asterSigner || '')
|
||||
@@ -2069,6 +2080,29 @@ function ExchangeConfigModal({
|
||||
<div className="text-xs mt-1" style={{ color: '#848E9C' }}>
|
||||
{t('hyperliquidPrivateKeyDesc', language)}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label
|
||||
className="block text-sm font-semibold mb-2"
|
||||
style={{ color: '#EAECEF' }}
|
||||
>
|
||||
钱包地址
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={hyperliquidWalletAddr}
|
||||
onChange={(e) => setHyperliquidWalletAddr(e.target.value)}
|
||||
placeholder="钱包地址(可选,通常由私钥自动生成)"
|
||||
className="w-full px-3 py-2 rounded"
|
||||
style={{
|
||||
background: '#0B0E11',
|
||||
border: '1px solid #2B3139',
|
||||
color: '#EAECEF',
|
||||
}}
|
||||
/>
|
||||
<div className="text-xs mt-1" style={{ color: '#848E9C' }}>
|
||||
钱包地址通常由私钥自动生成,编辑时可查看或修改
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user