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 ¶
const DefaultTier = TierHot
DefaultTier is the tier a wallet gets when the request omits one.
Variables ¶
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 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.
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.
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.