feat: fix Lighter V2 integration and improve error handling

- Fix Lighter API field name mismatches (position/size, avg_entry_price/entry_price, sign/side)
- Fix GetBalance return format to match standard fields (totalWalletBalance, totalUnrealizedProfit)
- Fix GetPositions return format to match standard fields (positionAmt, markPrice, unRealizedProfit)
- Add API Key Index field to frontend with explanation
- Update Lighter referral link
- Disable Lighter testnet (mainnet only)
- Add load error tracking for better error messages
- Remove old Lighter V1 implementation files
- Remove test credentials from test files
This commit is contained in:
tinkle-community
2025-12-14 20:50:10 +08:00
parent abaffaddb9
commit 4725548a55
22 changed files with 749 additions and 1774 deletions

View File

@@ -5,8 +5,9 @@ import (
"encoding/json"
"fmt"
"io"
"nofx/logger"
"mime/multipart"
"net/http"
"nofx/logger"
"strconv"
"github.com/elliottech/lighter-go/types"
@@ -271,10 +272,11 @@ func (t *LighterTraderV2) CancelOrder(symbol, orderID string) error {
}
// Get market index
marketIndex, err := t.getMarketIndex(symbol)
marketIndexU16, err := t.getMarketIndex(symbol)
if err != nil {
return fmt.Errorf("failed to get market index: %w", err)
}
marketIndex := uint8(marketIndexU16) // SDK expects uint8
// Convert orderID to int64
orderIndex, err := strconv.ParseInt(orderID, 10, 64)
@@ -313,30 +315,37 @@ func (t *LighterTraderV2) CancelOrder(symbol, orderID string) error {
return nil
}
// submitCancelOrder Submit signed cancel order to LIGHTER API
// submitCancelOrder Submit signed cancel order to LIGHTER API using multipart/form-data
func (t *LighterTraderV2) submitCancelOrder(signedTx []byte) (map[string]interface{}, error) {
const TX_TYPE_CANCEL_ORDER = 15
// Build request
req := SendTxRequest{
TxType: TX_TYPE_CANCEL_ORDER,
TxInfo: string(signedTx),
PriceProtection: false, // Cancel order doesn't need price protection
// Build multipart form data (Lighter API requires form-data, not JSON)
var body bytes.Buffer
writer := multipart.NewWriter(&body)
// Add tx_type field
if err := writer.WriteField("tx_type", strconv.Itoa(TX_TYPE_CANCEL_ORDER)); err != nil {
return nil, fmt.Errorf("failed to write tx_type: %w", err)
}
reqBody, err := json.Marshal(req)
if err != nil {
return nil, fmt.Errorf("failed to serialize request: %w", err)
// Add tx_info field
if err := writer.WriteField("tx_info", string(signedTx)); err != nil {
return nil, fmt.Errorf("failed to write tx_info: %w", err)
}
// Close multipart writer
if err := writer.Close(); err != nil {
return nil, fmt.Errorf("failed to close multipart writer: %w", err)
}
// Send POST request to /api/v1/sendTx
endpoint := fmt.Sprintf("%s/api/v1/sendTx", t.baseURL)
httpReq, err := http.NewRequest("POST", endpoint, bytes.NewBuffer(reqBody))
httpReq, err := http.NewRequest("POST", endpoint, &body)
if err != nil {
return nil, err
}
httpReq.Header.Set("Content-Type", "application/json")
httpReq.Header.Set("Content-Type", writer.FormDataContentType())
resp, err := t.client.Do(httpReq)
if err != nil {
@@ -344,15 +353,15 @@ func (t *LighterTraderV2) submitCancelOrder(signedTx []byte) (map[string]interfa
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
// Parse response
var sendResp SendTxResponse
if err := json.Unmarshal(body, &sendResp); err != nil {
return nil, fmt.Errorf("failed to parse response: %w, body: %s", err, string(body))
if err := json.Unmarshal(respBody, &sendResp); err != nil {
return nil, fmt.Errorf("failed to parse response: %w, body: %s", err, string(respBody))
}
// Check response code