Skip to content

Commit 415ffa0

Browse files
authored
Merge pull request #185 from pegnet/develop
PIP 10 implementation
2 parents 08a0449 + a363943 commit 415ffa0

File tree

17 files changed

+1274
-182
lines changed

17 files changed

+1274
-182
lines changed

cmd/api.go

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,13 @@ import (
1313
"text/tabwriter"
1414
"time"
1515

16-
"github.com/pegnet/pegnet/modules/conversions"
16+
"github.com/pegnet/pegnetd/node"
1717

1818
"github.com/Factom-Asset-Tokens/factom"
1919
"github.com/pegnet/pegnetd/config"
2020
"github.com/pegnet/pegnetd/fat/fat2"
21-
"github.com/pegnet/pegnetd/node"
21+
22+
"github.com/pegnet/pegnetd/node/conversions"
2223
"github.com/pegnet/pegnetd/node/pegnet"
2324
"github.com/pegnet/pegnetd/srv"
2425
"github.com/spf13/cobra"
@@ -350,8 +351,8 @@ var conv = &cobra.Command{
350351

351352
// Let's check the pXXX -> pFCT first
352353
status := getStatus()
353-
if (destAsset == "pFCT" || destAsset == "FCT") && uint32(status.Current) >= node.OneWaypFCTConversions {
354-
cmd.PrintErrln(fmt.Sprintf("pXXX -> pFCT conversions are not allowed since block height %d. If you need to acquire pFCT, you have to burn FCT -> pFCT", node.OneWaypFCTConversions))
354+
if (destAsset == "pFCT" || destAsset == "FCT") && uint32(status.Current) >= config.OneWaypFCTConversions {
355+
cmd.PrintErrln(fmt.Sprintf("pXXX -> pFCT conversions are not allowed since block height %d. If you need to acquire pFCT, you have to burn FCT -> pFCT", config.OneWaypFCTConversions))
355356
os.Exit(1)
356357
}
357358

@@ -360,8 +361,8 @@ var conv = &cobra.Command{
360361
if (destAsset == "PEG" || destAsset == "pDCR" || destAsset == "pDGB" || destAsset == "pDOGE" || destAsset == "pHBAR" ||
361362
destAsset == "pONT" || destAsset == "pRVN" || destAsset == "pBAT" || destAsset == "pALGO" || destAsset == "pBIF" ||
362363
destAsset == "pETB" || destAsset == "pKES" || destAsset == "pNGN" || destAsset == "pRWF" || destAsset == "pTZS" ||
363-
destAsset == "pUGX") && uint32(status.Current) >= node.OneWaySmallAssetsConversions {
364-
cmd.PrintErrln(fmt.Sprintf("pXXX -> pSmallAssets conversions are not allowed since block height %d.", node.OneWaySmallAssetsConversions))
364+
destAsset == "pUGX") && uint32(status.Current) >= config.OneWaySmallAssetsConversions {
365+
cmd.PrintErrln(fmt.Sprintf("pXXX -> pSmallAssets conversions are not allowed since block height %d.", config.OneWaySmallAssetsConversions))
365366
os.Exit(1)
366367
}
367368

@@ -793,7 +794,7 @@ var getBank = &cobra.Command{
793794
cl := srv.NewClient()
794795
cl.PegnetdServer = viper.GetString(config.Pegnetd)
795796
var res pegnet.BankEntry
796-
err = cl.Request("get-bank", srv.ParamsGetBank{Height: int32(height)}, &res)
797+
err = cl.Request("get-bank", srv.ParamsGetBank{Height: int32(height)}, &res) //TODO: height should be uint32
797798
if err != nil {
798799
fmt.Printf("Failed to make RPC request\nDetails:\n%v\n", err)
799800
os.Exit(1)
@@ -822,9 +823,9 @@ var getBank = &cobra.Command{
822823
if err == nil {
823824
fmt.Println("")
824825
fmt.Println("Value in USD")
825-
dAmt, _ := conversions.Convert(res.BankAmount, rates[fat2.PTickerPEG], rates[fat2.PTickerUSD])
826-
dUsed, _ := conversions.Convert(res.BankUsed, rates[fat2.PTickerPEG], rates[fat2.PTickerUSD])
827-
dReq, _ := conversions.Convert(res.PEGRequested, rates[fat2.PTickerPEG], rates[fat2.PTickerUSD])
826+
dAmt, _ := conversions.Convert(uint32(height), res.BankAmount, rates[fat2.PTickerPEG], rates[fat2.PTickerPEG], rates[fat2.PTickerUSD], rates[fat2.PTickerUSD])
827+
dUsed, _ := conversions.Convert(uint32(height), res.BankUsed, rates[fat2.PTickerPEG], rates[fat2.PTickerPEG], rates[fat2.PTickerUSD], rates[fat2.PTickerUSD])
828+
dReq, _ := conversions.Convert(uint32(height), res.PEGRequested, rates[fat2.PTickerPEG], rates[fat2.PTickerPEG], rates[fat2.PTickerUSD], rates[fat2.PTickerUSD])
828829
fmt.Printf("PEG in Bank : $%s\n", FactoshiToFactoid(dAmt))
829830
fmt.Printf("PEG Consumed : $%s\n", FactoshiToFactoid(dUsed))
830831
fmt.Printf("PEG Requested : $%s\n", FactoshiToFactoid(dReq))

cmd/root.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,12 +149,12 @@ func always(cmd *cobra.Command, args []string) {
149149
}
150150

151151
// Set all activations for testing
152-
node.SetAllActivations(uint32(act))
152+
config.SetAllActivations(uint32(act))
153153
}
154154

155155
if testingact, _ := cmd.Flags().GetInt32("testingact"); testingact >= 0 {
156156
fat2.Fat2RCDEActivation = uint32(testingact)
157-
node.V20HeightActivation = uint32(testingact)
157+
config.V20HeightActivation = uint32(testingact)
158158
// Also updaet hardfork
159159
pegnet.Hardforks[1].ActivationHeight = uint32(testingact)
160160
}

cmd/tx.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@ import (
44
"fmt"
55
"strings"
66

7+
"github.com/pegnet/pegnetd/config"
8+
79
"github.com/spf13/cobra"
810

911
"github.com/Factom-Asset-Tokens/factom"
1012
"github.com/pegnet/pegnetd/fat/fat2"
11-
"github.com/pegnet/pegnetd/node"
1213
)
1314

1415
func addressRules(input string, output string) error {
@@ -67,7 +68,7 @@ func signAndSend(source string, tx *fat2.Transaction, cl *factom.Client, payment
6768
var txBatch fat2.TransactionBatch
6869
txBatch.Version = 1
6970
txBatch.Transactions = []fat2.Transaction{*tx}
70-
txBatch.Entry.ChainID = &node.TransactionChain
71+
txBatch.Entry.ChainID = &config.TransactionChain //TODO consider not passing a pointer to config.TransactionChain
7172

7273
// Sign the tx and make an entry
7374
entry, err := txBatch.Sign(priv)

config/activations.go

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
package config
2+
3+
import (
4+
"github.com/Factom-Asset-Tokens/factom"
5+
"github.com/pegnet/pegnetd/fat/fat2"
6+
)
7+
8+
var (
9+
OPRChain = factom.NewBytes32("a642a8674f46696cc47fdb6b65f9c87b2a19c5ea8123b3d2f0c13b6f33a9d5ef")
10+
SPRChain = factom.NewBytes32("d5e395125335a21cef0ceca528168e87fe929fdac1f156870c1b1be6502448b4")
11+
TransactionChain = factom.NewBytes32("cffce0f409ebba4ed236d49d89c70e4bd1f1367d86402a3363366683265a242d")
12+
13+
// Acivation Heights
14+
15+
PegnetActivation uint32 = 206421
16+
GradingV2Activation uint32 = 210330
17+
18+
// TransactionConversionActivation indicates when tx/conversions go live on mainnet.
19+
// Target Activation Height is Oct 7, 2019 15 UTC
20+
TransactionConversionActivation uint32 = 213237
21+
22+
// This is when PEG is priced by the market cap equation
23+
// Estimated to be Oct 14 2019, 15:00:00 UTC
24+
PEGPricingActivation uint32 = 214287
25+
26+
// OneWaypFCTConversions makes pFCT a 1 way conversion. This means pFCT->pXXX,
27+
// but no asset can go into pFCT. AKA pXXX -/> pFCT.
28+
// The only way to aquire pFCT is to burn FCT. The burn command will remain.
29+
// Estimated to be Nov 25, 2019 17:47:00 UTC
30+
OneWaypFCTConversions uint32 = 220346
31+
32+
// Once this is activated, a maximum amount of PEG of 5,000 can be
33+
// converted per block. At a future height, a dynamic bank should be used.
34+
// Estimated to be Dec 9, 2019, 17:00 UTC
35+
PegnetConversionLimitActivation uint32 = 222270
36+
37+
// This is when PEG price is determined by the exchange price
38+
// Estimated to be Dec 9, 2019, 17:00 UTC
39+
PEGFreeFloatingPriceActivation uint32 = 222270
40+
41+
// V4OPRUpdate indicates the activation of additional currencies and ecdsa keys.
42+
// Estimated to be Feb 12, 2020, 18:00 UTC
43+
V4OPRUpdate uint32 = 231620
44+
45+
// V20HeightActivation indicates the activation of PegNet 2.0.
46+
// Estimated to be Aug 19th 2020 14:00 UTC
47+
V20HeightActivation uint32 = 258796
48+
49+
// Activation height for developer rewards
50+
V20DevRewardsHeightActivation uint32 = 260118
51+
52+
// SprSignatureActivation indicates the activation of SPR Signature.
53+
// Estimated to be Aug 28th 2020
54+
SprSignatureActivation uint32 = 260118
55+
56+
// OneWaypAssetsConversions makes some pAssets a 1 way conversion.
57+
// pDCR, pDGB, pDOGE, pHBAR, pONT, pRVN, pBAT, pALGO, pBIF, pETB, pKES, pNGN, pRWF, pTZS, pUGX
58+
// These pAssets have got small marketcap, and these will be disabled for conversion.
59+
// Estimated to be Dec 3th 2020
60+
OneWaySmallAssetsConversions uint32 = 274036
61+
62+
// V202EnhanceActivation indicates the activation of PegNet 2.0.2.
63+
// Estimated to be Dec 3th 2020
64+
V202EnhanceActivation uint32 = 274036
65+
66+
// V204EnhanceActivation indicates the activation of PegNet 2.0.4.
67+
// Estimated to be Mar 16th 2021
68+
V204EnhanceActivation uint32 = 288878
69+
70+
// V204EnhanceActivation indicates the activation that burns remaining airdrop amount.
71+
// Estimated to be April 16th 2021
72+
V204BurnMintedTokenActivation uint32 = 294206
73+
74+
// PIP10AveragingActivation changes conversions to use the lesser of a rolling average and market price
75+
// for the source of a conversion, and the higher of the rolling average and the market price for the
76+
// target of a conversion
77+
//
78+
// Activation of 2.0.5
79+
PIP10AverageActivation uint32 = 295190
80+
)
81+
82+
func SetAllActivations(act uint32) {
83+
PegnetActivation = act
84+
GradingV2Activation = act
85+
TransactionConversionActivation = act
86+
PEGPricingActivation = act
87+
OneWaypFCTConversions = act
88+
PegnetConversionLimitActivation = act
89+
PEGFreeFloatingPriceActivation = act
90+
fat2.Fat2RCDEActivation = act
91+
V4OPRUpdate = act
92+
V20HeightActivation = act
93+
V20DevRewardsHeightActivation = act
94+
OneWaySmallAssetsConversions = act
95+
SprSignatureActivation = act
96+
V202EnhanceActivation = act
97+
V204EnhanceActivation = act
98+
V204BurnMintedTokenActivation = act
99+
PIP10AverageActivation = act
100+
}

node/average.go

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
package node
2+
3+
import (
4+
"context"
5+
6+
"github.com/pegnet/pegnetd/fat/fat2"
7+
)
8+
9+
var AveragePeriod = uint64(288) // Our Average Period is 2 days (144 10 minute blocks per day)
10+
var AverageRequired = AveragePeriod / 2 // If we have at least half the rates, we can do conversions
11+
12+
// getPegNetRateAverages
13+
// Gets all the rates for the AveragePeriod (the number of blocks contributing to the average), and computes
14+
// the average rate for all assets. If values are missing for an asset for any of the blocks in the AveragePeriod,
15+
// then don't allow conversions by setting the averate to zero for that asset
16+
//
17+
// Return a map of averages of the form map[fat2.PTicker]uint64
18+
//
19+
// Also note that if asked twice about the same height, we cache the response.
20+
func (d *Pegnetd) GetPegNetRateAverages(ctx context.Context, height uint32) (Avg interface{}) {
21+
22+
if d.LastAveragesHeight == height { // If a cache hit is detected, return the cache value
23+
return d.LastAverages
24+
}
25+
26+
ratesOverPeriod := d.LastAveragesData // First collect all the values over the blocks
27+
averages := map[fat2.PTicker]uint64{} // in the average period, then compute the averages
28+
if ratesOverPeriod == nil { // If no map exists yet
29+
ratesOverPeriod = map[fat2.PTicker][]uint64{} // create one.
30+
}
31+
32+
defer func() { // Always set up the cache when exiting the routine
33+
d.LastAveragesData = ratesOverPeriod // Save the data we used to create averages
34+
d.LastAveragesHeight = height // Save the height of this data
35+
d.LastAverages = averages // Save the averages we computed
36+
}()
37+
38+
// collectRatesAtHeight
39+
// This routine collects all the data used to compute an average. If any data is missing, then
40+
// that data is represented by a zero.
41+
collectRatesAtHeight := func(h uint32) {
42+
for k := range ratesOverPeriod { // Make sure there is room for a new height
43+
for len(ratesOverPeriod[k]) >= int(AveragePeriod) { // If at the limit or above,
44+
copy(ratesOverPeriod[k], ratesOverPeriod[k][1:]) // Shift data down 1 element
45+
ratesOverPeriod[k] = ratesOverPeriod[k][:len(ratesOverPeriod[k])-1] // And drop off the last value
46+
}
47+
}
48+
49+
if rates, err := d.Pegnet.SelectRates(ctx, h); err != nil { // Pull the rates out of the database at each
50+
panic("no recovery from a database error getting rates")
51+
} else {
52+
for k, v := range rates { // For all the rates
53+
if ratesOverPeriod[k] == nil { // if no rates yet, at a slice for them
54+
ratesOverPeriod[k] = []uint64{} // Allocate the slice
55+
}
56+
ratesOverPeriod[k] = append(ratesOverPeriod[k], v) // Add the rates we find
57+
}
58+
}
59+
}
60+
61+
switch {
62+
// If the LastAveragesHeight is out of range given our current height, we just need to load
63+
// all the values
64+
case d.LastAveragesHeight+1 < height || d.LastAveragesHeight > height:
65+
for k, v := range ratesOverPeriod {
66+
if v != nil {
67+
ratesOverPeriod[k] = ratesOverPeriod[k][:0]
68+
}
69+
}
70+
startHeightS := int64(height) - (int64(AveragePeriod)) + 1 // startHeight is AveragePeriod before height+1
71+
// (add 1 so the block at height is included)
72+
if startHeightS < 1 { // If AveragePeriod blocks don't exist,
73+
startHeightS = 1 // then flour the start to 1
74+
}
75+
76+
startHeight := uint32(startHeightS)
77+
78+
for h := startHeight; h <= height; h++ { // Collect rates over the blocks (including height)
79+
collectRatesAtHeight(h) // and add them to ratesOverPeriod
80+
}
81+
82+
// If all we need is the next height, then only collect that height.
83+
case d.LastAveragesHeight+1 == height:
84+
collectRatesAtHeight(height) // Add the current height to the dataset so far
85+
}
86+
87+
for k, v := range ratesOverPeriod { // The average rate is zero for any asset without
88+
averages[k] = 0 // the number of required rates
89+
if AveragePeriod-numberMissing(v) < AverageRequired { // Count the missing values, and if not enough
90+
continue // skip it
91+
}
92+
for _, v2 := range v { // Sum up all the rates found for an asset
93+
averages[k] += v2 // The assumption is that rates are no where near
94+
} // 64 bits, so they won't overflow
95+
averages[k] = averages[k] / uint64(len(v)) // Divide the sum of the rates by the number of rates
96+
}
97+
98+
return averages // Return the rates we found.
99+
}
100+
101+
func numberMissing(dataset []uint64) (numZeros uint64) {
102+
for _, v := range dataset {
103+
if v == 0 {
104+
numZeros++
105+
}
106+
}
107+
if len(dataset) < int(AveragePeriod) {
108+
numZeros += AveragePeriod - uint64(len(dataset))
109+
}
110+
return numZeros
111+
}

0 commit comments

Comments
 (0)