-
Notifications
You must be signed in to change notification settings - Fork 0
/
account.go
140 lines (116 loc) · 3.8 KB
/
account.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package types
import (
"fmt"
"github.com/tendermint/tendermint/crypto"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
)
// CustomAccount is customised to allow temporary freezing of coins to exclude them from transactions
type CustomAccount struct {
*auth.BaseAccount
FrozenCoins sdk.Coins `json:"coins" yaml:"coins"`
}
func NewCustomAccount(address sdk.AccAddress, coins sdk.Coins, frozenCoins sdk.Coins,
pubKey crypto.PubKey, accountNumber uint64, sequence uint64) *CustomAccount {
return &CustomAccount{
BaseAccount: &auth.BaseAccount{
Address: address,
Coins: coins,
PubKey: pubKey,
AccountNumber: accountNumber,
Sequence: sequence,
},
FrozenCoins: frozenCoins,
}
}
// String implements fmt.Stringer
func (acc CustomAccount) String() string {
var pubkey string
if acc.PubKey != nil {
pubkey = sdk.MustBech32ifyAccPub(acc.PubKey)
}
return fmt.Sprintf(`Account:
Address: %s
Pubkey: %s
Coins: %s
FrozenCoins: %s
AccountNumber: %d
Sequence: %d`,
acc.Address, pubkey, acc.Coins, acc.FrozenCoins, acc.AccountNumber, acc.Sequence,
)
}
// GetFrozenCoins retrieves frozen coins from account
func (acc *CustomAccount) GetFrozenCoins() sdk.Coins {
return acc.FrozenCoins
}
// SetFrozenCoins sets frozen coins for account
func (acc *CustomAccount) SetFrozenCoins(frozen sdk.Coins) error {
acc.FrozenCoins = frozen
return nil
}
func AreAnyCoinsZero(coins *sdk.Coins) bool {
for _, coin := range *coins {
if sdk.NewInt(0).Equal(coin.Amount) {
return true
}
}
return false
}
// FreezeCoins freezes unfrozen coins for account according to input
func (acc *CustomAccount) FreezeCoins(coinsToFreeze sdk.Coins) error {
// Have enough coins to freeze?
if coinsToFreeze == nil || coinsToFreeze.Empty() || coinsToFreeze.IsAnyNegative() || AreAnyCoinsZero(&coinsToFreeze) {
return sdk.ErrInvalidCoins("No coins chosen to freeze")
}
currentCoins := acc.GetCoins()
if currentCoins == nil || currentCoins.IsAllLT(coinsToFreeze) {
return sdk.ErrInvalidCoins("Not enough coins to freeze")
}
// Freeze coins
if newBalance, isNegative := currentCoins.SafeSub(coinsToFreeze); !isNegative {
if err := acc.SetCoins(newBalance); err != nil {
return sdk.ErrInvalidCoins(fmt.Sprintf("failed to set coins: %s", err))
}
} else {
return sdk.ErrInternal("failed to subtract coins for freezing")
}
frozen := acc.GetFrozenCoins()
if frozen == nil {
frozen = coinsToFreeze
} else {
frozen = frozen.Add(coinsToFreeze)
}
if err := acc.SetFrozenCoins(frozen); err != nil {
return sdk.ErrInvalidCoins(fmt.Sprintf("failed to set frozen coins: %s", err))
}
return nil
}
// UnfreezeCoins unfreezes frozen coins for account according to input
func (acc *CustomAccount) UnfreezeCoins(coinsToUnfreeze sdk.Coins) error {
// Have enough coins to unfreeze?
if coinsToUnfreeze == nil || coinsToUnfreeze.Empty() || coinsToUnfreeze.IsAnyNegative() {
return sdk.ErrInvalidCoins("No coins chosen to unfreeze")
}
currentlyFrozen := acc.GetFrozenCoins()
if currentlyFrozen == nil || currentlyFrozen.IsAllLT(coinsToUnfreeze) {
return sdk.ErrInvalidCoins("Not enough coins to unfreeze")
}
// Unfreeze coins
currentCoins := acc.GetCoins()
if currentCoins == nil {
currentCoins = coinsToUnfreeze
} else {
currentCoins = currentCoins.Add(coinsToUnfreeze)
}
if newFrozenBalance, isNegative := currentlyFrozen.SafeSub(coinsToUnfreeze); !isNegative {
if err := acc.SetFrozenCoins(newFrozenBalance); err != nil {
return sdk.ErrInvalidCoins(fmt.Sprintf("failed to set frozen coins: %s", err))
}
} else {
return sdk.ErrInternal("failed to subtract coins for unfreezing")
}
if err := acc.SetCoins(currentCoins); err != nil {
return sdk.ErrInvalidCoins(fmt.Sprintf("failed to set coins: %s", err))
}
return nil
}