lockup

package module
v0.2.0-rc.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 18, 2024 License: Apache-2.0 Imports: 20 Imported by: 1

README

Lockup Accounts

The x/accounts/defaults/lockup module provides the implementation for lockup accounts within the x/accounts module.

Lockup Account Types

BaseLockup

The base lockup account is used by all default lockup accounts. It contains the basic information for a lockup account. The Base lockup account keeps knowledge of the staking delegations from the account.

type BaseLockup struct {
	// Owner is the address of the account owner.
	Owner            collections.Item[[]byte]
	OriginalLocking  collections.Map[string, math.Int]
	DelegatedFree    collections.Map[string, math.Int]
	DelegatedLocking collections.Map[string, math.Int]
	WithdrawedCoins  collections.Map[string, math.Int]
	addressCodec     address.Codec
	headerService    header.Service
	// lockup end time.
	EndTime collections.Item[time.Time]
}
ContinuousLockup

The continuous lockup account has a future start time and begins unlocking continuously until the specified end date.

To determine the amount of coins that are vested for a given block time T, the following is performed:

  1. Compute X := T - StartTime
  2. Compute Y := EndTime - StartTime
  3. Compute V' := OV * (X / Y)
  4. Compute V := OV - V'

Thus, the total amount of vested coins is V' and the remaining amount, V, is lockup.

type ContinuousLockingAccount struct {
	*BaseLockup
	StartTime collections.Item[time.Time]
}
DelayedLockup

The delayed lockup account unlocks all tokens at a specific time. The account can receive coins and send coins. The account can be used to lock coins for a long period of time.

type DelayedLockingAccount struct {
	*BaseLockup
}
PeriodicLockup

The periodic lockup account locks tokens for a series of periods. The account can receive coins and send coins. After all the periods, all the coins are unlocked and the account can send coins.

Periodic lockup accounts require calculating the coins released during each period for a given block time T. Note that multiple periods could have passed when calling GetVestedCoins, so we must iterate over each period until the end of that period is after T.

  1. Set CT := StartTime
  2. Set V' := 0

For each Period P:

  1. Compute X := T - CT
  2. IF X >= P.Length
    1. Compute V' += P.Amount
    2. Compute CT += P.Length
    3. ELSE break
  3. Compute V := OV - V'
type PeriodicLockingAccount struct {
	*BaseLockup
	StartTime      collections.Item[time.Time]
	LockingPeriods collections.Vec[lockuptypes.Period]
}
PermanentLocked

The permanent lockup account permanently locks the coins in the account. The account can only receive coins and cannot send coins. The account can be used to lock coins for a long period of time.

type PermanentLockingAccount struct {
	*BaseLockup
}

Genesis Initialization

In An Event Of Slashing

As defined, base lockup store DelegatedLocking by amount. In an event of a validator that the lockup account delegate to is slash which affect the actual delegation amount, this will leave the DelegatedLocking have an excess amount even if user undelegate all of the account delegated amount. This excess amount would affect the spendable amount, further details are as below:

The spendable amount is calculated as: spendableAmount = balance - notBondedLockedAmount where notBondedLockedAmount = lockedAmount - Min(lockedAmount, delegatedLockedAmount)

As seen in the formula notBondedLockedAmout can only be 0 or a positive value when DelegatedLockedAmount < LockedAmount. Let call NewDelegatedLockedAmount is the delegatedLockedAmount when applying N slash

  1. Case 1: Originally DelegatedLockedAmount > lockedAmount but when applying the slash amount the NewDelegatedLockedAmount < lockedAmount then
    • When not applying slash notBondedLockedAmout will be 0
    • When apply slash notBondedLockedAmout will be lockedAmount - NewDelegatedLockedAmount = a positive amount
  2. Case 2: where originally DelegatedLockedAmount < lockedAmount when applying the slash amount the NewDelegatedLockedAmount < lockedAmount then
    • When not applying slash lockedAmount - DelegatedLockedAmount
    • When apply slash notBondedLockedAmout will be lockedAmount - NewDelegatedLockedAmount = lockedAmount - (DelegatedLockedAmount - N) = lockedAmount - DelegatedLockedAmount + N
  3. Case 3: where originally DelegatedLockedAmount > lockedAmount when applying the slash amount still the NewDelegatedLockedAmount > lockedAmount then notBondedLockedAmout will be 0 applying slash or not

