feat(bond,cover,standing): P4 MAB + Cover Claims Voucher + Shadow vouch
v0.7 P4 (REQ-054, REQ-055, REQ-060, REQ-063, D-080, D-089, D-090): x/bond (Mutual Aid Bond): MAB struct (Bond anonymous embed) mirroring GrowthBond; CouponDenom enum (CoverCall/MutualAidCredit/Bread-rejected); MABIssuanceCeilingAnnualSurplusMultiple=3 locked const; ValidateMAB rejects CouponDenomBread (FR-MAB-3 dual firewall); D-080 tagged streaming (reserve_build_out); 4 handlers (IssueMAB with 3x ceiling check, DebitMABProceeds with auto-Still on misuse, WitnessMABProceedsRelease with Watcher quorum, WatcherAttestMAB); CoverKeeper reverse edge (D-089). x/cover (Cover Claims Voucher + dissolution): CoverClaimsVoucher struct; D-090(2) cold-start bond = max(10x avgCallSize, MinimumVoucherBond); 4 handlers (RegisterCoverClaimsVoucher, AdjudicateCoverCall with FR-CPCV-2 no self-adjudication, SlashCoverClaimsVoucher with cross-Pool bucket drop, DissolveCoverPool with FR-MAB-4 waterfall Cover-Fee > MAB > Bread); MAB holders have NO Voice (REQ-063). x/standing (Shadow vouch): Vouch.IsShadow field; ShadowVouchWeightMultiplier =0.5 locked const (REQ-060); GetVoucherWeight extended with isShadow param (post-step 0.5x multiplier; all call sites updated); SlashReasonFraudulent CoverCall const (REQ-055). Coverage: bond/keeper 92.1%, cover/keeper 95.0%, standing/types 90.3%. G-006/G-028 intact. go.mod/go.sum diff EMPTY. go vet clean. Lexicon green. ---ci--- project: oy phase: 4 milestone: v0.7 status: execute ---/ci---
This commit is contained in:
@@ -203,6 +203,84 @@ func (k Keeper) AllCoverCalls(ctx sdk.Context) []types.CoverCall {
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user