Files
cloudinit-bot 9abda8d01e feat(cover,guild,stand): P5 Anti-Capture Bill ceremony + secession + Pier
P5 (final execution phase) of v0.7 delivers REQ-056, REQ-059, REQ-064,
REQ-066:

x/cover — Bill of Rights ceremony (REQ-056) + Pier Selection (REQ-066):
MsgCounselReviewBillOfRights (bonded Counsel, Staked=true gate);
MsgSelectPier (Guild Council + GuildKeeper shim + PierSelectionIndex);
MsgRevokePierSelection (supermajority + Counsel witness); PierSelectionIndex
+ PierSelectionRecord structs; bill_review/pier_selection/pier_index stores.

x/guild — Secession cooling (REQ-064) + Stand->Pier (REQ-059, D-074):
MsgInitiateSecession (SecessionStartedAt + lien audit); MsgCompleteSecession
(21d Cover-active / 14d non-Cover cooling + lien audit + covenant clearance
+ pro-rata settlement event); MsgEscalateStandToPier (10M Grain-cents D-074
threshold, soft upgrade); MsgAcceptPierInvitation; Guild.SecessionStartedAt
+ SecededAt + Lien.Cleared additive; LOCAL StandPierEscalationAnnualPass
VolumeCents const (G-003 local-const mirror of x/stand canonical).

x/stand — StandPierEscalationAnnualPassVolumeCents=10000000 canonical const.

Coverage: cover/keeper 94.6%, guild/keeper 94.1%, stand/types 100%.
G-006/G-028 intact. go.mod/go.sum diff EMPTY. go vet clean. Lexicon green.

---ci---
project: oy
phase: 5
milestone: v0.7
status: execute
---/ci---
2026-08-19 02:44:12 +00:00