In cases 1 and 2, notBondedLockedAmount decreases when not applying the slash, resulting in a higher spendableAmount.

Due to the nature of x/accounts, as other modules cannot assume certain account types exist so the handling of slashing event must be done internally within x/accounts's accounts. For lockup accounts, this would make the logic overcomplicated. Since these effects are only an edge case that affect a small number of users, so here we would accept the trade off for a simpler design. This design decision aligns with the legacy vesting account implementation.

Examples

Simple

Given a continuous lockup account with 10 vested coins.

OV = 10
DF = 0
DV = 0
BC = 10
V = 10
V' = 0
  1. Immediately receives 1 coin

    BC = 11
    
  2. Time passes, 2 coins vest

    V = 8
    V' = 2
    
  3. Delegates 4 coins to validator A

    DV = 4
    BC = 7
    
  4. Sends 3 coins

    BC = 4
    
  5. More time passes, 2 more coins vest

    V = 6
    V' = 4
    
  6. Sends 2 coins. At this point, the account cannot send anymore until further coins vest or it receives additional coins. It can still, however, delegate.

    BC = 2
    
Slashing

Same initial starting conditions as the simple example.

  1. Time passes, 5 coins vest

    V = 5
    V' = 5
    
  2. Delegate 5 coins to validator A

    DV = 5
    BC = 5
    
  3. Delegate 5 coins to validator B

    DF = 5
    BC = 0
    
  4. Validator A gets slashed by 50%, making the delegation to A now worth 2.5 coins

  5. Undelegate from validator A (2.5 coins)

    DF = 5 - 2.5 = 2.5
    BC = 0 + 2.5 = 2.5
    
  6. Undelegate from validator B (5 coins). The account at this point can only send 2.5 coins unless it receives more coins or until more coins vest. It can still, however, delegate.

    DV = 5 - 2.5 = 2.5
    DF = 2.5 - 2.5 = 0
    BC = 2.5 + 5 = 7.5
    

    Notice how we have an excess amount of DV. This is explained in In An Event Of Slashing

Periodic Lockup

A lockup account is created where 100 tokens will be released over 1 year, with 1/4 of tokens vesting each quarter. The lockup schedule would be as follows:

Periods:
- amount: 25stake, length: 7884000
- amount: 25stake, length: 7884000
- amount: 25stake, length: 7884000
- amount: 25stake, length: 7884000
OV = 100
DF = 0
DV = 0
BC = 100
V = 100
V' = 0
  1. Immediately receives 1 coin

    BC = 101
    
  2. Lockup period 1 passes, 25 coins vest

    V = 75
    V' = 25
    
  3. During lockup period 2, 5 coins are transferred and 5 coins are delegated

    DV = 5
    BC = 91
    
  4. Lockup period 2 passes, 25 coins vest

    V = 50
    V' = 50
    

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	OriginalLockingPrefix  = collections.NewPrefix(0)
	DelegatedFreePrefix    = collections.NewPrefix(1)
	DelegatedLockingPrefix = collections.NewPrefix(2)
	EndTimePrefix          = collections.NewPrefix(3)
	StartTimePrefix        = collections.NewPrefix(4)
	LockingPeriodsPrefix   = collections.NewPrefix(5)
	OwnerPrefix            = collections.NewPrefix(6)
	UnbondEntriesPrefix    = collections.NewPrefix(7)
)
View Source
var (
	CONTINUOUS_LOCKING_ACCOUNT = "continuous-locking-account"
	DELAYED_LOCKING_ACCOUNT    = "delayed-locking-account"
	PERIODIC_LOCKING_ACCOUNT   = "periodic-locking-account"
	PERMANENT_LOCKING_ACCOUNT  = "permanent-locking-account"
)

