package main import ( "encoding/json" "errors" "os" "path/filepath" "strings" "time" ) // ================== Stato locale (anti-doppio ordine) ================== type Lock struct { TS time.Time `json:"ts"` From string `json:"from"` To string `json:"to"` AmountFrom float64 `json:"amount_from"` Status string `json:"status"` // pending/confirmed/cancelled } type PortfolioState struct { Version int `json:"version"` UpdatedAt time.Time `json:"updated_at"` Balances map[string]float64 `json:"balances"` Locks []Lock `json:"locks"` } func loadState(path string) (PortfolioState, error) { b, err := os.ReadFile(path) if errors.Is(err, os.ErrNotExist) { return PortfolioState{Version: 1, UpdatedAt: time.Now().UTC(), Balances: map[string]float64{}, Locks: []Lock{}}, nil } if err != nil { return PortfolioState{}, err } var s PortfolioState if err := json.Unmarshal(b, &s); err != nil { return PortfolioState{}, err } return s, nil } func saveState(path string, s PortfolioState) error { s.UpdatedAt = time.Now().UTC() if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil { return err } b, _ := json.Marshal(s) return os.WriteFile(path, b, 0o644) } func assetShort(label string) string { parts := strings.Split(label, ".") if len(parts) != 2 { return label } right := parts[1] if i := strings.Index(right, "-"); i > 0 { right = right[:i] } return parts[0] + "." + right }