)
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
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
}
// 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))
}