cosmos-sdk/x/auth/spec/05_vesting.md

635 lines
18 KiB
Markdown
Raw Normal View History

Docs: hide frontmatter, bugfixes (#5413) * encoding * working on baseapp doc * baseapp work * reorg * almost there * finish first draft * remove old files * module doc start * finish intro * working * workinnn * add transactions into core * hans comments * add transactions into core * working * gautier comments * clean * working * consolidate intro * querier * workiiiing * refactor for new module interface * karoly review * working on baseapp doc * baseapp work * reorg * almost there * finish first draft * remove old files * finish intro * workinnn * initial commit after rebase * query-lifecycle and started modules-interfaces * query-lifecycle first draft done * module interfaces first draft * rest and intro skeletons * rest and intro done * small edits and links * comments * revisions * cli.md comments * comments * minor edits * better flow for query lifecycle * add transactions into core * hans comments * add transactions into core * checkout master-docs files * deleted some * remove modules readme * cli.md comments * comments * module-interfaces comments * Merge PR #4857: Add Context concept doc * working * working * finish messages and queries * handler * querier * last comments! * punctuation * querier2 * consolidate intro * querier * workiiiing * refactor for new module interface * karoly review * working on baseapp doc * baseapp work * reorg * almost there * finish first draft * remove old files * finish intro * workinnn * initial commit after rebase * query-lifecycle and started modules-interfaces * query-lifecycle first draft done * module interfaces first draft * rest and intro skeletons * rest and intro done * small edits and links * comments * revisions * cli.md comments * comments * minor edits * better flow for query lifecycle * checkout master-docs files * deleted some * remove modules readme * cli.md comments * comments * module-interfaces comments * keeper * genesis * finish * Apply suggestions from code review Co-Authored-By: Hans Schoenburg <hschoenburg@users.noreply.github.com> * hans review * Update docs/core/baseapp.md Co-Authored-By: Hans Schoenburg <hschoenburg@users.noreply.github.com> * working * last comment * workin * Apply suggestions from code review * encoding and node * almost finish store * finish docs * fixes * fede comments + permalinks * hans review * add more permalinks * update docs theme version (#5239) * R4R: Docs Cleanup (#5246) * start * work * work * work * remove table of content * links intro * fix links * remove junk * cleanup * cleanup * work * finish cleanup * addback readmes * remove nft * fix links * remove dup * remove dup * remove dup * remove dup * remove dup * fix links * add subscribe events * refine rest * index page * sidebar * theme version * theme version * testing netlify * theme version * tooltip example * version * testing code embedding * reverting back * theme version * version * version * version * readme and version * cleanup * redo app anatomy * modules readme, theme version * theme version * fix modules list * theme version * new snippets * modules readme * update docs readme * modify synopsis * version * fix yaml * version * version * version * version * version * version * version * version * version * version * add hide banner * version * version * version * small fixes * modules readme, version * remove hotkeys dep, version * version * version * version * version * version * version * version * slight notice * fix links and hide * permalinks * small clean * version * resolve conflicts, add google analytics * fix merge remants * version * changelog 1/2 * Changelog: docs UI * version * remove merge conflicts * Code: Update link for Contributing to the docs to docs_readme * HTML/CSS: Update layout of homepage footer to match new layout in Figma * version * final modifs * modules, version * modules readme * link to module list from homepage * version * building modules link * version * version * fonts * version * version * fix link * fix package.json * links in explore sdk section * core concepts * version * change delimeters for frontmatter * frontmatter in comments * version * temp add tiny-cookie * fixed link issues * fixed styling issues, copy * hide frontmatter * hide frontmatter * layout fixes, padded ascii diagram * fira sans font for code
2019-12-17 03:44:44 -08:00
<!--
Final updates for new docs website (#5388) * consolidate intro * start anatomy of sdk app * wokring * working * querier * working * workiiiing * finish * add dep and makefile * Apply suggestions from code review Co-Authored-By: Alessio Treglia <quadrispro@ubuntu.com> * typo * typo * Apply suggestions from code review Co-Authored-By: Alexander Bezobchuk <alexanderbez@users.noreply.github.com> Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Co-Authored-By: Alessio Treglia <quadrispro@ubuntu.com> Co-Authored-By: frog power 4000 <rigel.rozanski@gmail.com> * refactor for new module interface * karoly review * Apply suggestions from code review Co-Authored-By: Karoly Albert Szabo <szabo.karoly.a@gmail.com> Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * encoding * working on baseapp doc * baseapp work * reorg * almost there * finish first draft * remove old files * module doc start * finish intro * working * workinnn * add transactions into core * hans comments * add transactions into core * working * gautier comments * clean * working * consolidate intro * querier * workiiiing * refactor for new module interface * karoly review * working on baseapp doc * baseapp work * reorg * almost there * finish first draft * remove old files * finish intro * workinnn * initial commit after rebase * query-lifecycle and started modules-interfaces * query-lifecycle first draft done * module interfaces first draft * rest and intro skeletons * rest and intro done * small edits and links * comments * revisions * cli.md comments * comments * minor edits * better flow for query lifecycle * add transactions into core * hans comments * add transactions into core * checkout master-docs files * deleted some * remove modules readme * cli.md comments * comments * module-interfaces comments * Merge PR #4857: Add Context concept doc * working * working * finish messages and queries * handler * querier * last comments! * punctuation * querier2 * consolidate intro * querier * workiiiing * refactor for new module interface * karoly review * working on baseapp doc * baseapp work * reorg * almost there * finish first draft * remove old files * finish intro * workinnn * initial commit after rebase * query-lifecycle and started modules-interfaces * query-lifecycle first draft done * module interfaces first draft * rest and intro skeletons * rest and intro done * small edits and links * comments * revisions * cli.md comments * comments * minor edits * better flow for query lifecycle * checkout master-docs files * deleted some * remove modules readme * cli.md comments * comments * module-interfaces comments * keeper * genesis * finish * Apply suggestions from code review Co-Authored-By: Hans Schoenburg <hschoenburg@users.noreply.github.com> * hans review * Update docs/core/baseapp.md Co-Authored-By: Hans Schoenburg <hschoenburg@users.noreply.github.com> * working * last comment * workin * Apply suggestions from code review * encoding and node * almost finish store * finish docs * fixes * fede comments + permalinks * hans review * add more permalinks * update docs theme version (#5239) * R4R: Docs Cleanup (#5246) * start * work * work * work * remove table of content * links intro * fix links * remove junk * cleanup * cleanup * work * finish cleanup * addback readmes * remove nft * fix links * remove dup * remove dup * remove dup * remove dup * remove dup * fix links * add subscribe events * refine rest * index page * sidebar * theme version * theme version * testing netlify * theme version * tooltip example * version * testing code embedding * reverting back * theme version * version * version * version * readme and version * cleanup * redo app anatomy * modules readme, theme version * theme version * fix modules list * theme version * new snippets * modules readme * update docs readme * modify synopsis * version * fix yaml * version * version * version * version * version * version * version * version * version * version * add hide banner * version * version * version * small fixes * modules readme, version * remove hotkeys dep, version * version * version * version * version * version * version * version * slight notice * fix links and hide * permalinks * small clean * version * resolve conflicts, add google analytics * fix merge remants * version * changelog 1/2 * Changelog: docs UI * version * remove merge conflicts * Code: Update link for Contributing to the docs to docs_readme * HTML/CSS: Update layout of homepage footer to match new layout in Figma * version * final modifs * modules, version * modules readme * link to module list from homepage * version * building modules link * version * version * fonts * version * Update post.sh
2019-12-11 09:35:27 -08:00
order: 6
Docs: hide frontmatter, bugfixes (#5413) * encoding * working on baseapp doc * baseapp work * reorg * almost there * finish first draft * remove old files * module doc start * finish intro * working * workinnn * add transactions into core * hans comments * add transactions into core * working * gautier comments * clean * working * consolidate intro * querier * workiiiing * refactor for new module interface * karoly review * working on baseapp doc * baseapp work * reorg * almost there * finish first draft * remove old files * finish intro * workinnn * initial commit after rebase * query-lifecycle and started modules-interfaces * query-lifecycle first draft done * module interfaces first draft * rest and intro skeletons * rest and intro done * small edits and links * comments * revisions * cli.md comments * comments * minor edits * better flow for query lifecycle * add transactions into core * hans comments * add transactions into core * checkout master-docs files * deleted some * remove modules readme * cli.md comments * comments * module-interfaces comments * Merge PR #4857: Add Context concept doc * working * working * finish messages and queries * handler * querier * last comments! * punctuation * querier2 * consolidate intro * querier * workiiiing * refactor for new module interface * karoly review * working on baseapp doc * baseapp work * reorg * almost there * finish first draft * remove old files * finish intro * workinnn * initial commit after rebase * query-lifecycle and started modules-interfaces * query-lifecycle first draft done * module interfaces first draft * rest and intro skeletons * rest and intro done * small edits and links * comments * revisions * cli.md comments * comments * minor edits * better flow for query lifecycle * checkout master-docs files * deleted some * remove modules readme * cli.md comments * comments * module-interfaces comments * keeper * genesis * finish * Apply suggestions from code review Co-Authored-By: Hans Schoenburg <hschoenburg@users.noreply.github.com> * hans review * Update docs/core/baseapp.md Co-Authored-By: Hans Schoenburg <hschoenburg@users.noreply.github.com> * working * last comment * workin * Apply suggestions from code review * encoding and node * almost finish store * finish docs * fixes * fede comments + permalinks * hans review * add more permalinks * update docs theme version (#5239) * R4R: Docs Cleanup (#5246) * start * work * work * work * remove table of content * links intro * fix links * remove junk * cleanup * cleanup * work * finish cleanup * addback readmes * remove nft * fix links * remove dup * remove dup * remove dup * remove dup * remove dup * fix links * add subscribe events * refine rest * index page * sidebar * theme version * theme version * testing netlify * theme version * tooltip example * version * testing code embedding * reverting back * theme version * version * version * version * readme and version * cleanup * redo app anatomy * modules readme, theme version * theme version * fix modules list * theme version * new snippets * modules readme * update docs readme * modify synopsis * version * fix yaml * version * version * version * version * version * version * version * version * version * version * add hide banner * version * version * version * small fixes * modules readme, version * remove hotkeys dep, version * version * version * version * version * version * version * version * slight notice * fix links and hide * permalinks * small clean * version * resolve conflicts, add google analytics * fix merge remants * version * changelog 1/2 * Changelog: docs UI * version * remove merge conflicts * Code: Update link for Contributing to the docs to docs_readme * HTML/CSS: Update layout of homepage footer to match new layout in Figma * version * final modifs * modules, version * modules readme * link to module list from homepage * version * building modules link * version * version * fonts * version * version * fix link * fix package.json * links in explore sdk section * core concepts * version * change delimeters for frontmatter * frontmatter in comments * version * temp add tiny-cookie * fixed link issues * fixed styling issues, copy * hide frontmatter * hide frontmatter * layout fixes, padded ascii diagram * fira sans font for code
2019-12-17 03:44:44 -08:00
-->
Final updates for new docs website (#5388) * consolidate intro * start anatomy of sdk app * wokring * working * querier * working * workiiiing * finish * add dep and makefile * Apply suggestions from code review Co-Authored-By: Alessio Treglia <quadrispro@ubuntu.com> * typo * typo * Apply suggestions from code review Co-Authored-By: Alexander Bezobchuk <alexanderbez@users.noreply.github.com> Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Co-Authored-By: Alessio Treglia <quadrispro@ubuntu.com> Co-Authored-By: frog power 4000 <rigel.rozanski@gmail.com> * refactor for new module interface * karoly review * Apply suggestions from code review Co-Authored-By: Karoly Albert Szabo <szabo.karoly.a@gmail.com> Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * encoding * working on baseapp doc * baseapp work * reorg * almost there * finish first draft * remove old files * module doc start * finish intro * working * workinnn * add transactions into core * hans comments * add transactions into core * working * gautier comments * clean * working * consolidate intro * querier * workiiiing * refactor for new module interface * karoly review * working on baseapp doc * baseapp work * reorg * almost there * finish first draft * remove old files * finish intro * workinnn * initial commit after rebase * query-lifecycle and started modules-interfaces * query-lifecycle first draft done * module interfaces first draft * rest and intro skeletons * rest and intro done * small edits and links * comments * revisions * cli.md comments * comments * minor edits * better flow for query lifecycle * add transactions into core * hans comments * add transactions into core * checkout master-docs files * deleted some * remove modules readme * cli.md comments * comments * module-interfaces comments * Merge PR #4857: Add Context concept doc * working * working * finish messages and queries * handler * querier * last comments! * punctuation * querier2 * consolidate intro * querier * workiiiing * refactor for new module interface * karoly review * working on baseapp doc * baseapp work * reorg * almost there * finish first draft * remove old files * finish intro * workinnn * initial commit after rebase * query-lifecycle and started modules-interfaces * query-lifecycle first draft done * module interfaces first draft * rest and intro skeletons * rest and intro done * small edits and links * comments * revisions * cli.md comments * comments * minor edits * better flow for query lifecycle * checkout master-docs files * deleted some * remove modules readme * cli.md comments * comments * module-interfaces comments * keeper * genesis * finish * Apply suggestions from code review Co-Authored-By: Hans Schoenburg <hschoenburg@users.noreply.github.com> * hans review * Update docs/core/baseapp.md Co-Authored-By: Hans Schoenburg <hschoenburg@users.noreply.github.com> * working * last comment * workin * Apply suggestions from code review * encoding and node * almost finish store * finish docs * fixes * fede comments + permalinks * hans review * add more permalinks * update docs theme version (#5239) * R4R: Docs Cleanup (#5246) * start * work * work * work * remove table of content * links intro * fix links * remove junk * cleanup * cleanup * work * finish cleanup * addback readmes * remove nft * fix links * remove dup * remove dup * remove dup * remove dup * remove dup * fix links * add subscribe events * refine rest * index page * sidebar * theme version * theme version * testing netlify * theme version * tooltip example * version * testing code embedding * reverting back * theme version * version * version * version * readme and version * cleanup * redo app anatomy * modules readme, theme version * theme version * fix modules list * theme version * new snippets * modules readme * update docs readme * modify synopsis * version * fix yaml * version * version * version * version * version * version * version * version * version * version * add hide banner * version * version * version * small fixes * modules readme, version * remove hotkeys dep, version * version * version * version * version * version * version * version * slight notice * fix links and hide * permalinks * small clean * version * resolve conflicts, add google analytics * fix merge remants * version * changelog 1/2 * Changelog: docs UI * version * remove merge conflicts * Code: Update link for Contributing to the docs to docs_readme * HTML/CSS: Update layout of homepage footer to match new layout in Figma * version * final modifs * modules, version * modules readme * link to module list from homepage * version * building modules link * version * version * fonts * version * Update post.sh
2019-12-11 09:35:27 -08:00
2018-11-01 15:13:40 -07:00
# Vesting
- [Vesting](#vesting)
- [Intro and Requirements](#intro-and-requirements)
2020-01-30 13:31:16 -08:00
- [Note](#note)
2018-11-01 15:13:40 -07:00
- [Vesting Account Types](#vesting-account-types)
- [Vesting Account Specification](#vesting-account-specification)
- [Determining Vesting & Vested Amounts](#determining-vesting--vested-amounts)
- [Continuously Vesting Accounts](#continuously-vesting-accounts)
2020-01-30 13:31:16 -08:00
- [Periodic Vesting Accounts](#periodic-vesting-accounts)
2018-11-01 15:13:40 -07:00
- [Delayed/Discrete Vesting Accounts](#delayeddiscrete-vesting-accounts)
- [Transferring/Sending](#transferringsending)
- [Keepers/Handlers](#keepershandlers)
2018-11-01 15:13:40 -07:00
- [Delegating](#delegating)
- [Keepers/Handlers](#keepershandlers-1)
2018-11-01 15:13:40 -07:00
- [Undelegating](#undelegating)
- [Keepers/Handlers](#keepershandlers-2)
2018-11-01 15:13:40 -07:00
- [Keepers & Handlers](#keepers--handlers)
- [Genesis Initialization](#genesis-initialization)
2018-11-01 15:13:40 -07:00
- [Examples](#examples)
- [Simple](#simple)
- [Slashing](#slashing)
2020-01-30 13:31:16 -08:00
- [Periodic Vesting](#periodic-vesting)
2018-11-01 15:13:40 -07:00
- [Glossary](#glossary)
## Intro and Requirements
This specification defines the vesting account implementation that is used by
the Cosmos Hub. The requirements for this vesting account is that it should be
initialized during genesis with a starting balance `X` and a vesting end
time `ET`. A vesting account may be initialized with a vesting start time `ST`
and a number of vesting periods `P`. If a vesting start time is included, the
vesting period will not begin until start time is reached. If vesting periods
are included, the vesting will occur over the specified number of periods.
For all vesting accounts, the owner of the vesting account is able to delegate
and undelegate from validators, however they cannot transfer coins to another
account until those coins are vested. This specification allows for three
different kinds of vesting:
- Delayed vesting, where all coins are vested once `ET` is reached.
- Continous vesting, where coins begin to vest at `ST` and vest linearly with
respect to time until `ET` is reached
- Periodic vesting, where coins begin to vest at `ST` and vest periodically
according to number of periods and the vesting amount per period.
The number of periods, length per period, and amount per period are
configurable. A periodic vesting account is distinguished from a continuous
vesting account in that coins can be released in staggered tranches. For
example, a periodic vesting account could be used for vesting arrangements
where coins are relased quarterly, yearly, or over any other function of
tokens over time.
## Note
Vesting accounts can be initialized with some vesting and non-vesting coins.
The non-vesting coins would be immediately transferable. The current
specification does not allow for vesting accounts to be created with normal
messages after genesis. All vesting accounts must be created at genesis, or as
part of a manual network upgrade. The current specification only allows
for _unconditional_ vesting (ie. there is no possibility of reaching `ET` and
having coins fail to vest).
2018-11-01 15:13:40 -07:00
## Vesting Account Types
2018-07-27 18:35:21 -07:00
```go
2018-11-01 15:13:40 -07:00
// VestingAccount defines an interface that any vesting account type must
// implement.
2018-07-31 18:11:19 -07:00
type VestingAccount interface {
2020-01-30 13:31:16 -08:00
Account
2018-11-01 15:13:40 -07:00
2020-01-30 13:31:16 -08:00
GetVestedCoins(Time) Coins
GetVestingCoins(Time) Coins
2020-01-30 13:31:16 -08:00
// TrackDelegation performs internal vesting accounting necessary when
// delegating from a vesting account. It accepts the current block time, the
// delegation amount and balance of all coins whose denomination exists in
// the account's original vesting balance.
TrackDelegation(Time, Coins, Coins)
2020-01-30 13:31:16 -08:00
// TrackUndelegation performs internal vesting accounting necessary when a
// vesting account performs an undelegation.
TrackUndelegation(Coins)
GetStartTime() int64
GetEndTime() int64
2018-11-01 15:13:40 -07:00
}
// BaseVestingAccount implements the VestingAccount interface. It contains all
// the necessary fields needed for any vesting account implementation.
type BaseVestingAccount struct {
2020-01-30 13:31:16 -08:00
BaseAccount
2018-08-07 17:02:28 -07:00
2020-01-30 13:31:16 -08:00
OriginalVesting Coins // coins in account upon initialization
DelegatedFree Coins // coins that are vested and delegated
DelegatedVesting Coins // coins that vesting and delegated
2020-01-30 13:31:16 -08:00
EndTime int64 // when the coins become unlocked
2018-07-27 18:35:21 -07:00
}
2018-11-01 15:13:40 -07:00
// ContinuousVestingAccount implements the VestingAccount interface. It
// continuously vests by unlocking coins linearly with respect to time.
2018-07-31 18:11:19 -07:00
type ContinuousVestingAccount struct {
2020-01-30 13:31:16 -08:00
BaseVestingAccount
2020-01-30 13:31:16 -08:00
StartTime int64 // when the coins start to vest
2018-07-31 18:11:19 -07:00
}
2018-07-27 18:35:21 -07:00
2018-11-01 15:13:40 -07:00
// DelayedVestingAccount implements the VestingAccount interface. It vests all
// coins after a specific time, but non prior. In other words, it keeps them
// locked until a specified time.
type DelayedVestingAccount struct {
2020-01-30 13:31:16 -08:00
BaseVestingAccount
2018-11-01 15:13:40 -07:00
}
// VestingPeriod defines a length of time and amount of coins that will vest
type Period struct {
Length int64 // length of the period, in seconds
Amount Coins // amount of coins vesting during this period
}
// Stores all vesting periods passed as part of a PeriodicVestingAccount
type Periods []Period
// PeriodicVestingAccount implements the VestingAccount interface. It
// periodically vests by unlocking coins during each specified period
type PeriodicVestingAccount struct {
BaseVestingAccount
StartTime int64
Periods Periods // the vesting schedule
}
2018-11-01 15:13:40 -07:00
```
2018-08-15 13:54:03 -07:00
In order to facilitate less ad-hoc type checking and assertions and to support
2020-01-30 13:31:16 -08:00
flexibility in account balance usage, the existing `x/bank` `ViewKeeper` interface
is updated to contain the following:
```go
2020-01-30 13:31:16 -08:00
type ViewKeeper interface {
// ...
2020-01-30 13:31:16 -08:00
// Calculates the total locked account balance.
LockedCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins
// Calculates the total spendable balance that can be sent to other accounts.
SpendableCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins
}
```
2018-11-01 15:13:40 -07:00
## Vesting Account Specification
2018-08-15 13:54:03 -07:00
2018-11-01 15:13:40 -07:00
Given a vesting account, we define the following in the proceeding operations:
2018-11-01 15:13:40 -07:00
- `OV`: The original vesting coin amount. It is a constant value.
- `V`: The number of `OV` coins that are still _vesting_. It is derived by
`OV`, `StartTime` and `EndTime`. This value is computed on demand and not on a
per-block basis.
- `V'`: The number of `OV` coins that are _vested_ (unlocked). This value is
computed on demand and not a per-block basis.
- `DV`: The number of delegated _vesting_ coins. It is a variable value. It is
stored and modified directly in the vesting account.
- `DF`: The number of delegated _vested_ (unlocked) coins. It is a variable
value. It is stored and modified directly in the vesting account.
- `BC`: The number of `OV` coins less any coins that are transferred
(which can be negative or delegated). It is considered to be balance of the
embedded base account. It is stored and modified directly in the vesting account.
2018-11-01 15:13:40 -07:00
### Determining Vesting & Vested Amounts
It is important to note that these values are computed on demand and not on a
mandatory per-block basis (e.g. `BeginBlocker` or `EndBlocker`).
2018-11-01 15:13:40 -07:00
#### Continuously Vesting Accounts
To determine the amount of coins that are vested for a given block time `T`, the
2018-11-01 15:13:40 -07:00
following is performed:
1. Compute `X := T - StartTime`
2018-11-01 15:13:40 -07:00
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 _vesting_.
```go
func (cva ContinuousVestingAccount) GetVestedCoins(t Time) Coins {
if t <= cva.StartTime {
// We must handle the case where the start time for a vesting account has
// been set into the future or when the start of the chain is not exactly
// known.
2018-11-01 15:13:40 -07:00
return ZeroCoins
} else if t >= cva.EndTime {
return cva.OriginalVesting
2018-11-01 15:13:40 -07:00
}
x := t - cva.StartTime
2018-11-01 15:13:40 -07:00
y := cva.EndTime - cva.StartTime
return cva.OriginalVesting * (x / y)
}
func (cva ContinuousVestingAccount) GetVestingCoins(t Time) Coins {
return cva.OriginalVesting - cva.GetVestedCoins(t)
2018-11-01 15:13:40 -07:00
}
2018-07-31 18:11:19 -07:00
```
2018-07-27 18:35:21 -07:00
### Periodic Vesting Accounts
Periodic vesting 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'`
```go
func (pva PeriodicVestingAccount) GetVestedCoins(t Time) Coins {
if t < pva.StartTime {
return ZeroCoins
}
ct := pva.StartTime // The start of the vesting schedule
vested := 0
periods = pva.GetPeriods()
for _, period := range periods {
if t - ct < period.Length {
break
}
vested += period.Amount
ct += period.Length // increment ct to the start of the next vesting period
}
return vested
}
func (pva PeriodicVestingAccount) GetVestingCoins(t Time) Coins {
return pva.OriginalVesting - cva.GetVestedCoins(t)
}
```
2018-11-01 15:13:40 -07:00
#### Delayed/Discrete Vesting Accounts
Delayed vesting accounts are easier to reason about as they only have the full
amount vesting up until a certain time, then all the coins become vested (unlocked).
This does not include any unlocked coins the account may have initially.
2018-07-27 18:35:21 -07:00
2018-07-31 18:11:19 -07:00
```go
func (dva DelayedVestingAccount) GetVestedCoins(t Time) Coins {
if t >= dva.EndTime {
2018-11-01 15:13:40 -07:00
return dva.OriginalVesting
}
return ZeroCoins
}
func (dva DelayedVestingAccount) GetVestingCoins(t Time) Coins {
return dva.OriginalVesting - dva.GetVestedCoins(t)
2018-11-01 15:13:40 -07:00
}
2018-07-31 18:11:19 -07:00
```
2018-07-27 18:35:21 -07:00
2018-11-01 15:13:40 -07:00
### Transferring/Sending
At any given time, a vesting account may transfer: `min((BC + DV) - V, BC)`.
2018-07-27 18:35:21 -07:00
2018-11-01 15:13:40 -07:00
In other words, a vesting account may transfer the minimum of the base account
balance and the base account balance plus the number of currently delegated
vesting coins less the number of coins vested so far.
2020-01-30 13:31:16 -08:00
However, given that account balances are tracked via the `x/bank` module and that
we want to avoid loading the entire account balance, we can instead determine
the locked balance, which can be defined as `max(V - DV, 0)`, and infer the
spendable balance from that.
```go
2020-01-30 13:31:16 -08:00
func (va VestingAccount) LockedCoins(t Time) Coins {
return max(va.GetVestingCoins(t) - va.DelegatedVesting, 0)
}
```
The `x/bank` `ViewKeeper` can then provide APIs to determine locked and spendable
coins for any account:
```go
func (k Keeper) LockedCoins(ctx Context, addr AccAddress) Coins {
acc := k.GetAccount(ctx, addr)
if acc != nil {
if acc.IsVesting() {
return acc.LockedCoins(ctx.BlockTime())
}
}
// non-vesting accounts do not have any locked coins
return NewCoins()
2018-11-01 15:13:40 -07:00
}
```
#### Keepers/Handlers
2018-07-31 18:11:19 -07:00
2018-11-01 15:13:40 -07:00
The corresponding `x/bank` keeper should appropriately handle sending coins
based on if the account is a vesting account or not.
2018-07-27 18:35:21 -07:00
2018-11-01 15:13:40 -07:00
```go
2020-01-30 13:31:16 -08:00
func (k Keeper) SendCoins(ctx Context, from Account, to Account, amount Coins) {
bc := k.GetBalances(ctx, from)
v := k.LockedCoins(ctx, from)
2020-01-30 13:31:16 -08:00
spendable := bc - v
newCoins := spendable - amount
assert(newCoins >= 0)
2020-01-30 13:31:16 -08:00
from.SetBalance(newCoins)
to.AddBalance(amount)
2020-01-30 13:31:16 -08:00
// save balances...
2018-11-01 15:13:40 -07:00
}
```
2018-07-27 18:35:21 -07:00
2018-11-01 15:13:40 -07:00
### Delegating
For a vesting account attempting to delegate `D` coins, the following is performed:
2018-11-01 15:13:40 -07:00
1. Verify `BC >= D > 0`
2. Compute `X := min(max(V - DV, 0), D)` (portion of `D` that is vesting)
3. Compute `Y := D - X` (portion of `D` that is free)
4. Set `DV += X`
5. Set `DF += Y`
2018-07-29 19:29:54 -07:00
```go
2020-01-30 13:31:16 -08:00
func (va VestingAccount) TrackDelegation(t Time, balance Coins, amount Coins) {
assert(balance <= amount)
x := min(max(va.GetVestingCoins(t) - va.DelegatedVesting, 0), amount)
2018-11-01 15:13:40 -07:00
y := amount - x
va.DelegatedVesting += x
va.DelegatedFree += y
2018-07-29 19:29:54 -07:00
}
2018-11-01 15:13:40 -07:00
```
**Note** `TrackDelegation` only modifies the `DelegatedVesting` and `DelegatedFree`
fields, so upstream callers MUST modify the `Coins` field by subtracting `amount`.
#### Keepers/Handlers
2018-11-01 15:13:40 -07:00
```go
func DelegateCoins(t Time, from Account, amount Coins) {
if isVesting(from) {
from.TrackDelegation(t, amount)
2018-11-01 15:13:40 -07:00
} else {
2020-01-30 13:31:16 -08:00
from.SetBalance(sc - amount)
2018-11-01 15:13:40 -07:00
}
// save account...
2018-11-01 15:13:40 -07:00
}
2018-07-29 19:29:54 -07:00
```
2018-11-01 15:13:40 -07:00
### Undelegating
For a vesting account attempting to undelegate `D` coins, the following is performed:
NOTE: `DV < D` and `(DV + DF) < D` may be possible due to quirks in the rounding of
delegation/undelegation logic.
1. Verify `D > 0`
2. Compute `X := min(DF, D)` (portion of `D` that should become free, prioritizing free coins)
3. Compute `Y := min(DV, D - X)` (portion of `D` that should remain vesting)
4. Set `DF -= X`
5. Set `DV -= Y`
2018-11-01 15:13:40 -07:00
```go
func (cva ContinuousVestingAccount) TrackUndelegation(amount Coins) {
x := min(cva.DelegatedFree, amount)
y := amount - x
cva.DelegatedFree -= x
cva.DelegatedVesting -= y
2018-11-01 15:13:40 -07:00
}
```
**Note** `TrackUnDelegation` only modifies the `DelegatedVesting` and `DelegatedFree`
fields, so upstream callers MUST modify the `Coins` field by adding `amount`.
2018-11-01 15:13:40 -07:00
**Note**: If a delegation is slashed, the continuous vesting account will end up
with an excess `DV` amount, even after all its coins have vested. This is because
2018-11-01 15:13:40 -07:00
undelegating free coins are prioritized.
**Note**: The undelegation (bond refund) amount may exceed the delegated
vesting (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.
#### Keepers/Handlers
2018-11-01 15:13:40 -07:00
```go
func UndelegateCoins(to Account, amount Coins) {
if isVesting(to) {
if to.DelegatedFree + to.DelegatedVesting >= amount {
to.TrackUndelegation(amount)
// save account ...
}
} else {
2020-01-30 13:31:16 -08:00
AddBalance(to, amount)
2018-11-01 15:13:40 -07:00
// save account...
}
}
```
## Keepers & Handlers
The `VestingAccount` implementations reside in `x/auth`. However, any keeper in
2019-01-11 12:08:01 -08:00
a module (e.g. staking in `x/staking`) wishing to potentially utilize any vesting
2018-11-01 15:13:40 -07:00
coins, must call explicit methods on the `x/bank` keeper (e.g. `DelegateCoins`)
opposed to `SendCoins` and `SubtractCoins`.
In addition, the vesting account should also be able to spend any coins it
receives from other users. Thus, the bank module's `MsgSend` handler should
error if a vesting account is trying to send an amount that exceeds their
unlocked coin amount.
2018-11-01 15:13:40 -07:00
See the above specification for full implementation details.
2018-08-07 17:02:28 -07:00
## Genesis Initialization
2018-11-01 15:13:40 -07:00
To initialize both vesting and non-vesting accounts, the `GenesisAccount` struct will
include new fields: `Vesting`, `StartTime`, and `EndTime`. Accounts meant to be
of type `BaseAccount` or any non-vesting type will have `Vesting = false`. The
genesis initialization logic (e.g. `initFromGenesisState`) will have to parse
and return the correct accounts accordingly based off of these new fields.
2018-11-01 15:13:40 -07:00
```go
type GenesisAccount struct {
// ...
// vesting account fields
OriginalVesting sdk.Coins `json:"original_vesting"`
DelegatedFree sdk.Coins `json:"delegated_free"`
DelegatedVesting sdk.Coins `json:"delegated_vesting"`
StartTime int64 `json:"start_time"`
EndTime int64 `json:"end_time"`
2018-11-01 15:13:40 -07:00
}
func ToAccount(gacc GenesisAccount) Account {
bacc := NewBaseAccount(gacc)
2018-11-01 15:13:40 -07:00
if gacc.OriginalVesting > 0 {
if ga.StartTime != 0 && ga.EndTime != 0 {
// return a continuous vesting account
} else if ga.EndTime != 0 {
// return a delayed vesting account
2018-11-01 15:13:40 -07:00
} else {
// invalid genesis vesting account provided
panic()
2018-11-01 15:13:40 -07:00
}
}
return bacc
2018-11-01 15:13:40 -07:00
}
```
## Examples
### Simple
Given a continuous vesting account with 10 vesting coins.
```
OV = 10
DF = 0
DV = 0
BC = 10
V = 10
V' = 0
```
2018-11-01 15:13:40 -07:00
1. Immediately receives 1 coin
```
2018-11-01 15:13:40 -07:00
BC = 11
```
2018-11-01 15:13:40 -07:00
2. Time passes, 2 coins vest
```
2018-11-01 15:13:40 -07:00
V = 8
V' = 2
```
2018-11-01 15:13:40 -07:00
3. Delegates 4 coins to validator A
```
2018-11-01 15:13:40 -07:00
DV = 4
BC = 7
```
2018-11-01 15:13:40 -07:00
4. Sends 3 coins
```
2018-11-01 15:13:40 -07:00
BC = 4
```
2018-11-01 15:13:40 -07:00
5. More time passes, 2 more coins vest
```
2018-11-01 15:13:40 -07:00
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.
```
2018-11-01 15:13:40 -07:00
BC = 2
```
### Slashing
Same initial starting conditions as the simple example.
1. Time passes, 5 coins vest
```
2018-11-01 15:13:40 -07:00
V = 5
V' = 5
```
2018-11-01 15:13:40 -07:00
2. Delegate 5 coins to validator A
```
2018-11-01 15:13:40 -07:00
DV = 5
BC = 5
```
2018-11-01 15:13:40 -07:00
3. Delegate 5 coins to validator B
```
2018-11-01 15:13:40 -07:00
DF = 5
BC = 0
```
2018-11-01 15:13:40 -07:00
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)
```
2018-11-01 15:13:40 -07:00
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.
```
2018-11-01 15:13:40 -07:00
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`.
2018-11-01 15:13:40 -07:00
### Periodic Vesting
A vesting account is created where 100 tokens will be released over 1 year, with
1/4 of tokens vesting each quarter. The vesting schedule would be as follows:
```yaml
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. Vesting period 1 passes, 25 coins vest
```
V = 75
V' = 25
```
3. During vesting period 2, 5 coins are transfered and 5 coins are delegated
```
DV = 5
BC = 91
```
4. Vesting period 2 passes, 25 coins vest
```
V = 50
V' = 50
```
2018-11-01 15:13:40 -07:00
## Glossary
- OriginalVesting: The amount of coins (per denomination) that are initially
part of a vesting account. These coins are set at genesis.
2018-11-01 15:13:40 -07:00
- StartTime: The BFT time at which a vesting account starts to vest.
- EndTime: The BFT time at which a vesting account is fully vested.
- DelegatedFree: The tracked amount of coins (per denomination) that are
delegated from a vesting account that have been fully vested at time of delegation.
- DelegatedVesting: The tracked amount of coins (per denomination) that are
delegated from a vesting account that were vesting at time of delegation.
- ContinuousVestingAccount: A vesting account implementation that vests coins
linearly over time.
- DelayedVestingAccount: A vesting account implementation that only fully vests
all coins at a given time.
- PeriodicVestingAccount: A vesting account implementation that vests coins
according to a custom vesting schedule.