X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;ds=sidebyside;f=application%2Fmov%2Fmatch%2Ffee_strategy.go;h=3d0de99d4c28ea3dec0c31d9321f8c1b05d44c2b;hb=HEAD;hp=1d307a0b544efd6063bd1c1d7b5fb5bc1ed436b2;hpb=feca8c7b2ce797e4df5131e5405706f6d5899fe2;p=bytom%2Fvapor.git diff --git a/application/mov/match/fee_strategy.go b/application/mov/match/fee_strategy.go index 1d307a0b..3d0de99d 100644 --- a/application/mov/match/fee_strategy.go +++ b/application/mov/match/fee_strategy.go @@ -8,10 +8,12 @@ import ( ) var ( - // ErrAmountOfFeeOutOfRange represent The fee charged is out of range - ErrAmountOfFeeOutOfRange = errors.New("amount of fee is out of range") + // ErrInvalidAmountOfFee represent The fee charged is invalid + ErrInvalidAmountOfFee = errors.New("amount of fee is invalid") ) +const forkBlockHeightAt20201028 = 78968400 + // AllocatedAssets represent reallocated assets after calculating fees type AllocatedAssets struct { Receives []*bc.AssetAmount @@ -22,12 +24,11 @@ type AllocatedAssets struct { type FeeStrategy interface { // Allocate will allocate the price differential in matching transaction to the participants and the fee // @param receiveAmounts the amount of assets that the participants in the matching transaction can received when no fee is considered - // @param priceDiffs price differential of matching transaction // @return reallocated assets after calculating fees - Allocate(receiveAmounts, priceDiffs []*bc.AssetAmount) *AllocatedAssets + Allocate(receiveAmounts, priceDiffs []*bc.AssetAmount, takerPos int) *AllocatedAssets // Validate verify that the fee charged for a matching transaction is correct - Validate(receiveAmounts []*bc.AssetAmount, feeAmounts map[bc.AssetID]uint64) error + Validate(receiveAmounts, priceDiffs []*bc.AssetAmount, feeAmounts map[bc.AssetID]uint64, blockHeight uint64) error } // DefaultFeeStrategy represent the default fee charge strategy @@ -39,40 +40,84 @@ func NewDefaultFeeStrategy() *DefaultFeeStrategy { } // Allocate will allocate the price differential in matching transaction to the participants and the fee -func (d *DefaultFeeStrategy) Allocate(receiveAmounts, priceDiffs []*bc.AssetAmount) *AllocatedAssets { +func (d *DefaultFeeStrategy) Allocate(receiveAmounts, priceDiffs []*bc.AssetAmount, takerPos int) *AllocatedAssets { receives := make([]*bc.AssetAmount, len(receiveAmounts)) fees := make([]*bc.AssetAmount, len(receiveAmounts)) for i, receiveAmount := range receiveAmounts { - standFee := d.calcMinFeeAmount(receiveAmount.Amount) - fee := standFee + priceDiffs[i].Amount - if maxFeeAmount := d.calcMaxFeeAmount(receiveAmount.Amount); fee > maxFeeAmount { - fee = maxFeeAmount - } - - receives[i] = &bc.AssetAmount{AssetId: receiveAmount.AssetId, Amount: receiveAmount.Amount - standFee} + fee := calcMinFeeAmount(receiveAmount.Amount) + receives[i] = &bc.AssetAmount{AssetId: receiveAmount.AssetId, Amount: receiveAmount.Amount - fee} fees[i] = &bc.AssetAmount{AssetId: receiveAmount.AssetId, Amount: fee} + + if i == takerPos { + for _, priceDiff := range priceDiffs { + if *priceDiff.AssetId == *receiveAmount.AssetId { + fee = calcMinFeeAmount(priceDiff.Amount) + priceDiff.Amount -= fee + fees[i].Amount += fee + } + } + } } return &AllocatedAssets{Receives: receives, Fees: fees} } // Validate verify that the fee charged for a matching transaction is correct -func (d *DefaultFeeStrategy) Validate(receiveAmounts []*bc.AssetAmount, feeAmounts map[bc.AssetID]uint64) error { +func (d *DefaultFeeStrategy) Validate(receiveAmounts, priceDiffs []*bc.AssetAmount, feeAmounts map[bc.AssetID]uint64, blockHeight uint64) error { + if blockHeight < forkBlockHeightAt20201028 { + return legendValidateFee(receiveAmounts, feeAmounts) + } + return validateFee(receiveAmounts, priceDiffs, feeAmounts) +} + +func validateFee(receiveAmounts, priceDiffs []*bc.AssetAmount, feeAmounts map[bc.AssetID]uint64) error { + existTaker := false + for _, receiveAmount := range receiveAmounts { + feeAmount := calcMinFeeAmount(receiveAmount.Amount) + realFeeAmount := feeAmounts[*receiveAmount.AssetId] + if equalsFeeAmount(realFeeAmount, feeAmount) { + continue + } + + if existTaker { + return ErrInvalidAmountOfFee + } + + for _, priceDiff := range priceDiffs { + if *priceDiff.AssetId == *receiveAmount.AssetId { + feeAmount += calcMinFeeAmount(priceDiff.Amount) + } + } + + if !equalsFeeAmount(realFeeAmount, feeAmount) { + return ErrInvalidAmountOfFee + } + existTaker = true + } + return nil +} + +func equalsFeeAmount(realFeeAmount, feeAmount uint64) bool { + var tolerance float64 = 5 + return math.Abs(float64(realFeeAmount)-float64(feeAmount)) < tolerance +} + +func legendValidateFee(receiveAmounts []*bc.AssetAmount, feeAmounts map[bc.AssetID]uint64) error { for _, receiveAmount := range receiveAmounts { - feeAmount := feeAmounts[*receiveAmount.AssetId] - maxFeeAmount := d.calcMaxFeeAmount(receiveAmount.Amount) - minFeeAmount := d.calcMinFeeAmount(receiveAmount.Amount) - if feeAmount < minFeeAmount || feeAmount > maxFeeAmount { - return ErrAmountOfFeeOutOfRange + realFeeAmount := feeAmounts[*receiveAmount.AssetId] + minFeeAmount := calcMinFeeAmount(receiveAmount.Amount) + maxFeeAmount := calcMaxFeeAmount(receiveAmount.Amount) + if realFeeAmount < minFeeAmount || realFeeAmount > maxFeeAmount { + return ErrInvalidAmountOfFee } } return nil } -func (d *DefaultFeeStrategy) calcMinFeeAmount(amount uint64) uint64 { +func calcMinFeeAmount(amount uint64) uint64 { return uint64(math.Ceil(float64(amount) / 1000)) } -func (d *DefaultFeeStrategy) calcMaxFeeAmount(amount uint64) uint64 { +func calcMaxFeeAmount(amount uint64) uint64 { return uint64(math.Ceil(float64(amount) * 0.05)) }