Skip to content

Commit

Permalink
Merge pull request #185 from pegnet/develop
Browse files Browse the repository at this point in the history
PIP 10 implementation
  • Loading branch information
PaulSnow authored Apr 27, 2021
2 parents 08a0449 + a363943 commit 415ffa0
Show file tree
Hide file tree
Showing 17 changed files with 1,274 additions and 182 deletions.
21 changes: 11 additions & 10 deletions cmd/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@ import (
"text/tabwriter"
"time"

"github.com/pegnet/pegnet/modules/conversions"
"github.com/pegnet/pegnetd/node"

"github.com/Factom-Asset-Tokens/factom"
"github.com/pegnet/pegnetd/config"
"github.com/pegnet/pegnetd/fat/fat2"
"github.com/pegnet/pegnetd/node"

"github.com/pegnet/pegnetd/node/conversions"
"github.com/pegnet/pegnetd/node/pegnet"
"github.com/pegnet/pegnetd/srv"
"github.com/spf13/cobra"
Expand Down Expand Up @@ -350,8 +351,8 @@ var conv = &cobra.Command{

// Let's check the pXXX -> pFCT first
status := getStatus()
if (destAsset == "pFCT" || destAsset == "FCT") && uint32(status.Current) >= node.OneWaypFCTConversions {
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))
if (destAsset == "pFCT" || destAsset == "FCT") && uint32(status.Current) >= config.OneWaypFCTConversions {
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))
os.Exit(1)
}

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

