tutus-chain/pkg/core/state/sese.go

721 lines
23 KiB
Go

package state
import (
"errors"
"fmt"
"math/big"
"github.com/tutus-one/tutus-chain/pkg/util"
"github.com/tutus-one/tutus-chain/pkg/vm/stackitem"
)
// LifePlanAccountStatus represents the status of a life planning account.
type LifePlanAccountStatus uint8
const (
// LifePlanAccountActive indicates an active account.
LifePlanAccountActive LifePlanAccountStatus = 0
// LifePlanAccountSuspended indicates a suspended account.
LifePlanAccountSuspended LifePlanAccountStatus = 1
// LifePlanAccountClosed indicates a closed account.
LifePlanAccountClosed LifePlanAccountStatus = 2
)
// CareerCycleStatus represents the status of a career cycle.
type CareerCycleStatus uint8
const (
// CareerCycleActive indicates an active career.
CareerCycleActive CareerCycleStatus = 0
// CareerCycleCompleted indicates a completed career.
CareerCycleCompleted CareerCycleStatus = 1
// CareerCycleTransitioning indicates transitioning to new career.
CareerCycleTransitioning CareerCycleStatus = 2
)
// SabbaticalStatus represents the status of a sabbatical.
type SabbaticalStatus uint8
const (
// SabbaticalPlanned indicates a planned sabbatical.
SabbaticalPlanned SabbaticalStatus = 0
// SabbaticalActive indicates an active sabbatical.
SabbaticalActive SabbaticalStatus = 1
// SabbaticalCompleted indicates a completed sabbatical.
SabbaticalCompleted SabbaticalStatus = 2
// SabbaticalCancelled indicates a cancelled sabbatical.
SabbaticalCancelled SabbaticalStatus = 3
)
// SabbaticalPurpose represents the purpose of a sabbatical.
type SabbaticalPurpose uint8
const (
// SabbaticalPurposeEducation for education and learning.
SabbaticalPurposeEducation SabbaticalPurpose = 0
// SabbaticalPurposeHealth for health and recovery.
SabbaticalPurposeHealth SabbaticalPurpose = 1
// SabbaticalPurposeFamily for family care.
SabbaticalPurposeFamily SabbaticalPurpose = 2
// SabbaticalPurposeExploration for personal exploration.
SabbaticalPurposeExploration SabbaticalPurpose = 3
// SabbaticalPurposeTransition for career transition.
SabbaticalPurposeTransition SabbaticalPurpose = 4
// SabbaticalPurposeVolunteer for volunteering.
SabbaticalPurposeVolunteer SabbaticalPurpose = 5
)
// MilestoneType represents the type of life milestone.
type MilestoneType uint8
const (
// MilestoneCareerStart for starting a career.
MilestoneCareerStart MilestoneType = 0
// MilestoneCareerEnd for ending a career.
MilestoneCareerEnd MilestoneType = 1
// MilestoneEducation for educational achievements.
MilestoneEducation MilestoneType = 2
// MilestoneFamily for family events.
MilestoneFamily MilestoneType = 3
// MilestoneHealth for health milestones.
MilestoneHealth MilestoneType = 4
// MilestoneFinancial for financial goals.
MilestoneFinancial MilestoneType = 5
// MilestonePersonal for personal achievements.
MilestonePersonal MilestoneType = 6
)
// GoalStatus represents the status of a life goal.
type GoalStatus uint8
const (
// GoalStatusPlanned indicates a planned goal.
GoalStatusPlanned GoalStatus = 0
// GoalStatusInProgress indicates an in-progress goal.
GoalStatusInProgress GoalStatus = 1
// GoalStatusCompleted indicates a completed goal.
GoalStatusCompleted GoalStatus = 2
// GoalStatusAbandoned indicates an abandoned goal.
GoalStatusAbandoned GoalStatus = 3
)
// LifePlanAccount represents a citizen's life planning account.
type LifePlanAccount struct {
VitaID uint64 // Owner's Vita token ID
Owner util.Uint160 // Owner's address
TotalContributions uint64 // Lifetime contributions
EmployerContributions uint64 // Employer contributions
GovernmentContributions uint64 // Government matching
CurrentBalance uint64 // Current account balance
SabbaticalCredits uint64 // Available sabbatical credits
LongevityMultiplier uint32 // Age-based benefit multiplier (basis points)
CurrentCareerCycleID uint64 // Active career cycle ID
TotalCareerCycles uint32 // Number of career cycles
TotalSabbaticals uint32 // Number of sabbaticals taken
Status LifePlanAccountStatus // Account status
CreatedAt uint32 // Block height when created
UpdatedAt uint32 // Block height of last update
}
// ToStackItem implements stackitem.Convertible interface.
func (a *LifePlanAccount) ToStackItem() (stackitem.Item, error) {
return stackitem.NewStruct([]stackitem.Item{
stackitem.NewBigInteger(big.NewInt(int64(a.VitaID))),
stackitem.NewByteArray(a.Owner.BytesBE()),
stackitem.NewBigInteger(big.NewInt(int64(a.TotalContributions))),
stackitem.NewBigInteger(big.NewInt(int64(a.EmployerContributions))),
stackitem.NewBigInteger(big.NewInt(int64(a.GovernmentContributions))),
stackitem.NewBigInteger(big.NewInt(int64(a.CurrentBalance))),
stackitem.NewBigInteger(big.NewInt(int64(a.SabbaticalCredits))),
stackitem.NewBigInteger(big.NewInt(int64(a.LongevityMultiplier))),
stackitem.NewBigInteger(big.NewInt(int64(a.CurrentCareerCycleID))),
stackitem.NewBigInteger(big.NewInt(int64(a.TotalCareerCycles))),
stackitem.NewBigInteger(big.NewInt(int64(a.TotalSabbaticals))),
stackitem.NewBigInteger(big.NewInt(int64(a.Status))),
stackitem.NewBigInteger(big.NewInt(int64(a.CreatedAt))),
stackitem.NewBigInteger(big.NewInt(int64(a.UpdatedAt))),
}), nil
}
// FromStackItem implements stackitem.Convertible interface.
func (a *LifePlanAccount) FromStackItem(item stackitem.Item) error {
items, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not a struct")
}
if len(items) != 14 {
return fmt.Errorf("wrong number of elements: expected 14, got %d", len(items))
}
vitaID, err := items[0].TryInteger()
if err != nil {
return fmt.Errorf("invalid vitaID: %w", err)
}
a.VitaID = vitaID.Uint64()
owner, err := items[1].TryBytes()
if err != nil {
return fmt.Errorf("invalid owner: %w", err)
}
a.Owner, err = util.Uint160DecodeBytesBE(owner)
if err != nil {
return fmt.Errorf("invalid owner address: %w", err)
}
totalContributions, err := items[2].TryInteger()
if err != nil {
return fmt.Errorf("invalid totalContributions: %w", err)
}
a.TotalContributions = totalContributions.Uint64()
employerContributions, err := items[3].TryInteger()
if err != nil {
return fmt.Errorf("invalid employerContributions: %w", err)
}
a.EmployerContributions = employerContributions.Uint64()
governmentContributions, err := items[4].TryInteger()
if err != nil {
return fmt.Errorf("invalid governmentContributions: %w", err)
}
a.GovernmentContributions = governmentContributions.Uint64()
currentBalance, err := items[5].TryInteger()
if err != nil {
return fmt.Errorf("invalid currentBalance: %w", err)
}
a.CurrentBalance = currentBalance.Uint64()
sabbaticalCredits, err := items[6].TryInteger()
if err != nil {
return fmt.Errorf("invalid sabbaticalCredits: %w", err)
}
a.SabbaticalCredits = sabbaticalCredits.Uint64()
longevityMultiplier, err := items[7].TryInteger()
if err != nil {
return fmt.Errorf("invalid longevityMultiplier: %w", err)
}
a.LongevityMultiplier = uint32(longevityMultiplier.Uint64())
currentCareerCycleID, err := items[8].TryInteger()
if err != nil {
return fmt.Errorf("invalid currentCareerCycleID: %w", err)
}
a.CurrentCareerCycleID = currentCareerCycleID.Uint64()
totalCareerCycles, err := items[9].TryInteger()
if err != nil {
return fmt.Errorf("invalid totalCareerCycles: %w", err)
}
a.TotalCareerCycles = uint32(totalCareerCycles.Uint64())
totalSabbaticals, err := items[10].TryInteger()
if err != nil {
return fmt.Errorf("invalid totalSabbaticals: %w", err)
}
a.TotalSabbaticals = uint32(totalSabbaticals.Uint64())
status, err := items[11].TryInteger()
if err != nil {
return fmt.Errorf("invalid status: %w", err)
}
a.Status = LifePlanAccountStatus(status.Uint64())
createdAt, err := items[12].TryInteger()
if err != nil {
return fmt.Errorf("invalid createdAt: %w", err)
}
a.CreatedAt = uint32(createdAt.Uint64())
updatedAt, err := items[13].TryInteger()
if err != nil {
return fmt.Errorf("invalid updatedAt: %w", err)
}
a.UpdatedAt = uint32(updatedAt.Uint64())
return nil
}
// CareerCycle represents a career phase in a person's life.
type CareerCycle struct {
ID uint64 // Unique career cycle ID
VitaID uint64 // Owner's Vita ID
Owner util.Uint160 // Owner's address
CareerField string // Industry/profession
StartedAt uint32 // Block height when started
EndedAt uint32 // Block height when ended (0 = active)
ContributionTotal uint64 // Total contributions in this cycle
TransitionReason string // Why career ended
Status CareerCycleStatus // Career status
}
// ToStackItem implements stackitem.Convertible interface.
func (c *CareerCycle) ToStackItem() (stackitem.Item, error) {
return stackitem.NewStruct([]stackitem.Item{
stackitem.NewBigInteger(big.NewInt(int64(c.ID))),
stackitem.NewBigInteger(big.NewInt(int64(c.VitaID))),
stackitem.NewByteArray(c.Owner.BytesBE()),
stackitem.NewByteArray([]byte(c.CareerField)),
stackitem.NewBigInteger(big.NewInt(int64(c.StartedAt))),
stackitem.NewBigInteger(big.NewInt(int64(c.EndedAt))),
stackitem.NewBigInteger(big.NewInt(int64(c.ContributionTotal))),
stackitem.NewByteArray([]byte(c.TransitionReason)),
stackitem.NewBigInteger(big.NewInt(int64(c.Status))),
}), nil
}
// FromStackItem implements stackitem.Convertible interface.
func (c *CareerCycle) FromStackItem(item stackitem.Item) error {
items, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not a struct")
}
if len(items) != 9 {
return fmt.Errorf("wrong number of elements: expected 9, got %d", len(items))
}
id, err := items[0].TryInteger()
if err != nil {
return fmt.Errorf("invalid id: %w", err)
}
c.ID = id.Uint64()
vitaID, err := items[1].TryInteger()
if err != nil {
return fmt.Errorf("invalid vitaID: %w", err)
}
c.VitaID = vitaID.Uint64()
owner, err := items[2].TryBytes()
if err != nil {
return fmt.Errorf("invalid owner: %w", err)
}
c.Owner, err = util.Uint160DecodeBytesBE(owner)
if err != nil {
return fmt.Errorf("invalid owner address: %w", err)
}
careerField, err := items[3].TryBytes()
if err != nil {
return fmt.Errorf("invalid careerField: %w", err)
}
c.CareerField = string(careerField)
startedAt, err := items[4].TryInteger()
if err != nil {
return fmt.Errorf("invalid startedAt: %w", err)
}
c.StartedAt = uint32(startedAt.Uint64())
endedAt, err := items[5].TryInteger()
if err != nil {
return fmt.Errorf("invalid endedAt: %w", err)
}
c.EndedAt = uint32(endedAt.Uint64())
contributionTotal, err := items[6].TryInteger()
if err != nil {
return fmt.Errorf("invalid contributionTotal: %w", err)
}
c.ContributionTotal = contributionTotal.Uint64()
transitionReason, err := items[7].TryBytes()
if err != nil {
return fmt.Errorf("invalid transitionReason: %w", err)
}
c.TransitionReason = string(transitionReason)
status, err := items[8].TryInteger()
if err != nil {
return fmt.Errorf("invalid status: %w", err)
}
c.Status = CareerCycleStatus(status.Uint64())
return nil
}
// Sabbatical represents a career break.
type Sabbatical struct {
ID uint64 // Unique sabbatical ID
VitaID uint64 // Owner's Vita ID
Owner util.Uint160 // Owner's address
Purpose SabbaticalPurpose // Purpose of sabbatical
Description string // Description of plans
StartedAt uint32 // Block height when started
Duration uint32 // Planned duration in blocks
EndedAt uint32 // Block height when ended (0 = ongoing)
FundingUsed uint64 // Credits spent during sabbatical
Outcome string // Sabbatical results
Status SabbaticalStatus // Sabbatical status
}
// ToStackItem implements stackitem.Convertible interface.
func (s *Sabbatical) ToStackItem() (stackitem.Item, error) {
return stackitem.NewStruct([]stackitem.Item{
stackitem.NewBigInteger(big.NewInt(int64(s.ID))),
stackitem.NewBigInteger(big.NewInt(int64(s.VitaID))),
stackitem.NewByteArray(s.Owner.BytesBE()),
stackitem.NewBigInteger(big.NewInt(int64(s.Purpose))),
stackitem.NewByteArray([]byte(s.Description)),
stackitem.NewBigInteger(big.NewInt(int64(s.StartedAt))),
stackitem.NewBigInteger(big.NewInt(int64(s.Duration))),
stackitem.NewBigInteger(big.NewInt(int64(s.EndedAt))),
stackitem.NewBigInteger(big.NewInt(int64(s.FundingUsed))),
stackitem.NewByteArray([]byte(s.Outcome)),
stackitem.NewBigInteger(big.NewInt(int64(s.Status))),
}), nil
}
// FromStackItem implements stackitem.Convertible interface.
func (s *Sabbatical) FromStackItem(item stackitem.Item) error {
items, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not a struct")
}
if len(items) != 11 {
return fmt.Errorf("wrong number of elements: expected 11, got %d", len(items))
}
id, err := items[0].TryInteger()
if err != nil {
return fmt.Errorf("invalid id: %w", err)
}
s.ID = id.Uint64()
vitaID, err := items[1].TryInteger()
if err != nil {
return fmt.Errorf("invalid vitaID: %w", err)
}
s.VitaID = vitaID.Uint64()
owner, err := items[2].TryBytes()
if err != nil {
return fmt.Errorf("invalid owner: %w", err)
}
s.Owner, err = util.Uint160DecodeBytesBE(owner)
if err != nil {
return fmt.Errorf("invalid owner address: %w", err)
}
purpose, err := items[3].TryInteger()
if err != nil {
return fmt.Errorf("invalid purpose: %w", err)
}
s.Purpose = SabbaticalPurpose(purpose.Uint64())
description, err := items[4].TryBytes()
if err != nil {
return fmt.Errorf("invalid description: %w", err)
}
s.Description = string(description)
startedAt, err := items[5].TryInteger()
if err != nil {
return fmt.Errorf("invalid startedAt: %w", err)
}
s.StartedAt = uint32(startedAt.Uint64())
duration, err := items[6].TryInteger()
if err != nil {
return fmt.Errorf("invalid duration: %w", err)
}
s.Duration = uint32(duration.Uint64())
endedAt, err := items[7].TryInteger()
if err != nil {
return fmt.Errorf("invalid endedAt: %w", err)
}
s.EndedAt = uint32(endedAt.Uint64())
fundingUsed, err := items[8].TryInteger()
if err != nil {
return fmt.Errorf("invalid fundingUsed: %w", err)
}
s.FundingUsed = fundingUsed.Uint64()
outcome, err := items[9].TryBytes()
if err != nil {
return fmt.Errorf("invalid outcome: %w", err)
}
s.Outcome = string(outcome)
status, err := items[10].TryInteger()
if err != nil {
return fmt.Errorf("invalid status: %w", err)
}
s.Status = SabbaticalStatus(status.Uint64())
return nil
}
// LifeMilestone represents a significant life event.
type LifeMilestone struct {
ID uint64 // Unique milestone ID
VitaID uint64 // Owner's Vita ID
Owner util.Uint160 // Owner's address
MilestoneType MilestoneType // Type of milestone
Title string // Milestone title
Description string // Milestone description
ContentHash util.Uint256 // Hash of supporting documentation
AchievedAt uint32 // Block height when achieved
IsVerified bool // Whether milestone is verified
}
// ToStackItem implements stackitem.Convertible interface.
func (m *LifeMilestone) ToStackItem() (stackitem.Item, error) {
return stackitem.NewStruct([]stackitem.Item{
stackitem.NewBigInteger(big.NewInt(int64(m.ID))),
stackitem.NewBigInteger(big.NewInt(int64(m.VitaID))),
stackitem.NewByteArray(m.Owner.BytesBE()),
stackitem.NewBigInteger(big.NewInt(int64(m.MilestoneType))),
stackitem.NewByteArray([]byte(m.Title)),
stackitem.NewByteArray([]byte(m.Description)),
stackitem.NewByteArray(m.ContentHash.BytesBE()),
stackitem.NewBigInteger(big.NewInt(int64(m.AchievedAt))),
stackitem.NewBool(m.IsVerified),
}), nil
}
// FromStackItem implements stackitem.Convertible interface.
func (m *LifeMilestone) FromStackItem(item stackitem.Item) error {
items, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not a struct")
}
if len(items) != 9 {
return fmt.Errorf("wrong number of elements: expected 9, got %d", len(items))
}
id, err := items[0].TryInteger()
if err != nil {
return fmt.Errorf("invalid id: %w", err)
}
m.ID = id.Uint64()
vitaID, err := items[1].TryInteger()
if err != nil {
return fmt.Errorf("invalid vitaID: %w", err)
}
m.VitaID = vitaID.Uint64()
owner, err := items[2].TryBytes()
if err != nil {
return fmt.Errorf("invalid owner: %w", err)
}
m.Owner, err = util.Uint160DecodeBytesBE(owner)
if err != nil {
return fmt.Errorf("invalid owner address: %w", err)
}
milestoneType, err := items[3].TryInteger()
if err != nil {
return fmt.Errorf("invalid milestoneType: %w", err)
}
m.MilestoneType = MilestoneType(milestoneType.Uint64())
title, err := items[4].TryBytes()
if err != nil {
return fmt.Errorf("invalid title: %w", err)
}
m.Title = string(title)
description, err := items[5].TryBytes()
if err != nil {
return fmt.Errorf("invalid description: %w", err)
}
m.Description = string(description)
contentHash, err := items[6].TryBytes()
if err != nil {
return fmt.Errorf("invalid contentHash: %w", err)
}
m.ContentHash, err = util.Uint256DecodeBytesBE(contentHash)
if err != nil {
return fmt.Errorf("invalid contentHash value: %w", err)
}
achievedAt, err := items[7].TryInteger()
if err != nil {
return fmt.Errorf("invalid achievedAt: %w", err)
}
m.AchievedAt = uint32(achievedAt.Uint64())
isVerified, err := items[8].TryBool()
if err != nil {
return fmt.Errorf("invalid isVerified: %w", err)
}
m.IsVerified = isVerified
return nil
}
// LifeGoal represents a future life goal.
type LifeGoal struct {
ID uint64 // Unique goal ID
VitaID uint64 // Owner's Vita ID
Owner util.Uint160 // Owner's address
Title string // Goal title
Description string // Goal description
TargetBlock uint32 // Target block height for completion
Progress uint32 // Progress percentage (0-10000 basis points)
Status GoalStatus // Goal status
CreatedAt uint32 // Block height when created
CompletedAt uint32 // Block height when completed (0 = incomplete)
}
// ToStackItem implements stackitem.Convertible interface.
func (g *LifeGoal) ToStackItem() (stackitem.Item, error) {
return stackitem.NewStruct([]stackitem.Item{
stackitem.NewBigInteger(big.NewInt(int64(g.ID))),
stackitem.NewBigInteger(big.NewInt(int64(g.VitaID))),
stackitem.NewByteArray(g.Owner.BytesBE()),
stackitem.NewByteArray([]byte(g.Title)),
stackitem.NewByteArray([]byte(g.Description)),
stackitem.NewBigInteger(big.NewInt(int64(g.TargetBlock))),
stackitem.NewBigInteger(big.NewInt(int64(g.Progress))),
stackitem.NewBigInteger(big.NewInt(int64(g.Status))),
stackitem.NewBigInteger(big.NewInt(int64(g.CreatedAt))),
stackitem.NewBigInteger(big.NewInt(int64(g.CompletedAt))),
}), nil
}
// FromStackItem implements stackitem.Convertible interface.
func (g *LifeGoal) FromStackItem(item stackitem.Item) error {
items, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not a struct")
}
if len(items) != 10 {
return fmt.Errorf("wrong number of elements: expected 10, got %d", len(items))
}
id, err := items[0].TryInteger()
if err != nil {
return fmt.Errorf("invalid id: %w", err)
}
g.ID = id.Uint64()
vitaID, err := items[1].TryInteger()
if err != nil {
return fmt.Errorf("invalid vitaID: %w", err)
}
g.VitaID = vitaID.Uint64()
owner, err := items[2].TryBytes()
if err != nil {
return fmt.Errorf("invalid owner: %w", err)
}
g.Owner, err = util.Uint160DecodeBytesBE(owner)
if err != nil {
return fmt.Errorf("invalid owner address: %w", err)
}
title, err := items[3].TryBytes()
if err != nil {
return fmt.Errorf("invalid title: %w", err)
}
g.Title = string(title)
description, err := items[4].TryBytes()
if err != nil {
return fmt.Errorf("invalid description: %w", err)
}
g.Description = string(description)
targetBlock, err := items[5].TryInteger()
if err != nil {
return fmt.Errorf("invalid targetBlock: %w", err)
}
g.TargetBlock = uint32(targetBlock.Uint64())
progress, err := items[6].TryInteger()
if err != nil {
return fmt.Errorf("invalid progress: %w", err)
}
g.Progress = uint32(progress.Uint64())
status, err := items[7].TryInteger()
if err != nil {
return fmt.Errorf("invalid status: %w", err)
}
g.Status = GoalStatus(status.Uint64())
createdAt, err := items[8].TryInteger()
if err != nil {
return fmt.Errorf("invalid createdAt: %w", err)
}
g.CreatedAt = uint32(createdAt.Uint64())
completedAt, err := items[9].TryInteger()
if err != nil {
return fmt.Errorf("invalid completedAt: %w", err)
}
g.CompletedAt = uint32(completedAt.Uint64())
return nil
}
// SeseConfig represents configurable parameters for the Sese contract.
type SeseConfig struct {
DefaultSabbaticalCredits uint64 // Default sabbatical credits per year
MinSabbaticalDuration uint32 // Minimum sabbatical duration in blocks
MaxSabbaticalDuration uint32 // Maximum sabbatical duration in blocks
GovernmentMatchPercent uint32 // Government matching percentage (basis points)
LongevityBonusPercent uint32 // Longevity bonus percentage (basis points per year)
}
// ToStackItem implements stackitem.Convertible interface.
func (c *SeseConfig) ToStackItem() (stackitem.Item, error) {
return stackitem.NewStruct([]stackitem.Item{
stackitem.NewBigInteger(big.NewInt(int64(c.DefaultSabbaticalCredits))),
stackitem.NewBigInteger(big.NewInt(int64(c.MinSabbaticalDuration))),
stackitem.NewBigInteger(big.NewInt(int64(c.MaxSabbaticalDuration))),
stackitem.NewBigInteger(big.NewInt(int64(c.GovernmentMatchPercent))),
stackitem.NewBigInteger(big.NewInt(int64(c.LongevityBonusPercent))),
}), nil
}
// FromStackItem implements stackitem.Convertible interface.
func (c *SeseConfig) FromStackItem(item stackitem.Item) error {
items, ok := item.Value().([]stackitem.Item)
if !ok {
return errors.New("not a struct")
}
if len(items) != 5 {
return fmt.Errorf("wrong number of elements: expected 5, got %d", len(items))
}
defaultCredits, err := items[0].TryInteger()
if err != nil {
return fmt.Errorf("invalid defaultSabbaticalCredits: %w", err)
}
c.DefaultSabbaticalCredits = defaultCredits.Uint64()
minDuration, err := items[1].TryInteger()
if err != nil {
return fmt.Errorf("invalid minSabbaticalDuration: %w", err)
}
c.MinSabbaticalDuration = uint32(minDuration.Uint64())
maxDuration, err := items[2].TryInteger()
if err != nil {
return fmt.Errorf("invalid maxSabbaticalDuration: %w", err)
}
c.MaxSabbaticalDuration = uint32(maxDuration.Uint64())
govMatch, err := items[3].TryInteger()
if err != nil {
return fmt.Errorf("invalid governmentMatchPercent: %w", err)
}
c.GovernmentMatchPercent = uint32(govMatch.Uint64())
longevityBonus, err := items[4].TryInteger()
if err != nil {
return fmt.Errorf("invalid longevityBonusPercent: %w", err)
}
c.LongevityBonusPercent = uint32(longevityBonus.Uint64())
return nil
}