mirror of
https://github.com/NoFxAiOS/nofx.git
synced 2026-07-17 01:14:40 +08:00
Merge pull request #399 from tangmengqiu/fix/hyperliquid_setup
fix(setup): hyperliquid setup, no need to enter the wallet address, improve user experience
This commit is contained in:
@@ -2,10 +2,12 @@ package trader
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/ecdsa"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/sonirico/go-hyperliquid"
|
"github.com/sonirico/go-hyperliquid"
|
||||||
@@ -22,6 +24,9 @@ type HyperliquidTrader struct {
|
|||||||
|
|
||||||
// NewHyperliquidTrader 创建Hyperliquid交易器
|
// NewHyperliquidTrader 创建Hyperliquid交易器
|
||||||
func NewHyperliquidTrader(privateKeyHex string, walletAddr string, testnet bool) (*HyperliquidTrader, error) {
|
func NewHyperliquidTrader(privateKeyHex string, walletAddr string, testnet bool) (*HyperliquidTrader, error) {
|
||||||
|
// 去掉私钥的 0x 前缀(如果有,不区分大小写)
|
||||||
|
privateKeyHex = strings.TrimPrefix(strings.ToLower(privateKeyHex), "0x")
|
||||||
|
|
||||||
// 解析私钥
|
// 解析私钥
|
||||||
privateKey, err := crypto.HexToECDSA(privateKeyHex)
|
privateKey, err := crypto.HexToECDSA(privateKeyHex)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -34,13 +39,18 @@ func NewHyperliquidTrader(privateKeyHex string, walletAddr string, testnet bool)
|
|||||||
apiURL = hyperliquid.TestnetAPIURL
|
apiURL = hyperliquid.TestnetAPIURL
|
||||||
}
|
}
|
||||||
|
|
||||||
// // 从私钥生成钱包地址
|
// 从私钥生成钱包地址(如果未提供)
|
||||||
// pubKey := privateKey.Public()
|
if walletAddr == "" {
|
||||||
// publicKeyECDSA, ok := pubKey.(*ecdsa.PublicKey)
|
pubKey := privateKey.Public()
|
||||||
// if !ok {
|
publicKeyECDSA, ok := pubKey.(*ecdsa.PublicKey)
|
||||||
// return nil, fmt.Errorf("无法转换公钥")
|
if !ok {
|
||||||
// }
|
return nil, fmt.Errorf("无法转换公钥")
|
||||||
// walletAddr := crypto.PubkeyToAddress(*publicKeyECDSA).Hex()
|
}
|
||||||
|
walletAddr = crypto.PubkeyToAddress(*publicKeyECDSA).Hex()
|
||||||
|
log.Printf("✓ 从私钥自动生成钱包地址: %s", walletAddr)
|
||||||
|
} else {
|
||||||
|
log.Printf("✓ 使用提供的钱包地址: %s", walletAddr)
|
||||||
|
}
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
|
|||||||
@@ -123,10 +123,9 @@ export function AITradersPage({ onTraderSelect }: AITradersPageProps) {
|
|||||||
e.asterPrivateKey && e.asterPrivateKey.trim() !== '';
|
e.asterPrivateKey && e.asterPrivateKey.trim() !== '';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hyperliquid 只需要私钥(作为apiKey)和钱包地址
|
// Hyperliquid 只需要私钥(作为apiKey),钱包地址会自动从私钥生成
|
||||||
if (e.id === 'hyperliquid') {
|
if (e.id === 'hyperliquid') {
|
||||||
return e.apiKey && e.apiKey.trim() !== '' &&
|
return e.apiKey && e.apiKey.trim() !== '';
|
||||||
e.hyperliquidWalletAddr && e.hyperliquidWalletAddr.trim() !== '';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Binance 等其他交易所需要 apiKey 和 secretKey
|
// Binance 等其他交易所需要 apiKey 和 secretKey
|
||||||
@@ -1164,8 +1163,6 @@ function ExchangeConfigModal({
|
|||||||
const [testnet, setTestnet] = useState(false);
|
const [testnet, setTestnet] = useState(false);
|
||||||
const [showGuide, setShowGuide] = useState(false);
|
const [showGuide, setShowGuide] = useState(false);
|
||||||
|
|
||||||
// Hyperliquid 特定字段
|
|
||||||
const [hyperliquidWalletAddr, setHyperliquidWalletAddr] = useState('');
|
|
||||||
|
|
||||||
// Aster 特定字段
|
// Aster 特定字段
|
||||||
const [asterUser, setAsterUser] = useState('');
|
const [asterUser, setAsterUser] = useState('');
|
||||||
@@ -1183,9 +1180,6 @@ function ExchangeConfigModal({
|
|||||||
setPassphrase(''); // Don't load existing passphrase for security
|
setPassphrase(''); // Don't load existing passphrase for security
|
||||||
setTestnet(selectedExchange.testnet || false);
|
setTestnet(selectedExchange.testnet || false);
|
||||||
|
|
||||||
// Hyperliquid 字段
|
|
||||||
setHyperliquidWalletAddr(selectedExchange.hyperliquidWalletAddr || '');
|
|
||||||
|
|
||||||
// Aster 字段
|
// Aster 字段
|
||||||
setAsterUser(selectedExchange.asterUser || '');
|
setAsterUser(selectedExchange.asterUser || '');
|
||||||
setAsterSigner(selectedExchange.asterSigner || '');
|
setAsterSigner(selectedExchange.asterSigner || '');
|
||||||
@@ -1202,8 +1196,8 @@ function ExchangeConfigModal({
|
|||||||
if (!apiKey.trim() || !secretKey.trim()) return;
|
if (!apiKey.trim() || !secretKey.trim()) return;
|
||||||
await onSave(selectedExchangeId, apiKey.trim(), secretKey.trim(), testnet);
|
await onSave(selectedExchangeId, apiKey.trim(), secretKey.trim(), testnet);
|
||||||
} else if (selectedExchange?.id === 'hyperliquid') {
|
} else if (selectedExchange?.id === 'hyperliquid') {
|
||||||
if (!apiKey.trim() || !hyperliquidWalletAddr.trim()) return;
|
if (!apiKey.trim()) return; // 只验证私钥,钱包地址自动从私钥生成
|
||||||
await onSave(selectedExchangeId, apiKey.trim(), '', testnet, hyperliquidWalletAddr.trim());
|
await onSave(selectedExchangeId, apiKey.trim(), '', testnet, ''); // 传空字符串,后端自动生成地址
|
||||||
} else if (selectedExchange?.id === 'aster') {
|
} else if (selectedExchange?.id === 'aster') {
|
||||||
if (!asterUser.trim() || !asterSigner.trim() || !asterPrivateKey.trim()) return;
|
if (!asterUser.trim() || !asterSigner.trim() || !asterPrivateKey.trim()) return;
|
||||||
await onSave(selectedExchangeId, '', '', testnet, undefined, asterUser.trim(), asterSigner.trim(), asterPrivateKey.trim());
|
await onSave(selectedExchangeId, '', '', testnet, undefined, asterUser.trim(), asterSigner.trim(), asterPrivateKey.trim());
|
||||||
@@ -1370,24 +1364,6 @@ function ExchangeConfigModal({
|
|||||||
{t('hyperliquidPrivateKeyDesc', language)}
|
{t('hyperliquidPrivateKeyDesc', language)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
|
||||||
<label className="block text-sm font-semibold mb-2" style={{ color: '#EAECEF' }}>
|
|
||||||
{t('walletAddress', language)}
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
value={hyperliquidWalletAddr}
|
|
||||||
onChange={(e) => setHyperliquidWalletAddr(e.target.value)}
|
|
||||||
placeholder={t('enterWalletAddress', language)}
|
|
||||||
className="w-full px-3 py-2 rounded"
|
|
||||||
style={{ background: '#0B0E11', border: '1px solid #2B3139', color: '#EAECEF' }}
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
<div className="text-xs mt-1" style={{ color: '#848E9C' }}>
|
|
||||||
{t('hyperliquidWalletAddressDesc', language)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@@ -1485,7 +1461,7 @@ function ExchangeConfigModal({
|
|||||||
!selectedExchange ||
|
!selectedExchange ||
|
||||||
(selectedExchange.id === 'binance' && (!apiKey.trim() || !secretKey.trim())) ||
|
(selectedExchange.id === 'binance' && (!apiKey.trim() || !secretKey.trim())) ||
|
||||||
(selectedExchange.id === 'okx' && (!apiKey.trim() || !secretKey.trim() || !passphrase.trim())) ||
|
(selectedExchange.id === 'okx' && (!apiKey.trim() || !secretKey.trim() || !passphrase.trim())) ||
|
||||||
(selectedExchange.id === 'hyperliquid' && (!apiKey.trim() || !hyperliquidWalletAddr.trim())) ||
|
(selectedExchange.id === 'hyperliquid' && !apiKey.trim()) || // 只验证私钥,钱包地址可选
|
||||||
(selectedExchange.id === 'aster' && (!asterUser.trim() || !asterSigner.trim() || !asterPrivateKey.trim())) ||
|
(selectedExchange.id === 'aster' && (!asterUser.trim() || !asterSigner.trim() || !asterPrivateKey.trim())) ||
|
||||||
(selectedExchange.type === 'cex' && selectedExchange.id !== 'hyperliquid' && selectedExchange.id !== 'aster' && selectedExchange.id !== 'binance' && selectedExchange.id !== 'okx' && (!apiKey.trim() || !secretKey.trim()))
|
(selectedExchange.type === 'cex' && selectedExchange.id !== 'hyperliquid' && selectedExchange.id !== 'aster' && selectedExchange.id !== 'binance' && selectedExchange.id !== 'okx' && (!apiKey.trim() || !secretKey.trim()))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user