Expand Down Expand Up @@ -793,7 +794,7 @@ var getBank = &cobra.Command{
cl := srv.NewClient()
cl.PegnetdServer = viper.GetString(config.Pegnetd)
var res pegnet.BankEntry
err = cl.Request("get-bank", srv.ParamsGetBank{Height: int32(height)}, &res)
err = cl.Request("get-bank", srv.ParamsGetBank{Height: int32(height)}, &res) //TODO: height should be uint32
if err != nil {
fmt.Printf("Failed to make RPC request\nDetails:\n%v\n", err)
os.Exit(1)
Expand Down Expand Up @@ -822,9 +823,9 @@ var getBank = &cobra.Command{
if err == nil {
fmt.Println("")
fmt.Println("Value in USD")
dAmt, _ := conversions.Convert(res.BankAmount, rates[fat2.PTickerPEG], rates[fat2.PTickerUSD])
dUsed, _ := conversions.Convert(res.BankUsed, rates[fat2.PTickerPEG], rates[fat2.PTickerUSD])
dReq, _ := conversions.Convert(res.PEGRequested, rates[fat2.PTickerPEG], rates[fat2.PTickerUSD])
dAmt, _ := conversions.Convert(uint32(height), res.BankAmount, rates[fat2.PTickerPEG], rates[fat2.PTickerPEG], rates[fat2.PTickerUSD], rates[fat2.PTickerUSD])
dUsed, _ := conversions.Convert(uint32(height), res.BankUsed, rates[fat2.PTickerPEG], rates[fat2.PTickerPEG], rates[fat2.PTickerUSD], rates[fat2.PTickerUSD])
dReq, _ := conversions.Convert(uint32(height), res.PEGRequested, rates[fat2.PTickerPEG], rates[fat2.PTickerPEG], rates[fat2.PTickerUSD], rates[fat2.PTickerUSD])
fmt.Printf("PEG in Bank : $%s\n", FactoshiToFactoid(dAmt))
fmt.Printf("PEG Consumed : $%s\n", FactoshiToFactoid(dUsed))
fmt.Printf("PEG Requested : $%s\n", FactoshiToFactoid(dReq))
Expand Down
4 changes: 2 additions & 2 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,12 +149,12 @@ func always(cmd *cobra.Command, args []string) {
}

// Set all activations for testing
node.SetAllActivations(uint32(act))
config.SetAllActivations(uint32(act))
}

if testingact, _ := cmd.Flags().GetInt32("testingact"); testingact >= 0 {
fat2.Fat2RCDEActivation = uint32(testingact)
node.V20HeightActivation = uint32(testingact)
config.V20HeightActivation = uint32(testingact)
// Also updaet hardfork
pegnet.Hardforks[1].ActivationHeight = uint32(testingact)
}
Expand Down
5 changes: 3 additions & 2 deletions cmd/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ import (
"fmt"
"strings"

"github.com/pegnet/pegnetd/config"

"github.com/spf13/cobra"

"github.com/Factom-Asset-Tokens/factom"
"github.com/pegnet/pegnetd/fat/fat2"
"github.com/pegnet/pegnetd/node"
)

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

// Sign the tx and make an entry
entry, err := txBatch.Sign(priv)
Expand Down
100 changes: 100 additions & 0 deletions config/activations.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package config

import (
"github.com/Factom-Asset-Tokens/factom"
"github.com/pegnet/pegnetd/fat/fat2"
)

var (
OPRChain = factom.NewBytes32("a642a8674f46696cc47fdb6b65f9c87b2a19c5ea8123b3d2f0c13b6f33a9d5ef")
SPRChain = factom.NewBytes32("d5e395125335a21cef0ceca528168e87fe929fdac1f156870c1b1be6502448b4")
TransactionChain = factom.NewBytes32("cffce0f409ebba4ed236d49d89c70e4bd1f1367d86402a3363366683265a242d")

// Acivation Heights

PegnetActivation uint32 = 206421
GradingV2Activation uint32 = 210330

// TransactionConversionActivation indicates when tx/conversions go live on mainnet.
// Target Activation Height is Oct 7, 2019 15 UTC
TransactionConversionActivation uint32 = 213237

// This is when PEG is priced by the market cap equation
// Estimated to be Oct 14 2019, 15:00:00 UTC
PEGPricingActivation uint32 = 214287

// OneWaypFCTConversions makes pFCT a 1 way conversion. This means pFCT->pXXX,
// but no asset can go into pFCT. AKA pXXX -/> pFCT.
// The only way to aquire pFCT is to burn FCT. The burn command will remain.
// Estimated to be Nov 25, 2019 17:47:00 UTC
OneWaypFCTConversions uint32 = 220346

// Once this is activated, a maximum amount of PEG of 5,000 can be
// converted per block. At a future height, a dynamic bank should be used.
// Estimated to be Dec 9, 2019, 17:00 UTC
PegnetConversionLimitActivation uint32 = 222270

// This is when PEG price is determined by the exchange price
// Estimated to be Dec 9, 2019, 17:00 UTC
PEGFreeFloatingPriceActivation uint32 = 222270

// V4OPRUpdate indicates the activation of additional currencies and ecdsa keys.
// Estimated to be Feb 12, 2020, 18:00 UTC
V4OPRUpdate uint32 = 231620

// V20HeightActivation indicates the activation of PegNet 2.0.
// Estimated to be Aug 19th 2020 14:00 UTC
V20HeightActivation uint32 = 258796

// Activation height for developer rewards
V20DevRewardsHeightActivation uint32 = 260118

// SprSignatureActivation indicates the activation of SPR Signature.
// Estimated to be Aug 28th 2020
SprSignatureActivation uint32 = 260118

// OneWaypAssetsConversions makes some pAssets a 1 way conversion.
// pDCR, pDGB, pDOGE, pHBAR, pONT, pRVN, pBAT, pALGO, pBIF, pETB, pKES, pNGN, pRWF, pTZS, pUGX
// These pAssets have got small marketcap, and these will be disabled for conversion.
// Estimated to be Dec 3th 2020
OneWaySmallAssetsConversions uint32 = 274036

// V202EnhanceActivation indicates the activation of PegNet 2.0.2.
// Estimated to be Dec 3th 2020
V202EnhanceActivation uint32 = 274036

// V204EnhanceActivation indicates the activation of PegNet 2.0.4.
// Estimated to be Mar 16th 2021
V204EnhanceActivation uint32 = 288878

// V204EnhanceActivation indicates the activation that burns remaining airdrop amount.
// Estimated to be April 16th 2021
V204BurnMintedTokenActivation uint32 = 294206

// PIP10AveragingActivation changes conversions to use the lesser of a rolling average and market price
// for the source of a conversion, and the higher of the rolling average and the market price for the
// target of a conversion
//
// Activation of 2.0.5
PIP10AverageActivation uint32 = 295190
)

func SetAllActivations(act uint32) {
PegnetActivation = act
GradingV2Activation = act
TransactionConversionActivation = act
PEGPricingActivation = act
OneWaypFCTConversions = act
PegnetConversionLimitActivation = act
PEGFreeFloatingPriceActivation = act
fat2.Fat2RCDEActivation = act
V4OPRUpdate = act
V20HeightActivation = act
V20DevRewardsHeightActivation = act
OneWaySmallAssetsConversions = act
SprSignatureActivation = act
V202EnhanceActivation = act
V204EnhanceActivation = act
V204BurnMintedTokenActivation = act
PIP10AverageActivation = act
}
111 changes: 111 additions & 0 deletions node/average.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package node

import (
"context"

"github.com/pegnet/pegnetd/fat/fat2"
)

var AveragePeriod = uint64(288) // Our Average Period is 2 days (144 10 minute blocks per day)
var AverageRequired = AveragePeriod / 2 // If we have at least half the rates, we can do conversions

// getPegNetRateAverages
// Gets all the rates for the AveragePeriod (the number of blocks contributing to the average), and computes
// the average rate for all assets. If values are missing for an asset for any of the blocks in the AveragePeriod,
// then don't allow conversions by setting the averate to zero for that asset
//
// Return a map of averages of the form map[fat2.PTicker]uint64
//
// Also note that if asked twice about the same height, we cache the response.
func (d *Pegnetd) GetPegNetRateAverages(ctx context.Context, height uint32) (Avg interface{}) {

if d.LastAveragesHeight == height { // If a cache hit is detected, return the cache value
return d.LastAverages
}

ratesOverPeriod := d.LastAveragesData // First collect all the values over the blocks
averages := map[fat2.PTicker]uint64{} // in the average period, then compute the averages
if ratesOverPeriod == nil { // If no map exists yet
ratesOverPeriod = map[fat2.PTicker][]uint64{} // create one.
}

defer func() { // Always set up the cache when exiting the routine
d.LastAveragesData = ratesOverPeriod // Save the data we used to create averages
d.LastAveragesHeight = height // Save the height of this data
d.LastAverages = averages // Save the averages we computed
}()

// collectRatesAtHeight
// This routine collects all the data used to compute an average. If any data is missing, then
// that data is represented by a zero.
collectRatesAtHeight := func(h uint32) {
for k := range ratesOverPeriod { // Make sure there is room for a new height
for len(ratesOverPeriod[k]) >= int(AveragePeriod) { // If at the limit or above,
copy(ratesOverPeriod[k], ratesOverPeriod[k][1:]) // Shift data down 1 element
ratesOverPeriod[k] = ratesOverPeriod[k][:len(ratesOverPeriod[k])-1] // And drop off the last value
}
}

if rates, err := d.Pegnet.SelectRates(ctx, h); err != nil { // Pull the rates out of the database at each
panic("no recovery from a database error getting rates")
} else {
for k, v := range rates { // For all the rates
if ratesOverPeriod[k] == nil { // if no rates yet, at a slice for them
ratesOverPeriod[k] = []uint64{} // Allocate the slice
}
ratesOverPeriod[k] = append(ratesOverPeriod[k], v) // Add the rates we find
}
}
}

switch {
// If the LastAveragesHeight is out of range given our current height, we just need to load
// all the values
case d.LastAveragesHeight+1 < height || d.LastAveragesHeight > height:
for k, v := range ratesOverPeriod {
if v != nil {
ratesOverPeriod[k] = ratesOverPeriod[k][:0]
}
}
startHeightS := int64(height) - (int64(AveragePeriod)) + 1 // startHeight is AveragePeriod before height+1
// (add 1 so the block at height is included)
if startHeightS < 1 { // If AveragePeriod blocks don't exist,
startHeightS = 1 // then flour the start to 1
}

startHeight := uint32(startHeightS)

for h := startHeight; h <= height; h++ { // Collect rates over the blocks (including height)
collectRatesAtHeight(h) // and add them to ratesOverPeriod
}

// If all we need is the next height, then only collect that height.
case d.LastAveragesHeight+1 == height:
collectRatesAtHeight(height) // Add the current height to the dataset so far
}

for k, v := range ratesOverPeriod { // The average rate is zero for any asset without
averages[k] = 0 // the number of required rates
if AveragePeriod-numberMissing(v) < AverageRequired { // Count the missing values, and if not enough
continue // skip it
}
for _, v2 := range v { // Sum up all the rates found for an asset
averages[k] += v2 // The assumption is that rates are no where near
} // 64 bits, so they won't overflow
averages[k] = averages[k] / uint64(len(v)) // Divide the sum of the rates by the number of rates
}

return averages // Return the rates we found.
}

func numberMissing(dataset []uint64) (numZeros uint64) {
for _, v := range dataset {
if v == 0 {
numZeros++
}
}
if len(dataset) < int(AveragePeriod) {
numZeros += AveragePeriod - uint64(len(dataset))
}
return numZeros
}
Loading

0 comments on commit 415ffa0

Please sign in to comment.