Functions

This section is empty.

Types

type BaseLockup

type BaseLockup struct {
	// Owner is the address of the account owner.
	Owner            collections.Item[[]byte]
	OriginalLocking  collections.Map[string, math.Int]
	DelegatedFree    collections.Map[string, math.Int]
	DelegatedLocking collections.Map[string, math.Int]
	// map val address to unbonding entries
	UnbondEntries collections.Map[string, lockuptypes.UnbondingEntries]

	// lockup end time.
	EndTime collections.Item[time.Time]
	// contains filtered or unexported fields
}

func (*BaseLockup) Delegate

func (bva *BaseLockup) Delegate(
	ctx context.Context, msg *lockuptypes.MsgDelegate, getLockedCoinsFunc getLockedCoinsFunc,
) (
	*lockuptypes.MsgExecuteMessagesResponse, error,
)

func (BaseLockup) GetNotBondedLockedCoin

func (bva BaseLockup) GetNotBondedLockedCoin(ctx context.Context, lockedCoin sdk.Coin, denom string) (sdk.Coin, error)

GetNotBondedLockedCoin returns the coin that are not spendable that are not bonded by denom for a lockup account. If the coin by the provided denom are not locked, an coin with zero amount is returned.

func (BaseLockup) IterateCoinEntries

func (bva BaseLockup) IterateCoinEntries(
	ctx context.Context,
	entries collections.Map[string, math.Int],
	cb func(denom string, value math.Int) (bool, error),
) error

IterateCoinEntries iterates over all the CoinEntries entries.

func (BaseLockup) QueryLockupAccountBaseInfo

QueryLockupAccountBaseInfo returns a lockup account's info

func (BaseLockup) QuerySpendableTokens

func (bva BaseLockup) QuerySpendableTokens(ctx context.Context, lockedCoins sdk.Coins) (
	*lockuptypes.QuerySpendableAmountResponse, error,
)

func (BaseLockup) RegisterExecuteHandlers

func (bva BaseLockup) RegisterExecuteHandlers(builder *accountstd.ExecuteBuilder)

func (BaseLockup) RegisterQueryHandlers

func (bva BaseLockup) RegisterQueryHandlers(builder *accountstd.QueryBuilder)

func (*BaseLockup) SendCoins

func (bva *BaseLockup) SendCoins(
	ctx context.Context, msg *lockuptypes.MsgSend, getLockedCoinsFunc getLockedCoinsFunc,
) (
	*lockuptypes.MsgExecuteMessagesResponse, error,
)

func (*BaseLockup) TrackDelegation

func (bva *BaseLockup) TrackDelegation(
	ctx context.Context, balance, lockedCoins, amount sdk.Coins,
) error

TrackDelegation tracks a delegation amount for any given lockup account type given the amount of coins currently being locked and the current account balance of the delegation denominations.

CONTRACT: The account's coins, delegation coins, locked coins, and delegated locking coins must be sorted.

func (*BaseLockup) TrackUndelegation

func (bva *BaseLockup) TrackUndelegation(ctx context.Context, amount sdk.Coins) error

TrackUndelegation tracks an undelegation amount by setting the necessary values by which delegated locking and delegated free need to decrease and by which amount the base coins need to increase.

NOTE: The undelegation (bond refund) amount may exceed the delegated locking (bond) amount due to the way undelegation truncates the bond refund, which can increase the validator's exchange rate (tokens/shares) slightly if the undelegated tokens are non-integral.

CONTRACT: The account's coins and undelegation coins must be sorted.

func (*BaseLockup) Undelegate

func (*BaseLockup) WithdrawReward

type ContinuousLockingAccount

type ContinuousLockingAccount struct {
	*BaseLockup
	StartTime collections.Item[time.Time]
}

func NewContinuousLockingAccount

func NewContinuousLockingAccount(d accountstd.Dependencies) (*ContinuousLockingAccount, error)

NewContinuousLockingAccount creates a new ContinuousLockingAccount object.

func (*ContinuousLockingAccount) Delegate

