-
Notifications
You must be signed in to change notification settings - Fork 2
/
supply.go
123 lines (110 loc) · 4.15 KB
/
supply.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
package chain
import (
"math/big"
"time"
"github.com/PositionExchange/posichain/consensus/engine"
"github.com/PositionExchange/posichain/consensus/reward"
"github.com/PositionExchange/posichain/numeric"
"github.com/PositionExchange/posichain/shard"
stakingReward "github.com/PositionExchange/posichain/staking/reward"
"github.com/ethereum/go-ethereum/common"
"github.com/pkg/errors"
)
// Circulating supply calculation
var (
// InaccessibleAddresses are a list of known eth addresses that cannot spend ONE tokens.
InaccessibleAddresses = []common.Address{
// one10000000000000000000000000000dead5shlag
common.HexToAddress("0x7bDeF7Bdef7BDeF7BDEf7bDef7bdef7bdeF6E7AD"),
}
)
// InaccessibleAddressInfo is the structure for inaccessible addresses
type InaccessibleAddressInfo struct {
EthAddress common.Address
Address string // One address
Balance numeric.Dec
Nonce uint64
}
// GetCirculatingSupply get the circulating supply.
// The value is the total circulating supply sub the tokens burnt at
// inaccessible addresses.
// WARNING: only works on beacon chain if in staking era.
func GetCirculatingSupply(chain engine.ChainReader) (numeric.Dec, error) {
total, err := getTotalCirculatingSupply(chain)
if err != nil {
return numeric.Dec{}, err
}
invalid, err := getAllInaccessibleTokens(chain)
if err != nil {
return numeric.Dec{}, err
}
if total.LT(invalid) {
return numeric.Dec{}, errors.New("FATAL: negative circulating supply")
}
return total.Sub(invalid), nil
}
// GetInaccessibleAddressInfo return the information of all inaccessible
// addresses.
func GetInaccessibleAddressInfo(chain engine.ChainReader) ([]*InaccessibleAddressInfo, error) {
return getAllInaccessibleAddresses(chain)
}
// GetInaccessibleTokens get the total inaccessible tokens.
// The amount is the sum of balance at all inaccessible addresses.
func GetInaccessibleTokens(chain engine.ChainReader) (numeric.Dec, error) {
return getAllInaccessibleTokens(chain)
}
// getTotalCirculatingSupply using the following formula:
// (TotalInitialTokens * percentReleased) + PreStakingBlockRewards + StakingBlockRewards
//
// Note that PreStakingBlockRewards is set to the amount of rewards given out by the
// LAST BLOCK of the pre-staking era regardless of what the current block height is
// if network is in the pre-staking era. This is for implementation reasons, reference
// stakingReward.GetTotalPreStakingTokens for more details.
func getTotalCirculatingSupply(chain engine.ChainReader) (ret numeric.Dec, err error) {
currHeader, timestamp := chain.CurrentHeader(), time.Now().Unix()
stakingBlockRewards := big.NewInt(0)
if chain.Config().IsStaking(currHeader.Epoch()) {
if chain.ShardID() != shard.BeaconChainShardID {
return numeric.Dec{}, stakingReward.ErrInvalidBeaconChain
}
if stakingBlockRewards, err = chain.ReadBlockRewardAccumulator(currHeader.Number().Uint64()); err != nil {
return numeric.Dec{}, err
}
}
releasedInitSupply := stakingReward.TotalInitialTokens.Mul(
reward.PercentageForTimeStamp(timestamp),
)
preStakingBlockRewards := stakingReward.GetTotalPreStakingTokens().Sub(stakingReward.TotalInitialTokens)
return releasedInitSupply.Add(preStakingBlockRewards).Add(
numeric.NewDecFromBigIntWithPrec(stakingBlockRewards, 18),
), nil
}
func getAllInaccessibleTokens(chain engine.ChainReader) (numeric.Dec, error) {
ais, err := getAllInaccessibleAddresses(chain)
if err != nil {
return numeric.Dec{}, err
}
total := numeric.NewDecFromBigIntWithPrec(big.NewInt(0), numeric.Precision)
for _, ai := range ais {
total = total.Add(ai.Balance)
}
return total, nil
}
func getAllInaccessibleAddresses(chain engine.ChainReader) ([]*InaccessibleAddressInfo, error) {
state, err := chain.StateAt(chain.CurrentHeader().Root())
if err != nil {
return nil, err
}
accs := make([]*InaccessibleAddressInfo, 0, len(InaccessibleAddresses))
for _, addr := range InaccessibleAddresses {
nonce := state.GetNonce(addr)
balance := state.GetBalance(addr)
accs = append(accs, &InaccessibleAddressInfo{
EthAddress: addr,
Address: addr.Hex(),
Balance: numeric.NewDecFromBigIntWithPrec(balance, numeric.Precision),
Nonce: nonce,
})
}
return accs, nil
}