wallets

package
v1.786.120 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 7, 2026 License: Apache-2.0 Imports: 24 Imported by: 0

Documentation

Overview

Package wallets is the Hanzo Cloud accounts/wallets/custody/keys/sign surface (/v1/wallets/*): one configurable custody seam over three orthogonal signing backends, selected PER WALLET by its Kind.

TOPOLOGY (HIP-0106). Custody composes the two canonical Hanzo key services without fusing either into the hot binary:

  • KMS single-sig (KindKMS) is IN-PROCESS via the embedded luxfi/kms client (deps.KMS, a cloud.KMSClient). This is the fully-exercised spine: a real secp256k1 key is generated, its private bytes sealed under the KMS envelope, and every Sign recovers to the wallet address. No network hop.

  • MPC m-of-n (KindMPC) and treasury named-signer custody (KindTreasury) DELEGATE over HTTP to the DEPLOYED luxfi/mpc cluster (mpcclient.go), a thin typed REST client. cloud is a faithful CLIENT of the real service — it never imports github.com/luxfi/mpc (that drags chi/Postgres/HSM/ webauthn into the binary). Exactly the clients/mpcseal precedent. When the cluster is not configured these backends fail CLOSED (ErrMPCNotConfigured); a signature is NEVER fabricated.

The seam is the whole point: swapping a wallet's custody is a config value on one row, not a code path. custody.go owns the interface + the three backends; mpcclient.go owns the mpc wire; store.go owns persistence; wallets.go owns HTTP.

wallets.go owns the HTTP surface (/v1/wallets/*), the Mount/config seam that selects the custody set, the process singleton, and the finance seam.

POST /v1/wallets/accounts   {name}                              -> create account
GET  /v1/wallets/accounts                                       -> list MY accounts
POST /v1/wallets            {accountId,name,custody,tier,chain}  -> create wallet (Provision)
GET  /v1/wallets                                                -> list MY wallets
GET  /v1/wallets/:id                                            -> get one (404 if not my org)
POST /v1/wallets/:id/keys                                       -> rotate key material
POST /v1/wallets/:id/sign   {message?|digest?}                  -> sign (digest=hex 32B, else Keccak256(message))

Every handler derives the tenant through principal.Tenant (the ONE trust signal) and refuses with 403 when absent. Config selects the custody set: KMS is ALWAYS available (deps.KMS); MPC + treasury only when the cluster is wired (CLOUD_WALLETS_MPC_ADDR) and the JWT secret resolves from KMS — else those Kinds fail closed with ErrMPCNotConfigured.

Index

Constants

View Source
const DefaultTier = TierHot

DefaultTier is the tier a wallet gets when the request omits one.

Variables

View Source
var (
	ErrMPCNotConfigured = errors.New("mpc cluster not configured; set CLOUD_WALLETS_MPC_ADDR")
	ErrUnknownCustody   = errors.New("unknown custody kind")
)

Fail-closed sentinels. ErrMPCNotConfigured is returned whenever an MPC/treasury wallet is provisioned or signed without a configured cluster + JWT secret — the operator must wire CLOUD_WALLETS_MPC_ADDR (and the KMS JWT secret ref).

Functions

func Mount

func Mount(app *zip.App, deps cloud.Deps) error

Mount wires the wallets surface onto app per HIP-0106.

func Shutdown

func Shutdown() error

Shutdown closes the store. Idempotent.

func WalletForLedgerAccount

func WalletForLedgerAccount(ctx context.Context, org, ledgerAccount string) (address string, ok bool)

WalletForLedgerAccount resolves the on-chain wallet bound to a finance ledger account — the seam by which the treasury reserve signer BECOMES an MPC treasury wallet later. Pure lookup; ("",false) when unmounted/unbound. Does NOT modify treasury.

Types

type Account

type Account struct {
	ID        string `json:"id"`
	Org       string `json:"org"`
	Name      string `json:"name"`
	CreatedAt int64  `json:"createdAt"`
}

Account is a named grouping of wallets owned by exactly one org.

type Custody

type Custody interface {
	Kind() Kind
	Provision(ctx context.Context, w *Wallet) (address string, err error)       // create signing material, set w.KeyRef, return address
	Sign(ctx context.Context, w *Wallet, digest []byte) (sig []byte, err error) // sign a 32-byte digest
	Rotate(ctx context.Context, w *Wallet) (address string, err error)          // roll key material, set w.KeyRef, return address
}

Custody is the ONE seam. Each backend creates signing material (Provision), signs a 32-byte digest (Sign), and rolls the material (Rotate). Provision and Rotate return the resulting pubkey ADDRESS and set w.KeyRef to the backend's handle for that material.

type Kind

type Kind string

Kind selects a wallet's custody backend. One interface, three backends.

const (
	KindKMS      Kind = "kms"      // in-process single-sig via the embedded luxfi/kms
	KindMPC      Kind = "mpc"      // m-of-n threshold via the deployed luxfi/mpc cluster (HTTP)
	KindTreasury Kind = "treasury" // named-signer governance via luxfi/mpc's treasury surface (HTTP)
)

func (Kind) Valid

func (k Kind) Valid() bool

Valid reports whether k is one of the three supported custody kinds.

type Tier

type Tier string

Tier mirrors luxfi/mpc's 9-tier wallet model (pkg/wallet/tier.go) as string constants so cloud never imports the mpc package. The values are the wire contract the cluster keys its TierPolicy on; a local mirror keeps them in ONE place here and refuses an unknown tier at the boundary.

const (
	TierHot           Tier = "hot"
	TierWarm          Tier = "warm"
	TierCold          Tier = "cold"
	TierGas           Tier = "gas"
	TierBridge        Tier = "bridge"
	TierContractAdmin Tier = "contract_admin"
	TierValidator     Tier = "validator"
	TierQuarantine    Tier = "quarantine"
	TierDR            Tier = "disaster_recovery"
)

type Wallet

type Wallet struct {
	ID             string `json:"id"`
	Org            string `json:"org"`
	AccountID      string `json:"accountId"`
	Name           string `json:"name"`
	Custody        Kind   `json:"custody"`
	Tier           Tier   `json:"tier"`
	Chain          string `json:"chain"`
	Address        string `json:"address"`
	KeyRef         string `json:"-"` // custody-internal handle; never serialized
	FinanceAccount string `json:"financeAccount,omitempty"`
	CreatedAt      int64  `json:"createdAt"`
}

Wallet is one signing identity. Custody selects the backend; KeyRef is the custody-internal HANDLE to the signing material (a KMS secret ref, or the mpc wallet id) — set by Provision, never a private-key VALUE, and never returned over the API.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL