OSDN Git Service

fix fee (#523)
[bytom/vapor.git] / application / mov / match / fee_strategy.go
1 package match
2
3 import (
4         "math"
5
6         "github.com/bytom/vapor/errors"
7         "github.com/bytom/vapor/protocol/bc"
8 )
9
10 var (
11         // ErrAmountOfFeeOutOfRange represent The fee charged is out of range
12         ErrAmountOfFeeOutOfRange = errors.New("amount of fee is out of range")
13 )
14
15 // AllocatedAssets represent reallocated assets after calculating fees
16 type AllocatedAssets struct {
17         Receives []*bc.AssetAmount
18         Fees     []*bc.AssetAmount
19 }
20
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
28
29         // Validate verify that the fee charged for a matching transaction is correct
30         Validate(receiveAmounts []*bc.AssetAmount, feeAmounts map[bc.AssetID]uint64) error
31 }
32
33 // DefaultFeeStrategy represent the default fee charge strategy
34 type DefaultFeeStrategy struct{}
35
36 // NewDefaultFeeStrategy return a new instance of DefaultFeeStrategy
37 func NewDefaultFeeStrategy() *DefaultFeeStrategy {
38         return &DefaultFeeStrategy{}
39 }
40
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))
45
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 {
50                         fee = maxFeeAmount
51                 }
52
53                 receives[i] = &bc.AssetAmount{AssetId: receiveAmount.AssetId, Amount: receiveAmount.Amount - standFee}
54                 fees[i] = &bc.AssetAmount{AssetId: receiveAmount.AssetId, Amount: fee}
55         }
56         return &AllocatedAssets{Receives: receives, Fees: fees}
57 }
58
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
67                 }
68         }
69         return nil
70 }
71
72 func (d *DefaultFeeStrategy) calcMinFeeAmount(amount uint64) uint64 {
73         return uint64(math.Ceil(float64(amount) / 1000))
74 }
75
76 func (d *DefaultFeeStrategy) calcMaxFeeAmount(amount uint64) uint64 {
77         return uint64(math.Ceil(float64(amount) * 0.05))
78 }