func (ContinuousLockingAccount) GetLockCoinInfoWithDenom

func (cva ContinuousLockingAccount) GetLockCoinInfoWithDenom(ctx context.Context, blockTime time.Time, denom string) (unlockedCoin, lockedCoin *sdk.Coin, err error)

GetLockCoinInfoWithDenom returns the number of locked coin for a specific denom. If no coins are locked, nil is returned.

func (ContinuousLockingAccount) GetLockCoinsInfo

func (cva ContinuousLockingAccount) GetLockCoinsInfo(ctx context.Context, blockTime time.Time) (unlockedCoins, lockedCoins sdk.Coins, err error)

GetLockCoinsInfo returns the total number of unlocked and locked coins.

func (ContinuousLockingAccount) GetLockedCoins

func (cva ContinuousLockingAccount) GetLockedCoins(ctx context.Context, blockTime time.Time) (sdk.Coins, error)

GetLockedCoins returns the total number of locked coins.

func (ContinuousLockingAccount) GetLockedCoinsWithDenoms

func (cva ContinuousLockingAccount) GetLockedCoinsWithDenoms(ctx context.Context, blockTime time.Time, denoms ...string) (sdk.Coins, error)

GetLockedCoinsWithDenoms returns the number of locked coin for a specific denom.

func (ContinuousLockingAccount) RegisterExecuteHandlers

func (cva ContinuousLockingAccount) RegisterExecuteHandlers(builder *accountstd.ExecuteBuilder)

func (ContinuousLockingAccount) RegisterInitHandler

func (cva ContinuousLockingAccount) RegisterInitHandler(builder *accountstd.InitBuilder)

Implement smart account interface

func (ContinuousLockingAccount) RegisterQueryHandlers

func (cva ContinuousLockingAccount) RegisterQueryHandlers(builder *accountstd.QueryBuilder)

func (*ContinuousLockingAccount) SendCoins

type DelayedLockingAccount

type DelayedLockingAccount struct {
	*BaseLockup
}

func NewDelayedLockingAccount

func NewDelayedLockingAccount(d accountstd.Dependencies) (*DelayedLockingAccount, error)

NewDelayedLockingAccount creates a new DelayedLockingAccount object.

func (*DelayedLockingAccount) Delegate

func (DelayedLockingAccount) GetLockCoinInfoWithDenom

func (dva DelayedLockingAccount) GetLockCoinInfoWithDenom(ctx context.Context, blockTime time.Time, denom string) (*sdk.Coin, *sdk.Coin, error)

GetLockCoinInfoWithDenom returns the number of unlocked and locked coin for a specific denom.

func (DelayedLockingAccount) GetLockCoinsInfo

func (dva DelayedLockingAccount) GetLockCoinsInfo(ctx context.Context, blockTime time.Time) (sdk.Coins, sdk.Coins, error)

GetLockCoinsInfo returns the total number of unlocked and locked coins.

func (DelayedLockingAccount) GetLockedCoins

func (dva DelayedLockingAccount) GetLockedCoins(ctx context.Context, blockTime time.Time) (sdk.Coins, error)

GetLockedCoins returns the total number of locked coins. If no coins are locked, nil is returned.

func (DelayedLockingAccount) GetLockedCoinsWithDenoms

func (dva DelayedLockingAccount) GetLockedCoinsWithDenoms(ctx context.Context, blockTime time.Time, denoms ...string) (sdk.Coins, error)

GetLockedCoinsWithDenoms returns the number of locked coin for a specific denom.

func (DelayedLockingAccount) RegisterExecuteHandlers

func (dva DelayedLockingAccount) RegisterExecuteHandlers(builder *accountstd.ExecuteBuilder)

func (DelayedLockingAccount) RegisterInitHandler

func (dva DelayedLockingAccount) RegisterInitHandler(builder *accountstd.InitBuilder)

Implement smart account interface

func (DelayedLockingAccount) RegisterQueryHandlers

func (dva DelayedLockingAccount) RegisterQueryHandlers(builder *accountstd.QueryBuilder)

func (*DelayedLockingAccount) SendCoins

