Files
mpc/pkg/api/webhook_sender.go
T
zeekay f110e06800 feat: MPC wallet dashboard - full-stack implementation
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
2026-02-28 13:27:34 -08:00

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()
}