Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Custom vesting curves #1

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
456 changes: 456 additions & 0 deletions docs/spec/vesting/01_state.md

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions docs/spec/vesting/02_messages.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Messages

The vesting module currently has no messages. All accounts must be created as part of a genesis event.
103 changes: 45 additions & 58 deletions x/auth/alias.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,45 +29,35 @@ const (

var (
// functions aliases
NewAnteHandler = ante.NewAnteHandler
GetSignerAcc = ante.GetSignerAcc
ValidateSigCount = ante.ValidateSigCount
ValidateMemo = ante.ValidateMemo
ProcessPubKey = ante.ProcessPubKey
DefaultSigVerificationGasConsumer = ante.DefaultSigVerificationGasConsumer
DeductFees = ante.DeductFees
EnsureSufficientMempoolFees = ante.EnsureSufficientMempoolFees
SetGasMeter = ante.SetGasMeter
GetSignBytes = ante.GetSignBytes
NewAccountKeeper = keeper.NewAccountKeeper
NewQuerier = keeper.NewQuerier
NewBaseAccount = types.NewBaseAccount
ProtoBaseAccount = types.ProtoBaseAccount
NewBaseAccountWithAddress = types.NewBaseAccountWithAddress
NewBaseVestingAccount = types.NewBaseVestingAccount
NewContinuousVestingAccountRaw = types.NewContinuousVestingAccountRaw
NewContinuousVestingAccount = types.NewContinuousVestingAccount
NewDelayedVestingAccountRaw = types.NewDelayedVestingAccountRaw
NewDelayedVestingAccount = types.NewDelayedVestingAccount
NewAccountRetriever = types.NewAccountRetriever
RegisterCodec = types.RegisterCodec
NewGenesisState = types.NewGenesisState
DefaultGenesisState = types.DefaultGenesisState
ValidateGenesis = types.ValidateGenesis
AddressStoreKey = types.AddressStoreKey
NewParams = types.NewParams
ParamKeyTable = types.ParamKeyTable
DefaultParams = types.DefaultParams
NewQueryAccountParams = types.NewQueryAccountParams
NewStdTx = types.NewStdTx
CountSubKeys = types.CountSubKeys
NewStdFee = types.NewStdFee
StdSignBytes = types.StdSignBytes
DefaultTxDecoder = types.DefaultTxDecoder
DefaultTxEncoder = types.DefaultTxEncoder
NewTxBuilder = types.NewTxBuilder
NewTxBuilderFromCLI = types.NewTxBuilderFromCLI
MakeSignature = types.MakeSignature
NewBaseAccount = types.NewBaseAccount
ProtoBaseAccount = types.ProtoBaseAccount
NewBaseAccountWithAddress = types.NewBaseAccountWithAddress
NewBaseVestingAccount = types.NewBaseVestingAccount
NewContinuousVestingAccountRaw = types.NewContinuousVestingAccountRaw
NewContinuousVestingAccount = types.NewContinuousVestingAccount
NewDelayedVestingAccountRaw = types.NewDelayedVestingAccountRaw
NewDelayedVestingAccount = types.NewDelayedVestingAccount
NewPeriodicVestingAccountRaw = types.NewPeriodicVestingAccountRaw
NewPeriodicVestingAccount = types.NewPeriodicVestingAccount
RegisterCodec = types.RegisterCodec
NewGenesisState = types.NewGenesisState
DefaultGenesisState = types.DefaultGenesisState
ValidateGenesis = types.ValidateGenesis
AddressStoreKey = types.AddressStoreKey
NewParams = types.NewParams
ParamKeyTable = types.ParamKeyTable
DefaultParams = types.DefaultParams
NewQueryAccountParams = types.NewQueryAccountParams
NewStdTx = types.NewStdTx
CountSubKeys = types.CountSubKeys
NewStdFee = types.NewStdFee
StdSignBytes = types.StdSignBytes
DefaultTxDecoder = types.DefaultTxDecoder
DefaultTxEncoder = types.DefaultTxEncoder
NewTxBuilder = types.NewTxBuilder
NewTxBuilderFromCLI = types.NewTxBuilderFromCLI
MakeSignature = types.MakeSignature
NewAccountRetriever = types.NewAccountRetriever

// variable aliases
ModuleCdc = types.ModuleCdc
Expand All @@ -81,23 +71,20 @@ var (
)

type (
SignatureVerificationGasConsumer = ante.SignatureVerificationGasConsumer
Account = exported.Account
VestingAccount = exported.VestingAccount
AccountKeeper = keeper.AccountKeeper
BaseAccount = types.BaseAccount
BaseVestingAccount = types.BaseVestingAccount
ContinuousVestingAccount = types.ContinuousVestingAccount
DelayedVestingAccount = types.DelayedVestingAccount
NodeQuerier = types.NodeQuerier
AccountRetriever = types.AccountRetriever
GenesisState = types.GenesisState
Params = types.Params
QueryAccountParams = types.QueryAccountParams
StdSignMsg = types.StdSignMsg
StdTx = types.StdTx
StdFee = types.StdFee
StdSignDoc = types.StdSignDoc
StdSignature = types.StdSignature
TxBuilder = types.TxBuilder
Account = exported.Account
VestingAccount = exported.VestingAccount
BaseAccount = types.BaseAccount
BaseVestingAccount = types.BaseVestingAccount
ContinuousVestingAccount = types.ContinuousVestingAccount
DelayedVestingAccount = types.DelayedVestingAccount
PeriodicVestingAccount = types.PeriodicVestingAccount
GenesisState = types.GenesisState
Params = types.Params
QueryAccountParams = types.QueryAccountParams
StdSignMsg = types.StdSignMsg
StdTx = types.StdTx
StdFee = types.StdFee
StdSignDoc = types.StdSignDoc
StdSignature = types.StdSignature
TxBuilder = types.TxBuilder
)
29 changes: 29 additions & 0 deletions x/auth/exported/exported.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package exported

import (
"time"
"fmt"
"strings"

"github.com/tendermint/tendermint/crypto"

Expand Down Expand Up @@ -56,4 +58,31 @@ type VestingAccount interface {
GetOriginalVesting() sdk.Coins
GetDelegatedFree() sdk.Coins
GetDelegatedVesting() sdk.Coins

GetVestingPeriods() VestingPeriods
}

// VestingPeriod defines a length of time and amount of coins that will vest
type VestingPeriod struct {
PeriodLength int64 // length of the period, in seconds
VestingAmount sdk.Coins // amount of coins vesting during this period
}

// VestingPeriods stores all vesting periods passed as part of a PeriodicVestingAccount
type VestingPeriods []VestingPeriod

// String VestingPeriod implements stringer interface
func (p VestingPeriod) String() string {
return fmt.Sprintf(`Period Length: %d
VestingAmount: %s`, p.PeriodLength, p.VestingAmount)
}

// String VestingPeriods implements stringer interface
func (vp VestingPeriods) String() string {
var periodsListString []string
for _, period := range vp {
periodsListString = append(periodsListString, period.String())
}
return strings.TrimSpace(fmt.Sprintf(`Vesting Periods:
%s`, strings.Join(periodsListString, ", ")))
}
159 changes: 159 additions & 0 deletions x/auth/types/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,160 @@ func (cva *ContinuousVestingAccount) GetEndTime() int64 {
return cva.EndTime
}

// GetVestingPeriods returns empty since a continuous vesting account has no vesting periods.
func (cva *ContinuousVestingAccount) GetVestingPeriods() exported.VestingPeriods {
return exported.VestingPeriods{}
}

//-----------------------------------------------------------------------------
// Continuous Vesting Account

var _ exported.VestingAccount = (*PeriodicVestingAccount)(nil)

// PeriodicVestingAccount implements the VestingAccount interface. It
// periodically vests by unlocking coins during each specified period
type PeriodicVestingAccount struct {
*ContinuousVestingAccount
VestingPeriods exported.VestingPeriods // the vesting schedule
}

// NewPeriodicVestingAccountRaw creates a new PeriodicVestingAccount object from BaseVestingAccount
func NewPeriodicVestingAccountRaw(bva *BaseVestingAccount,
startTime int64, periods exported.VestingPeriods) *PeriodicVestingAccount {

cva := &ContinuousVestingAccount{
StartTime: startTime,
BaseVestingAccount: bva,
}
return &PeriodicVestingAccount{
ContinuousVestingAccount: cva,
VestingPeriods: periods,
}
}

// NewPeriodicVestingAccount returns a new PeriodicVestingAccount
func NewPeriodicVestingAccount(
baseAcc *BaseAccount, StartTime int64, periods exported.VestingPeriods) *PeriodicVestingAccount {

endTime := StartTime
for _, p := range periods {
endTime += p.PeriodLength
}
baseVestingAcc := &BaseVestingAccount{
BaseAccount: baseAcc,
OriginalVesting: baseAcc.Coins,
EndTime: endTime,
}

cva := &ContinuousVestingAccount{
StartTime: StartTime,
BaseVestingAccount: baseVestingAcc,
}

return &PeriodicVestingAccount{
ContinuousVestingAccount: cva,
VestingPeriods: periods,
}
}

func (pva PeriodicVestingAccount) String() string {
var pubkey string

if pva.PubKey != nil {
pubkey = sdk.MustBech32ifyAccPub(pva.PubKey)
}

return fmt.Sprintf(`Periodic Vesting Account:
Address: %s
Pubkey: %s
Coins: %s
AccountNumber: %d
Sequence: %d
OriginalVesting: %s
DelegatedFree: %s
DelegatedVesting: %s
StartTime: %d
End Time: %d
VestingPeriods: %s `,
pva.Address, pubkey, pva.Coins, pva.AccountNumber, pva.Sequence,
pva.OriginalVesting, pva.DelegatedFree, pva.DelegatedVesting,
pva.StartTime, pva.EndTime, pva.VestingPeriods,
)
}

// GetVestedCoins returns the total number of vested coins. If no coins are vested,
// nil is returned.
func (pva PeriodicVestingAccount) GetVestedCoins(blockTime time.Time) sdk.Coins {
var vestedCoins sdk.Coins

// 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.
if blockTime.Unix() <= pva.StartTime {
return vestedCoins
} else if blockTime.Unix() >= pva.EndTime {
return pva.OriginalVesting
}

// track the start time of the next period
currentPeriodStartTime := pva.StartTime
numberPeriods := len(pva.VestingPeriods)
for i := 0; i < numberPeriods; i++ {
x := blockTime.Unix() - currentPeriodStartTime
// fmt.Printf(`Current Period: %v
// Current Period Start Time: %v
// Current value of x: %v
// Current Period Length: %v
// `, i, currentPeriodStartTime, x, pva.VestingPeriods[i].PeriodLength)
if x >= pva.VestingPeriods[i].PeriodLength {
// fmt.Printf(`
// Adding some coins for period %v
// `, i)
vestedCoins = vestedCoins.Add(pva.VestingPeriods[i].VestingAmount)
// Update the start time of the next period
currentPeriodStartTime += pva.VestingPeriods[i].PeriodLength
} else {
break
}
}
return vestedCoins
}

// GetVestingCoins returns the total number of vesting coins. If no coins are
// vesting, nil is returned.
func (pva PeriodicVestingAccount) GetVestingCoins(blockTime time.Time) sdk.Coins {
return pva.OriginalVesting.Sub(pva.GetVestedCoins(blockTime))
}

// SpendableCoins returns the total number of spendable coins per denom for a
// periodic vesting account.
func (pva PeriodicVestingAccount) SpendableCoins(blockTime time.Time) sdk.Coins {
return pva.spendableCoins(pva.GetVestingCoins(blockTime))
}

// TrackDelegation tracks a desired delegation amount by setting the appropriate
// values for the amount of delegated vesting, delegated free, and reducing the
// overall amount of base coins.
func (pva *PeriodicVestingAccount) TrackDelegation(blockTime time.Time, amount sdk.Coins) {
pva.trackDelegation(pva.GetVestingCoins(blockTime), amount)
}

// GetStartTime returns the time when vesting starts for a periodic vesting
// account.
func (pva *PeriodicVestingAccount) GetStartTime() int64 {
return pva.StartTime
}

// GetEndTime returns the time when vesting ends for a periodic vesting account.
func (pva *PeriodicVestingAccount) GetEndTime() int64 {
return pva.EndTime
}

// GetVestingPeriods returns vesting periods associated with periodic vesting account.
func (pva *PeriodicVestingAccount) GetVestingPeriods() exported.VestingPeriods {
return pva.VestingPeriods
}

//-----------------------------------------------------------------------------
// Delayed Vesting Account

Expand Down Expand Up @@ -535,3 +689,8 @@ func (dva *DelayedVestingAccount) GetStartTime() int64 {
func (dva *DelayedVestingAccount) GetEndTime() int64 {
return dva.EndTime
}

// GetVestingPeriods returns empty since a continuous vesting account has no vesting periods.
func (dva *DelayedVestingAccount) GetVestingPeriods() exported.VestingPeriods {
return exported.VestingPeriods{}
}
8 changes: 4 additions & 4 deletions x/auth/types/account_retriever_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
"github.com/cosmos/cosmos-sdk/tests/mocks"
)

var errFoo = errors.New("dummy")
var errDummy = errors.New("dummy")

func TestAccountRetriever(t *testing.T) {
mockCtrl := gomock.NewController(t)
Expand All @@ -23,18 +23,18 @@ func TestAccountRetriever(t *testing.T) {
require.NoError(t, err)

mockNodeQuerier.EXPECT().QueryWithData(gomock.Eq("custom/acc/account"),
gomock.Eq(bs)).Return(nil, int64(0), errFoo).Times(1)
gomock.Eq(bs)).Return(nil, int64(0), errDummy).Times(1)
_, err = accRetr.GetAccount(addr)
require.Error(t, err)

mockNodeQuerier.EXPECT().QueryWithData(gomock.Eq("custom/acc/account"),
gomock.Eq(bs)).Return(nil, int64(0), errFoo).Times(1)
gomock.Eq(bs)).Return(nil, int64(0), errDummy).Times(1)
n, s, err := accRetr.GetAccountNumberSequence(addr)
require.Error(t, err)
require.Equal(t, uint64(0), n)
require.Equal(t, uint64(0), s)

mockNodeQuerier.EXPECT().QueryWithData(gomock.Eq("custom/acc/account"),
gomock.Eq(bs)).Return(nil, int64(0), errFoo).Times(1)
gomock.Eq(bs)).Return(nil, int64(0), errDummy).Times(1)
require.Error(t, accRetr.EnsureExists(addr))
}
Loading