mirror of
https://github.com/luxfi/mpc.git
synced 2026-09-24 00:26:24 +00:00
- Replace github.com/dgraph-io/badger/v4 with github.com/luxfi/zapdb/v4 v4.9.2 throughout pkg/kvstore/, pkg/transport/, cmd/mpcd/, e2e/, scripts/ - Rename BadgerPath/BadgerPassword → ZapDBPath/ZapDBPassword in FactoryConfig - Remove local replace directives from go.mod: - hanzoai/orm: now uses published v0.3.2 (tagged on GitHub) - hanzoai/kv-go/v9: now uses published v9.17.2-hanzo.1 - Only remaining replace: agl/ed25519 → luxfi/edwards25519 - Add vendor/ directory (GOWORK=off go mod vendor) for reproducible builds - Update Dockerfile to golang:1.26-alpine + -mod=vendor build flag - Update CI/CD to use self-hosted linux/amd64 runners (no cross-compilation) - Add k8s/valkey.yaml for session KV store - Update k8s manifests: api-kv support, ZapDB password env, fresh secrets - Dashboard API and MPC nodes all tested running on cluster (3/3 nodes healthy)
129 lines
2.8 KiB
Go
129 lines
2.8 KiB
Go
package api
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"math/big"
|
|
"sort"
|
|
|
|
"github.com/hanzoai/orm"
|
|
"github.com/luxfi/mpc/pkg/db"
|
|
)
|
|
|
|
type PolicyDecision struct {
|
|
Action string `json:"action"`
|
|
Reason string `json:"reason"`
|
|
RequiredApprovers int `json:"required_approvers"`
|
|
}
|
|
|
|
type PolicyConditions struct {
|
|
MaxAmount string `json:"max_amount,omitempty"`
|
|
AllowedChains []string `json:"allowed_chains,omitempty"`
|
|
AllowedAddresses []string `json:"allowed_addresses,omitempty"`
|
|
}
|
|
|
|
func evaluateTransaction(amount, chain, toAddress string, policies []*db.Policy) PolicyDecision {
|
|
// Sort by priority descending
|
|
sort.Slice(policies, func(i, j int) bool {
|
|
return policies[i].Priority > policies[j].Priority
|
|
})
|
|
|
|
for _, policy := range policies {
|
|
if !policy.Enabled {
|
|
continue
|
|
}
|
|
|
|
var conditions PolicyConditions
|
|
if err := json.Unmarshal(policy.Conditions, &conditions); err != nil {
|
|
continue
|
|
}
|
|
|
|
if !matchesConditions(amount, chain, toAddress, conditions) {
|
|
continue
|
|
}
|
|
|
|
switch policy.Action {
|
|
case "deny":
|
|
return PolicyDecision{Action: "deny", Reason: policy.Name}
|
|
case "approve":
|
|
return PolicyDecision{Action: "approve", Reason: policy.Name}
|
|
case "require_approval":
|
|
return PolicyDecision{
|
|
Action: "require_approval",
|
|
Reason: policy.Name,
|
|
RequiredApprovers: policy.RequiredApprovers,
|
|
}
|
|
}
|
|
}
|
|
|
|
// Default: require approval with 1 admin
|
|
return PolicyDecision{
|
|
Action: "require_approval",
|
|
Reason: "default policy",
|
|
RequiredApprovers: 1,
|
|
}
|
|
}
|
|
|
|
func matchesConditions(amount, chain, toAddress string, cond PolicyConditions) bool {
|
|
if len(cond.AllowedChains) > 0 {
|
|
found := false
|
|
for _, c := range cond.AllowedChains {
|
|
if c == chain {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
if !found {
|
|
return false
|
|
}
|
|
}
|
|
|
|
if len(cond.AllowedAddresses) > 0 {
|
|
found := false
|
|
for _, a := range cond.AllowedAddresses {
|
|
if a == toAddress {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
if !found {
|
|
return false
|
|
}
|
|
}
|
|
|
|
if cond.MaxAmount != "" && amount != "" {
|
|
max, ok1 := new(big.Float).SetString(cond.MaxAmount)
|
|
val, ok2 := new(big.Float).SetString(amount)
|
|
if ok1 && ok2 && val.Cmp(max) > 0 {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
func (s *Server) loadPolicies(ctx context.Context, orgID string, vaultID *string) ([]*db.Policy, error) {
|
|
q := orm.TypedQuery[db.Policy](s.db.ORM).
|
|
Filter("orgId =", orgID).
|
|
Filter("enabled =", true).
|
|
Order("-priority")
|
|
|
|
policies, err := q.GetAll(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Filter by vaultID if provided (include policies with no vaultID or matching vaultID)
|
|
if vaultID != nil {
|
|
var filtered []*db.Policy
|
|
for _, p := range policies {
|
|
if p.VaultID == nil || *p.VaultID == *vaultID {
|
|
filtered = append(filtered, p)
|
|
}
|
|
}
|
|
return filtered, nil
|
|
}
|
|
|
|
return policies, nil
|
|
}
|