mirror of
https://github.com/luxfi/mpc.git
synced 2026-09-24 00:26:24 +00:00
Complete MPC wallet management platform rivaling Fireblocks/Utila/Fordefi: Backend (Go): - REST API with 60+ endpoints on chi router (pkg/api/) - PostgreSQL schema with 13 tables (pkg/db/) - JWT + MFA auth, bcrypt passwords, API key management - Policy engine (deny/approve/require_approval) - Transaction signing flow with approval workflow - Subscription scheduler for recurring payments - Payment requests with public pay pages - Safe + ERC-4337 smart wallet integration (pkg/smart/) - Rate limiting, webhook delivery (HMAC-SHA256), audit logging - 27 passing tests (auth, policy engine, middleware) Frontend (Next.js 14): - 27 routes with monochrome dark theme (Tailwind + Geist fonts) - Full API client with JWT auto-refresh - React Query hooks for all resources - Pages: dashboard, vaults, wallets, transactions, policies, whitelist, team, settings, API keys, webhooks, audit, subscriptions, payments, smart wallets Infrastructure: - Dockerfiles for API (Go) and dashboard (Next.js standalone) - compose.yml for local development (PostgreSQL + API + dashboard) - K8s manifests for mpc.lux.network + cloud.lux.network - GitHub Actions deploy workflow (build → push GHCR → kubectl apply) - TLS via cert-manager, Traefik IngressRoute for both domains
65 lines
1.3 KiB
Go
65 lines
1.3 KiB
Go
package api
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"crypto/hmac"
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"net/http"
|
|
"time"
|
|
)
|
|
|
|
func (s *Server) fireWebhook(ctx context.Context, orgID, event string, data interface{}) {
|
|
rows, err := s.db.Pool.Query(ctx,
|
|
`SELECT url, secret FROM webhooks
|
|
WHERE org_id = $1 AND enabled = true AND $2 = ANY(events)`,
|
|
orgID, event)
|
|
if err != nil {
|
|
return
|
|
}
|
|
defer rows.Close()
|
|
|
|
payload := map[string]interface{}{
|
|
"event": event,
|
|
"data": data,
|
|
"timestamp": time.Now().UTC().Format(time.RFC3339),
|
|
}
|
|
|
|
for rows.Next() {
|
|
var url, secret string
|
|
if err := rows.Scan(&url, &secret); err != nil {
|
|
continue
|
|
}
|
|
go deliverWebhook(url, secret, payload)
|
|
}
|
|
}
|
|
|
|
func deliverWebhook(url, secret string, payload interface{}) {
|
|
body, err := json.Marshal(payload)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
// HMAC-SHA256 signature
|
|
mac := hmac.New(sha256.New, []byte(secret))
|
|
mac.Write(body)
|
|
sig := hex.EncodeToString(mac.Sum(nil))
|
|
|
|
req, err := http.NewRequest("POST", url, bytes.NewReader(body))
|
|
if err != nil {
|
|
return
|
|
}
|
|
req.Header.Set("Content-Type", "application/json")
|
|
req.Header.Set("X-Webhook-Signature", sig)
|
|
req.Header.Set("X-Webhook-Timestamp", time.Now().UTC().Format(time.RFC3339))
|
|
|
|
client := &http.Client{Timeout: 10 * time.Second}
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
return
|
|
}
|
|
resp.Body.Close()
|
|
}
|