721 lines
23 KiB
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
|
|
}
|