742 lines
27 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package keeper
// keeper.go holds the store-backed Keeper for the cover module's Cover Pool
// runtime (REQ-046, REQ-047, REQ-049, REQ-050, REQ-055, D-077, D-086,
// D-088, D-089).
//
// The Keeper wraps an sdk.KVStore via a storeKey. It holds:
// - the CoverPool records (pool-id -> CoverPool);
// - the CoverCall records (call-id -> CoverCall; the FileCoverCall
// handler persists here; P4 adds the Voucher adjudication).
//
// The Cover-Fee routing (RouteCoverFee) does NOT persist a separate record
// in P1 — the routing is the event (the reserve balance update is a
// simtest-grade stub). P2 may add a CoverFeeRouting record; P1 ships the
// event-only path.
//
// The Keeper also holds the FOUR expected-keeper shims (StandingKeeper for
// the D-077 gate; WatcherKeeper for the launch attestation; BondKeeper for
// the P4 MAB check; StillKeeper for the below-floor auto-pause). The shims
// are interfaces (G-003 — no struct import of x/standing/types,
// x/watcher/types, x/bond/types, x/still/types); the concrete keepers (or
// simtest stubs) satisfy them structurally.
//
// State-machine ordering (vision §7, enforced in every handler):
// ValidateBasic -> handler authz/gate -> state mutation -> ctx.EventManager().EmitEvent
import (
"encoding/json"
"fmt"
storetypes "cosmossdk.io/store/types"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/oy/openyield/x/cover/types"
)
// Keeper is the store-backed cover Cover-Pool keeper.
type Keeper struct {
cdc codec.Codec
storeKey storetypes.StoreKey
standingKeeper types.StandingKeeper
watcherKeeper types.WatcherKeeper
bondKeeper types.BondKeeper
stillKeeper types.StillKeeper
guildKeeper types.GuildKeeper
// paramsOverride is a simtest-grade Params override (nil = use
// DefaultParams). A future P2+ will load the Params from the params
// store; for now the handler uses DefaultParams unless an override is
// set via SetParamsOverride (the D-086 simtest case (f) uses this to
// restrict FactoryAllowedPhases to [Phase2, Phase3] only and reject a
// Phase4 launch).
paramsOverride *types.Params
}
// NewKeeper constructs a new store-backed cover Keeper. The four expected-
// keeper shims are injected (all nil-able for partial tests; the handlers
// guard nil shims and skip the corresponding check, still mutating state —
// the simtest wiring documents this). The StandingKeeper gates the launch
// (D-077); the WatcherKeeper attests the launch (REQ-046); the BondKeeper
// is held for P4 (the P1 handlers do not call it); the StillKeeper records
// the below-floor auto-pause (D-089(1)). The P5 GuildKeeper verifies a
// Guild exists on Pier selection (REQ-066; a nil shim skips the check).
func NewKeeper(cdc codec.Codec, storeKey storetypes.StoreKey, sk types.StandingKeeper, wk types.WatcherKeeper, bk types.BondKeeper, stK types.StillKeeper) Keeper {
return Keeper{
cdc: cdc,
storeKey: storeKey,
standingKeeper: sk,
watcherKeeper: wk,
bondKeeper: bk,
stillKeeper: stK,
}
}
// SetStandingKeeper sets the StandingKeeper expected-keeper shim (for
// post-construction wiring, e.g., app wiring or test setup).
func (k *Keeper) SetStandingKeeper(sk types.StandingKeeper) { k.standingKeeper = sk }
// SetWatcherKeeper sets the WatcherKeeper expected-keeper shim.
func (k *Keeper) SetWatcherKeeper(wk types.WatcherKeeper) { k.watcherKeeper = wk }
// SetBondKeeper sets the BondKeeper expected-keeper shim.
func (k *Keeper) SetBondKeeper(bk types.BondKeeper) { k.bondKeeper = bk }
// SetStillKeeper sets the StillKeeper expected-keeper shim.
func (k *Keeper) SetStillKeeper(stK types.StillKeeper) { k.stillKeeper = stK }
// SetGuildKeeper sets the GuildKeeper expected-keeper shim (P5 — REQ-066
// Pier Selection uses this to verify the selecting Guild exists; a nil
// shim skips the existence check, simtest wiring).
func (k *Keeper) SetGuildKeeper(gk types.GuildKeeper) { k.guildKeeper = gk }
// SetParamsOverride sets a simtest-grade Params override (nil = use
// DefaultParams). The D-086 simtest case (f) uses this to restrict
// FactoryAllowedPhases to [Phase2, Phase3] only and reject a Phase4
// launch. A future P2+ will replace this with a params-store load.
func (k *Keeper) SetParamsOverride(p types.Params) { k.paramsOverride = &p }
// Params returns the effective Params (the override if set, else
// DefaultParams). The handler calls this to get FactoryAllowedPhases +
// PoolStandingGate.
func (k Keeper) Params() types.Params {
if k.paramsOverride != nil {
return *k.paramsOverride
}
return types.DefaultParams()
}
// StoreKey returns the keeper's store key (exported for simtest access to
// the underlying KVStore, e.g. to inject corrupt bytes for marshal-error
// coverage). Mirrors the x/hub simtest pattern (the simtest reaches the
// store via ctx.KVStore(k.StoreKey())).
func (k Keeper) StoreKey() storetypes.StoreKey { return k.storeKey }
// --- CoverPool store ----------------------------------------------------------
var poolKeyPrefix = []byte("pool/")
func poolKey(poolID string) []byte {
return append(poolKeyPrefix, []byte(poolID)...)
}
// GetCoverPool loads a CoverPool by pool-id. Returns the pool and true if
// found, or zero value + false if not.
func (k Keeper) GetCoverPool(ctx sdk.Context, poolID string) (types.CoverPool, bool) {
store := ctx.KVStore(k.storeKey)
bz := store.Get(poolKey(poolID))
if bz == nil {
return types.CoverPool{}, false
}
var p types.CoverPool
if err := json.Unmarshal(bz, &p); err != nil {
return types.CoverPool{}, false
}
return p, true
}
// SetCoverPool persists a CoverPool by pool-id.
func (k Keeper) SetCoverPool(ctx sdk.Context, p types.CoverPool) {
store := ctx.KVStore(k.storeKey)
bz, err := json.Marshal(p)
if err != nil {
panic(fmt.Sprintf("cover: marshal pool %q: %v", p.PoolID, err))
}
store.Set(poolKey(p.PoolID), bz)
}
// AllCoverPools returns all persisted CoverPool records (iteration helper,
// unordered).
func (k Keeper) AllCoverPools(ctx sdk.Context) []types.CoverPool {
store := ctx.KVStore(k.storeKey)
iterator := store.Iterator(poolKeyPrefix, prefixEnd(poolKeyPrefix))
defer iterator.Close()
out := []types.CoverPool{}
for ; iterator.Valid(); iterator.Next() {
var p types.CoverPool
if err := json.Unmarshal(iterator.Value(), &p); err == nil {
out = append(out, p)
}
}
return out
}
// --- CoverCall store ----------------------------------------------------------
var callKeyPrefix = []byte("call/")
func callKey(callID string) []byte {
return append(callKeyPrefix, []byte(callID)...)
}
// GetCoverCall loads a CoverCall by call-id. Returns the call and true if
// found, or zero value + false if not.
func (k Keeper) GetCoverCall(ctx sdk.Context, callID string) (types.CoverCall, bool) {
store := ctx.KVStore(k.storeKey)
bz := store.Get(callKey(callID))
if bz == nil {
return types.CoverCall{}, false
}
var c types.CoverCall
if err := json.Unmarshal(bz, &c); err != nil {
return types.CoverCall{}, false
}
return c, true
}
// SetCoverCall persists a CoverCall by call-id.
func (k Keeper) SetCoverCall(ctx sdk.Context, c types.CoverCall) {
store := ctx.KVStore(k.storeKey)
bz, err := json.Marshal(c)
if err != nil {
panic(fmt.Sprintf("cover: marshal call %q: %v", c.CallID, err))
}
store.Set(callKey(c.CallID), bz)
}
// AllCoverCalls returns all persisted CoverCall records (iteration helper,
// unordered).
func (k Keeper) AllCoverCalls(ctx sdk.Context) []types.CoverCall {
store := ctx.KVStore(k.storeKey)
iterator := store.Iterator(callKeyPrefix, prefixEnd(callKeyPrefix))
defer iterator.Close()
out := []types.CoverCall{}
for ; iterator.Valid(); iterator.Next() {
var c types.CoverCall
if err := json.Unmarshal(iterator.Value(), &c); err == nil {
out = append(out, c)
}
}
return out
}
// --- P4: CoverClaimsVoucher store (REQ-055, D-090(2)) ------------------------
//
// The Voucher store is keyed by voucher-reach-id + pool-id (composite key)
// -> CoverClaimsVoucher. A Voucher is registered per-Pool; the composite key
// enforces idempotency (no duplicate Voucher for the same Pool). The
// GetAvgCallSize helper computes the average Cover Call amount for a Pool
// from the call/ store (returns 0 if no Calls — the D-090(2) cold-start
// case).
var voucherKeyPrefix = []byte("voucher/")
func voucherKey(voucherReachID, poolID string) []byte {
return append(append(voucherKeyPrefix, []byte(voucherReachID)...), []byte("/"+poolID)...)
}
// GetCoverClaimsVoucher loads a CoverClaimsVoucher by voucher-reach-id +
// pool-id. Returns the Voucher and true if found, or zero value + false if
// not.
func (k Keeper) GetCoverClaimsVoucher(ctx sdk.Context, voucherReachID, poolID string) (types.CoverClaimsVoucher, bool) {
store := ctx.KVStore(k.storeKey)
bz := store.Get(voucherKey(voucherReachID, poolID))
if bz == nil {
return types.CoverClaimsVoucher{}, false
}
var v types.CoverClaimsVoucher
if err := json.Unmarshal(bz, &v); err != nil {
return types.CoverClaimsVoucher{}, false
}
return v, true
}
// SetCoverClaimsVoucher persists a CoverClaimsVoucher by voucher-reach-id +
// pool-id.
func (k Keeper) SetCoverClaimsVoucher(ctx sdk.Context, v types.CoverClaimsVoucher) {
store := ctx.KVStore(k.storeKey)
bz, err := json.Marshal(v)
if err != nil {
panic(fmt.Sprintf("cover: marshal voucher %q/%q: %v", v.VoucherReachID, v.PoolID, err))
}
store.Set(voucherKey(v.VoucherReachID, v.PoolID), bz)
}
// AllCoverClaimsVouchers returns all persisted CoverClaimsVoucher records
// (iteration helper, unordered).
func (k Keeper) AllCoverClaimsVouchers(ctx sdk.Context) []types.CoverClaimsVoucher {
store := ctx.KVStore(k.storeKey)
iterator := store.Iterator(voucherKeyPrefix, prefixEnd(voucherKeyPrefix))
defer iterator.Close()
out := []types.CoverClaimsVoucher{}
for ; iterator.Valid(); iterator.Next() {
var v types.CoverClaimsVoucher
if err := json.Unmarshal(iterator.Value(), &v); err == nil {
out = append(out, v)
}
}
return out
}
// GetAvgCallSize computes the average Cover Call amount (Grain) for a Pool
// from the call/ store (REQ-055, D-090(2)). Returns 0 if no Calls have been
// filed for the Pool — the D-090(2) cold-start case (the Voucher bond falls
// back to MinimumVoucherBond, NOT zero).
func (k Keeper) GetAvgCallSize(ctx sdk.Context, poolID string) int64 {
calls := k.AllCoverCalls(ctx)
sum := int64(0)
n := 0
for _, c := range calls {
if c.PoolID == poolID {
sum += c.AmountGrain
n++
}
}
if n == 0 {
return 0
}
return sum / int64(n)
}
// --- prefixEnd helper ---------------------------------------------------------
// prefixEnd returns the key that sorts immediately after all keys sharing
// the given prefix (the standard prefix-iteration end key: increment the
// last byte, drop overflow). Used for store.Iterator(start, prefixEnd(start))
// prefix scans. Mirrors x/hub/keeper/keeper.go.
func prefixEnd(prefix []byte) []byte {
if len(prefix) == 0 {
return nil
}
end := make([]byte, len(prefix))
copy(end, prefix)
for i := len(end) - 1; i >= 0; i-- {
end[i]++
if end[i] != 0 {
return end
}
}
// All bytes were 0xFF; return nil (iterate to end of store).
return nil
}
// --- P2: CoverCharter / PoolCouncil / CoverCallVote / CharterAmendment stores --
//
// (REQ-052, REQ-062). Four new stores keyed by ID-string. The
// CoverCharter store is keyed by CharterID; the PoolCouncil store is keyed
// by PoolID (one council per pool); the CoverCallVote store is keyed by
// VoteID; the CharterAmendment store is keyed by AmendmentID. All four
// use the same JSON-marshal pattern as the P1 CoverPool / CoverCall
// stores. The Get/Set/All helpers mirror the P1 helpers.
var charterKeyPrefix = []byte("charter/")
func charterKey(charterID string) []byte {
return append(charterKeyPrefix, []byte(charterID)...)
}
// GetCoverCharter loads a CoverCharter by charter-id. Returns the charter
// and true if found, or zero value + false if not.
func (k Keeper) GetCoverCharter(ctx sdk.Context, charterID string) (types.CoverCharter, bool) {
store := ctx.KVStore(k.storeKey)
bz := store.Get(charterKey(charterID))
if bz == nil {
return types.CoverCharter{}, false
}
var c types.CoverCharter
if err := json.Unmarshal(bz, &c); err != nil {
return types.CoverCharter{}, false
}
return c, true
}
// SetCoverCharter persists a CoverCharter by charter-id.
func (k Keeper) SetCoverCharter(ctx sdk.Context, c types.CoverCharter) {
store := ctx.KVStore(k.storeKey)
bz, err := json.Marshal(c)
if err != nil {
panic(fmt.Sprintf("cover: marshal charter %q: %v", c.CharterID, err))
}
store.Set(charterKey(c.CharterID), bz)
}
// AllCoverCharters returns all persisted CoverCharter records (iteration
// helper, unordered).
func (k Keeper) AllCoverCharters(ctx sdk.Context) []types.CoverCharter {
store := ctx.KVStore(k.storeKey)
iterator := store.Iterator(charterKeyPrefix, prefixEnd(charterKeyPrefix))
defer iterator.Close()
out := []types.CoverCharter{}
for ; iterator.Valid(); iterator.Next() {
var c types.CoverCharter
if err := json.Unmarshal(iterator.Value(), &c); err == nil {
out = append(out, c)
}
}
return out
}
var councilKeyPrefix = []byte("council/")
func councilKey(poolID string) []byte {
return append(councilKeyPrefix, []byte(poolID)...)
}
// GetPoolCouncil loads a PoolCouncil by pool-id. Returns the council and
// true if found, or zero value + false if not.
func (k Keeper) GetPoolCouncil(ctx sdk.Context, poolID string) (types.PoolCouncil, bool) {
store := ctx.KVStore(k.storeKey)
bz := store.Get(councilKey(poolID))
if bz == nil {
return types.PoolCouncil{}, false
}
var c types.PoolCouncil
if err := json.Unmarshal(bz, &c); err != nil {
return types.PoolCouncil{}, false
}
return c, true
}
// SetPoolCouncil persists a PoolCouncil by pool-id.
func (k Keeper) SetPoolCouncil(ctx sdk.Context, c types.PoolCouncil) {
store := ctx.KVStore(k.storeKey)
bz, err := json.Marshal(c)
if err != nil {
panic(fmt.Sprintf("cover: marshal council for pool %q: %v", c.PoolID, err))
}
store.Set(councilKey(c.PoolID), bz)
}
// AllPoolCouncils returns all persisted PoolCouncil records (iteration
// helper, unordered).
func (k Keeper) AllPoolCouncils(ctx sdk.Context) []types.PoolCouncil {
store := ctx.KVStore(k.storeKey)
iterator := store.Iterator(councilKeyPrefix, prefixEnd(councilKeyPrefix))
defer iterator.Close()
out := []types.PoolCouncil{}
for ; iterator.Valid(); iterator.Next() {
var c types.PoolCouncil
if err := json.Unmarshal(iterator.Value(), &c); err == nil {
out = append(out, c)
}
}
return out
}
var voteKeyPrefix = []byte("vote/")
func voteKey(voteID string) []byte {
return append(voteKeyPrefix, []byte(voteID)...)
}
// GetCoverCallVote loads a CoverCallVote by vote-id. Returns the vote and
// true if found, or zero value + false if not.
func (k Keeper) GetCoverCallVote(ctx sdk.Context, voteID string) (types.CoverCallVote, bool) {
store := ctx.KVStore(k.storeKey)
bz := store.Get(voteKey(voteID))
if bz == nil {
return types.CoverCallVote{}, false
}
var v types.CoverCallVote
if err := json.Unmarshal(bz, &v); err != nil {
return types.CoverCallVote{}, false
}
return v, true
}
// SetCoverCallVote persists a CoverCallVote by vote-id.
func (k Keeper) SetCoverCallVote(ctx sdk.Context, v types.CoverCallVote) {
store := ctx.KVStore(k.storeKey)
bz, err := json.Marshal(v)
if err != nil {
panic(fmt.Sprintf("cover: marshal vote %q: %v", v.VoteID, err))
}
store.Set(voteKey(v.VoteID), bz)
}
// AllCoverCallVotes returns all persisted CoverCallVote records (iteration
// helper, unordered).
func (k Keeper) AllCoverCallVotes(ctx sdk.Context) []types.CoverCallVote {
store := ctx.KVStore(k.storeKey)
iterator := store.Iterator(voteKeyPrefix, prefixEnd(voteKeyPrefix))
defer iterator.Close()
out := []types.CoverCallVote{}
for ; iterator.Valid(); iterator.Next() {
var v types.CoverCallVote
if err := json.Unmarshal(iterator.Value(), &v); err == nil {
out = append(out, v)
}
}
return out
}
var amendmentKeyPrefix = []byte("amendment/")
func amendmentKey(amendmentID string) []byte {
return append(amendmentKeyPrefix, []byte(amendmentID)...)
}
// GetCharterAmendment loads a CharterAmendment by amendment-id. Returns
// the amendment and true if found, or zero value + false if not.
func (k Keeper) GetCharterAmendment(ctx sdk.Context, amendmentID string) (types.CharterAmendment, bool) {
store := ctx.KVStore(k.storeKey)
bz := store.Get(amendmentKey(amendmentID))
if bz == nil {
return types.CharterAmendment{}, false
}
var a types.CharterAmendment
if err := json.Unmarshal(bz, &a); err != nil {
return types.CharterAmendment{}, false
}
return a, true
}
// SetCharterAmendment persists a CharterAmendment by amendment-id.
func (k Keeper) SetCharterAmendment(ctx sdk.Context, a types.CharterAmendment) {
store := ctx.KVStore(k.storeKey)
bz, err := json.Marshal(a)
if err != nil {
panic(fmt.Sprintf("cover: marshal amendment %q: %v", a.AmendmentID, err))
}
store.Set(amendmentKey(a.AmendmentID), bz)
}
// AllCharterAmendments returns all persisted CharterAmendment records
// (iteration helper, unordered).
func (k Keeper) AllCharterAmendments(ctx sdk.Context) []types.CharterAmendment {
store := ctx.KVStore(k.storeKey)
iterator := store.Iterator(amendmentKeyPrefix, prefixEnd(amendmentKeyPrefix))
defer iterator.Close()
out := []types.CharterAmendment{}
for ; iterator.Valid(); iterator.Next() {
var a types.CharterAmendment
if err := json.Unmarshal(iterator.Value(), &a); err == nil {
out = append(out, a)
}
}
return out
}
// CoolCharterAmendment transitions a Proposed CharterAmendment to Cooled
// if the 7-day cooling has elapsed (REQ-052). Returns an error if the
// amendment is not found, not in the Proposed status, or the cooling has
// not elapsed. The handler (or simtest) calls this after the cooling
// period; a separate RatifyCharterAmendment transitions to Ratified.
func (k Keeper) CoolCharterAmendment(ctx sdk.Context, amendmentID string, now int64) (types.CharterAmendment, error) {
a, ok := k.GetCharterAmendment(ctx, amendmentID)
if !ok {
return types.CharterAmendment{}, fmt.Errorf("cover: amendment %q not found", amendmentID)
}
if a.Status != types.AmendmentProposed {
return types.CharterAmendment{}, fmt.Errorf("cover: amendment %q status %q (only Proposed can be Cooled)", amendmentID, a.Status)
}
if now-a.ProposedAt < types.CharterAmendmentCoolingSeconds {
return types.CharterAmendment{}, fmt.Errorf("cover: amendment %q cooling not elapsed (now=%d ProposedAt=%d, need %d seconds)", amendmentID, now, a.ProposedAt, types.CharterAmendmentCoolingSeconds)
}
a.Status = types.AmendmentCooled
a.CooledAt = now
k.SetCharterAmendment(ctx, a)
return a, nil
}
// RatifyCharterAmendment transitions a Cooled CharterAmendment to
// Ratified (REQ-052). Returns an error if the amendment is not found or
// not in the Cooled status. The Pool supermajority + Watcher + Counsel
// are checked upstream (the handler); this helper does the state
// transition + appends the amendment to the parent charter's Amendments
// slice.
func (k Keeper) RatifyCharterAmendment(ctx sdk.Context, amendmentID string, now int64) (types.CharterAmendment, error) {
a, ok := k.GetCharterAmendment(ctx, amendmentID)
if !ok {
return types.CharterAmendment{}, fmt.Errorf("cover: amendment %q not found", amendmentID)
}
if a.Status != types.AmendmentCooled {
return types.CharterAmendment{}, fmt.Errorf("cover: amendment %q status %q (only Cooled can be Ratified)", amendmentID, a.Status)
}
a.Status = types.AmendmentRatified
a.RatifiedAt = now
k.SetCharterAmendment(ctx, a)
return a, nil
}
// --- P5: Bill of Rights review + Pier Selection stores (REQ-056, REQ-066) ------
//
// (REQ-056, REQ-066). Two new stores. The bill_review/ store is keyed by
// ReviewID -> the MsgCounselReviewBillOfRights record (the handler persists
// the review on a bonded-Counsel ceremony). The pier_selection/ store is
// keyed by GuildID -> PierSelectionRecord (the MsgSelectPier handler
// persists + MsgRevokePierSelection removes). The pier_index/ store is
// keyed by PierID -> PierSelectionIndex (the mesh-maintained index; the
// MsgSelectPier handler creates or updates the entry, accumulating scores
// from successive selections). All three use the same JSON-marshal pattern
// as the P1/P2 stores.
var billReviewKeyPrefix = []byte("bill_review/")
func billReviewKey(reviewID string) []byte {
return append(billReviewKeyPrefix, []byte(reviewID)...)
}
// BillOfRightsReview is the persisted record of a Counsel review of the
// Anti-Capture Bill of Rights (REQ-056 §7 acceptance ceremony). The
// MsgCounselReviewBillOfRights handler persists this in the bill_review/
// store keyed by ReviewID.
type BillOfRightsReview struct {
ReviewID string `json:"review_id" yaml:"review_id"`
CounselReachID string `json:"counsel_reach_id" yaml:"counsel_reach_id"`
Staked bool `json:"staked" yaml:"staked"`
ReviewResult string `json:"review_result" yaml:"review_result"`
ReviewedAt int64 `json:"reviewed_at" yaml:"reviewed_at"`
}
// GetBillOfRightsReview loads a BillOfRightsReview by review-id. Returns
// the review and true if found, or zero value + false if not.
func (k Keeper) GetBillOfRightsReview(ctx sdk.Context, reviewID string) (BillOfRightsReview, bool) {
store := ctx.KVStore(k.storeKey)
bz := store.Get(billReviewKey(reviewID))
if bz == nil {
return BillOfRightsReview{}, false
}
var r BillOfRightsReview
if err := json.Unmarshal(bz, &r); err != nil {
return BillOfRightsReview{}, false
}
return r, true
}
// SetBillOfRightsReview persists a BillOfRightsReview by review-id.
func (k Keeper) SetBillOfRightsReview(ctx sdk.Context, r BillOfRightsReview) {
store := ctx.KVStore(k.storeKey)
bz, err := json.Marshal(r)
if err != nil {
panic(fmt.Sprintf("cover: marshal bill-of-rights review %q: %v", r.ReviewID, err))
}
store.Set(billReviewKey(r.ReviewID), bz)
}
// AllBillOfRightsReviews returns all persisted BillOfRightsReview records
// (iteration helper, unordered).
func (k Keeper) AllBillOfRightsReviews(ctx sdk.Context) []BillOfRightsReview {
store := ctx.KVStore(k.storeKey)
iterator := store.Iterator(billReviewKeyPrefix, prefixEnd(billReviewKeyPrefix))
defer iterator.Close()
out := []BillOfRightsReview{}
for ; iterator.Valid(); iterator.Next() {
var r BillOfRightsReview
if err := json.Unmarshal(iterator.Value(), &r); err == nil {
out = append(out, r)
}
}
return out
}
var pierSelectionKeyPrefix = []byte("pier_selection/")
func pierSelectionKey(guildID string) []byte {
return append(pierSelectionKeyPrefix, []byte(guildID)...)
}
// GetPierSelectionRecord loads a PierSelectionRecord by guild-id. Returns
// the record and true if found, or zero value + false if not.
func (k Keeper) GetPierSelectionRecord(ctx sdk.Context, guildID string) (types.PierSelectionRecord, bool) {
store := ctx.KVStore(k.storeKey)
bz := store.Get(pierSelectionKey(guildID))
if bz == nil {
return types.PierSelectionRecord{}, false
}
var r types.PierSelectionRecord
if err := json.Unmarshal(bz, &r); err != nil {
return types.PierSelectionRecord{}, false
}
return r, true
}
// SetPierSelectionRecord persists a PierSelectionRecord by guild-id.
func (k Keeper) SetPierSelectionRecord(ctx sdk.Context, r types.PierSelectionRecord) {
store := ctx.KVStore(k.storeKey)
bz, err := json.Marshal(r)
if err != nil {
panic(fmt.Sprintf("cover: marshal pier selection for guild %q: %v", r.GuildID, err))
}
store.Set(pierSelectionKey(r.GuildID), bz)
}
// RemovePierSelectionRecord removes a PierSelectionRecord by guild-id (the
// MsgRevokePierSelection handler calls this). Returns true if a record was
// removed, false if no record existed.
func (k Keeper) RemovePierSelectionRecord(ctx sdk.Context, guildID string) bool {
store := ctx.KVStore(k.storeKey)
key := pierSelectionKey(guildID)
if store.Get(key) == nil {
return false
}
store.Delete(key)
return true
}
var pierIndexKeyPrefix = []byte("pier_index/")
func pierIndexKey(pierID string) []byte {
return append(pierIndexKeyPrefix, []byte(pierID)...)
}
// GetPierSelectionIndex loads a PierSelectionIndex by pier-id (REQ-066 —
// the mesh-maintained index query). Returns the index and true if found,
// or zero value + false if not.
func (k Keeper) GetPierSelectionIndex(ctx sdk.Context, pierID string) (types.PierSelectionIndex, bool) {
store := ctx.KVStore(k.storeKey)
bz := store.Get(pierIndexKey(pierID))
if bz == nil {
return types.PierSelectionIndex{}, false
}
var idx types.PierSelectionIndex
if err := json.Unmarshal(bz, &idx); err != nil {
return types.PierSelectionIndex{}, false
}
return idx, true
}
// SetPierSelectionIndex persists a PierSelectionIndex by pier-id.
func (k Keeper) SetPierSelectionIndex(ctx sdk.Context, idx types.PierSelectionIndex) {
store := ctx.KVStore(k.storeKey)
bz, err := json.Marshal(idx)
if err != nil {
panic(fmt.Sprintf("cover: marshal pier selection index for pier %q: %v", idx.PierID, err))
}
store.Set(pierIndexKey(idx.PierID), bz)
}
// AllPierSelectionIndexes returns all persisted PierSelectionIndex records
// (iteration helper, unordered).
func (k Keeper) AllPierSelectionIndexes(ctx sdk.Context) []types.PierSelectionIndex {
store := ctx.KVStore(k.storeKey)
iterator := store.Iterator(pierIndexKeyPrefix, prefixEnd(pierIndexKeyPrefix))
defer iterator.Close()
out := []types.PierSelectionIndex{}
for ; iterator.Valid(); iterator.Next() {
var idx types.PierSelectionIndex
if err := json.Unmarshal(iterator.Value(), &idx); err == nil {
out = append(out, idx)
}
}
return out
}
// DefaultPierScores are the simtest-grade default scores for a fresh
// PierSelectionIndex entry (the mesh assigns these on a Pier's first
// selection — the live mesh oracle is a v0.8+ concern; the simtest uses
// these deterministic defaults so the index is non-empty on first
// selection). All three scores are in [0,1]; the OverallScore is the
// weighted aggregate (a deterministic blend: 0.4 × JurisdictionalReliability
// + 0.3 × IntegrationQuality + 0.3 × (FiduciaryRecordHash non-empty ? 1.0
// : 0.0)).
const (
DefaultPierJurisdictionalReliabilityScore = 0.8
DefaultPierIntegrationQualityScore = 0.7
)
// DefaultPierOverallScore computes the deterministic OverallScore blend
// for a PierSelectionIndex (the keeper uses this when creating or updating
// an index entry). The blend is 0.4 × JurisdictionalReliability + 0.3 ×
// IntegrationQuality + 0.3 × FiduciaryConfidence (FiduciaryConfidence is
// 1.0 if the FiduciaryRecordHash is non-empty, else 0.0). The simtest
// asserts the OverallScore is non-decreasing on successive selections (a
// second selection with the same scores yields the same OverallScore).
func DefaultPierOverallScore(jurisdictionalReliability, integrationQuality float64, fiduciaryRecordHash []byte) float64 {
fiduciaryConfidence := 0.0
if len(fiduciaryRecordHash) > 0 {
fiduciaryConfidence = 1.0
}
return 0.4*jurisdictionalReliability + 0.3*integrationQuality + 0.3*fiduciaryConfidence
}