decred.org/dcrwallet/v3@v3.1.0/wallet/txrules/poolfees.go (about) 1 // Copyright (c) 2016 The Decred developers 2 // Use of this source code is governed by an ISC 3 // license that can be found in the LICENSE file. 4 5 package txrules 6 7 import ( 8 "math" 9 "math/big" 10 "sync" 11 12 blockchain "github.com/decred/dcrd/blockchain/standalone/v2" 13 "github.com/decred/dcrd/chaincfg/v3" 14 "github.com/decred/dcrd/dcrutil/v4" 15 ) 16 17 // ValidPoolFeeRate tests to see if a pool fee is a valid percentage from 18 // 0.01% to 100.00%. 19 func ValidPoolFeeRate(feeRate float64) bool { 20 poolFeeRateTest := feeRate * 100 21 poolFeeRateTest = math.Floor(poolFeeRateTest) 22 return poolFeeRateTest >= 1.0 && poolFeeRateTest <= 10000.0 23 } 24 25 var subsidyCache *blockchain.SubsidyCache 26 var initSubsidyCacheOnce sync.Once 27 28 // StakePoolTicketFee determines the stake pool ticket fee for a given ticket 29 // from the passed percentage. Pool fee as a percentage is truncated from 0.01% 30 // to 100.00%. This all must be done with integers, so bear with the big.Int 31 // usage below. 32 // 33 // See the included doc.go of this package for more information about the 34 // calculation of this fee. 35 func StakePoolTicketFee(stakeDiff dcrutil.Amount, relayFee dcrutil.Amount, 36 height int32, poolFee float64, params *chaincfg.Params, 37 dcp0010Active bool) dcrutil.Amount { 38 // Shift the decimal two places, e.g. 1.00% 39 // to 100. This assumes that the proportion 40 // is already multiplied by 100 to give a 41 // percentage, thus making the entirety 42 // be a multiplication by 10000. 43 poolFeeAbs := math.Floor(poolFee * 100.0) 44 poolFeeInt := int64(poolFeeAbs) 45 46 // Subsidy is fetched from the blockchain package, then 47 // pushed forward a number of adjustment periods for 48 // compensation in gradual subsidy decay. Recall that 49 // the average time to claiming 50% of the tickets as 50 // votes is the approximately the same as the ticket 51 // pool size (params.TicketPoolSize), so take the 52 // ceiling of the ticket pool size divided by the 53 // reduction interval. 54 adjs := int(math.Ceil(float64(params.TicketPoolSize) / 55 float64(params.SubsidyReductionInterval))) 56 initSubsidyCacheOnce.Do(func() { 57 subsidyCache = blockchain.NewSubsidyCache(params) 58 }) 59 subsidy := subsidyCache.CalcStakeVoteSubsidyV2(int64(height), 60 dcp0010Active) 61 for i := 0; i < adjs; i++ { 62 subsidy *= 100 63 subsidy /= 101 64 } 65 66 // The numerator is (p*10000*s*(v+z)) << 64. 67 shift := uint(64) 68 s := new(big.Int).SetInt64(subsidy) 69 v := new(big.Int).SetInt64(int64(stakeDiff)) 70 z := new(big.Int).SetInt64(int64(relayFee)) 71 num := new(big.Int).SetInt64(poolFeeInt) 72 num.Mul(num, s) 73 vPlusZ := new(big.Int).Add(v, z) 74 num.Mul(num, vPlusZ) 75 num.Lsh(num, shift) 76 77 // The denominator is 10000*(s+v). 78 // The extra 10000 above cancels out. 79 den := new(big.Int).Set(s) 80 den.Add(den, v) 81 den.Mul(den, new(big.Int).SetInt64(10000)) 82 83 // Divide and shift back. 84 num.Div(num, den) 85 num.Rsh(num, shift) 86 87 return dcrutil.Amount(num.Int64()) 88 }