type PeriodicLockingAccount

type PeriodicLockingAccount struct {
	*BaseLockup
	StartTime      collections.Item[time.Time]
	LockingPeriods collections.Vec[lockuptypes.Period]
}

func NewPeriodicLockingAccount

func NewPeriodicLockingAccount(d accountstd.Dependencies) (*PeriodicLockingAccount, error)

NewPeriodicLockingAccount creates a new PeriodicLockingAccount object.

func (*PeriodicLockingAccount) Delegate

func (PeriodicLockingAccount) GetLockCoinInfoWithDenom

func (pva PeriodicLockingAccount) GetLockCoinInfoWithDenom(ctx context.Context, blockTime time.Time, denom string) (unlockedCoin, lockedCoin *sdk.Coin, err error)

GetLockCoinInfoWithDenom returns the total number of locked and unlocked coin for a specific denom.

func (PeriodicLockingAccount) GetLockCoinsInfo

func (pva PeriodicLockingAccount) GetLockCoinsInfo(ctx context.Context, blockTime time.Time) (unlockedCoins, lockedCoins sdk.Coins, err error)

GetLockCoinsInfo returns the total number of locked and unlocked coins.

func (PeriodicLockingAccount) GetLockedCoins

func (pva PeriodicLockingAccount) GetLockedCoins(ctx context.Context, blockTime time.Time) (sdk.Coins, error)

GetLockedCoins returns the total number of locked coins. If no coins are locked, nil is returned.

func (PeriodicLockingAccount) GetLockedCoinsWithDenoms

func (pva PeriodicLockingAccount) GetLockedCoinsWithDenoms(ctx context.Context, blockTime time.Time, denoms ...string) (sdk.Coins, error)

GetLockedCoinsWithDenoms returns the total number of locked coins. If no coins are locked, nil is returned.

func (PeriodicLockingAccount) IteratePeriods

func (pva PeriodicLockingAccount) IteratePeriods(
	ctx context.Context,
	cb func(value lockuptypes.Period) (bool, error),
) error

IteratePeriods iterates over all the Periods entries.

func (PeriodicLockingAccount) RegisterExecuteHandlers

func (pva PeriodicLockingAccount) RegisterExecuteHandlers(builder *accountstd.ExecuteBuilder)

func (PeriodicLockingAccount) RegisterInitHandler

func (pva PeriodicLockingAccount) RegisterInitHandler(builder *accountstd.InitBuilder)

Implement smart account interface

func (PeriodicLockingAccount) RegisterQueryHandlers

func (pva PeriodicLockingAccount) RegisterQueryHandlers(builder *accountstd.QueryBuilder)

func (*PeriodicLockingAccount) SendCoins

type PermanentLockingAccount

type PermanentLockingAccount struct {
	*BaseLockup
}

func NewPermanentLockingAccount

func NewPermanentLockingAccount(d accountstd.Dependencies) (*PermanentLockingAccount, error)

NewPermanentLockingAccount creates a new PermanentLockingAccount object.

func (*PermanentLockingAccount) Delegate

func (PermanentLockingAccount) GetlockedCoinsWithDenoms

func (plva PermanentLockingAccount) GetlockedCoinsWithDenoms(ctx context.Context, blockTime time.Time, denoms ...string) (sdk.Coins, error)

GetlockedCoinsWithDenoms returns the total number of locked coins. If no coins are locked, nil is returned.

func (PermanentLockingAccount) RegisterExecuteHandlers

func (plva PermanentLockingAccount) RegisterExecuteHandlers(builder *accountstd.ExecuteBuilder)

func (PermanentLockingAccount) RegisterInitHandler

func (plva PermanentLockingAccount) RegisterInitHandler(builder *accountstd.InitBuilder)

Implement smart account interface

func (PermanentLockingAccount) RegisterQueryHandlers

func (plva PermanentLockingAccount) RegisterQueryHandlers(builder *accountstd.QueryBuilder)

func (*PermanentLockingAccount) SendCoins

func (*PermanentLockingAccount) Undelegate

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL