OSDN Git Service

fix fee (#523)
authorPaladz <yzhu101@uottawa.ca>
Thu, 26 Mar 2020 01:49:34 +0000 (09:49 +0800)
committerGitHub <noreply@github.com>
Thu, 26 Mar 2020 01:49:34 +0000 (09:49 +0800)
* fix fee

* elegant the code

* handle edge case

* allow 5% fee

* fix typo

* fix typo

* edit back 5% fee

* add for fix

* fix ci

* elegant the code

* god bless us

* fix the overheader

* fix format

Co-authored-by: paladz <453256728@qq.com>
Co-authored-by: shenao78 <shenao.78@163.com>
application/mov/match/engine.go
application/mov/match/fee_strategy.go
application/mov/mock/mock.go

index 4e5a029..d332d75 100644 (file)
@@ -62,20 +62,44 @@ func (e *Engine) NextMatchedTx(tradePairs ...*common.TradePair) (*types.Tx, erro
        return tx, nil
 }
 
-func (e *Engine) addMatchTxFeeOutput(txData *types.TxData, refunds RefundAssets, fees []*bc.AssetAmount) error {
+func (e *Engine) addMatchTxFeeOutput(txData *types.TxData, fees []*bc.AssetAmount) error {
        for _, feeAmount := range fees {
                txData.Outputs = append(txData.Outputs, types.NewIntraChainOutput(*feeAmount.AssetId, feeAmount.Amount, e.rewardProgram))
        }
 
-       for i, refund := range refunds {
-               // each trading participant may be refunded multiple assets
-               for _, assetAmount := range refund {
-                       contractArgs, err := segwit.DecodeP2WMCProgram(txData.Inputs[i].ControlProgram())
-                       if err != nil {
-                               return err
-                       }
+       refoundAmount := map[bc.AssetID]uint64{}
+       assetIDs := []bc.AssetID{}
+       refoundScript := [][]byte{}
+       for _, input := range txData.Inputs {
+               refoundAmount[input.AssetID()] += input.Amount()
+               contractArgs, err := segwit.DecodeP2WMCProgram(input.ControlProgram())
+               if err != nil {
+                       return err
+               }
+
+               assetIDs = append(assetIDs, input.AssetID())
+               refoundScript = append(refoundScript, contractArgs.SellerProgram)
+       }
 
-                       txData.Outputs = append(txData.Outputs, types.NewIntraChainOutput(*assetAmount.AssetId, assetAmount.Amount, contractArgs.SellerProgram))
+       for _, output := range txData.Outputs {
+               assetAmount := output.AssetAmount()
+               refoundAmount[*assetAmount.AssetId] -= assetAmount.Amount
+       }
+
+       refoundCount := len(refoundScript)
+       for _, assetID := range assetIDs {
+               amount := refoundAmount[assetID]
+               averageAmount := amount / uint64(refoundCount)
+               if averageAmount == 0 {
+                       averageAmount = 1
+               }
+
+               for i := 0; i < refoundCount && amount > 0; i++ {
+                       if i == refoundCount-1 {
+                               averageAmount = amount
+                       }
+                       txData.Outputs = append(txData.Outputs, types.NewIntraChainOutput(assetID, averageAmount, refoundScript[i]))
+                       amount -= averageAmount
                }
        }
        return nil
@@ -110,7 +134,7 @@ func (e *Engine) buildMatchTx(orders []*common.Order) (*types.Tx, error) {
                return nil, err
        }
 
-       if err := e.addMatchTxFeeOutput(txData, allocatedAssets.Refunds, allocatedAssets.Fees); err != nil {
+       if err := e.addMatchTxFeeOutput(txData, allocatedAssets.Fees); err != nil {
                return nil, err
        }
 
@@ -140,8 +164,6 @@ func addMatchTxOutput(txData *types.TxData, orders []*common.Order, receivedAmou
                txData.Outputs = append(txData.Outputs, types.NewIntraChainOutput(*order.ToAssetID, allocatedAssets.Receives[i].Amount, contractArgs.SellerProgram))
                if isPartialTrade {
                        txData.Outputs = append(txData.Outputs, types.NewIntraChainOutput(*order.FromAssetID, exchangeAmount, order.Utxo.ControlProgram))
-               } else if exchangeAmount > 0 {
-                       allocatedAssets.Refunds.Add(i, *order.FromAssetID, exchangeAmount)
                }
        }
        return nil
@@ -184,10 +206,9 @@ func CalcReceivedAmount(orders []*common.Order) ([]*bc.AssetAmount, []*bc.AssetA
 
        for i, receivedAmount := range receivedAmounts {
                oppositeShouldPayAmount := shouldPayAmounts[calcOppositeIndex(len(orders), i)]
+               priceDiffs = append(priceDiffs, &bc.AssetAmount{AssetId: oppositeShouldPayAmount.AssetId, Amount: 0})
                if oppositeShouldPayAmount.Amount > receivedAmount.Amount {
-                       assetID := oppositeShouldPayAmount.AssetId
-                       amount := oppositeShouldPayAmount.Amount - receivedAmount.Amount
-                       priceDiffs = append(priceDiffs, &bc.AssetAmount{AssetId: assetID, Amount: amount})
+                       priceDiffs[i].Amount = oppositeShouldPayAmount.Amount - receivedAmount.Amount
                }
        }
        return receivedAmounts, priceDiffs
index 70a58a6..1d307a0 100644 (file)
@@ -15,28 +15,9 @@ var (
 // AllocatedAssets represent reallocated assets after calculating fees
 type AllocatedAssets struct {
        Receives []*bc.AssetAmount
-       Refunds  RefundAssets
        Fees     []*bc.AssetAmount
 }
 
-// RefundAssets represent alias for assetAmount array, because each transaction participant can be refunded multiple assets
-type RefundAssets [][]*bc.AssetAmount
-
-// Add used to add a refund to specify order
-func (r RefundAssets) Add(index int, asset bc.AssetID, amount uint64) {
-       if index >= len(r) {
-               index = 0
-       }
-
-       for _, assetAmount := range r[index] {
-               if *assetAmount.AssetId == asset {
-                       assetAmount.Amount += amount
-                       return
-               }
-       }
-       r[index] = append(r[index], &bc.AssetAmount{AssetId: &asset, Amount: amount})
-}
-
 // FeeStrategy used to indicate how to charge a matching fee
 type FeeStrategy interface {
        // Allocate will allocate the price differential in matching transaction to the participants and the fee
@@ -50,7 +31,7 @@ type FeeStrategy interface {
 }
 
 // DefaultFeeStrategy represent the default fee charge strategy
-type DefaultFeeStrategy struct {}
+type DefaultFeeStrategy struct{}
 
 // NewDefaultFeeStrategy return a new instance of DefaultFeeStrategy
 func NewDefaultFeeStrategy() *DefaultFeeStrategy {
@@ -59,46 +40,20 @@ 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 {
-       feeMap := make(map[bc.AssetID]uint64)
-       for _, priceDiff := range priceDiffs {
-               feeMap[*priceDiff.AssetId] = priceDiff.Amount
-       }
-
-       var fees []*bc.AssetAmount
-       refunds := make([][]*bc.AssetAmount, len(receiveAmounts))
        receives := make([]*bc.AssetAmount, len(receiveAmounts))
+       fees := make([]*bc.AssetAmount, len(receiveAmounts))
 
        for i, receiveAmount := range receiveAmounts {
-               amount := receiveAmount.Amount
-               minFeeAmount := d.calcMinFeeAmount(amount)
-               receives[i] = &bc.AssetAmount{AssetId: receiveAmount.AssetId, Amount: amount - minFeeAmount}
-               feeMap[*receiveAmount.AssetId] += minFeeAmount
-
-               maxFeeAmount := d.calcMaxFeeAmount(amount)
-               feeAmount, reminder := feeMap[*receiveAmount.AssetId], uint64(0)
-               if feeAmount > maxFeeAmount {
-                       reminder = feeAmount - maxFeeAmount
-                       feeAmount = maxFeeAmount
+               standFee := d.calcMinFeeAmount(receiveAmount.Amount)
+               fee := standFee + priceDiffs[i].Amount
+               if maxFeeAmount := d.calcMaxFeeAmount(receiveAmount.Amount); fee > maxFeeAmount {
+                       fee = maxFeeAmount
                }
 
-               fees = append(fees, &bc.AssetAmount{AssetId: receiveAmount.AssetId, Amount: feeAmount})
-
-               // There is the remaining amount after paying the handling fee, assign it evenly to participants in the transaction
-               averageAmount := reminder / uint64(len(receiveAmounts))
-               if averageAmount == 0 {
-                       averageAmount = 1
-               }
-
-               for j := 0; j < len(receiveAmounts) && reminder > 0; j++ {
-                       refundAmount := averageAmount
-                       if j == len(receiveAmounts)-1 {
-                               refundAmount = reminder
-                       }
-                       refunds[j] = append(refunds[j], &bc.AssetAmount{AssetId: receiveAmount.AssetId, Amount: refundAmount})
-                       reminder -= averageAmount
-               }
+               receives[i] = &bc.AssetAmount{AssetId: receiveAmount.AssetId, Amount: receiveAmount.Amount - standFee}
+               fees[i] = &bc.AssetAmount{AssetId: receiveAmount.AssetId, Amount: fee}
        }
-       return &AllocatedAssets{Receives: receives, Refunds: refunds, Fees: fees}
+       return &AllocatedAssets{Receives: receives, Fees: fees}
 }
 
 // Validate verify that the fee charged for a matching transaction is correct
index 46f0bcc..0b5da6c 100644 (file)
@@ -453,10 +453,10 @@ var (
                                types.NewIntraChainOutput(*Btc2EthOrders[0].ToAssetID, 25, RewardProgram),
                                types.NewIntraChainOutput(*Eth2BtcOrders[3].ToAssetID, 1, RewardProgram),
                                // refund
-                               types.NewIntraChainOutput(*Btc2EthOrders[0].ToAssetID, 38, testutil.MustDecodeHexString("0014f928b723999312df4ed51cb275a2644336c19251")),
                                types.NewIntraChainOutput(*Eth2BtcOrders[3].ToAssetID, 3, testutil.MustDecodeHexString("0014f928b723999312df4ed51cb275a2644336c19251")),
-                               types.NewIntraChainOutput(*Btc2EthOrders[0].ToAssetID, 38, testutil.MustDecodeHexString("0014f928b723999312df4ed51cb275a2644336c19256")),
                                types.NewIntraChainOutput(*Eth2BtcOrders[3].ToAssetID, 3, testutil.MustDecodeHexString("0014f928b723999312df4ed51cb275a2644336c19256")),
+                               types.NewIntraChainOutput(*Btc2EthOrders[0].ToAssetID, 38, testutil.MustDecodeHexString("0014f928b723999312df4ed51cb275a2644336c19251")),
+                               types.NewIntraChainOutput(*Btc2EthOrders[0].ToAssetID, 38, testutil.MustDecodeHexString("0014f928b723999312df4ed51cb275a2644336c19256")),
                        },
                }),
        }