6 "github.com/bytom/vapor/errors"
7 "github.com/bytom/vapor/protocol/bc"
11 // ErrAmountOfFeeOutOfRange represent The fee charged is out of range
12 ErrAmountOfFeeOutOfRange = errors.New("amount of fee is out of range")
15 // AllocatedAssets represent reallocated assets after calculating fees
16 type AllocatedAssets struct {
17 Receives []*bc.AssetAmount
18 Fees []*bc.AssetAmount
21 // FeeStrategy used to indicate how to charge a matching fee
22 type FeeStrategy interface {
23 // Allocate will allocate the price differential in matching transaction to the participants and the fee
24 // @param receiveAmounts the amount of assets that the participants in the matching transaction can received when no fee is considered
25 // @param priceDiffs price differential of matching transaction
26 // @return reallocated assets after calculating fees
27 Allocate(receiveAmounts, priceDiffs []*bc.AssetAmount) *AllocatedAssets
29 // Validate verify that the fee charged for a matching transaction is correct
30 Validate(receiveAmounts []*bc.AssetAmount, feeAmounts map[bc.AssetID]uint64) error
33 // DefaultFeeStrategy represent the default fee charge strategy
34 type DefaultFeeStrategy struct{}
36 // NewDefaultFeeStrategy return a new instance of DefaultFeeStrategy
37 func NewDefaultFeeStrategy() *DefaultFeeStrategy {
38 return &DefaultFeeStrategy{}
41 // Allocate will allocate the price differential in matching transaction to the participants and the fee
42 func (d *DefaultFeeStrategy) Allocate(receiveAmounts, priceDiffs []*bc.AssetAmount) *AllocatedAssets {
43 receives := make([]*bc.AssetAmount, len(receiveAmounts))
44 fees := make([]*bc.AssetAmount, len(receiveAmounts))
46 for i, receiveAmount := range receiveAmounts {
47 standFee := d.calcMinFeeAmount(receiveAmount.Amount)
48 fee := standFee + priceDiffs[i].Amount
49 if maxFeeAmount := d.calcMaxFeeAmount(receiveAmount.Amount); fee > maxFeeAmount {
53 receives[i] = &bc.AssetAmount{AssetId: receiveAmount.AssetId, Amount: receiveAmount.Amount - standFee}
54 fees[i] = &bc.AssetAmount{AssetId: receiveAmount.AssetId, Amount: fee}
56 return &AllocatedAssets{Receives: receives, Fees: fees}
59 // Validate verify that the fee charged for a matching transaction is correct
60 func (d *DefaultFeeStrategy) Validate(receiveAmounts []*bc.AssetAmount, feeAmounts map[bc.AssetID]uint64) error {
61 for _, receiveAmount := range receiveAmounts {
62 feeAmount := feeAmounts[*receiveAmount.AssetId]
63 maxFeeAmount := d.calcMaxFeeAmount(receiveAmount.Amount)
64 minFeeAmount := d.calcMinFeeAmount(receiveAmount.Amount)
65 if feeAmount < minFeeAmount || feeAmount > maxFeeAmount {
66 return ErrAmountOfFeeOutOfRange
72 func (d *DefaultFeeStrategy) calcMinFeeAmount(amount uint64) uint64 {
73 return uint64(math.Ceil(float64(amount) / 1000))
76 func (d *DefaultFeeStrategy) calcMaxFeeAmount(amount uint64) uint64 {
77 return uint64(math.Ceil(float64(amount) * 0.05))